diff --git a/commitizen/changelog.py b/commitizen/changelog.py index bc05fd6d6d..1aab969aad 100644 --- a/commitizen/changelog.py +++ b/commitizen/changelog.py @@ -61,7 +61,7 @@ @dataclass class Metadata: """ - Metadata extracted from the changelog pproduced by a plugin + Metadata extracted from the changelog produced by a plugin """ unreleased_start: int | None = None diff --git a/commitizen/cli.py b/commitizen/cli.py index 42c5b9a999..50c134eb0b 100644 --- a/commitizen/cli.py +++ b/commitizen/cli.py @@ -7,6 +7,7 @@ from functools import partial from pathlib import Path from types import TracebackType +from typing import Any, Sequence import argcomplete from decli import cli @@ -16,6 +17,7 @@ CommitizenException, ExitCode, ExpectedExit, + InvalidCommandArgumentError, NoCommandFoundError, ) @@ -41,9 +43,25 @@ class ParseKwargs(argparse.Action): } """ - def __call__(self, parser, namespace, kwarg, option_string=None): + def __call__( + self, + parser: argparse.ArgumentParser, + namespace: argparse.Namespace, + kwarg: str | Sequence[Any] | None, + option_string: str | None = None, + ): + if not isinstance(kwarg, str): + return + if "=" not in kwarg: + raise InvalidCommandArgumentError( + f"Option {option_string} expect a key=value format" + ) kwargs = getattr(namespace, self.dest, None) or {} key, value = kwarg.split("=", 1) + if not key: + raise InvalidCommandArgumentError( + f"Option {option_string} expect a key=value format" + ) kwargs[key] = value.strip("'\"") setattr(namespace, self.dest, kwargs) diff --git a/commitizen/commands/bump.py b/commitizen/commands/bump.py index cd457d1672..e7c36240a4 100644 --- a/commitizen/commands/bump.py +++ b/commitizen/commands/bump.py @@ -22,6 +22,7 @@ NotAllowed, NoVersionSpecifiedError, ) +from commitizen.formats import get_format from commitizen.providers import get_provider from commitizen.version_schemes import InvalidVersion, get_version_scheme @@ -79,15 +80,15 @@ def __init__(self, config: BaseConfig, arguments: dict): self.scheme = get_version_scheme( self.config, arguments["version_scheme"] or deprecated_version_type ) + self.file_name = arguments["file_name"] or self.config.settings.get( + "changelog_file" + ) + self.format = get_format(self.config, self.file_name) + self.template = ( arguments["template"] or self.config.settings.get("template") - or self.cz.template - ) - self.file_name = ( - arguments["file_name"] - or self.config.settings.get("changelog_file") - or self.cz.changelog_file + or self.format.template ) self.extras = arguments["extras"] diff --git a/commitizen/commands/changelog.py b/commitizen/commands/changelog.py index c2d575ef2f..7aefd1ecfe 100644 --- a/commitizen/commands/changelog.py +++ b/commitizen/commands/changelog.py @@ -17,6 +17,7 @@ NotAGitProjectError, NotAllowed, ) +from commitizen.formats import get_format from commitizen.git import GitTag, smart_open from commitizen.version_schemes import get_version_scheme @@ -35,11 +36,17 @@ def __init__(self, config: BaseConfig, args): self.start_rev = args.get("start_rev") or self.config.settings.get( "changelog_start_rev" ) - self.file_name = ( - args.get("file_name") - or self.config.settings.get("changelog_file") - or self.cz.changelog_file + self.file_name = args.get("file_name") or self.config.settings.get( + "changelog_file" ) + if not isinstance(self.file_name, str): + raise NotAllowed( + "Changelog file name is broken.\n" + "Check the flag `--file-name` in the terminal " + f"or the setting `changelog_file` in {self.config.path}" + ) + self.format = get_format(self.config, self.file_name) + self.incremental = args["incremental"] or self.config.settings.get( "changelog_incremental" ) @@ -72,7 +79,7 @@ def __init__(self, config: BaseConfig, args): self.template = ( args.get("template") or self.config.settings.get("template") - or self.cz.template + or self.format.template ) self.extras = args.get("extras") or {} self.export_template_to = args.get("export_template") @@ -106,13 +113,6 @@ def _find_incremental_rev(self, latest_version: str, tags: list[GitTag]) -> str: def write_changelog( self, changelog_out: str, lines: list[str], changelog_meta: changelog.Metadata ): - if not isinstance(self.file_name, str): - raise NotAllowed( - "Changelog file name is broken.\n" - "Check the flag `--file-name` in the terminal " - f"or the setting `changelog_file` in {self.config.path}" - ) - changelog_hook: Callable | None = self.cz.changelog_hook with smart_open(self.file_name, "w", encoding=self.encoding) as changelog_file: partial_changelog: str | None = None @@ -162,7 +162,7 @@ def __call__(self): end_rev = "" if self.incremental: - changelog_meta = self.cz.get_metadata(self.file_name) + changelog_meta = self.format.get_metadata(self.file_name) if changelog_meta.latest_version: latest_tag_version: str = bump.normalize_tag( changelog_meta.latest_version, diff --git a/commitizen/cz/base.py b/commitizen/cz/base.py index 48e10de335..d9bf5ea4a0 100644 --- a/commitizen/cz/base.py +++ b/commitizen/cz/base.py @@ -1,16 +1,12 @@ from __future__ import annotations from abc import ABCMeta, abstractmethod -import os -import re -from typing import IO, Any, Callable +from typing import Any, Callable from jinja2 import BaseLoader, PackageLoader from prompt_toolkit.styles import Style, merge_styles from commitizen import git -from commitizen import defaults -from commitizen.changelog import Metadata from commitizen.config.base_config import BaseConfig from commitizen.defaults import Questions @@ -48,9 +44,7 @@ class BaseCommitizen(metaclass=ABCMeta): # Executed only at the end of the changelog generation changelog_hook: Callable[[str, str | None], str] | None = None - changelog_file: str = "CHANGELOG.md" - - # template: str = DEFAULT_TEMPLATE + # Plugins can override templates and provide extra template data template_loader: BaseLoader = PackageLoader("commitizen", "templates") template_extras: dict[str, Any] = {} @@ -59,10 +53,6 @@ def __init__(self, config: BaseConfig): if not self.config.settings.get("style"): self.config.settings.update({"style": BaseCommitizen.default_style_config}) - @property - def template(self) -> str: - return f"{self.changelog_file}.j2" - @abstractmethod def questions(self) -> Questions: """Questions regarding the commit message.""" @@ -102,56 +92,3 @@ def process_commit(self, commit: str) -> str: If not overwritten, it returns the first line of commit. """ return commit.split("\n")[0] - - def get_metadata(self, filepath: str) -> Metadata: - if not os.path.isfile(filepath): - return Metadata() - - with open(filepath, "r") as changelog_file: - return self.get_metadata_from_file(changelog_file) - - def get_metadata_from_file(self, file: IO[Any]) -> Metadata: - meta = Metadata() - unreleased_title: str | None = None - for index, line in enumerate(file): - line = line.strip().lower() - - unreleased: str | None = None - if "unreleased" in line: - unreleased = self.parse_title_type_of_line(line) - # Try to find beginning and end lines of the unreleased block - if unreleased: - meta.unreleased_start = index - unreleased_title = unreleased - continue - elif ( - isinstance(unreleased_title, str) - and self.parse_title_type_of_line(line) == unreleased_title - ): - meta.unreleased_end = index - - # Try to find the latest release done - version = self.parse_version_from_changelog(line) - if version: - meta.latest_version = version - meta.latest_version_position = index - break # there's no need for more info - if meta.unreleased_start is not None and meta.unreleased_end is None: - meta.unreleased_end = index - - return meta - - def parse_version_from_changelog(self, line: str) -> str | None: - if not line.startswith("#"): - return None - m = re.search(defaults.version_parser, line) - if not m: - return None - return m.groupdict().get("version") - - def parse_title_type_of_line(self, line: str) -> str | None: - md_title_parser = r"^(?P#+)" - m = re.search(md_title_parser, line) - if not m: - return None - return m.groupdict().get("title") diff --git a/commitizen/cz/conventional_commits/__init__.py b/commitizen/cz/conventional_commits/__init__.py index 54767e1298..52624d2ddb 100644 --- a/commitizen/cz/conventional_commits/__init__.py +++ b/commitizen/cz/conventional_commits/__init__.py @@ -1,6 +1 @@ -from .conventional_commits import ( - ConventionalCommitsCz, # noqa: F401 - ConventionalCommitsTextile, # noqa: F401 - ConventionalCommitsAsciiDoc, # noqa: F401 - ConventionalCommitsRst, # noqa: F401 -) +from .conventional_commits import ConventionalCommitsCz # noqa: F401 diff --git a/commitizen/cz/conventional_commits/conventional_commits.py b/commitizen/cz/conventional_commits/conventional_commits.py index 4f59026395..1382622fee 100644 --- a/commitizen/cz/conventional_commits/conventional_commits.py +++ b/commitizen/cz/conventional_commits/conventional_commits.py @@ -1,9 +1,7 @@ import os import re -from typing import IO, Any, Optional from commitizen import defaults -from commitizen.changelog import Metadata from commitizen.cz.base import BaseCommitizen from commitizen.cz.utils import multiple_line_breaker, required_validator from commitizen.defaults import Questions @@ -214,104 +212,3 @@ def process_commit(self, commit: str) -> str: if m is None: return "" return m.group(3).strip() - - -class ConventionalCommitsTextile(ConventionalCommitsCz): - changelog_file = "CHANGELOG.textile" - - def parse_version_from_changelog(self, line: str) -> Optional[str]: - if not line.startswith("h2. "): - return None - m = re.search(defaults.version_parser, line) - if not m: - return None - return m.groupdict().get("version") - - def parse_title_type_of_line(self, line: str) -> Optional[str]: - md_title_parser = r"^(?P<title>h\d\. )" - m = re.search(md_title_parser, line) - if not m: - return None - return m.groupdict().get("title") - - -class ConventionalCommitsAsciiDoc(ConventionalCommitsCz): - changelog_file = "CHANGELOG.adoc" - - def parse_version_from_changelog(self, line: str) -> Optional[str]: - if not line.startswith("== "): - return None - m = re.search(defaults.version_parser, line) - if not m: - return None - return m.groupdict().get("version") - - def parse_title_type_of_line(self, line: str) -> Optional[str]: - md_title_parser = r"^(?P<title>=+)" - m = re.search(md_title_parser, line) - if not m: - return None - return m.groupdict().get("title") - - -class ConventionalCommitsRst(ConventionalCommitsCz): - changelog_file = "CHANGELOG.rst" - - def get_metadata_from_file(self, file: IO[Any]) -> Metadata: - """ - RestructuredText section titles are not one-line-based, - it requires its own algorithm. - - This method does not extract metadata from any restructuredtext file - but only from the one generated by this plugin with its template. - - For a more generic approach, you need to rely on `docutils`. - """ - meta = Metadata() - unreleased_title: Optional[str] = None - lines = file.readlines() - for index, (line, next_line) in enumerate(zip(lines, lines[1:])): - line = line.strip().lower() - next_line = next_line.strip() - - unreleased: Optional[str] = None - if "unreleased" in line: - unreleased = self.title_type_of_line(line, next_line) - # Try to find beginning and end lines of the unreleased block - if unreleased: - meta.unreleased_start = index - unreleased_title = unreleased - continue - elif ( - isinstance(unreleased_title, str) - and self.title_type_of_line(line, next_line) == unreleased_title - ): - meta.unreleased_end = index - - # Try to find the latest release done - version = self.version_from_changelog(line, next_line) - if version: - meta.latest_version = version - meta.latest_version_position = index - break # there's no need for more info - if meta.unreleased_start is not None and meta.unreleased_end is None: - meta.unreleased_end = index + 1 - - return meta - - def version_from_changelog(self, line: str, next_line: str) -> Optional[str]: - if not len(next_line) >= len(line): - return None - elif not next_line == "=" * len(next_line): - return None - m = re.search(defaults.version_parser, line) - if not m: - return None - return m.groupdict().get("version") - - def title_type_of_line(self, line: str, next_line: str) -> Optional[str]: - if not len(next_line) >= len(line): - return None - elif not next_line == "=" * len(next_line): - return None - return next_line[0] diff --git a/commitizen/defaults.py b/commitizen/defaults.py index 120608f3b9..89f3642025 100644 --- a/commitizen/defaults.py +++ b/commitizen/defaults.py @@ -43,7 +43,7 @@ class Settings(TypedDict, total=False): bump_message: str | None allow_abort: bool allowed_prefixes: list[str] - changelog_file: str | None + changelog_file: str changelog_incremental: bool changelog_start_rev: str | None changelog_merge_prerelease: bool @@ -56,6 +56,7 @@ class Settings(TypedDict, total=False): post_bump_hooks: list[str] | None prerelease_offset: int encoding: str + format: str | None template: str | None extras: dict[str, Any] @@ -87,7 +88,7 @@ class Settings(TypedDict, total=False): "fixup!", "squash!", ], - "changelog_file": None, # default provided by plugin + "changelog_file": "CHANGELOG.md", "changelog_incremental": False, "changelog_start_rev": None, "changelog_merge_prerelease": False, @@ -98,6 +99,11 @@ class Settings(TypedDict, total=False): "post_bump_hooks": [], "prerelease_offset": 0, "encoding": encoding, +<<<<<<< HEAD +======= + "version_type": None, + "format": None, # default guessed from changelog_file +>>>>>>> 0a6694e (feat(formats): expose customizable changelog formats on the `commitizen.formats` endpoint) "template": None, # default provided by plugin "extras": {}, } @@ -105,7 +111,6 @@ class Settings(TypedDict, total=False): MAJOR = "MAJOR" MINOR = "MINOR" PATCH = "PATCH" -TEMPLATE_EXTENSION = "j2" bump_pattern = r"^(((BREAKING[\-\ ]CHANGE|feat|fix|refactor|perf)(\(.+\))?(!)?)|\w+!):" bump_map = OrderedDict( diff --git a/commitizen/formats/__init__.py b/commitizen/formats/__init__.py new file mode 100644 index 0000000000..ffc6723813 --- /dev/null +++ b/commitizen/formats/__init__.py @@ -0,0 +1,94 @@ +from __future__ import annotations + +import sys + +from typing import ClassVar, Optional + +import importlib_metadata as metadata + +from commitizen.changelog import Metadata +from commitizen.config.base_config import BaseConfig + +from .errors import FormatUnknown + +if sys.version_info >= (3, 8): + from typing import Protocol +else: + from typing_extensions import Protocol + +FORMAT_ENTRYPOINT = "commitizen.format" +DEFAULT_FORMAT = "markdown" +DEFAULT_TEMPLATE_EXTENSION = "j2" + + +class Format(Protocol): + extension: ClassVar[str] + """Standard known extension associated with this format""" + + alternative_extensions: ClassVar[set[str]] + """Known alternatives extensions for this format""" + + config: BaseConfig + + def __init__(self, config: BaseConfig): + self.config = config + + @property + def ext(self) -> str: + """Dotted version of extensions, as in `pathlib` and `os` modules""" + return f".{self.extension}" + + @property + def template(self) -> str: + """Expected template name for this format""" + return f"CHANGELOG.{self.extension}.{DEFAULT_TEMPLATE_EXTENSION}" + + @property + def default_changelog_file(self) -> str: + return f"CHANGELOG.{self.extension}" + + def get_metadata(self, filepath: str) -> Metadata: + """ + Extract the changelog metadata. + """ + + +KNOWN_FORMATS: dict[str, type[Format]] = { + ep.name: ep.load() for ep in metadata.entry_points(group=FORMAT_ENTRYPOINT) +} + + +def get_format(config: BaseConfig, filename: Optional[str] = None) -> Format: + """ + Get a format from its name + + :raises FormatUnknown: if a non-empty name is provided but cannot be found in the known formats + """ + name: Optional[str] = config.settings.get("format") + format: Optional[type[Format]] = guess_format(filename) + + if name and name in KNOWN_FORMATS: + format = KNOWN_FORMATS[name] + + if not format: + raise FormatUnknown(f"unknown format '{name}'") + + return format(config) + + +def guess_format(filename: Optional[str]) -> Optional[type[Format]]: + """ + Try guessing the file format from the filename. + + Algorithm is basic, extension-based, and won't work + for extension-less file names like `CHANGELOG` or `NEWS`. + """ + if not filename or not isinstance(filename, str): + return None + for format in KNOWN_FORMATS.values(): + if filename.endswith(f".{format.extension}"): + return format + for alt_extension in format.alternative_extensions: + if filename.endswith(f".{alt_extension}"): + return format + return None diff --git a/commitizen/formats/asciidoc.py b/commitizen/formats/asciidoc.py new file mode 100644 index 0000000000..8053da7171 --- /dev/null +++ b/commitizen/formats/asciidoc.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +import re + +from typing import Optional + +from commitizen import defaults + +from .base import BaseFormat + + +class AsciiDoc(BaseFormat): + extension = "adoc" + + RE_TITLE = re.compile(r"^(?P<level>=+) (?P<title>.*)$") + + def parse_version_from_title(self, line: str) -> Optional[str]: + m = self.RE_TITLE.match(line) + if not m: + return None + # Capture last match as AsciiDoc use postfixed URL labels + matches = list(re.finditer(defaults.version_parser, m.group("title"))) + if not matches: + return None + return matches[-1].group("version") + + def parse_title_level(self, line: str) -> Optional[int]: + m = self.RE_TITLE.match(line) + if not m: + return None + return len(m.group("level")) diff --git a/commitizen/formats/base.py b/commitizen/formats/base.py new file mode 100644 index 0000000000..e449c0aa2a --- /dev/null +++ b/commitizen/formats/base.py @@ -0,0 +1,76 @@ +from __future__ import annotations +from abc import ABCMeta + +import os + +from typing import IO, Any, ClassVar, Optional + +from commitizen.changelog import Metadata +from commitizen.config.base_config import BaseConfig + +from . import Format + + +class BaseFormat(Format, metaclass=ABCMeta): + """ + Base class to extend to implement a changelog file format. + """ + + extension: ClassVar[str] = "" + alternative_extensions: ClassVar[set[str]] = set() + + def __init__(self, config: BaseConfig): + # Constructor needs to be redefined because `Protocol` prevent instantiation by default + # See: https://bugs.python.org/issue44807 + self.config = config + + def get_metadata(self, filepath: str) -> Metadata: + if not os.path.isfile(filepath): + return Metadata() + + with open(filepath, "r") as changelog_file: + return self.get_metadata_from_file(changelog_file) + + def get_metadata_from_file(self, file: IO[Any]) -> Metadata: + meta = Metadata() + unreleased_level: Optional[int] = None + for index, line in enumerate(file): + line = line.strip().lower() + + unreleased: Optional[int] = None + if "unreleased" in line: + unreleased = self.parse_title_level(line) + # Try to find beginning and end lines of the unreleased block + if unreleased: + meta.unreleased_start = index + unreleased_level = unreleased + continue + elif unreleased_level and self.parse_title_level(line) == unreleased_level: + meta.unreleased_end = index + + # Try to find the latest release done + version = self.parse_version_from_title(line) + if version: + meta.latest_version = version + meta.latest_version_position = index + break # there's no need for more info + if meta.unreleased_start is not None and meta.unreleased_end is None: + meta.unreleased_end = index + + return meta + + def parse_version_from_title(self, line: str) -> Optional[str]: + """ + Extract the version from a title line if any + """ + raise NotImplementedError( + "Default `get_metadata_from_file` requires `parse_version_from_changelog` to be implemented" + ) + + def parse_title_level(self, line: str) -> Optional[int]: + """ + Get the title level/type of a line if any + """ + raise NotImplementedError( + "Default `get_metadata_from_file` requires `parse_title_type_of_line` to be implemented" + ) diff --git a/commitizen/formats/errors.py b/commitizen/formats/errors.py new file mode 100644 index 0000000000..e68e785785 --- /dev/null +++ b/commitizen/formats/errors.py @@ -0,0 +1,9 @@ +from __future__ import annotations + + +class FormatError(Exception): + """Base class for format-related errors""" + + +class FormatUnknown(FormatError): + """Raised when a format identifier is unknown""" diff --git a/commitizen/formats/markdown.py b/commitizen/formats/markdown.py new file mode 100644 index 0000000000..45dee588a0 --- /dev/null +++ b/commitizen/formats/markdown.py @@ -0,0 +1,29 @@ +from __future__ import annotations +import re +from typing import Optional +from commitizen import defaults + +from .base import BaseFormat + + +class Markdown(BaseFormat): + extension = "md" + + alternative_extensions = {"markdown", "mkd"} + + RE_TITLE = re.compile(r"^(?P<level>#+) (?P<title>.*)$") + + def parse_version_from_title(self, line: str) -> Optional[str]: + m = self.RE_TITLE.match(line) + if not m: + return None + m = re.search(defaults.version_parser, m.group("title")) + if not m: + return None + return m.group("version") + + def parse_title_level(self, line: str) -> Optional[int]: + m = self.RE_TITLE.match(line) + if not m: + return None + return len(m.group("level")) diff --git a/commitizen/formats/restructuredtext.py b/commitizen/formats/restructuredtext.py new file mode 100644 index 0000000000..d367ef7c83 --- /dev/null +++ b/commitizen/formats/restructuredtext.py @@ -0,0 +1,95 @@ +from __future__ import annotations + +import re +import sys +from itertools import zip_longest +from typing import IO, TYPE_CHECKING, Any, Optional, Union, Tuple + +from commitizen import defaults +from commitizen.changelog import Metadata + +from .base import BaseFormat + +if TYPE_CHECKING: + # TypeAlias is Python 3.10+ but backported in typing-extensions + if sys.version_info >= (3, 10): + from typing import TypeAlias + else: + from typing_extensions import TypeAlias + + +TitleKind: TypeAlias = Union[str, Tuple[str, str]] + + +class RestructuredText(BaseFormat): + extension = "rst" + + def get_metadata_from_file(self, file: IO[Any]) -> Metadata: + """ + RestructuredText section titles are not one-line-based, + they spread on 2 or 3 lines and levels are not predefined + but determined byt their occurrence order. + + It requires its own algorithm. + + For a more generic approach, you need to rely on `docutils`. + """ + meta = Metadata() + unreleased_title_kind: Optional[TitleKind] = None + in_overlined_title = False + lines = file.readlines() + for index, (first, second, third) in enumerate( + zip_longest(lines, lines[1:], lines[2:], fillvalue="") + ): + first = first.strip().lower() + second = second.strip().lower() + third = third.strip().lower() + title: Optional[str] = None + kind: Optional[TitleKind] = None + + if self.is_overlined_title(first, second, third): + title = second + kind = (first[0], third[0]) + in_overlined_title = True + elif not in_overlined_title and self.is_underlined_title(first, second): + title = first + kind = second[0] + else: + in_overlined_title = False + + if title: + if "unreleased" in title: + unreleased_title_kind = kind + meta.unreleased_start = index + continue + elif unreleased_title_kind and unreleased_title_kind == kind: + meta.unreleased_end = index + # Try to find the latest release done + m = re.search(defaults.version_parser, title) + if m: + version = m.group("version") + meta.latest_version = version + meta.latest_version_position = index + break # there's no need for more info + if meta.unreleased_start is not None and meta.unreleased_end is None: + meta.unreleased_end = ( + meta.latest_version_position if meta.latest_version else index + 1 + ) + + return meta + + def is_overlined_title(self, first: str, second: str, third: str) -> bool: + return ( + len(first) >= len(second) + and len(first) == len(third) + and all(char == first[0] for char in first[1:]) + and first[0] == third[0] + and self.is_underlined_title(second, third) + ) + + def is_underlined_title(self, first: str, second: str) -> bool: + return ( + len(second) >= len(first) + and not second.isalnum() + and all(char == second[0] for char in second[1:]) + ) diff --git a/commitizen/formats/textile.py b/commitizen/formats/textile.py new file mode 100644 index 0000000000..361cd302f6 --- /dev/null +++ b/commitizen/formats/textile.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import re + +from typing import Optional + +from commitizen import defaults + +from .base import BaseFormat + + +class Textile(BaseFormat): + extension = "textile" + + RE_TITLE = re.compile(r"^h(?P<level>\d)\. (?P<title>.*)$") + + def parse_version_from_title(self, line: str) -> Optional[str]: + if not self.RE_TITLE.match(line): + return None + m = re.search(defaults.version_parser, line) + if not m: + return None + return m.group("version") + + def parse_title_level(self, line: str) -> Optional[int]: + m = self.RE_TITLE.match(line) + if not m: + return None + return int(m.group("level")) diff --git a/poetry.lock b/poetry.lock index 4289fdcd59..b8dc1d1332 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,9 +1,10 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry and should not be changed by hand. [[package]] name = "appnope" version = "0.1.3" description = "Disable App Nap on macOS >= 10.9" +category = "dev" optional = false python-versions = "*" files = [ @@ -13,17 +14,18 @@ files = [ [[package]] name = "argcomplete" -version = "3.1.1" +version = "3.0.8" description = "Bash tab completion for argparse" +category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "argcomplete-3.1.1-py3-none-any.whl", hash = "sha256:35fa893a88deea85ea7b20d241100e64516d6af6d7b0ae2bed1d263d26f70948"}, - {file = "argcomplete-3.1.1.tar.gz", hash = "sha256:6c4c563f14f01440aaffa3eae13441c5db2357b5eec639abe7c0b15334627dff"}, + {file = "argcomplete-3.0.8-py3-none-any.whl", hash = "sha256:e36fd646839933cbec7941c662ecb65338248667358dd3d968405a4506a60d9b"}, + {file = "argcomplete-3.0.8.tar.gz", hash = "sha256:b9ca96448e14fa459d7450a4ab5a22bbf9cee4ba7adddf03e65c398b5daeea28"}, ] [package.dependencies] -importlib-metadata = {version = ">=0.23,<7", markers = "python_version < \"3.8\""} +importlib-metadata = {version = ">=0.23,<7", markers = "python_version == \"3.7\""} [package.extras] test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] @@ -32,6 +34,7 @@ test = ["coverage", "mypy", "pexpect", "ruff", "wheel"] name = "backcall" version = "0.2.0" description = "Specifications for callback functions passed in to an API" +category = "dev" optional = false python-versions = "*" files = [ @@ -43,6 +46,7 @@ files = [ name = "black" version = "22.12.0" description = "The uncompromising code formatter." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -79,6 +83,7 @@ uvloop = ["uvloop (>=0.15.2)"] name = "certifi" version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -90,6 +95,7 @@ files = [ name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." +category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -99,92 +105,94 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.1.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.1.0.tar.gz", hash = "sha256:34e0a2f9c370eb95597aae63bf85eb5e96826d81e3dcf88b8886012906f509b5"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0ac8959c929593fee38da1c2b64ee9778733cdf03c482c9ff1d508b6b593b2b"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7fc3fca01da18fbabe4625d64bb612b533533ed10045a2ac3dd194bfa656b60"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20064ead0717cf9a73a6d1e779b23d149b53daf971169289ed2ed43a71e8d3b0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1435ae15108b1cb6fffbcea2af3d468683b7afed0169ad718451f8db5d1aff6f"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c84132a54c750fda57729d1e2599bb598f5fa0344085dbde5003ba429a4798c0"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f2568b4189dda1c567339b48cba4ac7384accb9c2a7ed655cd86b04055c795"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11d3bcb7be35e7b1bba2c23beedac81ee893ac9871d0ba79effc7fc01167db6c"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:891cf9b48776b5c61c700b55a598621fdb7b1e301a550365571e9624f270c203"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:5f008525e02908b20e04707a4f704cd286d94718f48bb33edddc7d7b584dddc1"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b06f0d3bf045158d2fb8837c5785fe9ff9b8c93358be64461a1089f5da983137"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:49919f8400b5e49e961f320c735388ee686a62327e773fa5b3ce6721f7e785ce"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22908891a380d50738e1f978667536f6c6b526a2064156203d418f4856d6e86a"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win32.whl", hash = "sha256:12d1a39aa6b8c6f6248bb54550efcc1c38ce0d8096a146638fd4738e42284448"}, + {file = "charset_normalizer-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:65ed923f84a6844de5fd29726b888e58c62820e0769b76565480e1fdc3d062f8"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9a3267620866c9d17b959a84dd0bd2d45719b817245e49371ead79ed4f710d19"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6734e606355834f13445b6adc38b53c0fd45f1a56a9ba06c2058f86893ae8017"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf53a6cebad0eae578f062c7d462155eada9c172bd8c4d250b8c1d8eb7f916a"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dc5b6a8ecfdc5748a7e429782598e4f17ef378e3e272eeb1340ea57c9109f41"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e1b25e3ad6c909f398df8921780d6a3d120d8c09466720226fc621605b6f92b1"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ca564606d2caafb0abe6d1b5311c2649e8071eb241b2d64e75a0d0065107e62"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b82fab78e0b1329e183a65260581de4375f619167478dddab510c6c6fb04d9b6"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bd7163182133c0c7701b25e604cf1611c0d87712e56e88e7ee5d72deab3e76b5"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:11d117e6c63e8f495412d37e7dc2e2fff09c34b2d09dbe2bee3c6229577818be"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:cf6511efa4801b9b38dc5546d7547d5b5c6ef4b081c60b23e4d941d0eba9cbeb"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:abc1185d79f47c0a7aaf7e2412a0eb2c03b724581139193d2d82b3ad8cbb00ac"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cb7b2ab0188829593b9de646545175547a70d9a6e2b63bf2cd87a0a391599324"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win32.whl", hash = "sha256:c36bcbc0d5174a80d6cccf43a0ecaca44e81d25be4b7f90f0ed7bcfbb5a00909"}, + {file = "charset_normalizer-3.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:cca4def576f47a09a943666b8f829606bcb17e2bc2d5911a46c8f8da45f56755"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c95f12b74681e9ae127728f7e5409cbbef9cd914d5896ef238cc779b8152373"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac0aa6cd53ab9a31d397f8303f92c42f534693528fafbdb997c82bae6e477ad9"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c3af8e0f07399d3176b179f2e2634c3ce9c1301379a6b8c9c9aeecd481da494f"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5fc78f9e3f501a1614a98f7c54d3969f3ad9bba8ba3d9b438c3bc5d047dd28"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:628c985afb2c7d27a4800bfb609e03985aaecb42f955049957814e0491d4006d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:74db0052d985cf37fa111828d0dd230776ac99c740e1a758ad99094be4f1803d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:1e8fcdd8f672a1c4fc8d0bd3a2b576b152d2a349782d1eb0f6b8e52e9954731d"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:dd5653e67b149503c68c4018bf07e42eeed6b4e956b24c00ccdf93ac79cdff84"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d2686f91611f9e17f4548dbf050e75b079bbc2a82be565832bc8ea9047b61c8c"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:4155b51ae05ed47199dc5b2a4e62abccb274cee6b01da5b895099b61b1982974"}, + {file = "charset_normalizer-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322102cdf1ab682ecc7d9b1c5eed4ec59657a65e1c146a0da342b78f4112db23"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e633940f28c1e913615fd624fcdd72fdba807bf53ea6925d6a588e84e1151531"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3a06f32c9634a8705f4ca9946d667609f52cf130d5548881401f1eb2c39b1e2c"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7381c66e0561c5757ffe616af869b916c8b4e42b367ab29fedc98481d1e74e14"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3573d376454d956553c356df45bb824262c397c6e26ce43e8203c4c540ee0acb"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e89df2958e5159b811af9ff0f92614dabf4ff617c03a4c1c6ff53bf1c399e0e1"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78cacd03e79d009d95635e7d6ff12c21eb89b894c354bd2b2ed0b4763373693b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de5695a6f1d8340b12a5d6d4484290ee74d61e467c39ff03b39e30df62cf83a0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c60b9c202d00052183c9be85e5eaf18a4ada0a47d188a83c8f5c5b23252f649"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f645caaf0008bacf349875a974220f1f1da349c5dbe7c4ec93048cdc785a3326"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ea9f9c6034ea2d93d9147818f17c2a0860d41b71c38b9ce4d55f21b6f9165a11"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:80d1543d58bd3d6c271b66abf454d437a438dff01c3e62fdbcd68f2a11310d4b"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:73dc03a6a7e30b7edc5b01b601e53e7fc924b04e1835e8e407c12c037e81adbd"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6f5c2e7bc8a4bf7c426599765b1bd33217ec84023033672c1e9a8b35eaeaaaf8"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win32.whl", hash = "sha256:12a2b561af122e3d94cdb97fe6fb2bb2b82cef0cdca131646fdb940a1eda04f0"}, + {file = "charset_normalizer-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:3160a0fd9754aab7d47f95a6b63ab355388d890163eb03b2d2b87ab0a30cfa59"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:38e812a197bf8e71a59fe55b757a84c1f946d0ac114acafaafaf21667a7e169e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6baf0baf0d5d265fa7944feb9f7451cc316bfe30e8df1a61b1bb08577c554f31"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8f25e17ab3039b05f762b0a55ae0b3632b2e073d9c8fc88e89aca31a6198e88f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3747443b6a904001473370d7810aa19c3a180ccd52a7157aacc264a5ac79265e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b116502087ce8a6b7a5f1814568ccbd0e9f6cfd99948aa59b0e241dc57cf739f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d16fd5252f883eb074ca55cb622bc0bee49b979ae4e8639fff6ca3ff44f9f854"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21fa558996782fc226b529fdd2ed7866c2c6ec91cee82735c98a197fae39f706"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f6c7a8a57e9405cad7485f4c9d3172ae486cfef1344b5ddd8e5239582d7355e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ac3775e3311661d4adace3697a52ac0bab17edd166087d493b52d4f4f553f9f0"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:10c93628d7497c81686e8e5e557aafa78f230cd9e77dd0c40032ef90c18f2230"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:6f4f4668e1831850ebcc2fd0b1cd11721947b6dc7c00bf1c6bd3c929ae14f2c7"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0be65ccf618c1e7ac9b849c315cc2e8a8751d9cfdaa43027d4f6624bd587ab7e"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:53d0a3fa5f8af98a1e261de6a3943ca631c526635eb5817a87a59d9a57ebf48f"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win32.whl", hash = "sha256:a04f86f41a8916fe45ac5024ec477f41f886b3c435da2d4e3d2709b22ab02af1"}, + {file = "charset_normalizer-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:830d2948a5ec37c386d3170c483063798d7879037492540f10a475e3fd6f244b"}, + {file = "charset_normalizer-3.1.0-py3-none-any.whl", hash = "sha256:3d9098b479e78c85080c98e1e35ff40b4a31d8953102bb0fd7d1b6f8a2111a3d"}, ] [[package]] name = "click" version = "8.1.3" description = "Composable command line interface toolkit" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -200,6 +208,7 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -211,6 +220,7 @@ files = [ name = "coverage" version = "7.2.7" description = "Code coverage measurement for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -286,6 +296,7 @@ toml = ["tomli"] name = "decli" version = "0.6.1" description = "Minimal, easy-to-use, declarative cli tool" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -297,6 +308,7 @@ files = [ name = "decorator" version = "5.1.1" description = "Decorators for Humans" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -308,6 +320,7 @@ files = [ name = "deprecated" version = "1.2.14" description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -325,6 +338,7 @@ dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "sphinx (<2)", "tox"] name = "distlib" version = "0.3.6" description = "Distribution utilities" +category = "dev" optional = false python-versions = "*" files = [ @@ -336,6 +350,7 @@ files = [ name = "exceptiongroup" version = "1.1.1" description = "Backport of PEP 654 (exception groups)" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -350,6 +365,7 @@ test = ["pytest (>=6)"] name = "execnet" version = "1.9.0" description = "execnet: rapid multi-Python deployment" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ @@ -362,23 +378,25 @@ testing = ["pre-commit"] [[package]] name = "filelock" -version = "3.12.2" +version = "3.12.0" description = "A platform independent file lock." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "freezegun" version = "1.2.2" description = "Let your Python tests travel through time" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -393,6 +411,7 @@ python-dateutil = ">=2.7" name = "ghp-import" version = "2.1.0" description = "Copy your docs directly to the gh-pages branch." +category = "dev" optional = false python-versions = "*" files = [ @@ -410,6 +429,7 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "identify" version = "2.5.24" description = "File identification library for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -424,6 +444,7 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -433,13 +454,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.7.0" +version = "6.6.0" description = "Read metadata from Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, - {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, + {file = "importlib_metadata-6.6.0-py3-none-any.whl", hash = "sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed"}, + {file = "importlib_metadata-6.6.0.tar.gz", hash = "sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705"}, ] [package.dependencies] @@ -449,12 +471,13 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -466,6 +489,7 @@ files = [ name = "ipython" version = "7.34.0" description = "IPython: Productive Interactive Computing" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -502,6 +526,7 @@ test = ["ipykernel", "nbformat", "nose (>=0.10.1)", "numpy (>=1.17)", "pygments" name = "jedi" version = "0.18.2" description = "An autocompletion tool for Python that can be used for text editors." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -521,6 +546,7 @@ testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -538,6 +564,7 @@ i18n = ["Babel (>=2.7)"] name = "markdown" version = "3.3.7" description = "Python implementation of Markdown." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -555,6 +582,7 @@ testing = ["coverage", "pyyaml"] name = "markupsafe" version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -614,6 +642,7 @@ files = [ name = "matplotlib-inline" version = "0.1.6" description = "Inline Matplotlib backend for Jupyter" +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -628,6 +657,7 @@ traitlets = "*" name = "mergedeep" version = "1.3.4" description = "A deep merge function for 🐍." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -637,13 +667,14 @@ files = [ [[package]] name = "mkdocs" -version = "1.5.2" +version = "1.4.3" description = "Project documentation with Markdown." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs-1.5.2-py3-none-any.whl", hash = "sha256:60a62538519c2e96fe8426654a67ee177350451616118a41596ae7c876bb7eac"}, - {file = "mkdocs-1.5.2.tar.gz", hash = "sha256:70d0da09c26cff288852471be03c23f0f521fc15cf16ac89c7a3bfb9ae8d24f9"}, + {file = "mkdocs-1.4.3-py3-none-any.whl", hash = "sha256:6ee46d309bda331aac915cd24aab882c179a933bd9e77b80ce7d2eaaa3f689dd"}, + {file = "mkdocs-1.4.3.tar.gz", hash = "sha256:5955093bbd4dd2e9403c5afaf57324ad8b04f16886512a3ee6ef828956481c57"}, ] [package.dependencies] @@ -652,12 +683,9 @@ colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} ghp-import = ">=1.0" importlib-metadata = {version = ">=4.3", markers = "python_version < \"3.10\""} jinja2 = ">=2.11.1" -markdown = ">=3.2.1" -markupsafe = ">=2.0.1" +markdown = ">=3.2.1,<3.4" mergedeep = ">=1.3.4" packaging = ">=20.5" -pathspec = ">=0.11.1" -platformdirs = ">=2.2.0" pyyaml = ">=5.1" pyyaml-env-tag = ">=0.1" typing-extensions = {version = ">=3.10", markers = "python_version < \"3.8\""} @@ -665,24 +693,25 @@ watchdog = ">=2.0" [package.extras] i18n = ["babel (>=2.9.0)"] -min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pathspec (==0.11.1)", "platformdirs (==2.2.0)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.3)", "jinja2 (==2.11.1)", "markdown (==3.2.1)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "packaging (==20.5)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "typing-extensions (==3.10)", "watchdog (==2.0)"] [[package]] name = "mkdocs-material" -version = "9.1.21" +version = "9.1.15" description = "Documentation that simply works" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "mkdocs_material-9.1.21-py3-none-any.whl", hash = "sha256:58bb2f11ef240632e176d6f0f7d1cff06be1d11c696a5a1b553b808b4280ed47"}, - {file = "mkdocs_material-9.1.21.tar.gz", hash = "sha256:71940cdfca84ab296b6362889c25395b1621273fb16c93deda257adb7ff44ec8"}, + {file = "mkdocs_material-9.1.15-py3-none-any.whl", hash = "sha256:b49e12869ab464558e2dd3c5792da5b748a7e0c48ee83b4d05715f98125a7a39"}, + {file = "mkdocs_material-9.1.15.tar.gz", hash = "sha256:8513ab847c9a541ed3d11a3a7eed556caf72991ee786c31c5aac6691a121088a"}, ] [package.dependencies] colorama = ">=0.4" jinja2 = ">=3.0" markdown = ">=3.2" -mkdocs = ">=1.5.0" +mkdocs = ">=1.4.2" mkdocs-material-extensions = ">=1.1" pygments = ">=2.14" pymdown-extensions = ">=9.9.1" @@ -693,6 +722,7 @@ requests = ">=2.26" name = "mkdocs-material-extensions" version = "1.1.1" description = "Extension pack for Python Markdown and MkDocs Material." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -704,6 +734,7 @@ files = [ name = "mypy" version = "1.4.1" description = "Optional static typing for Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -751,6 +782,7 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -762,6 +794,7 @@ files = [ name = "nodeenv" version = "1.8.0" description = "Node.js virtual environment builder" +category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ @@ -776,6 +809,7 @@ setuptools = "*" name = "packaging" version = "23.1" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -787,6 +821,7 @@ files = [ name = "parso" version = "0.8.3" description = "A Python Parser" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -802,6 +837,7 @@ testing = ["docopt", "pytest (<6.0.0)"] name = "pathspec" version = "0.11.1" description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -813,6 +849,7 @@ files = [ name = "pexpect" version = "4.8.0" description = "Pexpect allows easy control of interactive console applications." +category = "dev" optional = false python-versions = "*" files = [ @@ -827,6 +864,7 @@ ptyprocess = ">=0.5" name = "pickleshare" version = "0.7.5" description = "Tiny 'shelve'-like database with concurrency support" +category = "dev" optional = false python-versions = "*" files = [ @@ -836,31 +874,33 @@ files = [ [[package]] name = "platformdirs" -version = "3.8.0" +version = "3.5.1" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.8.0-py3-none-any.whl", hash = "sha256:ca9ed98ce73076ba72e092b23d3c93ea6c4e186b3f1c3dad6edd98ff6ffcca2e"}, - {file = "platformdirs-3.8.0.tar.gz", hash = "sha256:b0cabcb11063d21a0b261d557acb0a9d2126350e63b70cdf7db6347baea456dc"}, + {file = "platformdirs-3.5.1-py3-none-any.whl", hash = "sha256:e2378146f1964972c03c085bb5662ae80b2b8c06226c54b2ff4aa9483e8a13a5"}, + {file = "platformdirs-3.5.1.tar.gz", hash = "sha256:412dae91f52a6f84830f39a8078cecd0e866cb72294a5c66808e74d5e88d251f"}, ] [package.dependencies] -typing-extensions = {version = ">=4.6.3", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=4.5", markers = "python_version < \"3.8\""} [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.2.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" -version = "1.2.0" +version = "1.0.0" description = "plugin and hook calling mechanisms for python" +category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] [package.dependencies] @@ -874,6 +914,7 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -893,6 +934,7 @@ virtualenv = ">=20.10.0" name = "prompt-toolkit" version = "3.0.38" description = "Library for building powerful interactive command lines in Python" +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -907,6 +949,7 @@ wcwidth = "*" name = "ptyprocess" version = "0.7.0" description = "Run a subprocess in a pseudo terminal" +category = "dev" optional = false python-versions = "*" files = [ @@ -918,6 +961,7 @@ files = [ name = "pygments" version = "2.15.1" description = "Pygments is a syntax highlighting package written in Python." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -932,6 +976,7 @@ plugins = ["importlib-metadata"] name = "pymdown-extensions" version = "10.0.1" description = "Extension pack for Python Markdown." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -945,13 +990,14 @@ pyyaml = "*" [[package]] name = "pytest" -version = "7.4.0" +version = "7.3.1" description = "pytest: simple powerful testing with Python" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.0-py3-none-any.whl", hash = "sha256:78bf16451a2eb8c7a2ea98e32dc119fd2aa758f1d5d66dbf0a59d69a3969df32"}, - {file = "pytest-7.4.0.tar.gz", hash = "sha256:b4bf8c45bd59934ed84001ad51e11b4ee40d40a1229d2c79f9c592b0a3f6bd8a"}, + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ] [package.dependencies] @@ -964,12 +1010,13 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-cov" version = "4.1.0" description = "Pytest plugin for measuring coverage." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -988,6 +1035,7 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale name = "pytest-datadir" version = "1.4.1" description = "pytest plugin for test data directories and files" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1000,13 +1048,14 @@ pytest = ">=5.0" [[package]] name = "pytest-freezer" -version = "0.4.8" +version = "0.4.6" description = "Pytest plugin providing a fixture interface for spulec/freezegun" +category = "dev" optional = false -python-versions = ">= 3.6" +python-versions = ">=3.6" files = [ - {file = "pytest_freezer-0.4.8-py3-none-any.whl", hash = "sha256:644ce7ddb8ba52b92a1df0a80a699bad2b93514c55cf92e9f2517b68ebe74814"}, - {file = "pytest_freezer-0.4.8.tar.gz", hash = "sha256:8ee2f724b3ff3540523fa355958a22e6f4c1c819928b78a7a183ae4248ce6ee6"}, + {file = "pytest_freezer-0.4.6-py3-none-any.whl", hash = "sha256:ca549c30a7e12bc7b242978b6fa0bb91e73cd1bd7d5b2bb658f0f9d7f1694cac"}, + {file = "pytest_freezer-0.4.6.tar.gz", hash = "sha256:8e88cd571d3ba10dd9e0cc09897eb01c32a37bef5ca4ff7c4ea8598c91aa6d96"}, ] [package.dependencies] @@ -1015,13 +1064,14 @@ pytest = ">=3.6" [[package]] name = "pytest-mock" -version = "3.11.1" +version = "3.10.0" description = "Thin-wrapper around the mock package for easier use with pytest" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, - {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, + {file = "pytest-mock-3.10.0.tar.gz", hash = "sha256:fbbdb085ef7c252a326fd8cdcac0aa3b1333d8811f131bdcc701002e1be7ed4f"}, + {file = "pytest_mock-3.10.0-py3-none-any.whl", hash = "sha256:f4c973eeae0282963eb293eb173ce91b091a79c1334455acfac9ddee8a1c784b"}, ] [package.dependencies] @@ -1034,6 +1084,7 @@ dev = ["pre-commit", "pytest-asyncio", "tox"] name = "pytest-regressions" version = "2.4.2" description = "Easy to use fixtures to write regression tests." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1056,6 +1107,7 @@ num = ["numpy", "pandas"] name = "pytest-xdist" version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1076,6 +1128,7 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1088,57 +1141,59 @@ six = ">=1.5" [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0" description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, + {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, + {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, + {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, + {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, + {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, + {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, + {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, + {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, + {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, + {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, + {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, + {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, + {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, + {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, + {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, + {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, + {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, + {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, + {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, + {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, + {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, + {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, + {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, + {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, + {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, ] [[package]] name = "pyyaml-env-tag" version = "0.1" description = "A custom YAML tag for referencing environment variables in YAML files. " +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1153,6 +1208,7 @@ pyyaml = "*" name = "questionary" version = "1.10.0" description = "Python library to build pretty command line user prompts ⭐️" +category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1170,6 +1226,7 @@ docs = ["Sphinx (>=3.3,<4.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphin name = "regex" version = "2023.6.3" description = "Alternative regular expression module, to replace re." +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1267,6 +1324,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1288,6 +1346,7 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "ruff" version = "0.0.282" description = "An extremely fast Python linter, written in Rust." +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1312,13 +1371,14 @@ files = [ [[package]] name = "setuptools" -version = "68.0.0" +version = "67.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, - {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, + {file = "setuptools-67.8.0-py3-none-any.whl", hash = "sha256:5df61bf30bb10c6f756eb19e7c9f3b473051f48db77fddbe06ff2ca307df9a6f"}, + {file = "setuptools-67.8.0.tar.gz", hash = "sha256:62642358adc77ffa87233bc4d2354c4b2682d214048f500964dbe760ccedf102"}, ] [package.extras] @@ -1330,6 +1390,7 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs ( name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1341,6 +1402,7 @@ files = [ name = "termcolor" version = "2.3.0" description = "ANSI color formatting for output in terminal" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1355,6 +1417,7 @@ tests = ["pytest", "pytest-cov"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1364,19 +1427,21 @@ files = [ [[package]] name = "tomlkit" -version = "0.12.1" +version = "0.11.8" description = "Style preserving TOML library" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"}, - {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"}, + {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, + {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, ] [[package]] name = "traitlets" version = "5.9.0" description = "Traitlets Python configuration system" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1392,6 +1457,7 @@ test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] name = "typed-ast" version = "1.5.4" description = "a fork of Python 2 and 3 ast modules with type comment support" +category = "dev" optional = false python-versions = ">=3.6" files = [ @@ -1425,6 +1491,7 @@ files = [ name = "types-deprecated" version = "1.2.9.3" description = "Typing stubs for Deprecated" +category = "dev" optional = false python-versions = "*" files = [ @@ -1436,6 +1503,7 @@ files = [ name = "types-python-dateutil" version = "2.8.19.14" description = "Typing stubs for python-dateutil" +category = "dev" optional = false python-versions = "*" files = [ @@ -1445,19 +1513,21 @@ files = [ [[package]] name = "types-pyyaml" -version = "6.0.12.11" +version = "5.4.12" description = "Typing stubs for PyYAML" +category = "dev" optional = false python-versions = "*" files = [ - {file = "types-PyYAML-6.0.12.11.tar.gz", hash = "sha256:7d340b19ca28cddfdba438ee638cd4084bde213e501a3978738543e27094775b"}, - {file = "types_PyYAML-6.0.12.11-py3-none-any.whl", hash = "sha256:a461508f3096d1d5810ec5ab95d7eeecb651f3a15b71959999988942063bf01d"}, + {file = "types-PyYAML-5.4.12.tar.gz", hash = "sha256:3f4daa754357491625ae8c3a39c9e1b0d7cd5632bc4e1c35e7a7f75a64aa124b"}, + {file = "types_PyYAML-5.4.12-py3-none-any.whl", hash = "sha256:e06083f85375a5678e4c19452ed6467ce2167b71db222313e1792cb8fc76859a"}, ] [[package]] name = "types-termcolor" version = "0.1.1" description = "Typing stubs for termcolor" +category = "dev" optional = false python-versions = "*" files = [ @@ -1467,24 +1537,26 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" +version = "4.6.3" description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.6.3-py3-none-any.whl", hash = "sha256:88a4153d8505aabbb4e13aacb7c486c2b4a33ca3b3f807914a9b4c844c471c26"}, + {file = "typing_extensions-4.6.3.tar.gz", hash = "sha256:d91d5919357fe7f681a9f2b5b4cb2a5f1ef0a1e9f59c4d8ff0d3491e05c0ffd5"}, ] [[package]] name = "urllib3" -version = "2.0.3" +version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "urllib3-2.0.3-py3-none-any.whl", hash = "sha256:48e7fafa40319d358848e1bc6809b208340fafe2096f1725d05d67443d0483d1"}, - {file = "urllib3-2.0.3.tar.gz", hash = "sha256:bee28b5e56addb8226c96f7f13ac28cb4c301dd5ea8a6ca179c0b9835e032825"}, + {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, + {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, ] [package.extras] @@ -1495,29 +1567,31 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.23.1" +version = "20.23.0" description = "Virtual Python Environment builder" +category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.23.1-py3-none-any.whl", hash = "sha256:34da10f14fea9be20e0fd7f04aba9732f84e593dac291b757ce42e3368a39419"}, - {file = "virtualenv-20.23.1.tar.gz", hash = "sha256:8ff19a38c1021c742148edc4f81cb43d7f8c6816d2ede2ab72af5b84c749ade1"}, + {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, + {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, ] [package.dependencies] distlib = ">=0.3.6,<1" -filelock = ">=3.12,<4" -importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} -platformdirs = ">=3.5.1,<4" +filelock = ">=3.11,<4" +importlib-metadata = {version = ">=6.4.1", markers = "python_version < \"3.8\""} +platformdirs = ">=3.2,<4" [package.extras] -docs = ["furo (>=2023.5.20)", "proselint (>=0.13)", "sphinx (>=7.0.1)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezer (>=0.4.6)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.8)", "time-machine (>=2.9)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] [[package]] name = "watchdog" version = "3.0.0" description = "Filesystem events monitoring" +category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1557,6 +1631,7 @@ watchmedo = ["PyYAML (>=3.10)"] name = "wcwidth" version = "0.2.6" description = "Measures the displayed width of unicode strings in a terminal" +category = "main" optional = false python-versions = "*" files = [ @@ -1568,6 +1643,7 @@ files = [ name = "wrapt" version = "1.15.0" description = "Module for decorators, wrappers and monkey patching." +category = "dev" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" files = [ @@ -1652,6 +1728,7 @@ files = [ name = "zipp" version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" optional = false python-versions = ">=3.7" files = [ diff --git a/pyproject.toml b/pyproject.toml index 92628aba52..b709a17b9f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -82,9 +82,12 @@ git-cz = "commitizen.cli:main" cz_conventional_commits = "commitizen.cz.conventional_commits:ConventionalCommitsCz" cz_jira = "commitizen.cz.jira:JiraSmartCz" cz_customize = "commitizen.cz.customize:CustomizeCommitsCz" -conventional_commits_asciidoc = "commitizen.cz.conventional_commits:ConventionalCommitsAsciiDoc" -conventional_commits_textile = "commitizen.cz.conventional_commits:ConventionalCommitsTextile" -conventional_commits_restructuredtext = "commitizen.cz.conventional_commits:ConventionalCommitsRst" + +[tool.poetry.plugins."commitizen.format"] +markdown = "commitizen.formats.markdown:Markdown" +asciidoc = "commitizen.formats.asciidoc:AsciiDoc" +textile = "commitizen.formats.textile:Textile" +restructuredtext = "commitizen.formats.restructuredtext:RestructuredText" [tool.poetry.plugins."commitizen.provider"] cargo = "commitizen.providers:CargoProvider" diff --git a/tests/commands/conftest.py b/tests/commands/conftest.py index 9eb82473af..91931849b2 100644 --- a/tests/commands/conftest.py +++ b/tests/commands/conftest.py @@ -1,6 +1,4 @@ import os -from pathlib import Path -from typing import NamedTuple import pytest @@ -45,47 +43,6 @@ def config_customize(): return _config -class Plugin(NamedTuple): - name: str - extension: str - - @property - def changelog_file(self) -> str: - return f"CHANGELOG{self.extension}" - - @property - def template(self) -> str: - return f"CHANGELOG{self.extension}.j2" - - @property - def cli_args(self): - return ["--file-name", self.changelog_file, "--template", self.template] - - -TESTED_PLUGINS = { - "Markdown": Plugin("cz_conventional_commits", ".md"), - "Textile": Plugin("conventional_commits_textile", ".textile"), - "AsciiDoc": Plugin("conventional_commits_asciidoc", ".adoc"), - "RestructuredText": Plugin("conventional_commits_restructuredtext", ".rst"), -} - - -@pytest.fixture( - params=[pytest.param(plugin, id=id) for id, plugin in TESTED_PLUGINS.items()] -) -def plugin( - config: BaseConfig, - request: pytest.FixtureRequest, - tmp_commitizen_project: Path, -) -> Plugin: - plugin: Plugin = request.param - config.settings["name"] = plugin.name - config.settings["changelog_file"] = plugin.changelog_file - with (tmp_commitizen_project / "pyproject.toml").open("a") as cfg: - cfg.write(f'name="{plugin.name}"') - return plugin - - @pytest.fixture() def changelog_path() -> str: return os.path.join(os.getcwd(), "CHANGELOG.md") diff --git a/tests/commands/test_bump_command.py b/tests/commands/test_bump_command.py index 6d777be773..1293431cfe 100644 --- a/tests/commands/test_bump_command.py +++ b/tests/commands/test_bump_command.py @@ -28,6 +28,7 @@ NotAllowed, NoVersionSpecifiedError, ) +from commitizen.formats import Format from tests.utils import create_file_and_commit, create_tag @@ -1117,7 +1118,7 @@ def test_bump_command_version_scheme_priority_over_version_type(mocker: MockFixt def test_bump_template_option_precedance( mocker: MockFixture, tmp_commitizen_project: Path, - mock_plugin: BaseCommitizen, + any_format: Format, arg: str, cfg: str, expected: str, @@ -1125,8 +1126,8 @@ def test_bump_template_option_precedance( project_root = Path(tmp_commitizen_project) cfg_template = project_root / "changelog.cfg" cmd_template = project_root / "changelog.cmd" - default_template = project_root / mock_plugin.template - changelog = project_root / mock_plugin.changelog_file + default_template = project_root / any_format.template + changelog = project_root / any_format.default_changelog_file cfg_template.write_text("from config") cmd_template.write_text("from cmd") @@ -1159,10 +1160,11 @@ def test_bump_template_option_precedance( def test_bump_template_extras_precedance( mocker: MockFixture, tmp_commitizen_project: Path, + any_format: Format, mock_plugin: BaseCommitizen, ): project_root = Path(tmp_commitizen_project) - changelog_tpl = project_root / mock_plugin.template + changelog_tpl = project_root / any_format.template changelog_tpl.write_text("{{first}} - {{second}} - {{third}}") mock_plugin.template_extras = dict( @@ -1196,17 +1198,17 @@ def test_bump_template_extras_precedance( mocker.patch.object(sys, "argv", testargs) cli.main() - changelog = project_root / mock_plugin.changelog_file + changelog = project_root / any_format.default_changelog_file assert changelog.read_text() == "from-command - from-config - from-plugin" def test_bump_template_extra_quotes( mocker: MockFixture, tmp_commitizen_project: Path, - mock_plugin: BaseCommitizen, + any_format: Format, ): project_root = Path(tmp_commitizen_project) - changelog_tpl = project_root / mock_plugin.template + changelog_tpl = project_root / any_format.template changelog_tpl.write_text("{{first}} - {{second}} - {{third}}") create_file_and_commit("feat: new file") @@ -1227,5 +1229,5 @@ def test_bump_template_extra_quotes( mocker.patch.object(sys, "argv", testargs) cli.main() - changelog = project_root / mock_plugin.changelog_file + changelog = project_root / any_format.default_changelog_file assert changelog.read_text() == "no-quote - single quotes - double quotes" diff --git a/tests/commands/test_changelog_command.py b/tests/commands/test_changelog_command.py index b10393d334..fe2bb83377 100644 --- a/tests/commands/test_changelog_command.py +++ b/tests/commands/test_changelog_command.py @@ -14,11 +14,13 @@ from commitizen.cz.base import BaseCommitizen from commitizen.exceptions import ( DryRunExit, + InvalidCommandArgumentError, NoCommitsFoundError, NoRevisionError, NotAGitProjectError, NotAllowed, ) +from commitizen.formats import Format from tests.utils import ( create_branch, create_file_and_commit, @@ -69,33 +71,61 @@ def test_changelog_with_different_cz(mocker: MockFixture, capsys, file_regressio @pytest.mark.usefixtures("tmp_commitizen_project") -def test_changelog_from_start(mocker: MockFixture, capsys, plugin, file_regression): +def test_changelog_from_start( + mocker: MockFixture, capsys, format: Format, file_regression +): create_file_and_commit("feat: new file") create_file_and_commit("refactor: is in changelog") create_file_and_commit("Merge into master") + changelog_file = f"CHANGELOG.{format.extension}" + template = f"CHANGELOG.{format.extension}.j2" - testargs = ["cz", "changelog"] + plugin.cli_args + testargs = [ + "cz", + "changelog", + "--file-name", + changelog_file, + "--template", + template, + ] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(plugin.changelog_file, "r") as f: + with open(changelog_file, "r") as f: out = f.read() - file_regression.check(out, extension=plugin.extension) + file_regression.check(out, extension=format.ext) @pytest.mark.usefixtures("tmp_commitizen_project") def test_changelog_replacing_unreleased_using_incremental( - mocker: MockFixture, capsys, plugin, file_regression + mocker: MockFixture, capsys, format: Format, file_regression ): create_file_and_commit("feat: add new output") create_file_and_commit("fix: output glitch") create_file_and_commit("Merge into master") + changelog_file = f"CHANGELOG.{format.extension}" + template = f"CHANGELOG.{format.extension}.j2" - testargs = ["cz", "changelog"] + plugin.cli_args + testargs = [ + "cz", + "changelog", + "--file-name", + changelog_file, + "--template", + template, + ] mocker.patch.object(sys, "argv", testargs) cli.main() - testargs = ["cz", "bump", "--yes"] + plugin.cli_args + testargs = [ + "cz", + "bump", + "--yes", + "--file-name", + changelog_file, + "--template", + template, + ] mocker.patch.object(sys, "argv", testargs) cli.main() @@ -103,16 +133,24 @@ def test_changelog_replacing_unreleased_using_incremental( create_file_and_commit("feat: add more stuff") create_file_and_commit("Merge into master") - testargs = ["cz", "changelog", "--incremental"] + plugin.cli_args + testargs = [ + "cz", + "changelog", + "--incremental", + "--file-name", + changelog_file, + "--template", + template, + ] mocker.patch.object(sys, "argv", testargs) cli.main() - with open(plugin.changelog_file, "r") as f: + with open(changelog_file, "r") as f: out = f.read().replace( datetime.strftime(datetime.now(), "%Y-%m-%d"), "2022-08-14" ) - file_regression.check(out, extension=plugin.extension) + file_regression.check(out, extension=format.ext) @pytest.mark.usefixtures("tmp_commitizen_project") @@ -1285,7 +1323,7 @@ def test_changelog_prerelease_rev_with_use_version_type_semver( def test_changelog_template_option_precedance( mocker: MockFixture, tmp_commitizen_project: Path, - mock_plugin: BaseCommitizen, + any_format: Format, arg: str, cfg: str, expected: str, @@ -1293,8 +1331,8 @@ def test_changelog_template_option_precedance( project_root = Path(tmp_commitizen_project) cfg_template = project_root / "changelog.cfg" cmd_template = project_root / "changelog.cmd" - default_template = project_root / mock_plugin.template - changelog = project_root / "CHANGELOG.md" + default_template = project_root / any_format.template + changelog = project_root / any_format.default_changelog_file cfg_template.write_text("from config") cmd_template.write_text("from cmd") @@ -1328,9 +1366,10 @@ def test_changelog_template_extras_precedance( mocker: MockFixture, tmp_commitizen_project: Path, mock_plugin: BaseCommitizen, + any_format: Format, ): project_root = Path(tmp_commitizen_project) - changelog_tpl = project_root / mock_plugin.template + changelog_tpl = project_root / any_format.template changelog_tpl.write_text("{{first}} - {{second}} - {{third}}") mock_plugin.template_extras = dict( @@ -1357,17 +1396,17 @@ def test_changelog_template_extras_precedance( mocker.patch.object(sys, "argv", testargs) cli.main() - changelog = project_root / mock_plugin.changelog_file + changelog = project_root / any_format.default_changelog_file assert changelog.read_text() == "from-command - from-config - from-plugin" def test_changelog_template_extra_quotes( mocker: MockFixture, tmp_commitizen_project: Path, - mock_plugin: BaseCommitizen, + any_format: Format, ): project_root = Path(tmp_commitizen_project) - changelog_tpl = project_root / mock_plugin.template + changelog_tpl = project_root / any_format.template changelog_tpl.write_text("{{first}} - {{second}} - {{third}}") create_file_and_commit("feat: new file") @@ -1385,18 +1424,63 @@ def test_changelog_template_extra_quotes( mocker.patch.object(sys, "argv", testargs) cli.main() - changelog = project_root / mock_plugin.changelog_file + changelog = project_root / any_format.default_changelog_file assert changelog.read_text() == "no-quote - single quotes - double quotes" +@pytest.mark.parametrize( + "extra, expected", + ( + pytest.param("key=value=", "value=", id="2-equals"), + pytest.param("key==value", "=value", id="2-consecutives-equals"), + pytest.param("key==value==", "=value==", id="multiple-equals"), + ), +) +def test_changelog_template_extra_weird_but_valid( + mocker: MockFixture, + tmp_commitizen_project: Path, + any_format: Format, + extra: str, + expected, +): + project_root = Path(tmp_commitizen_project) + changelog_tpl = project_root / any_format.template + changelog_tpl.write_text("{{key}}") + + create_file_and_commit("feat: new file") + + testargs = ["cz", "changelog", "-e", extra] + mocker.patch.object(sys, "argv", testargs) + cli.main() + + changelog = project_root / any_format.default_changelog_file + assert changelog.read_text() == expected + + +@pytest.mark.parametrize("extra", ("no-equal", "", "=no-key")) +def test_changelog_template_extra_bad_format( + mocker: MockFixture, tmp_commitizen_project: Path, any_format: Format, extra: str +): + project_root = Path(tmp_commitizen_project) + changelog_tpl = project_root / any_format.template + changelog_tpl.write_text("") + + create_file_and_commit("feat: new file") + + testargs = ["cz", "changelog", "-e", extra] + mocker.patch.object(sys, "argv", testargs) + with pytest.raises(InvalidCommandArgumentError): + cli.main() + + def test_export_changelog_template_from_default( mocker: MockFixture, tmp_commitizen_project: Path, - mock_plugin: BaseCommitizen, + any_format: Format, ): project_root = Path(tmp_commitizen_project) target = project_root / "changelog.jinja" - src = Path(commitizen_init).parent / "templates" / mock_plugin.template + src = Path(commitizen_init).parent / "templates" / any_format.template args = ["cz", "changelog", "--export-template", str(target)] @@ -1411,11 +1495,12 @@ def test_export_changelog_template_from_plugin( mocker: MockFixture, tmp_commitizen_project: Path, mock_plugin: BaseCommitizen, + format: Format, tmp_path: Path, ): project_root = Path(tmp_commitizen_project) target = project_root / "changelog.jinja" - src = tmp_path / mock_plugin.template + src = tmp_path / format.template tpl = "I am a custom template" src.write_text(tpl) mock_plugin.template_loader = FileSystemLoader(tmp_path) diff --git a/tests/commands/test_changelog_command/test_changelog_from_start_AsciiDoc_.adoc b/tests/commands/test_changelog_command/test_changelog_from_start_asciidoc_.adoc similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_from_start_AsciiDoc_.adoc rename to tests/commands/test_changelog_command/test_changelog_from_start_asciidoc_.adoc diff --git a/tests/commands/test_changelog_command/test_changelog_from_start_Markdown_.md b/tests/commands/test_changelog_command/test_changelog_from_start_markdown_.md similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_from_start_Markdown_.md rename to tests/commands/test_changelog_command/test_changelog_from_start_markdown_.md diff --git a/tests/commands/test_changelog_command/test_changelog_from_start_RestructuredText_.rst b/tests/commands/test_changelog_command/test_changelog_from_start_restructuredtext_.rst similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_from_start_RestructuredText_.rst rename to tests/commands/test_changelog_command/test_changelog_from_start_restructuredtext_.rst diff --git a/tests/commands/test_changelog_command/test_changelog_from_start_Textile_.textile b/tests/commands/test_changelog_command/test_changelog_from_start_textile_.textile similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_from_start_Textile_.textile rename to tests/commands/test_changelog_command/test_changelog_from_start_textile_.textile diff --git a/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_AsciiDoc_.adoc b/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_asciidoc_.adoc similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_AsciiDoc_.adoc rename to tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_asciidoc_.adoc diff --git a/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_Markdown_.md b/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_markdown_.md similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_Markdown_.md rename to tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_markdown_.md diff --git a/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_RestructuredText_.rst b/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_restructuredtext_.rst similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_RestructuredText_.rst rename to tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_restructuredtext_.rst diff --git a/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_Textile_.textile b/tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_textile_.textile similarity index 100% rename from tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_Textile_.textile rename to tests/commands/test_changelog_command/test_changelog_replacing_unreleased_using_incremental_textile_.textile diff --git a/tests/conftest.py b/tests/conftest.py index 980c4d053e..55f11db972 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -13,6 +13,7 @@ from commitizen.config import BaseConfig from commitizen.cz import registry from commitizen.cz.base import BaseCommitizen +from commitizen.formats import DEFAULT_FORMAT, Format, get_format from tests.utils import create_file_and_commit SIGNER = "GitHub Action" @@ -225,3 +226,25 @@ def mock_plugin(mocker: MockerFixture, config: BaseConfig) -> BaseCommitizen: mock = MockPlugin(config) mocker.patch("commitizen.factory.commiter_factory", return_value=mock) return mock + + +SUPPORTED_FORMATS = ("markdown", "textile", "asciidoc", "restructuredtext") + + +@pytest.fixture(params=SUPPORTED_FORMATS) +def format(config: BaseConfig, request: pytest.FixtureRequest) -> Format: + """For tests relying on formats specifics""" + format: str = request.param + config.settings["format"] = format + if "tmp_commitizen_project" in request.fixturenames: + tmp_commitizen_project = request.getfixturevalue("tmp_commitizen_project") + pyproject = tmp_commitizen_project / "pyproject.toml" + pyproject.write(f"{pyproject.read()}\n" f'format = "{format}"\n') + return get_format(config) + + +@pytest.fixture +def any_format(config: BaseConfig) -> Format: + """For test not relying on formats specifics, use the default""" + config.settings["format"] = DEFAULT_FORMAT + return get_format(config) diff --git a/tests/test_changelog.py b/tests/test_changelog.py index 0b1b00ccce..4364ee7b4d 100644 --- a/tests/test_changelog.py +++ b/tests/test_changelog.py @@ -8,6 +8,7 @@ ConventionalCommitsCz, ) from commitizen.exceptions import InvalidConfigurationError +from commitizen.formats import Format COMMITS_DATA = [ { @@ -1140,11 +1141,11 @@ def test_order_changelog_tree_raises(): assert "Change types contain duplicates types" in str(excinfo) -def test_render_changelog(gitcommits, tags, changelog_content): +def test_render_changelog(gitcommits, tags, changelog_content, any_format: Format): parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern loader = ConventionalCommitsCz.template_loader - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template tree = changelog.generate_tree_from_commits( gitcommits, tags, parser, changelog_pattern ) @@ -1153,12 +1154,12 @@ def test_render_changelog(gitcommits, tags, changelog_content): def test_render_changelog_from_default_plugin_values( - gitcommits, tags, changelog_content + gitcommits, tags, changelog_content, any_format: Format ): parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern loader = ConventionalCommitsCz.template_loader - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template tree = changelog.generate_tree_from_commits( gitcommits, tags, parser, changelog_pattern ) @@ -1168,7 +1169,7 @@ def test_render_changelog_from_default_plugin_values( def test_render_changelog_override_loader(gitcommits, tags, tmp_path: Path): loader = FileSystemLoader(tmp_path) - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = "tpl.j2" tpl = "loader overridden" (tmp_path / template).write_text(tpl) parser = ConventionalCommitsCz.commit_parser @@ -1180,9 +1181,11 @@ def test_render_changelog_override_loader(gitcommits, tags, tmp_path: Path): assert result == tpl -def test_render_changelog_override_template_from_cwd(gitcommits, tags, chdir: Path): +def test_render_changelog_override_template_from_cwd( + gitcommits, tags, chdir: Path, any_format: Format +): tpl = "overridden from cwd" - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template (chdir / template).write_text(tpl) parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern @@ -1239,12 +1242,12 @@ def test_render_changelog_support_arbitrary_kwargs(gitcommits, tags, tmp_path: P assert result == "value" -def test_render_changelog_unreleased(gitcommits): +def test_render_changelog_unreleased(gitcommits, any_format: Format): some_commits = gitcommits[:7] parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern loader = ConventionalCommitsCz.template_loader - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template tree = changelog.generate_tree_from_commits( some_commits, [], parser, changelog_pattern ) @@ -1252,7 +1255,7 @@ def test_render_changelog_unreleased(gitcommits): assert "Unreleased" in result -def test_render_changelog_tag_and_unreleased(gitcommits, tags): +def test_render_changelog_tag_and_unreleased(gitcommits, tags, any_format: Format): some_commits = gitcommits[:7] single_tag = [ tag for tag in tags if tag.rev == "56c8a8da84e42b526bcbe130bd194306f7c7e813" @@ -1261,7 +1264,7 @@ def test_render_changelog_tag_and_unreleased(gitcommits, tags): parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern loader = ConventionalCommitsCz.template_loader - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template tree = changelog.generate_tree_from_commits( some_commits, single_tag, parser, changelog_pattern ) @@ -1271,13 +1274,13 @@ def test_render_changelog_tag_and_unreleased(gitcommits, tags): assert "## v1.1.1" in result -def test_render_changelog_with_change_type(gitcommits, tags): +def test_render_changelog_with_change_type(gitcommits, tags, any_format: Format): new_title = ":some-emoji: feature" change_type_map = {"feat": new_title} parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern loader = ConventionalCommitsCz.template_loader - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template tree = changelog.generate_tree_from_commits( gitcommits, tags, parser, changelog_pattern, change_type_map=change_type_map ) @@ -1285,7 +1288,9 @@ def test_render_changelog_with_change_type(gitcommits, tags): assert new_title in result -def test_render_changelog_with_changelog_message_builder_hook(gitcommits, tags): +def test_render_changelog_with_changelog_message_builder_hook( + gitcommits, tags, any_format: Format +): def changelog_message_builder_hook(message: dict, commit: git.GitCommit) -> dict: message[ "message" @@ -1295,7 +1300,7 @@ def changelog_message_builder_hook(message: dict, commit: git.GitCommit) -> dict parser = ConventionalCommitsCz.commit_parser changelog_pattern = ConventionalCommitsCz.changelog_pattern loader = ConventionalCommitsCz.template_loader - template = f"{ConventionalCommitsCz.changelog_file}.{defaults.TEMPLATE_EXTENSION}" + template = any_format.template tree = changelog.generate_tree_from_commits( gitcommits, tags, diff --git a/tests/test_changelog_format_asciidoc.py b/tests/test_changelog_format_asciidoc.py new file mode 100644 index 0000000000..7ca2511d93 --- /dev/null +++ b/tests/test_changelog_format_asciidoc.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +from pathlib import Path + +import pytest + +from commitizen.changelog import Metadata +from commitizen.config.base_config import BaseConfig +from commitizen.formats.asciidoc import AsciiDoc + + +CHANGELOG_A = """ += Changelog + +All notable changes to this project will be documented in this file. + +The format is based on https://keepachangelog.com/en/1.0.0/[Keep a Changelog], +and this project adheres to https://semver.org/spec/v2.0.0.html[Semantic Versioning]. + +== [Unreleased] +* Start using "changelog" over "change log" since it's the common usage. + +== [1.0.0] - 2017-06-20 +=== Added +* New visual identity by https://github.com/tylerfortune8[@tylerfortune8]. +* Version navigation. +""".strip() + +EXPECTED_A = Metadata( + latest_version="1.0.0", + latest_version_position=10, + unreleased_end=10, + unreleased_start=7, +) + + +CHANGELOG_B = """ +== [Unreleased] +* Start using "changelog" over "change log" since it's the common usage. + +== 1.2.0 +""".strip() + +EXPECTED_B = Metadata( + latest_version="1.2.0", + latest_version_position=3, + unreleased_end=3, + unreleased_start=0, +) + + +CHANGELOG_C = """ += Unreleased + +== v1.0.0 +""" +EXPECTED_C = Metadata( + latest_version="1.0.0", + latest_version_position=3, + unreleased_end=3, + unreleased_start=1, +) + +CHANGELOG_D = """ +== Unreleased +* Start using "changelog" over "change log" since it's the common usage. +""" + +EXPECTED_D = Metadata( + latest_version=None, + latest_version_position=None, + unreleased_end=2, + unreleased_start=1, +) + + +@pytest.fixture +def format(config: BaseConfig) -> AsciiDoc: + return AsciiDoc(config) + + +VERSIONS_EXAMPLES = [ + ("== [1.0.0] - 2017-06-20", "1.0.0"), + ( + "= https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3[10.0.0-next.3] (2020-04-22)", + "10.0.0-next.3", + ), + ("=== 0.19.1 (Jan 7, 2020)", "0.19.1"), + ("== 1.0.0", "1.0.0"), + ("== v1.0.0", "1.0.0"), + ("== v1.0.0 - (2012-24-32)", "1.0.0"), + ("= version 2020.03.24", "2020.03.24"), + ("== [Unreleased]", None), + ("All notable changes to this project will be documented in this file.", None), + ("= Changelog", None), + ("=== Bug Fixes", None), +] + + +@pytest.mark.parametrize("line_from_changelog,output_version", VERSIONS_EXAMPLES) +def test_changelog_detect_version( + line_from_changelog: str, output_version: str, format: AsciiDoc +): + version = format.parse_version_from_title(line_from_changelog) + assert version == output_version + + +TITLES_EXAMPLES = [ + ("== [1.0.0] - 2017-06-20", 2), + ("== [Unreleased]", 2), + ("= Unreleased", 1), +] + + +@pytest.mark.parametrize("line_from_changelog,output_title", TITLES_EXAMPLES) +def test_parse_title_type_of_line( + line_from_changelog: str, output_title: str, format: AsciiDoc +): + title = format.parse_title_level(line_from_changelog) + assert title == output_title + + +@pytest.mark.parametrize( + "content, expected", + ( + pytest.param(CHANGELOG_A, EXPECTED_A, id="A"), + pytest.param(CHANGELOG_B, EXPECTED_B, id="B"), + pytest.param(CHANGELOG_C, EXPECTED_C, id="C"), + pytest.param(CHANGELOG_D, EXPECTED_D, id="D"), + ), +) +def test_get_matadata( + tmp_path: Path, format: AsciiDoc, content: str, expected: Metadata +): + changelog = tmp_path / format.default_changelog_file + changelog.write_text(content) + + assert format.get_metadata(str(changelog)) == expected diff --git a/tests/test_changelog_format_markdown.py b/tests/test_changelog_format_markdown.py new file mode 100644 index 0000000000..3af4cea26e --- /dev/null +++ b/tests/test_changelog_format_markdown.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +from pathlib import Path + +import pytest + +from commitizen.changelog import Metadata +from commitizen.config.base_config import BaseConfig +from commitizen.formats.markdown import Markdown + + +CHANGELOG_A = """ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] +- Start using "changelog" over "change log" since it's the common usage. + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +- Version navigation. +""".strip() + +EXPECTED_A = Metadata( + latest_version="1.0.0", + latest_version_position=10, + unreleased_end=10, + unreleased_start=7, +) + + +CHANGELOG_B = """ +## [Unreleased] +- Start using "changelog" over "change log" since it's the common usage. + +## 1.2.0 +""".strip() + +EXPECTED_B = Metadata( + latest_version="1.2.0", + latest_version_position=3, + unreleased_end=3, + unreleased_start=0, +) + + +CHANGELOG_C = """ +# Unreleased + +## v1.0.0 +""" +EXPECTED_C = Metadata( + latest_version="1.0.0", + latest_version_position=3, + unreleased_end=3, + unreleased_start=1, +) + +CHANGELOG_D = """ +## Unreleased +- Start using "changelog" over "change log" since it's the common usage. +""" + +EXPECTED_D = Metadata( + latest_version=None, + latest_version_position=None, + unreleased_end=2, + unreleased_start=1, +) + + +@pytest.fixture +def format(config: BaseConfig) -> Markdown: + return Markdown(config) + + +VERSIONS_EXAMPLES = [ + ("## [1.0.0] - 2017-06-20", "1.0.0"), + ( + "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)", + "10.0.0-next.3", + ), + ("### 0.19.1 (Jan 7, 2020)", "0.19.1"), + ("## 1.0.0", "1.0.0"), + ("## v1.0.0", "1.0.0"), + ("## v1.0.0 - (2012-24-32)", "1.0.0"), + ("# version 2020.03.24", "2020.03.24"), + ("## [Unreleased]", None), + ("All notable changes to this project will be documented in this file.", None), + ("# Changelog", None), + ("### Bug Fixes", None), +] + + +@pytest.mark.parametrize("line_from_changelog,output_version", VERSIONS_EXAMPLES) +def test_changelog_detect_version( + line_from_changelog: str, output_version: str, format: Markdown +): + version = format.parse_version_from_title(line_from_changelog) + assert version == output_version + + +TITLES_EXAMPLES = [ + ("## [1.0.0] - 2017-06-20", 2), + ("## [Unreleased]", 2), + ("# Unreleased", 1), +] + + +@pytest.mark.parametrize("line_from_changelog,output_title", TITLES_EXAMPLES) +def test_parse_title_type_of_line( + line_from_changelog: str, output_title: str, format: Markdown +): + title = format.parse_title_level(line_from_changelog) + assert title == output_title + + +@pytest.mark.parametrize( + "content, expected", + ( + pytest.param(CHANGELOG_A, EXPECTED_A, id="A"), + pytest.param(CHANGELOG_B, EXPECTED_B, id="B"), + pytest.param(CHANGELOG_C, EXPECTED_C, id="C"), + pytest.param(CHANGELOG_D, EXPECTED_D, id="D"), + ), +) +def test_get_matadata( + tmp_path: Path, format: Markdown, content: str, expected: Metadata +): + changelog = tmp_path / format.default_changelog_file + changelog.write_text(content) + + assert format.get_metadata(str(changelog)) == expected diff --git a/tests/test_changelog_format_restructuredtext.py b/tests/test_changelog_format_restructuredtext.py new file mode 100644 index 0000000000..7a2b77a70e --- /dev/null +++ b/tests/test_changelog_format_restructuredtext.py @@ -0,0 +1,313 @@ +from __future__ import annotations + +from pathlib import Path +from textwrap import dedent +from typing import TYPE_CHECKING, Optional + +import pytest + +from commitizen.changelog import Metadata +from commitizen.config.base_config import BaseConfig +from commitizen.formats.restructuredtext import RestructuredText + +if TYPE_CHECKING: + from _pytest.mark.structures import ParameterSet + + +CASES: list[ParameterSet] = [] + + +def case( + id: str, + content: str, + latest_version: Optional[str] = None, + latest_version_position: Optional[int] = None, + unreleased_start: Optional[int] = None, + unreleased_end: Optional[int] = None, +): + CASES.append( + pytest.param( + dedent(content).strip(), + Metadata( + latest_version=latest_version, + latest_version_position=latest_version_position, + unreleased_start=unreleased_start, + unreleased_end=unreleased_end, + ), + id=id, + ) + ) + + +case( + "underlined title with intro and unreleased section", + """ + Changelog + ######### + + All notable changes to this project will be documented in this file. + + The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`, + and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`. + + Unreleased + ========== + * Start using "changelog" over "change log" since it's the common usage. + + 1.0.0 - 2017-06-20 + ================== + Added + ----- + * New visual identity by `@tylerfortune8 <https://github.com/tylerfortune8>`. + * Version navigation. + """, + latest_version="1.0.0", + latest_version_position=12, + unreleased_start=8, + unreleased_end=12, +) + +case( + "unreleased section without preamble", + """ + Unreleased + ========== + * Start using "changelog" over "change log" since it's the common usage. + + 1.2.0 + ===== + """, + latest_version="1.2.0", + latest_version_position=4, + unreleased_start=0, + unreleased_end=4, +) + +case( + "basic underlined titles with v-prefixed version", + """ + Unreleased + ========== + + v1.0.0 + ====== + """, + latest_version="1.0.0", + latest_version_position=3, + unreleased_start=0, + unreleased_end=3, +) + +case( + "intermediate section in unreleased", + """ + Unreleased + ========== + + intermediate + ------------ + + 1.0.0 + ===== + """, + latest_version="1.0.0", + latest_version_position=6, + unreleased_start=0, + unreleased_end=6, +) + +case( + "weird section with different level than versions", + """ + Unreleased + ########## + + 1.0.0 + ===== + """, + latest_version="1.0.0", + latest_version_position=3, + unreleased_start=0, + unreleased_end=3, +) + +case( + "overlined title without release and intro", + """ + ========== + Unreleased + ========== + * Start using "changelog" over "change log" since it's the common usage. + """, + unreleased_start=0, + unreleased_end=4, +) + +case( + "underlined title with date", + """ + 1.0.0 - 2017-06-20 + ================== + """, + latest_version="1.0.0", + latest_version_position=0, +) + + +UNDERLINED_TITLES = ( + """ + title + ===== + """, + """ + title + ====== + """, + """ + title + ##### + """, + """ + title + ..... + """, + """ + title + !!!!! + """, +) + +NOT_UNDERLINED_TITLES = ( + """ + title + =.=.= + """, + """ + title + ==== + """, + """ + title + aaaaa + """, + """ + title + + """, +) + + +OVERLINED_TITLES = ( + """ + ===== + title + ===== + """, + """ + ====== + title + ====== + """, + """ + ##### + title + ##### + """, + """ + ..... + title + ..... + """, +) + +NOT_OVERLINED_TITLES = ( + """ + ==== + title + ===== + """, + """ + ===== + title + ==== + """, + """ + ==== + title + ==== + """, + """ + ===== + title + ##### + """, + """ + ##### + title + ===== + """, + """ + =.=.= + title + ===== + """, + """ + ===== + title + =.=.= + """, + """ + + title + ===== + """, + """ + ===== + title + + """, + """ + aaaaa + title + aaaaa + """, +) + + +@pytest.fixture +def format(config: BaseConfig) -> RestructuredText: + return RestructuredText(config) + + +@pytest.mark.parametrize("content, expected", CASES) +def test_get_matadata( + tmp_path: Path, format: RestructuredText, content: str, expected: Metadata +): + changelog = tmp_path / format.default_changelog_file + changelog.write_text(content) + + assert format.get_metadata(str(changelog)) == expected + + +@pytest.mark.parametrize( + "text, expected", + [(text, True) for text in UNDERLINED_TITLES] + + [(text, False) for text in NOT_UNDERLINED_TITLES], +) +def test_is_underlined_title(format: RestructuredText, text: str, expected: bool): + _, first, second = dedent(text).splitlines() + print( + f"format.is_underlined_title('{first}', '{second}'): {format.is_underlined_title(first, second)}" + ) + assert format.is_underlined_title(first, second) is expected + + +@pytest.mark.parametrize( + "text, expected", + [(text, True) for text in OVERLINED_TITLES] + + [(text, False) for text in NOT_OVERLINED_TITLES], +) +def test_is_overlined_title(format: RestructuredText, text: str, expected: bool): + _, first, second, third = dedent(text).splitlines() + + assert format.is_overlined_title(first, second, third) is expected diff --git a/tests/test_changelog_format_textile.py b/tests/test_changelog_format_textile.py new file mode 100644 index 0000000000..ec82f03235 --- /dev/null +++ b/tests/test_changelog_format_textile.py @@ -0,0 +1,138 @@ +from __future__ import annotations + +from pathlib import Path + +import pytest + +from commitizen.changelog import Metadata +from commitizen.config.base_config import BaseConfig +from commitizen.formats.textile import Textile + + +CHANGELOG_A = """ +h1. Changelog + +All notable changes to this project will be documented in this file. + +The format is based on "Keep a Changelog":https://keepachangelog.com/en/1.0.0/, +and this project adheres to "Semantic Versioning":https://semver.org/spec/v2.0.0.html. + +h2. [Unreleased] +- Start using "changelog" over "change log" since it's the common usage. + +h2. [1.0.0] - 2017-06-20 +h3. Added +* New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). +* Version navigation. +""".strip() + +EXPECTED_A = Metadata( + latest_version="1.0.0", + latest_version_position=10, + unreleased_end=10, + unreleased_start=7, +) + + +CHANGELOG_B = """ +h2. [Unreleased] +* Start using "changelog" over "change log" since it's the common usage. + +h2. 1.2.0 +""".strip() + +EXPECTED_B = Metadata( + latest_version="1.2.0", + latest_version_position=3, + unreleased_end=3, + unreleased_start=0, +) + + +CHANGELOG_C = """ +h1. Unreleased + +h2. v1.0.0 +""" +EXPECTED_C = Metadata( + latest_version="1.0.0", + latest_version_position=3, + unreleased_end=3, + unreleased_start=1, +) + +CHANGELOG_D = """ +h2. Unreleased +* Start using "changelog" over "change log" since it's the common usage. +""" + +EXPECTED_D = Metadata( + latest_version=None, + latest_version_position=None, + unreleased_end=2, + unreleased_start=1, +) + + +@pytest.fixture +def format(config: BaseConfig) -> Textile: + return Textile(config) + + +VERSIONS_EXAMPLES = [ + ("h2. [1.0.0] - 2017-06-20", "1.0.0"), + ( + 'h1. "10.0.0-next.3":https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3 (2020-04-22)', + "10.0.0-next.3", + ), + ("h3. 0.19.1 (Jan 7, 2020)", "0.19.1"), + ("h2. 1.0.0", "1.0.0"), + ("h2. v1.0.0", "1.0.0"), + ("h2. v1.0.0 - (2012-24-32)", "1.0.0"), + ("h1. version 2020.03.24", "2020.03.24"), + ("h2. [Unreleased]", None), + ("All notable changes to this project will be documented in this file.", None), + ("h1. Changelog", None), + ("h3. Bug Fixes", None), +] + + +@pytest.mark.parametrize("line_from_changelog,output_version", VERSIONS_EXAMPLES) +def test_changelog_detect_version( + line_from_changelog: str, output_version: str, format: Textile +): + version = format.parse_version_from_title(line_from_changelog) + assert version == output_version + + +TITLES_EXAMPLES = [ + ("h2. [1.0.0] - 2017-06-20", 2), + ("h2. [Unreleased]", 2), + ("h1. Unreleased", 1), +] + + +@pytest.mark.parametrize("line_from_changelog,output_title", TITLES_EXAMPLES) +def test_parse_title_type_of_line( + line_from_changelog: str, output_title: str, format: Textile +): + title = format.parse_title_level(line_from_changelog) + assert title == output_title + + +@pytest.mark.parametrize( + "content, expected", + ( + pytest.param(CHANGELOG_A, EXPECTED_A, id="A"), + pytest.param(CHANGELOG_B, EXPECTED_B, id="B"), + pytest.param(CHANGELOG_C, EXPECTED_C, id="C"), + pytest.param(CHANGELOG_D, EXPECTED_D, id="D"), + ), +) +def test_get_matadata( + tmp_path: Path, format: Textile, content: str, expected: Metadata +): + changelog = tmp_path / format.default_changelog_file + changelog.write_text(content) + + assert format.get_metadata(str(changelog)) == expected diff --git a/tests/test_changelog_formats.py b/tests/test_changelog_formats.py new file mode 100644 index 0000000000..e95f17b5bd --- /dev/null +++ b/tests/test_changelog_formats.py @@ -0,0 +1,55 @@ +from __future__ import annotations +from typing import Optional + +import pytest +from commitizen.config.base_config import BaseConfig +from commitizen.formats import ( + DEFAULT_FORMAT, + KNOWN_FORMATS, + Format, + get_format, + guess_format, +) +from commitizen.formats.errors import FormatUnknown + + +@pytest.mark.parametrize("format", KNOWN_FORMATS.values()) +def test_guess_format(format: type[Format]): + assert guess_format(f"CHANGELOG.{format.extension}") is format + for ext in format.alternative_extensions: + assert guess_format(f"CHANGELOG.{ext}") is format + + +@pytest.mark.parametrize("filename", ("CHANGELOG", "NEWS", "file.unknown", None)) +def test_guess_format_unknown(filename: str): + assert guess_format(filename) is None + + +@pytest.mark.parametrize( + "name, expected", + [pytest.param(name, format, id=name) for name, format in KNOWN_FORMATS.items()], +) +def test_get_format(config: BaseConfig, name: str, expected: type[Format]): + config.settings["format"] = name + assert isinstance(get_format(config), expected) + + +@pytest.mark.parametrize("filename", (None, "")) +def test_get_format_empty_filename(config: BaseConfig, filename: Optional[str]): + config.settings["format"] = DEFAULT_FORMAT + assert isinstance(get_format(config, filename), KNOWN_FORMATS[DEFAULT_FORMAT]) + + +@pytest.mark.parametrize("filename", (None, "")) +def test_get_format_empty_filename_no_setting( + config: BaseConfig, filename: Optional[str] +): + config.settings["format"] = None + with pytest.raises(FormatUnknown): + get_format(config, filename) + + +@pytest.mark.parametrize("filename", ("extensionless", "file.unknown")) +def test_get_format_unknown(config: BaseConfig, filename: Optional[str]): + with pytest.raises(FormatUnknown): + get_format(config, filename) diff --git a/tests/test_changelog_meta.py b/tests/test_changelog_meta.py deleted file mode 100644 index db0201a077..0000000000 --- a/tests/test_changelog_meta.py +++ /dev/null @@ -1,174 +0,0 @@ -from __future__ import annotations - -import os -from typing import TYPE_CHECKING - -import pytest - - -if TYPE_CHECKING: - from tests.conftest import MockPlugin - -CHANGELOG_A = """ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] -- Start using "changelog" over "change log" since it's the common usage. - -## [1.0.0] - 2017-06-20 -### Added -- New visual identity by [@tylerfortune8](https://github.com/tylerfortune8). -- Version navigation. -""".strip() - -CHANGELOG_B = """ -## [Unreleased] -- Start using "changelog" over "change log" since it's the common usage. - -## 1.2.0 -""".strip() - -CHANGELOG_C = """ -# Unreleased - -## v1.0.0 -""" - -CHANGELOG_D = """ -## Unreleased -- Start using "changelog" over "change log" since it's the common usage. -""" - - -@pytest.fixture -def changelog_a_file(): - changelog_path = "tests/CHANGELOG.md" - - with open(changelog_path, "w", encoding="utf-8") as f: - f.write(CHANGELOG_A) - - yield changelog_path - - os.remove(changelog_path) - - -@pytest.fixture -def changelog_b_file(): - changelog_path = "tests/CHANGELOG.md" - - with open(changelog_path, "w", encoding="utf-8") as f: - f.write(CHANGELOG_B) - - yield changelog_path - - os.remove(changelog_path) - - -@pytest.fixture -def changelog_c_file(): - changelog_path = "tests/CHANGELOG.md" - - with open(changelog_path, "w", encoding="utf-8") as f: - f.write(CHANGELOG_C) - - yield changelog_path - - os.remove(changelog_path) - - -@pytest.fixture -def changelog_d_file(): - changelog_path = "tests/CHANGELOG.md" - - with open(changelog_path, "w", encoding="utf-8") as f: - f.write(CHANGELOG_D) - - yield changelog_path - - os.remove(changelog_path) - - -VERSIONS_EXAMPLES = [ - ("## [1.0.0] - 2017-06-20", "1.0.0"), - ( - "# [10.0.0-next.3](https://github.com/angular/angular/compare/10.0.0-next.2...10.0.0-next.3) (2020-04-22)", - "10.0.0-next.3", - ), - ("### 0.19.1 (Jan 7, 2020)", "0.19.1"), - ("## 1.0.0", "1.0.0"), - ("## v1.0.0", "1.0.0"), - ("## v1.0.0 - (2012-24-32)", "1.0.0"), - ("# version 2020.03.24", "2020.03.24"), - ("## [Unreleased]", None), - ("All notable changes to this project will be documented in this file.", None), - ("# Changelog", None), - ("### Bug Fixes", None), -] - - -@pytest.mark.parametrize("line_from_changelog,output_version", VERSIONS_EXAMPLES) -def test_changelog_detect_version( - line_from_changelog, output_version, mock_plugin: MockPlugin -): - version = mock_plugin.parse_version_from_changelog(line_from_changelog) - assert version == output_version - - -TITLES_EXAMPLES = [ - ("## [1.0.0] - 2017-06-20", "##"), - ("## [Unreleased]", "##"), - ("# Unreleased", "#"), -] - - -@pytest.mark.parametrize("line_from_changelog,output_title", TITLES_EXAMPLES) -def test_parse_title_type_of_line( - line_from_changelog, output_title, mock_plugin: MockPlugin -): - title = mock_plugin.parse_title_type_of_line(line_from_changelog) - assert title == output_title - - -def test_get_metadata_from_a(changelog_a_file, mock_plugin: MockPlugin): - meta = mock_plugin.get_metadata(changelog_a_file) - assert meta.__dict__ == { - "latest_version": "1.0.0", - "latest_version_position": 10, - "unreleased_end": 10, - "unreleased_start": 7, - } - - -def test_get_metadata_from_b(changelog_b_file, mock_plugin: MockPlugin): - meta = mock_plugin.get_metadata(changelog_b_file) - assert meta.__dict__ == { - "latest_version": "1.2.0", - "latest_version_position": 3, - "unreleased_end": 3, - "unreleased_start": 0, - } - - -def test_get_metadata_from_c(changelog_c_file, mock_plugin: MockPlugin): - meta = mock_plugin.get_metadata(changelog_c_file) - assert meta.__dict__ == { - "latest_version": "1.0.0", - "latest_version_position": 3, - "unreleased_end": 3, - "unreleased_start": 1, - } - - -def test_get_metadata_from_d(changelog_d_file, mock_plugin: MockPlugin): - meta = mock_plugin.get_metadata(changelog_d_file) - assert meta.__dict__ == { - "latest_version": None, - "latest_version_position": None, - "unreleased_end": 2, - "unreleased_start": 1, - } diff --git a/tests/test_conf.py b/tests/test_conf.py index d112fefb56..3f66f6d033 100644 --- a/tests/test_conf.py +++ b/tests/test_conf.py @@ -55,7 +55,7 @@ "allowed_prefixes": ["Merge", "Revert", "Pull request", "fixup!", "squash!"], "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], - "changelog_file": None, + "changelog_file": "CHANGELOG.md", "changelog_incremental": False, "changelog_start_rev": None, "changelog_merge_prerelease": False, @@ -67,6 +67,7 @@ "prerelease_offset": 0, "encoding": "utf-8", "version_type": None, + "format": None, "template": None, "extras": {}, } @@ -82,7 +83,7 @@ "allowed_prefixes": ["Merge", "Revert", "Pull request", "fixup!", "squash!"], "version_files": ["commitizen/__version__.py", "pyproject.toml"], "style": [["pointer", "reverse"], ["question", "underline"]], - "changelog_file": None, + "changelog_file": "CHANGELOG.md", "changelog_incremental": False, "changelog_start_rev": None, "changelog_merge_prerelease": False, @@ -94,20 +95,11 @@ "prerelease_offset": 0, "encoding": "utf-8", "version_type": None, + "format": None, "template": None, "extras": {}, } -# _read_settings = { -# "name": "cz_jira", -# "version": "1.0.0", -# "version_files": ["commitizen/__version__.py", "pyproject.toml"], -# "style": [["pointer", "reverse"], ["question", "underline"]], -# "changelog_file": "CHANGELOG.md", -# "pre_bump_hooks": ["scripts/generate_documentation.sh"], -# "post_bump_hooks": ["scripts/slack_notification.sh"], -# } - @pytest.fixture def config_files_manager(request, tmpdir):