diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 728ced0..13a0363 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,3 +31,8 @@ repos: language: system entry: poetry run mypy types: [python] + - id: version + name: Version + language: system + entry: python -m tests.check_package_version + types: [python] diff --git a/.travis.yml b/.travis.yml index ebeb529..ce24e8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,29 +3,19 @@ language: python os: linux dist: xenial python: - - 3.9 - - 3.8 - - 3.7 - 3.6 + - 3.7 + - 3.8 + - 3.9 env: - - INSTALL_DEPS="" - - INSTALL_DEPS="--no-dev" - -before_install: - - curl -fsS -o get-poetry.py https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py - - python get-poetry.py -y - - export PATH="$PATH:$HOME/.poetry/bin" - - poetry config virtualenvs.in-project true + - EXTRA_INSTALLS="" + - EXTRA_INSTALLS="ipython pandas matplotlib bokeh plotly kaleido weasyprint beautifulsoup4 html5lib" install: - - poetry install $INSTALL_DEPS -E test + - pip install . pytest coverage $EXTRA_INSTALLS script: - - python -m tests.check_package_version - - black --check . - - flake8 - - mypy esparto tests - coverage run --append --source esparto -m pytest after_success: diff --git a/Makefile b/Makefile index 61cdbb2..3c0e077 100644 --- a/Makefile +++ b/Makefile @@ -75,24 +75,32 @@ coverage: ## check code coverage quickly with the default Python docstrings: ## generate google format docstrings pyment esparto -o google -w -docs: ## generate Sphinx HTML documentation, including API docs - mkdocs clean - mkdocs build +docs: class-diagram ## generate documentation, including API docs + mkdocs build --clean servedocs: ## compile the docs watching for changes mkdocs serve -a "`hostname -I | xargs`:8000" +deploydocs: ## deploy docs to github pages + mkdocs gh-deploy + class-diagram: ## make UML class diagram pyreverse esparto -o png -f ALL --ignore _contentdeps.py,_options.py,_publish.py mv classes.png devdocs/classes.png rm packages.png -release: dist class-diagram ## package and upload a release +reqs: ## output requirements.txt + poetry export -f requirements.txt -o requirements.txt --without-hashes + +release: dist ## package and upload a release poetry publish dist: clean ## builds source and wheel package poetry build ls -l dist +hooks: ## run pre-commit hooks on all files + pre-commit run -a + install: clean ## install the package to the active Python's site-packages poetry install diff --git a/devdocs/classes.png b/devdocs/classes.png index 6eb19b2..bf28d03 100644 Binary files a/devdocs/classes.png and b/devdocs/classes.png differ diff --git a/docs/04-about/release-notes.md b/docs/04-about/release-notes.md index f1a3f5d..cc518a2 100644 --- a/docs/04-about/release-notes.md +++ b/docs/04-about/release-notes.md @@ -1,6 +1,13 @@ Release Notes ============= +0.2.5 (2021-05-06) +------------------ + +- Fix linting errors. +- Add dataclasses dependency for Python < 3.7. + + 0.2.4 (2021-05-04) ------------------ diff --git a/esparto/_content.py b/esparto/_content.py index 576040f..ee7beea 100644 --- a/esparto/_content.py +++ b/esparto/_content.py @@ -93,9 +93,7 @@ def __eq__(self, other): if isinstance(other, self.__class__): if hasattr(self.content, "__iter__") and hasattr(other.content, "__iter__"): return all(x == y for x, y in zip(self.content, other.content)) - else: - return self.content == other.content - + return self.content == other.content return False def __ne__(self, other): @@ -479,13 +477,12 @@ def to_html(self, **kwargs) -> str: html = f"\n" return html - else: - html, js = components(self.content) + html, js = components(self.content) - # Remove outer
tag so we can give our own attributes - html = _remove_outer_div(html) + # Remove outer
tag so we can give our own attributes + html = _remove_outer_div(html) - return f"
{html}\n{js}\n
" + return f"
{html}\n{js}\n
" class FigurePlotly(Content): diff --git a/esparto/_contentdeps.py b/esparto/_contentdeps.py index 327894a..a92e2b7 100644 --- a/esparto/_contentdeps.py +++ b/esparto/_contentdeps.py @@ -1,11 +1,11 @@ from collections import UserDict -from dataclasses import dataclass +from dataclasses import dataclass, field from functools import lru_cache from pathlib import Path -from typing import Set +from typing import List, Set from esparto import _INSTALLED_MODULES, _MODULE_PATH -from esparto._options import _get_source_from_options +from esparto._options import get_source_from_options @dataclass @@ -16,16 +16,13 @@ class ContentDependency: target: str +@dataclass class ResolvedDeps: - def __init__(self): - self.head = list() - self.tail = list() + head: List[str] = field(default_factory=list) + tail: List[str] = field(default_factory=list) class ContentDependencyDict(UserDict): - def __init__(self): - super().__init__() - def __add__(self, other: ContentDependency): self.data[other.name] = other return self @@ -35,7 +32,7 @@ def __add__(self, other: ContentDependency): @lru_cache(maxsize=None) -def content_dependency_dict() -> ContentDependencyDict: +def lazy_content_dependency_dict() -> ContentDependencyDict: bootstrap_cdn = ( '' @@ -78,10 +75,10 @@ def resolve_deps( ) -> ResolvedDeps: resolved_deps = ResolvedDeps() - source = _get_source_from_options(source) + source = get_source_from_options(source) for dep in required_deps: - dep_details: ContentDependency = content_dependency_dict()[dep] + dep_details: ContentDependency = lazy_content_dependency_dict()[dep] getattr(resolved_deps, dep_details.target).append(getattr(dep_details, source)) return resolved_deps diff --git a/esparto/_layout.py b/esparto/_layout.py index c7068c0..8cb217c 100644 --- a/esparto/_layout.py +++ b/esparto/_layout.py @@ -281,8 +281,7 @@ def __eq__(self, other): return self._title == other._title and all( (x == y for x, y in zip(self.children, other.children)) ) - else: - return False + return False def __ne__(self, other): return not self.__eq__(other) @@ -349,8 +348,7 @@ def save_html( if return_html: return html - else: - return None + return None def save( self, @@ -380,8 +378,7 @@ def save( if return_html: return html - else: - return None + return None def save_pdf( self, filepath: str = "./esparto-doc.pdf", return_html: bool = False @@ -403,8 +400,7 @@ def save_pdf( if return_html: return html - else: - return None + return None def __init__( self, diff --git a/esparto/_options.py b/esparto/_options.py index 6250218..e7e2a89 100644 --- a/esparto/_options.py +++ b/esparto/_options.py @@ -15,7 +15,7 @@ class ConfigOptions: options = ConfigOptions() -def _get_source_from_options(source): +def get_source_from_options(source): if source == "esparto.options": if options.offline_mode: return options._offline_source @@ -23,5 +23,4 @@ def _get_source_from_options(source): return options._online_source elif source in ["cdn", "inline"]: return source - else: - raise ValueError(f"Unrecognised source: {source}") + raise ValueError(f"Unrecognised source: {source}") diff --git a/esparto/_publish.py b/esparto/_publish.py index ea7da1b..57cc5e6 100644 --- a/esparto/_publish.py +++ b/esparto/_publish.py @@ -2,7 +2,7 @@ from pathlib import Path from typing import TYPE_CHECKING, Optional, Union -from jinja2 import Environment, PackageLoader, select_autoescape # type: ignore +from jinja2 import Environment, PackageLoader # type: ignore if TYPE_CHECKING: from esparto._layout import Page, Layout @@ -10,11 +10,10 @@ from esparto import _INSTALLED_MODULES from esparto._contentdeps import resolve_deps -from esparto._options import _get_source_from_options, options +from esparto._options import get_source_from_options, options _ENV = Environment( loader=PackageLoader("esparto", "resources/jinja"), - autoescape=select_autoescape(["xml"]), ) _BASE_TEMPLATE = _ENV.get_template("base.html") @@ -42,7 +41,7 @@ def publish_html( """ required_deps = document._required_dependencies() - dependency_source = _get_source_from_options(dependency_source) + dependency_source = get_source_from_options(dependency_source) resolved_deps = resolve_deps(required_deps, source=dependency_source) html_rendered: str = _BASE_TEMPLATE.render( @@ -60,8 +59,7 @@ def publish_html( if return_html: return html_prettified - else: - return None + return None def publish_pdf( @@ -80,35 +78,31 @@ def publish_pdf( """ if "weasyprint" not in _INSTALLED_MODULES: raise ModuleNotFoundError("Install weasyprint for PDF support") - else: - import weasyprint as weasy # type: ignore + import weasyprint as weasy # type: ignore - temp_dir = Path(options.pdf_temp_dir) - temp_dir.mkdir(parents=True, exist_ok=True) + temp_dir = Path(options.pdf_temp_dir) + temp_dir.mkdir(parents=True, exist_ok=True) - html_rendered = publish_html( - document=document, - filepath=None, - return_html=True, - dependency_source="inline", - pdf_mode=True, - ) - pdf_doc = weasy.HTML( - string=html_rendered, base_url=options.pdf_temp_dir - ).render() - pdf_doc.metadata.title = document.title - pdf_doc.write_pdf(filepath) + html_rendered = publish_html( + document=document, + filepath=None, + return_html=True, + dependency_source="inline", + pdf_mode=True, + ) + pdf_doc = weasy.HTML(string=html_rendered, base_url=options.pdf_temp_dir).render() + pdf_doc.metadata.title = document.title + pdf_doc.write_pdf(filepath) - for f in temp_dir.iterdir(): - f.unlink() - temp_dir.rmdir() + for f in temp_dir.iterdir(): + f.unlink() + temp_dir.rmdir() - html_prettified = _prettify_html(html_rendered) + html_prettified = _prettify_html(html_rendered) - if return_html: - return html_prettified - else: - return None + if return_html: + return html_prettified + return None def nb_display( @@ -138,7 +132,7 @@ def nb_display( elif hasattr(item, "_dependencies"): required_deps = item._dependencies - dependency_source = _get_source_from_options(dependency_source) + dependency_source = get_source_from_options(dependency_source) resolved_deps = resolve_deps(required_deps, source=dependency_source) head_deps = "\n".join(resolved_deps.head) @@ -165,8 +159,7 @@ def nb_display( if return_html: return render_html - else: - return None + return None def _prettify_html(html: Optional[str]) -> str: diff --git a/poetry.lock b/poetry.lock index cea506c..edbf333 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,5 @@ [[package]] -category = "main" +category = "dev" description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." name = "appdirs" optional = false @@ -16,7 +16,7 @@ python-versions = "*" version = "0.1.2" [[package]] -category = "main" +category = "dev" description = "Atomic file writes." marker = "sys_platform == \"win32\"" name = "atomicwrites" @@ -25,18 +25,18 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.4.0" [[package]] -category = "main" +category = "dev" description = "Classes Without Boilerplate" name = "attrs" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -version = "20.3.0" +version = "21.1.0" [package.extras] -dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] -docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] category = "dev" @@ -64,7 +64,7 @@ html5lib = ["html5lib"] lxml = ["lxml"] [[package]] -category = "main" +category = "dev" description = "The uncompromising code formatter." name = "black" optional = false @@ -178,7 +178,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "4.0.0" [[package]] -category = "main" +category = "dev" description = "Composable command line interface toolkit" name = "click" optional = false @@ -186,7 +186,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "7.1.2" [[package]] -category = "main" +category = "dev" description = "Cross-platform colored terminal text." marker = "sys_platform == \"win32\" or platform_system == \"Windows\"" name = "colorama" @@ -195,7 +195,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" version = "0.4.4" [[package]] -category = "main" +category = "dev" description = "Code coverage measurement for Python" name = "coverage" optional = false @@ -288,7 +288,7 @@ python-versions = "*" version = "3.0.12" [[package]] -category = "main" +category = "dev" description = "the modular source code checker: pep8 pyflakes and co" name = "flake8" optional = false @@ -388,7 +388,7 @@ docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] -category = "main" +category = "dev" description = "iniconfig: brain-dead simple config-ini parsing" name = "iniconfig" optional = false @@ -487,7 +487,7 @@ python-versions = ">=3.6" version = "1.0.1" [[package]] -category = "main" +category = "dev" description = "Static image export for web-based visualization libraries with zero dependencies" name = "kaleido" optional = false @@ -578,7 +578,7 @@ pyparsing = ">=2.0.3,<2.0.4 || >2.0.4,<2.1.2 || >2.1.2,<2.1.6 || >2.1.6" python-dateutil = ">=2.1" [[package]] -category = "main" +category = "dev" description = "McCabe checker, plugin for flake8" name = "mccabe" optional = false @@ -647,7 +647,7 @@ description = "A Material Design theme for MkDocs" name = "mkdocs-material" optional = false python-versions = "*" -version = "7.1.3" +version = "7.1.4" [package.dependencies] Pygments = ">=2.4" @@ -685,7 +685,7 @@ pymdown-extensions = ">=6.3,<9.0" pytkdocs = ">=0.2.0,<0.12.0" [[package]] -category = "main" +category = "dev" description = "Optional static typing for Python" name = "mypy" optional = false @@ -701,7 +701,7 @@ typing-extensions = ">=3.7.4" dmypy = ["psutil (>=4.0)"] [[package]] -category = "main" +category = "dev" description = "Experimental type system extensions for programs checked with the mypy typechecker." name = "mypy-extensions" optional = false @@ -748,7 +748,7 @@ python-versions = ">=3.6" version = "1.19.5" [[package]] -category = "main" +category = "dev" description = "Core utilities for Python packages" name = "packaging" optional = false @@ -798,7 +798,7 @@ version = "0.7.1" testing = ["docopt", "pytest (>=3.0.7)"] [[package]] -category = "main" +category = "dev" description = "Utility library for gitignore style pattern matching of file paths." name = "pathspec" optional = false @@ -846,7 +846,7 @@ retrying = ">=1.3.3" six = "*" [[package]] -category = "main" +category = "dev" description = "plugin and hook calling mechanisms for python" name = "pluggy" optional = false @@ -906,7 +906,7 @@ python-versions = "*" version = "0.7.0" [[package]] -category = "main" +category = "dev" description = "library with cross-python path, ini-parsing, io, code, log facilities" name = "py" optional = false @@ -914,7 +914,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "1.10.0" [[package]] -category = "main" +category = "dev" description = "Python style guide checker" name = "pycodestyle" optional = false @@ -930,7 +930,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" version = "2.20" [[package]] -category = "main" +category = "dev" description = "passive checker of Python programs" name = "pyflakes" optional = false @@ -1012,7 +1012,7 @@ docs = ["sphinx (>=1.6.5)", "sphinx-rtd-theme"] tests = ["pytest (>=3.2.1,<3.3.0 || >3.3.0)", "hypothesis (>=3.27.0)"] [[package]] -category = "main" +category = "dev" description = "Python parsing module" name = "pyparsing" optional = false @@ -1028,12 +1028,12 @@ python-versions = "*" version = "0.10.0" [[package]] -category = "main" +category = "dev" description = "pytest: simple powerful testing with Python" name = "pytest" optional = false python-versions = ">=3.6" -version = "6.2.3" +version = "6.2.4" [package.dependencies] atomicwrites = ">=1.0" @@ -1091,7 +1091,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" version = "5.4.1" [[package]] -category = "main" +category = "dev" description = "Alternative regular expression module, to replace re." name = "regex" optional = false @@ -1144,7 +1144,7 @@ description = "Python 2 and 3 compatibility utilities" name = "six" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" -version = "1.15.0" +version = "1.16.0" [[package]] category = "main" @@ -1171,7 +1171,7 @@ doc = ["sphinx", "sphinx-rtd-theme"] test = ["pytest", "pytest-cov", "pytest-flake8", "pytest-isort", "coverage"] [[package]] -category = "main" +category = "dev" description = "Python Library for Tom's Obvious, Minimal Language" name = "toml" optional = false @@ -1192,7 +1192,7 @@ description = "tox is a generic virtualenv management and test command line tool name = "tox" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "3.23.0" +version = "3.23.1" [package.dependencies] colorama = ">=0.4.1" @@ -1243,7 +1243,7 @@ six = "*" test = ["pytest", "mock"] [[package]] -category = "main" +category = "dev" description = "a fork of Python 2 and 3 ast modules with type comment support" name = "typed-ast" optional = false @@ -1277,7 +1277,7 @@ description = "Virtual Python Environment builder" name = "virtualenv" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" -version = "20.4.4" +version = "20.4.6" [package.dependencies] appdirs = ">=1.4.3,<2" @@ -1358,11 +1358,10 @@ docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [extras] -extras = ["beautifulsoup4", "weasyprint", "kaleido"] -test = ["black", "flake8", "mypy", "pytest", "coverage", "html5lib"] +extras = ["beautifulsoup4", "weasyprint"] [metadata] -content-hash = "966602fd7154c2d2ea3fa8c759ee21c80bf846203ee2757074bcb331c902fb28" +content-hash = "65d69ad54fb9ae2bab6c2865dec82a0c30af484099367aa1cfe1d0bdf4c3f6aa" lock-version = "1.0" python-versions = "^3.6.1" @@ -1380,8 +1379,8 @@ atomicwrites = [ {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, - {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, + {file = "attrs-21.1.0-py2.py3-none-any.whl", hash = "sha256:8ee1e5f5a1afc5b19bdfae4fdf0c35ed324074bdce3500c939842c8f818645d9"}, + {file = "attrs-21.1.0.tar.gz", hash = "sha256:3901be1cb7c2a780f14668691474d9252c070a756be0a9ead98cfeabfa11aeb8"}, ] backcall = [ {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, @@ -1760,8 +1759,8 @@ mkdocs-git-committers-plugin = [ {file = "mkdocs_git_committers_plugin-0.2.1-py3-none-any.whl", hash = "sha256:f9bd6552999c7e3ded49731de50a5d46b1cbc1d9dbbec1dd7b862fb0f329f5ec"}, ] mkdocs-material = [ - {file = "mkdocs-material-7.1.3.tar.gz", hash = "sha256:e34bba93ad1a0e6f9afc371f4ef55bedabbf13b9a786b013b0ce26ac55ec2932"}, - {file = "mkdocs_material-7.1.3-py2.py3-none-any.whl", hash = "sha256:437638b0de7a9113d7f1c9ddc93c0a29a3b808c71c3606713d8c1fa437697a3e"}, + {file = "mkdocs-material-7.1.4.tar.gz", hash = "sha256:f2fe6014bd69c1651a2dfe2651de7b0fdea1c33ba652243809c767a7c60daa16"}, + {file = "mkdocs_material-7.1.4-py2.py3-none-any.whl", hash = "sha256:1fb299005b787b62ef70631f7adf418e592c22a359e633fdd2ca5c24be6e451c"}, ] mkdocs-material-extensions = [ {file = "mkdocs-material-extensions-1.0.1.tar.gz", hash = "sha256:6947fb7f5e4291e3c61405bad3539d81e0b3cd62ae0d66ced018128af509c68f"}, @@ -2013,8 +2012,8 @@ pyphen = [ {file = "Pyphen-0.10.0.tar.gz", hash = "sha256:719b21dfb4b04fbc11cc0f6112418535fe35474021120cccfffc43a25fe63128"}, ] pytest = [ - {file = "pytest-6.2.3-py3-none-any.whl", hash = "sha256:6ad9c7bdf517a808242b998ac20063c41532a570d088d77eec1ee12b0b5574bc"}, - {file = "pytest-6.2.3.tar.gz", hash = "sha256:671238a46e4df0f3498d1c3270e5deb9b32d25134c99b7d75370a68cfbe9b634"}, + {file = "pytest-6.2.4-py3-none-any.whl", hash = "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890"}, + {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, ] python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, @@ -2113,8 +2112,8 @@ rope = [ {file = "rope-0.18.0.tar.gz", hash = "sha256:786b5c38c530d4846aa68a42604f61b4e69a493390e3ca11b88df0fbfdc3ed04"}, ] six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] soupsieve = [ {file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"}, @@ -2172,8 +2171,8 @@ tornado = [ {file = "tornado-6.1.tar.gz", hash = "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791"}, ] tox = [ - {file = "tox-3.23.0-py2.py3-none-any.whl", hash = "sha256:e007673f3595cede9b17a7c4962389e4305d4a3682a6c5a4159a1453b4f326aa"}, - {file = "tox-3.23.0.tar.gz", hash = "sha256:05a4dbd5e4d3d8269b72b55600f0b0303e2eb47ad5c6fe76d3576f4c58d93661"}, + {file = "tox-3.23.1-py2.py3-none-any.whl", hash = "sha256:b0b5818049a1c1997599d42012a637a33f24c62ab8187223fdd318fa8522637b"}, + {file = "tox-3.23.1.tar.gz", hash = "sha256:307a81ddb82bd463971a273f33e9533a24ed22185f27db8ce3386bff27d324e3"}, ] tqdm = [ {file = "tqdm-4.60.0-py2.py3-none-any.whl", hash = "sha256:daec693491c52e9498632dfbe9ccfc4882a557f5fa08982db1b4d3adbe0887c3"}, @@ -2225,8 +2224,8 @@ urllib3 = [ {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, ] virtualenv = [ - {file = "virtualenv-20.4.4-py2.py3-none-any.whl", hash = "sha256:a935126db63128861987a7d5d30e23e8ec045a73840eeccb467c148514e29535"}, - {file = "virtualenv-20.4.4.tar.gz", hash = "sha256:09c61377ef072f43568207dc8e46ddeac6bcdcaf288d49011bda0e7f4d38c4a2"}, + {file = "virtualenv-20.4.6-py2.py3-none-any.whl", hash = "sha256:307a555cf21e1550885c82120eccaf5acedf42978fd362d32ba8410f9593f543"}, + {file = "virtualenv-20.4.6.tar.gz", hash = "sha256:72cf267afc04bf9c86ec932329b7e94db6a0331ae9847576daaa7ca3c86b29a4"}, ] wcwidth = [ {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"}, diff --git a/pyproject.toml b/pyproject.toml index 460b8fa..f2fbd4a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "esparto" -version = "0.2.4" +version = "0.2.5" description = "Simple HTML and PDF document generator for Python." authors = ["Dominic Thorn "] license = "MIT" @@ -13,15 +13,9 @@ python = "^3.6.1" jinja2 = "^2.10.1" markdown = "^3.1" Pillow = [">=7.0.0", "<9.0.0"] -beautifulsoup4 = {version = "^4.9.3", optional = true} -black = {version = "^20.8b1", optional = true} -flake8 = {version = "^3.9.0", optional = true} -mypy = {version = "^0.812", optional = true} -pytest = {version = "^6.2.2", optional = true} -coverage = {version = "^5.5", optional = true} -html5lib = {version = "^1.1", optional = true} -weasyprint = {version = "^52.5", optional = true} -kaleido = {version = "^0.2.1", optional = true} +dataclasses = {version = "*", python = "<3.7"} +beautifulsoup4 = {version = ">=4.7", optional = true} +weasyprint = {version = ">=51", optional = true} [tool.poetry.dev-dependencies] black = "^20.8b1" @@ -51,8 +45,7 @@ weasyprint = "^52.5" kaleido = "0.2.1" [tool.poetry.extras] -extras = ["beautifulsoup4", "weasyprint", "kaleido"] -test = ["black", "flake8", "mypy", "pytest", "coverage", "html5lib"] +extras = ["beautifulsoup4", "weasyprint"] [build-system] requires = ["poetry>=0.12"] diff --git a/tests/test_adaptors.py b/tests/test_adaptors.py index 0492ed9..5eba95d 100644 --- a/tests/test_adaptors.py +++ b/tests/test_adaptors.py @@ -21,7 +21,8 @@ def test_all_adaptors_covered(adaptor_list_fn): if _EXTRAS: adaptor_types.remove(ad.BokehObject) # Can't use abstract base class in a test adaptor_types.remove(None) - assert adaptor_types <= test_classes + missing = adaptor_types.difference(test_classes) + assert not missing, missing @pytest.mark.parametrize("input_,expected", adaptor_list) diff --git a/tests/test_content.py b/tests/test_content.py index 8119100..17f701e 100644 --- a/tests/test_content.py +++ b/tests/test_content.py @@ -14,7 +14,8 @@ def test_all_content_classes_covered(content_list_fn): module_classes = {c for c in co.Content.__subclasses__()} module_subclasses = [d.__subclasses__() for d in module_classes] module_all = set(chain.from_iterable(module_subclasses)) | module_classes - assert module_all <= test_classes + missing = module_all.difference(test_classes) + assert not missing, missing def test_all_content_classes_have_deps(content_list_fn): deps = [c._dependencies for c in content_list_fn] diff --git a/tests/test_layout.py b/tests/test_layout.py index 6839734..d1e5393 100644 --- a/tests/test_layout.py +++ b/tests/test_layout.py @@ -2,8 +2,8 @@ import pytest -import esparto._layout as la import esparto._content as co +import esparto._layout as la from tests.conftest import _irises_path, layout_list @@ -11,8 +11,9 @@ def test_all_layout_classes_covered(layout_list_fn): test_classes = [type(c) for c in layout_list_fn] module_classes = [c for c in la.Layout.__subclasses__()] module_subclasses = [d.__subclasses__() for d in module_classes] - module_all = list(chain.from_iterable(module_subclasses)) + module_classes - assert all([c in test_classes for c in module_all]) + module_all = set(list(chain.from_iterable(module_subclasses)) + module_classes) + missing = module_all.difference(test_classes) + assert not missing, missing def test_layout_smart_wrapping(page_layout): diff --git a/tests/test_publish.py b/tests/test_publish.py index 2526fe9..82997fc 100644 --- a/tests/test_publish.py +++ b/tests/test_publish.py @@ -2,26 +2,28 @@ from typing import Optional import pytest -from html5lib import HTMLParser # type: ignore import esparto as es import esparto._publish as pu from tests.conftest import _EXTRAS, content_list, layout_list -htmlparser = HTMLParser(strict=True) - def html_is_valid(html: Optional[str], fragment: bool = False): - try: - if fragment: - htmlparser.parseFragment(html) - else: - htmlparser.parse(html) - success = True - except Exception as e: - print(e) - success = False - return success + if _EXTRAS: + from html5lib import HTMLParser # type: ignore + + htmlparser = HTMLParser(strict=True) + try: + if fragment: + htmlparser.parseFragment(html) + else: + htmlparser.parse(html) + success = True + except Exception as e: + print(e) + success = False + return success + return True @pytest.mark.parametrize("content", (*content_list, *layout_list)) diff --git a/tox.ini b/tox.ini index 666fd64..f9c24e5 100644 --- a/tox.ini +++ b/tox.ini @@ -5,11 +5,14 @@ envlist = setup,codequal,py{36,37,38,39}-{alldeps,mindeps},coverage [testenv] allowlist_externals = poetry +deps = + pytest + coverage commands = - alldeps: poetry install -v --no-root -E test - mindeps: poetry install -v --no-root --no-dev -E test - poetry run coverage run -am pytest - poetry run python -m tests.check_package_version + alldeps: poetry install -v --no-root + mindeps: pip install . + coverage run -am pytest + py38-alldeps: poetry run python -m tests.check_package_version [testenv:setup] deps =