diff --git a/.cruft.json b/.cruft.json index ad3b4a4..be65852 100644 --- a/.cruft.json +++ b/.cruft.json @@ -1,6 +1,6 @@ { "template": "https://github.com/lyz-code/cookiecutter-python-project", - "commit": "3f608095368b696881be01f6ea0241f04aa084cf", + "commit": "44fcc76a48952c2c7ecda8399599ac04caad9235", "context": { "cookiecutter": { "project_name": "MkDocs Newsletter", diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dab2762..b7fcda2 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ name: Build on: # yamllint disable-line rule:truthy push: branches: - - master + - main workflow_dispatch: jobs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 0363e42..5f5ac74 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -4,7 +4,7 @@ name: Tests on: # yamllint disable-line rule:truthy push: branches: - - master + - main pull_request: types: [opened, synchronize] workflow_dispatch: diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 508dc0d..ac1e2ba 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -27,19 +27,6 @@ jobs: source .venv/bin/activate pdm config use_venv True - name: Update requirements - run: make update + run: make update-production - name: Run tests run: make all - - name: Commit files - run: | - rm -r .git/hooks - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - git add pdm.lock - git diff-index --quiet HEAD \ - || git commit -m "chore: update dependency requirements" - - name: Push changes - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - branch: master diff --git a/.gitignore b/.gitignore index 2729cb2..bc8c887 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.pdm.toml # Created by https://www.toptal.com/developers/gitignore/api/python # Edit at https://www.toptal.com/developers/gitignore?templates=python diff --git a/Makefile b/Makefile index 60cd96c..84afd12 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,27 @@ update: @echo "" +.PHONY: update-production +update-production: + @echo "------------------------------------" + @echo "- Updating production dependencies -" + @echo "------------------------------------" + + pdm update --production --no-sync + pdm sync --clean + + @echo "" + +.PHONY: outdated +outdated: + @echo "-------------------------" + @echo "- Outdated dependencies -" + @echo "-------------------------" + + pdm update --dry-run --unconstrained + + @echo "" + .PHONY: format format: @echo "----------------------" @@ -78,7 +99,7 @@ test-examples: @echo "" .PHONY: all -all: lint mypy test security +all: lint mypy test security build-docs .PHONY: clean clean: @@ -120,15 +141,15 @@ docs: test-examples @echo "" .PHONY: bump -bump: pull-master bump-version build-package upload-pypi clean +bump: pull-main bump-version build-package upload-pypi clean -.PHONY: pull-master -pull-master: +.PHONY: pull-main +pull-main: @echo "------------------------" @echo "- Updating repository -" @echo "------------------------" - git checkout master + git checkout main git pull @echo "" @@ -144,7 +165,7 @@ build-package: clean @echo "" .PHONY: build-docs -build-docs: test-examples +build-docs: @echo "--------------------------" @echo "- Building documentation -" @echo "--------------------------" diff --git a/README.md b/README.md index 57c20b2..3ba35f7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Actions Status](https://github.com/lyz-code/mkdocs-newsletter/workflows/Tests/badge.svg)](https://github.com/lyz-code/mkdocs-newsletter/actions) [![Actions Status](https://github.com/lyz-code/mkdocs-newsletter/workflows/Build/badge.svg)](https://github.com/lyz-code/mkdocs-newsletter/actions) -[![Coverage Status](https://coveralls.io/repos/github/lyz-code/mkdocs-newsletter/badge.svg?branch=master)](https://coveralls.io/github/lyz-code/mkdocs-newsletter?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/lyz-code/mkdocs-newsletter/badge.svg?branch=main)](https://coveralls.io/github/lyz-code/mkdocs-newsletter?branch=main) MkDocs plugin to show the changes of documentation repositories in a user friendly format, at the same time that it's easy for the authors to maintain. diff --git a/docs/index.md b/docs/index.md index df78b41..c814f10 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,6 @@ [![Actions Status](https://github.com/lyz-code/mkdocs-newsletter/workflows/Tests/badge.svg)](https://github.com/lyz-code/mkdocs-newsletter/actions) [![Actions Status](https://github.com/lyz-code/mkdocs-newsletter/workflows/Build/badge.svg)](https://github.com/lyz-code/mkdocs-newsletter/actions) -[![Coverage Status](https://coveralls.io/repos/github/lyz-code/mkdocs-newsletter/badge.svg?branch=master)](https://coveralls.io/github/lyz-code/mkdocs-newsletter?branch=master) +[![Coverage Status](https://coveralls.io/repos/github/lyz-code/mkdocs-newsletter/badge.svg?branch=main)](https://coveralls.io/github/lyz-code/mkdocs-newsletter?branch=main) MkDocs plugin to show the changes of documentation repositories in a user friendly format, at the same time that it's easy for the authors to maintain. @@ -77,13 +77,13 @@ giants, namely: [Black](https://black.readthedocs.io/en/stable/) : Python formatter to keep a nice style without effort. -[Autoimport](https://github.com/lyz-code/autoimport) +[Autoimport](https://lyz-code.github.io/autoimport) : Python formatter to automatically fix wrong import statements. [isort](https://github.com/timothycrosley/isort) : Python formatter to order the import statements. -[Pip-tools](https://github.com/jazzband/pip-tools) +[PDM](https://pdm.fming.dev/) : Command line tool to manage the dependencies. [Mkdocs](https://www.mkdocs.org/) diff --git a/pdm.lock b/pdm.lock index 7103042..ba7beb8 100644 --- a/pdm.lock +++ b/pdm.lock @@ -128,6 +128,11 @@ dependencies = [ "webencodings", ] +[[package]] +name = "cached-property" +version = "1.5.2" +summary = "A decorator for caching properties in classes." + [[package]] name = "certifi" version = "2022.5.18.1" @@ -573,6 +578,15 @@ dependencies = [ "typing-extensions>=3.7.4.3; python_version < \"3.8\"", ] +[[package]] +name = "griffe" +version = "0.20.0" +requires_python = ">=3.7" +summary = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +dependencies = [ + "cached-property; python_version < \"3.8\"", +] + [[package]] name = "htmlmin" version = "0.1.12" @@ -592,7 +606,7 @@ summary = "Internationalized Domain Names in Applications (IDNA)" [[package]] name = "importlib-metadata" -version = "4.11.1" +version = "4.11.4" requires_python = ">=3.7" summary = "Read metadata from Python packages" dependencies = [ @@ -821,6 +835,27 @@ dependencies = [ "pymdown-extensions>=6.3", ] +[[package]] +name = "mkdocstrings-python" +version = "0.7.0" +requires_python = ">=3.7" +summary = "A Python handler for mkdocstrings." +dependencies = [ + "griffe>=0.11.1", + "mkdocstrings>=0.19", +] + +[[package]] +name = "mkdocstrings" +version = "0.19.0" +extras = ["python"] +requires_python = ">=3.7" +summary = "Automatic documentation from sources, for MkDocs." +dependencies = [ + "mkdocstrings-python>=0.5.2", + "mkdocstrings>=0.18", +] + [[package]] name = "mypy" version = "0.961" @@ -1339,6 +1374,11 @@ version = "1.5.4" requires_python = ">=3.6" summary = "a fork of Python 2 and 3 ast modules with type comment support" +[[package]] +name = "types-click" +version = "7.1.8" +summary = "Typing stubs for click" + [[package]] name = "typing-extensions" version = "4.2.0" @@ -1427,7 +1467,7 @@ summary = "Backport of pathlib-compatible object wrapper for zip files" [metadata] lock_version = "3.1" -content_hash = "sha256:b7fb98a554123d662ad68399c2f65d5e1ad347e11e480507f62bf2cb78cf08fb" +content_hash = "sha256:a2f3a80fa7db031718b486395f1fc3ad1e3d9bdc5001b0e377f2dcabc4ad771e" [metadata.files] "argcomplete 1.12.3" = [ @@ -1506,6 +1546,10 @@ content_hash = "sha256:b7fb98a554123d662ad68399c2f65d5e1ad347e11e480507f62bf2cb7 {file = "bleach-5.0.0-py3-none-any.whl", hash = "sha256:08a1fe86d253b5c88c92cc3d810fd8048a16d15762e1e5b74d502256e5926aa1"}, {file = "bleach-5.0.0.tar.gz", hash = "sha256:c6d6cc054bdc9c83b48b8083e236e5f00f238428666d2ce2e083eaa5fd568565"}, ] +"cached-property 1.5.2" = [ + {file = "cached_property-1.5.2-py2.py3-none-any.whl", hash = "sha256:df4f613cf7ad9a588cc381aaf4a512d26265ecebd5eb9e1ba12f1319eb85a6a0"}, + {file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"}, +] "certifi 2022.5.18.1" = [ {file = "certifi-2022.5.18.1-py3-none-any.whl", hash = "sha256:f1d53542ee8cbedbe2118b5686372fb33c297fcd6379b050cca0ef13a597382a"}, {file = "certifi-2022.5.18.1.tar.gz", hash = "sha256:9c5705e395cd70084351dd8ad5c41e65655e08ce46f2ec9cf6c2c08390f71eb7"}, @@ -1816,6 +1860,10 @@ content_hash = "sha256:b7fb98a554123d662ad68399c2f65d5e1ad347e11e480507f62bf2cb7 {file = "GitPython-3.1.27-py3-none-any.whl", hash = "sha256:5b68b000463593e05ff2b261acff0ff0972df8ab1b70d3cdbd41b546c8b8fc3d"}, {file = "GitPython-3.1.27.tar.gz", hash = "sha256:1c885ce809e8ba2d88a29befeb385fcea06338d3640712b59ca623c220bb5704"}, ] +"griffe 0.20.0" = [ + {file = "griffe-0.20.0-py3-none-any.whl", hash = "sha256:899e0c9c09baf22b31de1c969a03edaf0ddf72d0a7183df8de746b6c26ed62f4"}, + {file = "griffe-0.20.0.tar.gz", hash = "sha256:bf181de6e661c0d2a229c1dc7e90db0def280ee3a89c6829fcc1695baee65f7f"}, +] "htmlmin 0.1.12" = [ {file = "htmlmin-0.1.12.tar.gz", hash = "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"}, ] @@ -1827,9 +1875,9 @@ content_hash = "sha256:b7fb98a554123d662ad68399c2f65d5e1ad347e11e480507f62bf2cb7 {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, ] -"importlib-metadata 4.11.1" = [ - {file = "importlib_metadata-4.11.1-py3-none-any.whl", hash = "sha256:e0bc84ff355328a4adfc5240c4f211e0ab386f80aa640d1b11f0618a1d282094"}, - {file = "importlib_metadata-4.11.1.tar.gz", hash = "sha256:175f4ee440a0317f6e8d81b7f8d4869f93316170a65ad2b007d2929186c8052c"}, +"importlib-metadata 4.11.4" = [ + {file = "importlib_metadata-4.11.4-py3-none-any.whl", hash = "sha256:c58c8eb8a762858f49e18436ff552e83914778e50e9d2f1660535ffb364552ec"}, + {file = "importlib_metadata-4.11.4.tar.gz", hash = "sha256:5d26852efe48c0a32b0509ffbc583fda1a2266545a78d104a6f4aff3db17d700"}, ] "iniconfig 1.1.1" = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -2063,6 +2111,10 @@ content_hash = "sha256:b7fb98a554123d662ad68399c2f65d5e1ad347e11e480507f62bf2cb7 {file = "mkdocstrings-0.19.0-py3-none-any.whl", hash = "sha256:3217d510d385c961f69385a670b2677e68e07b5fea4a504d86bf54c006c87c7d"}, {file = "mkdocstrings-0.19.0.tar.gz", hash = "sha256:efa34a67bad11229d532d89f6836a8a215937548623b64f3698a1df62e01cc3e"}, ] +"mkdocstrings-python 0.7.0" = [ + {file = "mkdocstrings_python-0.7.0-py3-none-any.whl", hash = "sha256:6964bd92f106766e771ac6cd5bc02643a960602b4d921b95362e31d491e9a6db"}, + {file = "mkdocstrings-python-0.7.0.tar.gz", hash = "sha256:e54c67890e8bb7dc4604360c8ef5dd214b23b6924de7706f461e3c998d4ea061"}, +] "mypy 0.961" = [ {file = "mypy-0.961-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:697540876638ce349b01b6786bc6094ccdaba88af446a9abb967293ce6eaa2b0"}, {file = "mypy-0.961-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b117650592e1782819829605a193360a08aa99f1fc23d1d71e1a75a142dc7e15"}, @@ -2416,6 +2468,10 @@ content_hash = "sha256:b7fb98a554123d662ad68399c2f65d5e1ad347e11e480507f62bf2cb7 {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] +"types-click 7.1.8" = [ + {file = "types_click-7.1.8-py3-none-any.whl", hash = "sha256:8cb030a669e2e927461be9827375f83c16b8178c365852c060a34e24871e7e81"}, + {file = "types-click-7.1.8.tar.gz", hash = "sha256:b6604968be6401dc516311ca50708a0a28baa7a0cb840efd7412f0dbbff4e092"}, +] "typing-extensions 4.2.0" = [ {file = "typing_extensions-4.2.0-py3-none-any.whl", hash = "sha256:6657594ee297170d19f67d55c05852a874e7eb634f4f753dbd667855e07c1708"}, {file = "typing_extensions-4.2.0.tar.gz", hash = "sha256:f1c24655a0da0d1b67f07e17a5e6b2a105894e6824b92096378bb3668ef02376"}, diff --git a/pyproject.toml b/pyproject.toml index 9f9c311..c259810 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,11 @@ version_files = [ "src/mkdocs_newsletter/version.py", ] +# --------- Autoimport ------------- + +[tool.autoimport.common_statements] +"factories" = "from tests import factories" + # --------- PDM ------------- [project] @@ -70,9 +75,7 @@ editable-backend = "path" [tool.pdm.overrides] # To be removed once https://github.com/flakeheaven/flakeheaven/issues/55 is solved -# To update to ">=3.10" once a version of pdm greater than 1.12.8 exists -# "importlib-metadata" = ">=3.10" -importlib-metadata = "4.11.1" +"importlib-metadata" = ">=3.10" [tool.pdm.dev-dependencies] lint = [ @@ -116,7 +119,7 @@ doc = [ "mkdocs-minify-plugin>=0.5.0", "mkdocs-autolinks-plugin>=0.4.0", "mkdocs-material>=8.0.5", - "mkdocstrings>=0.16.2", + "mkdocstrings[python]>=0.18", "markdown-include>=0.6.0", "mkdocs-section-index>=0.3.2", ] @@ -132,6 +135,7 @@ fixers = [ ] typing = [ "mypy>=0.910", + "types-click>=7.1.8", ] dev = [ "pre-commit>=2.16.0", @@ -230,7 +234,10 @@ flake8-annotations-complexity = ["+*"] flake8-bugbear = ["+*"] flake8-comprehensions = ["+*"] flake8-debugger = ["+*"] -flake8-docstrings = ["+*"] +flake8-docstrings = [ + "+*", + "-D101", # Missing docstring, already covered by C0115 of pylint +] flake8-eradicate = ["+*"] flake8-expression-complexity = ["+*"] flake8-fixme = ["+*"] @@ -246,7 +253,8 @@ flake8-use-fstring = [ flake8-typing-imports = [ "+*", "-TYP001", # guard import by `if False: # TYPE_CHECKING`: TYPE_CHECKING (not in - # 3.5.0, 3.5.1). We don't support Python < 3.6 + # 3.5.0, 3.5.1). We don't support Python 3.5 + "-TYP002", # @overload is broken in <3.5.2, but we don't support Python 3.5 ] flake8-variables-names = ["+*"] dlint = ["+*"] @@ -270,7 +278,11 @@ pycodestyle = [ # see https://github.com/PyCQA/pycodestyle/issues/197 # and https://github.com/psf/black/issues/113 ] -pyflakes = ["+*"] +pyflakes = [ + "+*", + "-F841", # Unused variable, already covered by W0612 of pylint + "-F821", # Undefined variable, already covered by E0602 of pylint +] [tool.flakeheaven.exceptions."tests/"] flake8-docstrings = [ @@ -281,7 +293,8 @@ flake8-eradicate = [ "-E800", # Found commented code, but it's not, it's a markdown header ] flake8-annotations = [ - "-ANN001" + "-ANN001", + "-ANN401", # Dynamically typed expressions (typing.Any) are disallowed ] pylint = [ "-R0201", # Method could be a function. Raised because the methods of a test class @@ -332,6 +345,15 @@ disallow_incomplete_defs = true disallow_untyped_decorators = true disallow_untyped_calls = true disallow_untyped_defs = true +plugins = [ + "pydantic.mypy" +] + +[tool.pydantic-mypy] +init_forbid_extra = true +init_typed = true +warn_required_dynamic_aliases = true +warn_untyped_fields = true [[tool.mypy.overrides]] module = "tests.*" diff --git a/src/mkdocs_newsletter/model.py b/src/mkdocs_newsletter/model.py index 90ee889..0cf6407 100644 --- a/src/mkdocs_newsletter/model.py +++ b/src/mkdocs_newsletter/model.py @@ -5,10 +5,10 @@ from datetime import datetime, timedelta from enum import Enum from pathlib import Path -from typing import Any, Dict, List, Optional +from typing import List, Optional from dateutil import tz -from pydantic import BaseModel, Field, HttpUrl, root_validator +from pydantic import BaseModel, Field, HttpUrl class Change(BaseModel): @@ -70,45 +70,44 @@ class Newsletter(BaseModel): """Represents a newsletter.""" file_: Path - date: datetime - type_: NewsletterType - basename: str - - @root_validator(pre=True) - @classmethod - def set_attributes(cls, values: Dict[str, Any]) -> Dict[str, Any]: - """Set the class attributes. - * basename: basename of the file. - * type_: Set the type of the newsletter. - * date: Set the datetime associated to the file name. - """ - basename = os.path.splitext(values["file_"].name)[0] - values["basename"] = basename - - if re.match(r"\d{4}$", basename): - values["type_"] = "yearly" - values["date"] = datetime(int(basename), 1, 1, tzinfo=tz.tzlocal()) - elif re.match(r"\d{4}_\d{2}$", basename): - values["type_"] = "monthly" - year = int(basename.split("_")[0]) - month = int(basename.split("_")[1]) - values["date"] = datetime(year, month, 1, tzinfo=tz.tzlocal()) - elif re.match(r"\d{4}_w\d{2}$", basename): - values["type_"] = "weekly" - year = int(basename.split("_")[0]) - week = int(basename.split("w")[1]) + @property + def basename(self) -> str: + """Return the basename of the Newsletter.""" + return os.path.splitext(self.file_.name)[0] + + @property + def type_(self) -> str: + """Return the type of the Newsletter.""" + if re.match(r"\d{4}$", self.basename): + return "yearly" + if re.match(r"\d{4}_\d{2}$", self.basename): + return "monthly" + if re.match(r"\d{4}_w\d{2}$", self.basename): + return "weekly" + if re.match(r"\d{4}_\d{2}_\d{2}$", self.basename): + return "daily" + raise ValueError("Can't extract type from file path") + + @property + def date(self) -> datetime: + """Return the date of the Newsletter.""" + if re.match(r"\d{4}$", self.basename): + return datetime(int(self.basename), 1, 1, tzinfo=tz.tzlocal()) + if re.match(r"\d{4}_\d{2}$", self.basename): + year = int(self.basename.split("_")[0]) + month = int(self.basename.split("_")[1]) + return datetime(year, month, 1, tzinfo=tz.tzlocal()) + if re.match(r"\d{4}_w\d{2}$", self.basename): + year = int(self.basename.split("_")[0]) + week = int(self.basename.split("w")[1]) first_day = datetime(year, 1, 1, tzinfo=tz.tzlocal()) - values["date"] = first_day + timedelta( - days=7 * (week - 1) - first_day.weekday() - ) - elif re.match(r"\d{4}_\d{2}_\d{2}$", basename): - values["type_"] = "daily" - values["date"] = datetime.strptime(basename, "%Y_%m_%d").replace( + return first_day + timedelta(days=7 * (week - 1) - first_day.weekday()) + if re.match(r"\d{4}_\d{2}_\d{2}$", self.basename): + return datetime.strptime(self.basename, "%Y_%m_%d").replace( tzinfo=tz.tzlocal() ) - - return values + raise ValueError("Can't extract date from file path") def __lt__(self, other: "Newsletter") -> bool: """Assert if an object is smaller than us. diff --git a/src/mkdocs_newsletter/services/newsletter.py b/src/mkdocs_newsletter/services/newsletter.py index 401cffc..597ee79 100644 --- a/src/mkdocs_newsletter/services/newsletter.py +++ b/src/mkdocs_newsletter/services/newsletter.py @@ -6,6 +6,7 @@ import os import re from contextlib import suppress +from pathlib import Path from typing import Callable, List, Optional, Tuple from dateutil import tz @@ -79,18 +80,19 @@ def _list_newsletters(newsletter_dir: str) -> Newsletters: Newsletters object. """ newsletters = Newsletters() - for file_ in os.scandir(newsletter_dir): - if file_.name == "0_newsletter_index.md": - continue - newsletter = Newsletter(file_=file_) - if newsletter.type_ == "yearly": - newsletters.yearly.append(newsletter) - elif newsletter.type_ == "monthly": - newsletters.monthly.append(newsletter) - elif newsletter.type_ == "weekly": - newsletters.weekly.append(newsletter) - elif newsletter.type_ == "daily": - newsletters.daily.append(newsletter) + with os.scandir(newsletter_dir) as files: + for file_ in files: + if file_.name == "0_newsletter_index.md": + continue + newsletter = Newsletter(file_=Path(file_.path)) + if newsletter.type_ == "yearly": + newsletters.yearly.append(newsletter) + elif newsletter.type_ == "monthly": + newsletters.monthly.append(newsletter) + elif newsletter.type_ == "weekly": + newsletters.weekly.append(newsletter) + elif newsletter.type_ == "daily": + newsletters.daily.append(newsletter) newsletters.sort() return newsletters diff --git a/src/mkdocs_newsletter/services/rss.py b/src/mkdocs_newsletter/services/rss.py index 9b6d921..99145db 100644 --- a/src/mkdocs_newsletter/services/rss.py +++ b/src/mkdocs_newsletter/services/rss.py @@ -70,9 +70,9 @@ def build_rss_feed(config: Config, working_dir: str, type_: str) -> Feed: ttl=TTL[type_], generator=f"mkdocs-newsletter - v{__version__}", title=config.get("site_name", None), - link=site_url, - rss_link=f"{site_url}/{type_}.xml", - logo=logo_url, + link=site_url, # type: ignore + rss_link=f"{site_url}/{type_}.xml", # type: ignore + logo=logo_url, # type: ignore description=config.get("site_description", None), author=author, published=published, @@ -137,7 +137,7 @@ def _build_rss_entries( entry = FeedEntry( title=title, - link=f"{site_url}/newsletter/{newsletter.basename}/", + link=f"{site_url}/newsletter/{newsletter.basename}/", # type: ignore published=published, description=description, author=author, diff --git a/src/mkdocs_newsletter/version.py b/src/mkdocs_newsletter/version.py index b442ad1..5e6d511 100644 --- a/src/mkdocs_newsletter/version.py +++ b/src/mkdocs_newsletter/version.py @@ -2,6 +2,7 @@ import platform import sys +from textwrap import dedent # Do not edit this line manually, let `make bump` do it. __version__ = "1.0.1" @@ -9,9 +10,11 @@ def version_info() -> str: """Display the version of the program, python and the platform.""" - info = { - "mkdocs_newsletter version": __version__, - "python version": sys.version.replace("\n", " "), - "platform": platform.platform(), - } - return "\n".join(f"{k + ':' :>30} {v}" for k, v in info.items()) + return dedent( + f"""\ + ------------------------------------------------------------------ + mkdocs_newsletter: {__version__} + Python: {sys.version.split(" ", maxsplit=1)[0]} + Platform: {platform.platform()} + ------------------------------------------------------------------""" + ) diff --git a/tests/unit/test_model.py b/tests/unit/test_model.py index 2194996..5afb2fb 100644 --- a/tests/unit/test_model.py +++ b/tests/unit/test_model.py @@ -3,6 +3,7 @@ from datetime import datetime from pathlib import Path +import pytest from dateutil import tz from mkdocs_newsletter.model import ( @@ -84,13 +85,13 @@ def test_feedentry_can_order_objects() -> None: # noqa: AAA01 greater = FeedEntry( published=datetime(2021, 1, 1), title="Greater", - link="https://test.com", + link="https://test.com", # type: ignore description="", ) smaller = FeedEntry( published=datetime(2020, 1, 1), title="Smaller", - link="https://test.com", + link="https://test.com", # type: ignore description="", ) @@ -98,3 +99,22 @@ def test_feedentry_can_order_objects() -> None: # noqa: AAA01 # SIM204, C0113: We don't want to simplify to important > unimportant because we # want to test the __lt__ method assert not greater < smaller # noqa: C0113, SIM204 + + +@pytest.mark.parametrize( + ("property_", "message"), + [ + ("type_", "Can't extract type from file path"), + ("date", "Can't extract date from file path"), + ], +) +def test_newsletter_handles_wrong_path(property_: str, message: str) -> None: + """ + Given: A Newsletter with a path that doesn't have a date. + When: calling the type_ and date methods + Then: Errors are raised + """ + newsletter = Newsletter(file_=Path("wrong_path.md")) + + with pytest.raises(ValueError, match=message): + getattr(newsletter, property_) diff --git a/tests/unit/test_version.py b/tests/unit/test_version.py index 41bac66..677e3a9 100644 --- a/tests/unit/test_version.py +++ b/tests/unit/test_version.py @@ -14,6 +14,6 @@ def test_version() -> None: """ result = version_info() - assert sys.version.replace("\n", " ") in result + assert sys.version.split(" ", maxsplit=1)[0] in result assert platform.platform() in result assert __version__ in result