diff --git a/blask/blaskapp.py b/blask/blaskapp.py index 8826822..17ecedb 100644 --- a/blask/blaskapp.py +++ b/blask/blaskapp.py @@ -16,9 +16,10 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from werkzeug.utils import safe_join -from flask import Flask, render_template, request, abort, Response +from flask import Flask, Response, abort, render_template, request from flask_wtf import CSRFProtect +from werkzeug.utils import safe_join + from blask.blasksettings import BlaskSettings from blask.blogrenderer import BlogRenderer from blask.errors import PageNotExistError @@ -47,28 +48,28 @@ def __init__(self, **kwargs): template_folder=self.settings["templateDir"], static_folder=self.settings["staticDir"], ) - + self.csrf = CSRFProtect() self.csrf.init_app(self.app) self.app.add_url_rule( - "/", endpoint="index", view_func=self._index, methods=["GET"]) - self.app.add_url_rule( - "/sitemap.xml", view_func=self._get_sitemap, methods=["GET"]) - self.app.add_url_rule( - "/", view_func=self._getpage, methods=["GET"]) - self.app.add_url_rule( - "//", - view_func=self._get_subpage, methods=["GET"]) + "/", endpoint="index", view_func=self._index, methods=["GET"] + ) self.app.add_url_rule( - "/tag/", view_func=self._gettag, methods=["GET"]) + "/sitemap.xml", view_func=self._get_sitemap, methods=["GET"] + ) + self.app.add_url_rule("/", view_func=self._getpage, methods=["GET"]) self.app.add_url_rule( - "/search", view_func=self.searchpages, methods=["POST"]) + "//", view_func=self._get_subpage, methods=["GET"] + ) + self.app.add_url_rule("/tag/", view_func=self._gettag, methods=["GET"]) + self.app.add_url_rule("/search", view_func=self.searchpages, methods=["POST"]) self.app.add_url_rule( - "/category/", - view_func=self._getcategory, methods=["GET"]) + "/category/", view_func=self._getcategory, methods=["GET"] + ) self.app.add_url_rule( - "/author/", view_func=self._getauthor, methods=["GET"]) + "/author/", view_func=self._getauthor, methods=["GET"] + ) # Register the error handler for each setting for error in self.settings["errors"].keys(): self.app.register_error_handler(error, f=self._handle_http_errors) @@ -83,7 +84,8 @@ def _index(self): if template is None: template = self.settings["defaultLayout"] return render_template( - template, title=self.settings["title"], content=entry.content) + template, title=self.settings["title"], content=entry.content + ) def _getpage(self, filename): """ @@ -129,7 +131,8 @@ def _get_sitemap(self): """ return Response( self.blogrenderer.generate_sitemap_xml( - self.settings["postDir"], request.url_root), + self.settings["postDir"], request.url_root + ), content_type="text/xml", ) @@ -144,7 +147,7 @@ def _gettag(self, tag): return render_template( self.settings["defaultLayout"], title=self.settings["title"], - content=content + content=content, ) def searchpages(self): @@ -157,7 +160,7 @@ def searchpages(self): return render_template( self.settings["defaultLayout"], title=self.settings["title"], - content=content + content=content, ) def _getcategory(self, category): @@ -171,7 +174,7 @@ def _getcategory(self, category): return render_template( self.settings["defaultLayout"], title=self.settings["title"], - content=content + content=content, ) def _getauthor(self, author): @@ -185,7 +188,7 @@ def _getauthor(self, author): return render_template( self.settings["defaultLayout"], title=self.settings["title"], - content=content + content=content, ) def _handle_http_errors(self, error_message): diff --git a/blask/blaskcli.py b/blask/blaskcli.py index 53a2c5f..ef9c356 100644 --- a/blask/blaskcli.py +++ b/blask/blaskcli.py @@ -16,12 +16,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from os import makedirs, path, getcwd -from pathlib import Path import shutil -from pkg_resources import get_distribution, DistributionNotFound +from os import getcwd, makedirs, path +from pathlib import Path import typer +from pkg_resources import DistributionNotFound, get_distribution from blask import BlaskApp, blasksettings @@ -33,15 +33,15 @@ class CLIController: Class that controls all the Command Line interface application """ - default_template_file = str(LIB_DIR / 'index_template.html') + default_template_file = str(LIB_DIR / "index_template.html") - default_index = str(LIB_DIR / 'markdown_template.md') + default_index = str(LIB_DIR / "markdown_template.md") - settings = str(LIB_DIR / 'default_env.env') + settings = str(LIB_DIR / "default_env.env") - not_found = str(LIB_DIR / 'default_404.md') + not_found = str(LIB_DIR / "default_404.md") - docker_template = str(LIB_DIR / 'Dockerfile_template') + docker_template = str(LIB_DIR / "Dockerfile_template") def createdefaultindexfile(self, filepath): """ @@ -61,7 +61,7 @@ def createsettingsfile(self): """ Create a new settings file """ - shutil.copy(self.settings, '.env') + shutil.copy(self.settings, ".env") def createnotfoundpage(self, filepath): """ @@ -92,17 +92,18 @@ def main() -> None: version = get_distribution("blask").version except DistributionNotFound: version = "test_version" - typer.echo("blask (C) version %s" % version) + typer.echo(f"blask (C) version {version}") @blaskcli.command(help="Run the instance of blask") def run( - debug: bool = typer.Option(False, "--debug", - help="Init with the debug flag", is_flag=True), - port: int = typer.Option(5000, "--port", - help="Port where the server is listening"), - host: str = typer.Option("127.0.0.1", "--host", - help="Default Network interface listening"), + debug: bool = typer.Option( + False, "--debug", help="Init with the debug flag", is_flag=True + ), + port: int = typer.Option(5000, "--port", help="Port where the server is listening"), + host: str = typer.Option( + "127.0.0.1", "--host", help="Default Network interface listening" + ), ) -> None: """ Run the current blask instance @@ -115,9 +116,12 @@ def run( @blaskcli.command(help="Initialize a new blask Project") def init( with_docker: bool = typer.Option( - False, "--with-docker", + False, + "--with-docker", help="Add a DockerFile to the blask directory", - is_flag=True)) -> None: + is_flag=True, + ) +) -> None: """ Inits a new blask Instance; with the default options. :param with_docker: if True, add a Dockerfile in the root directory. @@ -125,7 +129,8 @@ def init( typer.echo("Initializing new blask Project") typer.echo("Using default Settings") postdir = path.basename( - path.dirname(str(blasksettings.DEFAULT_SETTINGS["postDir"] + "/"))) + path.dirname(str(blasksettings.DEFAULT_SETTINGS["postDir"] + "/")) + ) templatedir = path.basename( path.dirname(str(blasksettings.DEFAULT_SETTINGS["templateDir"] + "/")) ) @@ -133,13 +138,14 @@ def init( makedirs(postdir) cliController.createdefaultindexfile(path.join(postdir, "index.md")) makedirs(templatedir) - cliController.createdefaulttemplatefile( - path.join(templatedir, "template.html")) + cliController.createdefaulttemplatefile(path.join(templatedir, "template.html")) cliController.createsettingsfile() - cliController.createnotfoundpage(path.join(postdir, '404.md')) + cliController.createnotfoundpage(path.join(postdir, "404.md")) if with_docker: cliController.createdockerfile(path.join("Dockerfile")) - typer.echo("Created new blask project on %s" % getcwd()) + + current_dir = getcwd() + typer.echo(f"Created new blask project on {current_dir}") typer.echo("Now you can execute: blaskcli run") except FileExistsError: typer.echo("There is an existing blask Project") diff --git a/blask/blasksettings.py b/blask/blasksettings.py index 2d18c0f..6f50e99 100644 --- a/blask/blasksettings.py +++ b/blask/blasksettings.py @@ -18,9 +18,9 @@ """ import os +from importlib import import_module from pathlib import Path from sys import path -from importlib import import_module BASE_DIR = Path(".").resolve() @@ -31,11 +31,11 @@ "staticDir": str(BASE_DIR / "static"), "theme": None, "title": "blask | A Simple Blog Engine Based on Flask", - "errors": {404: "404"} # Dictionary with errors handler + "errors": {404: "404"}, # Dictionary with errors handler } -class BlaskSettings(): # pylint: disable=too-few-public-methods +class BlaskSettings: # pylint: disable=too-few-public-methods """ blask configuration helper class """ @@ -59,18 +59,19 @@ def __init__(self, **kwargs): # Load settings from the module in environment variable settings_mod = import_module( - os.environ["BLASK_SETTINGS"], os.environ["BLASK_SETTINGS"]) + os.environ["BLASK_SETTINGS"], os.environ["BLASK_SETTINGS"] + ) # settings are stored in settings_mod.BASE_DIR, # settings_mod.templateDir, etc. self.settings = {} - for key in DEFAULT_SETTINGS: + for key, value in DEFAULT_SETTINGS.items(): # for each of default attributes, try first to read the value # in settings_mod and if not defined, use the default # Note: settings_mod attributes which are not # DEFAULT_SETTINGS are ignored - value = getattr(settings_mod, key, DEFAULT_SETTINGS[key]) + value = getattr(settings_mod, key, value) self.settings[key] = value else: # Copy default settings @@ -82,13 +83,15 @@ def __init__(self, **kwargs): self.settings[key] = os.environ[key] # arguments always override default and environment settings - for kwarg in kwargs: + for kwarg, value in kwargs.items(): if kwarg in DEFAULT_SETTINGS: - self.settings[kwarg] = kwargs[kwarg] + self.settings[kwarg] = value # Set theme - if self.settings["theme"] != None: - self.settings["templateDir"] = str(BASE_DIR / "themes" / self.settings['theme']) + if self.settings["theme"] is not None: + self.settings["templateDir"] = str( + BASE_DIR / "themes" / self.settings["theme"] + ) def __getitem__(self, key): """ @@ -96,4 +99,4 @@ def __getitem__(self, key): """ if key in self.settings: return self.settings[key] - raise KeyError("There is no blask setting called %s" % key) + raise KeyError(f"There is no blask setting called {key}") diff --git a/blask/blogrenderer.py b/blask/blogrenderer.py index 779b9a2..18a3aa9 100644 --- a/blask/blogrenderer.py +++ b/blask/blogrenderer.py @@ -16,20 +16,21 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from os import path, listdir -from hashlib import sha3_512 from datetime import datetime +from hashlib import sha3_512 +from os import listdir, path from xml.etree import ElementTree as ET -from werkzeug.utils import safe_join -from werkzeug.exceptions import NotFound from markdown import Markdown +from werkzeug.exceptions import NotFound +from werkzeug.utils import safe_join from blask.errors import PageNotExistError INDEX = "./index.md" DATE_FORMAT = "%Y-%m-%d" + class BlogRenderer: """ Class BlogRenderer: This class provides the feature for render posts from @@ -66,7 +67,8 @@ def renderfile(self, filename): would fall out of the posts directory. """ page_not_exist_exception = PageNotExistError( - f"{filename} does not exists in {self.postdir} directory") + f"{filename} does not exists in {self.postdir} directory" + ) try: file = f"{filename}.md" filepath = safe_join(self.postdir, file) @@ -85,7 +87,6 @@ def renderfile(self, filename): return self.cache[content_hash] - # pylint: disable=R0201 def rendertext(self, filename, text): """ Render a Markdown Text and returns the BlogEntry. @@ -93,20 +94,19 @@ def rendertext(self, filename, text): :param text: Text write in Markdown. :return: BlogEntry. """ - mark_down = Markdown( - extensions=["meta", "markdown.extensions.codehilite"]) + mark_down = Markdown(extensions=["meta", "markdown.extensions.codehilite"]) entry = BlogEntry(filename, mark_down, text) return entry # pylint: disable=dangerous-default-value def list_posts( - self, - tags=None, - exclusions=[INDEX, "404.md"], - search="", - category="", - author="", - orderbydate=True, + self, + tags=None, + exclusions=[INDEX, "404.md"], + search="", + category="", + author="", + orderbydate=True, ): """ Search a list of Posts returning a list of BlogEntry ordered By Date. @@ -125,8 +125,10 @@ def list_posts( self._listdirectoriesrecursive(self.postdir), ) ) + mapfilter = list(map(lambda l: path.splitext(l)[0], files)) - entries = list(map(lambda l: self.renderfile(l), mapfilter)) + entries = [self.renderfile(x) for x in mapfilter] + if tags: for tag in tags: entries = list(filter(lambda l, t=tag: t in l.tags, entries)) @@ -139,10 +141,10 @@ def list_posts( if orderbydate: # create a sublist with only entries with date dateredentries = list(filter(lambda e: e.date is None, entries)) - notdateredentries = list( - filter(lambda d: d.date is not None, entries)) + notdateredentries = list(filter(lambda d: d.date is not None, entries)) entries = list( - sorted(dateredentries, key=lambda t: t.date is not None, reverse=True)) + sorted(dateredentries, key=lambda t: t.date is not None, reverse=True) + ) entries.extend(notdateredentries) return entries @@ -156,8 +158,9 @@ def _listdirectoriesrecursive(self, directory, append=""): for file in listdir(directory): if path.isdir(safe_join(directory, file)): posts.extend( - self._listdirectoriesrecursive(safe_join(directory, file), - safe_join(append, file)) + self._listdirectoriesrecursive( + safe_join(directory, file), safe_join(append, file) + ) ) else: posts.append(safe_join(append, file)) @@ -170,12 +173,11 @@ def generate_sitemap_xml(self, postlist, baseurl="http://localhost:5000"): :return: return the xml output for the Sitemap.xml file. """ root = ET.Element( - "urlset", - attrib={"xmlns": "http://www.sitemaps.org/schemas/sitemap/0.9"}) + "urlset", attrib={"xmlns": "http://www.sitemaps.org/schemas/sitemap/0.9"} + ) rpostlist = self._listdirectoriesrecursive(postlist) rpostlist.remove(INDEX) - rpostlist = list(map(lambda l: path.splitext(l)[0], rpostlist)) - rpostlist = list(map(lambda l: self.renderfile(l), rpostlist)) + rpostlist = list(map(lambda l: self.renderfile(path.splitext(l)[0]), rpostlist)) # add index urlindex = ET.SubElement(root, "url") locindex = ET.SubElement(urlindex, "loc") @@ -206,7 +208,7 @@ def generate_sitemap_xml(self, postlist, baseurl="http://localhost:5000"): priority.text = "0.5" return ET.tostring(root, encoding="UTF-8", method="xml") - # pylint: disable=R0201 + def generatetagpage(self, postlist): """ Get a HTML with links of the entries. @@ -223,8 +225,9 @@ def generatetagpage(self, postlist): # pylint: disable=too-few-public-methods +# pylint: disable=too-many-instance-attributes class BlogEntry: - """" + """ " This class has the information about the Blog Posts. Author: Zerasul Version: 0.0.1. @@ -280,11 +283,6 @@ def __str__(self): Convert this object to String :return: String with the data of this object. """ - string = ( - f"['content': {self.content}, 'name': {self.name}, " - f"'date': {self.date}, 'tags':[{self.tags}], " - f"'author': {self.author}, 'category': {self.category}, " - f"'template': {self.template}]" - ) - - return string + return f"['content': {self.content}, 'name': {self.name}, 'date': {self.date}, \ + 'tags':[{self.tags}], 'author': {self.author}, 'category': {self.category}, \ + 'template': {self.template}]" diff --git a/main.py b/main.py index 46cd7a6..8418684 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,15 @@ import argparse import logging + from blask import BlaskApp + application = BlaskApp().app -if __name__ == '__main__': +if __name__ == "__main__": # Argument parsing parser = argparse.ArgumentParser() - parser.add_argument( - "-d", "--debug", action='store_true', help="Verbose output") - parser.add_argument( - "-v", "--verbose", action='store_true', help="Verbose output") + parser.add_argument("-d", "--debug", action="store_true", help="Verbose output") + parser.add_argument("-v", "--verbose", action="store_true", help="Verbose output") args = parser.parse_args() if args.debug or args.verbose: log = logging.getLogger() diff --git a/settings.py b/settings.py index 10c3cdd..31fc1a5 100644 --- a/settings.py +++ b/settings.py @@ -1,7 +1,7 @@ -from pathlib import Path from os import path +from pathlib import Path -BASE_DIR = Path('.').resolve() +BASE_DIR = Path(".").resolve() templateDir = path.join(BASE_DIR, "templates") postDir = path.join(BASE_DIR, "posts") diff --git a/setup.py b/setup.py index f10af29..37d3981 100644 --- a/setup.py +++ b/setup.py @@ -17,9 +17,10 @@ along with this program. If not, see . """ -from setuptools import setup, find_packages from pathlib import Path +from setuptools import find_packages, setup + base_dir = Path(__file__).resolve().parents[0] info_file = base_dir / "README.md" diff --git a/tests/blaskcli_test.py b/tests/blaskcli_test.py index 176a36b..66abb1b 100644 --- a/tests/blaskcli_test.py +++ b/tests/blaskcli_test.py @@ -1,26 +1,26 @@ +from pytest_mock import mocker from typer.testing import CliRunner + from blask import blaskcli -from pytest_mock import mocker class TestCLI: - tempdir = None runner = CliRunner() def test_init(self, mocker): - mocker.patch('os.makedirs') - mocker.patch('shutil.copy') - run = self.runner.invoke(blaskcli.blaskcli, ['init']) + mocker.patch("os.makedirs") + mocker.patch("shutil.copy") + run = self.runner.invoke(blaskcli.blaskcli, ["init"]) assert "Initializing new blask Project" in run.output def test_init_with_docker(self, mocker): - mocker.patch('os.makedirs') - mocker.patch('shutil.copy') - run = self.runner.invoke(blaskcli.blaskcli, ['init', '--with-docker']) + mocker.patch("os.makedirs") + mocker.patch("shutil.copy") + run = self.runner.invoke(blaskcli.blaskcli, ["init", "--with-docker"]) assert "Initializing new blask Project" in run.output def test_run(self, mocker): - mocker.patch('blask.blaskcli.blask.run') - run = self.runner.invoke(blaskcli.blaskcli, ['run']) + mocker.patch("blask.blaskcli.blask.run") + run = self.runner.invoke(blaskcli.blaskcli, ["run"]) assert "blask (C)" in run.output diff --git a/tests/blogrender_test.py b/tests/blogrender_test.py index 80ca1be..7bc413c 100644 --- a/tests/blogrender_test.py +++ b/tests/blogrender_test.py @@ -1,15 +1,15 @@ -from blask.blogrenderer import BlogRenderer -from settings import postDir -from pytest import fixture, raises from datetime import datetime + +from pytest import fixture, raises + +from blask.blogrenderer import BlogRenderer from blask.errors import PageNotExistError +from settings import postDir class TestblogRender: - blogrender = None - markdowntest = ( - "---\ntitle: test\ndate: 2018-03-03\ntags: test,test2\n ---\n test") + markdowntest = "---\ntitle: test\ndate: 2018-03-03\ntags: test,test2\n ---\n test" @fixture(autouse=True) def initialize(self): diff --git a/tests/main_test.py b/tests/main_test.py index 8fc36bc..b289bfd 100644 --- a/tests/main_test.py +++ b/tests/main_test.py @@ -1,13 +1,12 @@ from pytest import fixture -from blask import BlaskApp -import settings +import settings +from blask import BlaskApp RESPONSE_DATA = b"href='/about'" class TestMain: - test_client = None @fixture(autouse=True) @@ -21,7 +20,7 @@ def inittest(self): ) b.app.testing = True b.app.config["SECRET_KEY"] = "supersecretkeyfortesting" - b.app.config['WTF_CSRF_METHODS'] = [] + b.app.config["WTF_CSRF_METHODS"] = [] self.test_client = b.app.test_client() diff --git a/tests/settings.py b/tests/settings.py index 209831e..2574133 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -4,21 +4,18 @@ BASE_DIR = Path(".").resolve() # Templates directory -templateDir = os.path.join(BASE_DIR, 'templates') +templateDir = os.path.join(BASE_DIR, "templates") # Posts directory -postDir = os.path.join(BASE_DIR, 'posts') +postDir = os.path.join(BASE_DIR, "posts") # Default layout template defaultLayout = "template.html" # Static files directory -staticDir = os.path.join(BASE_DIR, 'static') +staticDir = os.path.join(BASE_DIR, "static") # Website title -title = 'The mantis revenge!' +title = "The mantis revenge!" -errors = { - 500: "500", - 404: "404" -} +errors = {500: "500", 404: "404"} diff --git a/tests/settings_test.py b/tests/settings_test.py index 11dd27a..b00e0e2 100644 --- a/tests/settings_test.py +++ b/tests/settings_test.py @@ -9,9 +9,7 @@ class TestBlaskSettings: - def test_defaults(self): - # remove all environment variables removed_vars = {} for key in blasksettings.DEFAULT_SETTINGS: @@ -28,7 +26,6 @@ def test_defaults(self): os.environ[key] = value def test_from_environ(self): - # remove all environment variables removed_vars = {} for key in blasksettings.DEFAULT_SETTINGS: @@ -37,17 +34,17 @@ def test_from_environ(self): removed_vars[key] = value # changed for new pytest - os.environ['BLASK_SETTINGS'] = 'tests.testsettings' + os.environ["BLASK_SETTINGS"] = "tests.testsettings" settings = BlaskSettings() for kw in blasksettings.DEFAULT_SETTINGS.keys(): - if kw == 'postDir': - assert settings[kw] == str(Path('.').resolve() / 'posts2') - elif kw == 'title': - assert settings[kw] == 'The mantis revenge!' + if kw == "postDir": + assert settings[kw] == str(Path(".").resolve() / "posts2") + elif kw == "title": + assert settings[kw] == "The mantis revenge!" else: assert settings[kw] == blasksettings.DEFAULT_SETTINGS[kw] - del(os.environ['BLASK_SETTINGS']) + del os.environ["BLASK_SETTINGS"] # put environment variables back for key, value in removed_vars.items(): @@ -68,9 +65,9 @@ def test_from_dotenv(self): # changed for new pytest settings = BlaskSettings() for kw in blasksettings.DEFAULT_SETTINGS.keys(): - if kw == 'postDir': - assert settings[kw] == 'posts-env' - elif kw == 'title': + if kw == "postDir": + assert settings[kw] == "posts-env" + elif kw == "title": assert settings[kw] == "The mantis with dotenv?!" else: assert settings[kw] == blasksettings.DEFAULT_SETTINGS[kw] @@ -85,7 +82,6 @@ def test_from_dotenv(self): os.environ[key] = value def test_kwargs(self): - # remove all environment variables removed_vars = {} for key in blasksettings.DEFAULT_SETTINGS: @@ -93,16 +89,16 @@ def test_kwargs(self): value = os.environ.pop(key) removed_vars[key] = value kwsettings = { - 'postDir': str(Path.cwd() / 'mantispostdir'), - 'title': 'The mantis has you!', + "postDir": str(Path.cwd() / "mantispostdir"), + "title": "The mantis has you!", } settings = BlaskSettings(**kwsettings) for kw in blasksettings.DEFAULT_SETTINGS.keys(): - if kw == 'postDir': - assert settings[kw] == str(Path.cwd() / 'mantispostdir') - elif kw == 'title': - assert settings[kw] == 'The mantis has you!' + if kw == "postDir": + assert settings[kw] == str(Path.cwd() / "mantispostdir") + elif kw == "title": + assert settings[kw] == "The mantis has you!" else: assert settings[kw] == blasksettings.DEFAULT_SETTINGS[kw] diff --git a/tests/testsettings.py b/tests/testsettings.py index b0c738d..12614eb 100644 --- a/tests/testsettings.py +++ b/tests/testsettings.py @@ -1,21 +1,21 @@ -from pathlib import Path import os +from pathlib import Path BASE_DIR = Path(".").resolve() # Templates directory -templateDir = os.path.join(BASE_DIR, 'templates') +templateDir = os.path.join(BASE_DIR, "templates") # Posts directory -postDir = os.path.join(BASE_DIR, 'posts2') +postDir = os.path.join(BASE_DIR, "posts2") # Default layout template defaultLayout = "template.html" # Static files directory -staticDir = os.path.join(BASE_DIR, 'static') +staticDir = os.path.join(BASE_DIR, "static") # Website title -title = 'The mantis revenge!' +title = "The mantis revenge!" errors = {404: "404"}