diff --git a/.vscode/settings.json b/.vscode/settings.json index eb0a85b..3023089 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,8 +5,19 @@ "python.testing.pytestArgs": [ "tests" ], + "python.formatting.provider": "black", + "python.formatting.blackPath": "${workspaceRoot}/__pypackages__/3.10/Scripts/black", "python.testing.unittestEnabled": false, "python.testing.pytestEnabled": true, - "python.autoComplete.extraPaths": ["__pypackages__//lib"], - "python.analysis.extraPaths": ["__pypackages__//lib"] + "python.autoComplete.extraPaths": [ + "__pypackages__/3.10/lib" + ], + "python.analysis.extraPaths": [ + "__pypackages__/3.10/lib" + ], + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true + }, + "python.analysis.typeCheckingMode": "basic" } \ No newline at end of file diff --git a/cppython/exceptions.py b/cppython/exceptions.py index 9d6f966..c9d3102 100644 --- a/cppython/exceptions.py +++ b/cppython/exceptions.py @@ -4,11 +4,21 @@ class ConfigError(Exception): - def __init__(self, error: Exception) -> None: + """ + Raised when there is a configuration error + """ + + def __init__(self, error: str) -> None: self._error = error - super().__init__(str(error)) + super().__init__(error) @property - def error(self) -> Exception: + def error(self) -> str: + """ + Returns the underlying error + + Returns: + str -- The underlying error + """ return self._error diff --git a/cppython/plugins/generator/cmake.py b/cppython/plugins/generator/cmake.py index 2fcb45b..ff859ce 100644 --- a/cppython/plugins/generator/cmake.py +++ b/cppython/plugins/generator/cmake.py @@ -1,18 +1,25 @@ -from cppython.schema import Generator, Metadata +""" +The default generator implementation for CPPython +""" +from typing import Type +from cppython.schema import Generator, GeneratorData, PyProject -class CMakeGenerator(Generator): + +class CMakeData(GeneratorData): """ - A CPPython generator implementing a CMake backend + The data schema required for the CMake tooling """ - def __init__(self) -> None: - pass +class CMakeGenerator(Generator): """ - Plugin Contract + A CPPython generator implementing a CMake backend """ + def __init__(self, pyproject: PyProject, cmake_data: CMakeData) -> None: + super().__init__(pyproject, cmake_data) + @staticmethod def name() -> str: """ @@ -20,25 +27,19 @@ def name() -> str: """ return "cmake" - """ - Generator Contract - """ - - def populate_metadata(self, data: dict): + @staticmethod + def data_type() -> Type[GeneratorData]: """ - data - The CPPoetry data taken from pyproject.toml + Returns the pydantic type to cast the generator configuration data to """ - pass + return CMakeData - def populate_plugin(self, data: dict): + def install_generator(self) -> bool: """ - data - The data taken from pyproject.toml that belongs to this generator + Installs the external tooling required by the generator if necessary + Returns whether anything was installed or not """ - pass - - """ - API Contract - """ + return False def install(self) -> None: raise NotImplementedError() diff --git a/cppython/plugins/interface/console.py b/cppython/plugins/interface/console.py index b724682..5f9d30c 100644 --- a/cppython/plugins/interface/console.py +++ b/cppython/plugins/interface/console.py @@ -1,41 +1,51 @@ -from cppython.project import Project -from cppython.schema import Interface, PEP621 +""" +A click CLI for CPPython interfacing +""" + from pathlib import Path +from typing import Type import click import tomlkit +from cppython.project import Project +from cppython.schema import GeneratorData, GeneratorDataType, Interface, PyProject + + +def _create_pyproject(): -def _read_data(): + # Search for a path upward path = Path.cwd() while not path.glob("pyproject.toml"): if path.is_absolute(): assert ( - "This is not a valid project. No pyproject.toml found in the current directory or any of its parents." - ) + False + ), "This is not a valid project. No pyproject.toml found in the current directory or any of its parents." - return tomlkit.loads(Path(path / "pyproject.toml").read_text(encoding="utf-8")) + path = Path(path / "pyproject.toml") + # Load file + data = tomlkit.loads(path.read_text(encoding="utf-8")) -class Config(object): + # Interpret and validate data + return PyProject(**data) + + +class Config: """ The data object that will be expanded alongside 'pass_obj' """ def __init__(self): - - data = _read_data() + pyproject = _create_pyproject() # Initialize the object hook into CPPython - interface = ConsoleInterface(data) + interface = ConsoleInterface(pyproject) # Initialize the CPPython context self.project = Project(interface) - def load(self): - self.project.load() - pass_config = click.make_pass_decorator(Config) @@ -43,77 +53,60 @@ def load(self): @click.group() @click.pass_context def cli(context): + """ + entry_point group for the CLI commands + """ context.ensure_object(Config) - # Initialize cppython - context.obj.load() - @cli.command() @pass_config def install(config): + """ + Fulfills the 'install' API requirement + """ config.project.install() @cli.command() @pass_config def update(config): + """ + Fulfills the 'update' API requirement + """ config.project.update() -@cli.result_callback() +@cli.command() @pass_config -def cleanup(config, result): - pass - - -class ConsoleInterface(Interface): +def build(config): """ - TODO: Description + Fulfills the 'build' API requirement """ + config.project.build() - def __init__(self, data: dict) -> None: - self._data = data +@cli.result_callback() +@pass_config +def cleanup(config, result): """ - Plugin Contract + Post-command cleanup """ - @staticmethod - def name() -> str: - """ - The name of the generator - """ - return "console" +class ConsoleInterface(Interface): """ - Interface Contract + Interface implementation to pass to the project """ - @staticmethod - def external_config() -> bool: - """ - True if the plugin can read its own configuration. - False otherwise - """ - - return False - - @staticmethod - def parse_pep_621(data: dict) -> PEP621: + def read_generator_data(self, generator_data_type: Type[GeneratorDataType]) -> GeneratorDataType: """ - Requests the plugin to read the available PEP 621 information. Only requested if the plugin is not the entrypoint + Requests generator information """ - raise NotImplementedError() + return generator_data_type() - def pep_621(self) -> PEP621: + def write_pyproject(self) -> None: """ - Requests PEP 621 information from the pyproject + Write output """ - return self.parse_pep_621(self._data) - - def write_pyproject(self) -> None: - raise NotImplementedError() - - def read_pyproject(self) -> dict: - return self._data + pass diff --git a/cppython/plugins/test/data.py b/cppython/plugins/test/data.py new file mode 100644 index 0000000..76a30e7 --- /dev/null +++ b/cppython/plugins/test/data.py @@ -0,0 +1,15 @@ +""" +Defaulted data to help testing +""" + +from pathlib import Path + +from cppython.schema import PEP621, CPPythonData, PyProject, TargetEnum + +default_pep621 = PEP621(name="test_name", version="1.0") + +# CMake is a default plugin +# TODO: Provide dynamic default +default_cppython_data = CPPythonData(generator="cmake", target=TargetEnum.EXE, install_path=Path()) + +default_pyproject = PyProject(pep_621=default_pep621, cppython_data=default_cppython_data) diff --git a/cppython/plugins/test/pytest.py b/cppython/plugins/test/pytest.py index fb55b68..68eb48c 100644 --- a/cppython/plugins/test/pytest.py +++ b/cppython/plugins/test/pytest.py @@ -1,33 +1,96 @@ +""" +Helper fixtures and plugin definitions for pytest +TODO: Should by a pytest plugin, removing the need for this module in production code. +""" +from abc import ABC +from importlib.metadata import entry_points + import pytest +from cppython.project import Project +from cppython.schema import Generator, Interface + + +class GeneratorTests(ABC): + """ + Shared functionality between the different Generator testing categories + """ + + @pytest.fixture(name="generator") + def fixture_generator(self) -> Generator: + """ + A hook allowing implementations to override the fixture with a parameterization + @pytest.mark.parametrize("generator", [CustomGenerator]) + """ + raise NotImplementedError -@pytest.fixture -def generator(): + +class GeneratorIntegrationTests(GeneratorTests): """ - A hook allowing implementations to override the fixture with a parameterization + Base class for all generator integration tests that test plugin agnostic behavior """ - raise NotImplementedError + + def test_plugin_registration(self, generator: Generator): + """ + TODO + """ + plugin_entries = entry_points(group=f"cppython.{generator.plugin_group()}") + assert len(plugin_entries) > 0 -class BaseGenerator: +class GeneratorUnitTests(GeneratorTests): """ - Implementations of the Generator class should inherit from this class for its tests + Custom implementations of the Generator class should inherit from this class for its tests. + Base class for all generator unit tests that test plugin agnostic behavior """ - pass + def test_name(self, generator: Generator): + """ + Test name restrictions + TODO: This should be a pydantic schema + """ + name = generator.name() + assert name != "" -@pytest.fixture -def interface(): + def test_data_type(self, generator: Generator): + """ + Test data_type restrictions + TODO: This should be a pydantic schema + """ + data_type = generator.data_type() + + assert data_type != "" + + +class InterfaceTests(ABC): """ - A hook allowing implementations to override the fixture with a parameterization + Shared functionality between the different Interface testing categories """ - raise NotImplementedError + + @pytest.fixture(name="interface") + def fixture_interface(self) -> Interface: + """ + A hook allowing implementations to override the fixture with a parameterization + @pytest.mark.parametrize("interface", [CustomInterface]) + """ + raise NotImplementedError -class BaseInterface: +class InterfaceIntegrationTests(InterfaceTests): """ - Implementations of the Interface class should inherit from this class for its tests + Base class for all interface integration tests that test plugin agnostic behavior """ - pass + def test_project(self, interface: Interface): + """ + Test that the project can be constructed from the given interface + """ + Project(interface) + + +class InterfaceUnitTests(InterfaceTests): + """ + Custom implementations of the Interface class should inherit from this class for its tests. + Base class for all interface unit tests that test plugin agnostic behavior + """ diff --git a/cppython/project.py b/cppython/project.py index 8b339aa..7765761 100644 --- a/cppython/project.py +++ b/cppython/project.py @@ -1,112 +1,52 @@ -from typing import Type, Callable +""" +The central delegation of the CPPython project +""" -from cppython.schema import API, Interface, Generator, Metadata, PEP621, Plugin -from cppython.exceptions import ConfigError +from importlib import metadata +from typing import Callable, Optional, Type, TypeVar -import pkgutil -import importlib -import inspect +from cppython.exceptions import ConfigError +from cppython.schema import API, Generator, Interface, Plugin class Project(API): + """ + The object constructed at each entry_point + """ + def __init__(self, interface: Interface) -> None: self._interface = interface - self.loaded = False - def _parse_PEP621_data(self, data: dict, interface_type: Interface) -> PEP621: - """ - Extracts the PEP621 metadata from the various possible project formats - """ + PluginType = TypeVar("PluginType", bound=Type[Plugin]) - # Each plugin reads its own configuration file, interfaces without external data need a helping hand parsing it - if not interface_type.external_config(): + def find_plugin_type(plugin_type: PluginType, condition: Callable[[str], bool]) -> Optional[PluginType]: """ - If the interface doesn't support an external configuration, search for a plugin that does + Finds the first plugin that satisfies the given condition """ - temporary_interface_type = self._load_interface([*data["tool"]]) - - if temporary_interface_type is None: - """ - If there is no applicable plugin, we are interfaceing the toml project without a python buildsystem - """ - return self._interface.pep_621() - - else: - return temporary_interface_type.parse_pep_621(data) - - else: - return self._interface.pep_621() - - def _parse_cppython_data(self, data: dict) -> Metadata: - """ - TODO: - """ - return Metadata(**data["tool"]["cppython"]) - - def _parse_generator_data(self, data: dict, generator_type): - """ - TODO: - """ - generator_config_type = generator_type.data_type() - return generator_config_type(**data[generator_type.name()]) + entry_points = metadata.entry_points(group=f"cppython.{plugin_type.plugin_group()}") - def _find_first_plugin( - self, namespace_package, plugin_type: Type[Plugin], condition: Callable[[str], bool] - ) -> Type[Plugin]: - """ - Finds the first plugin that satisfies the given condition - """ - for _, name, is_package in pkgutil.iter_modules(namespace_package.__path__, namespace_package.__name__ + "."): - if not is_package: - module = importlib.import_module(name) - class_members = inspect.getmembers(module, inspect.isclass) - for (_, value) in class_members: - if issubclass(value, plugin_type) & (value is not plugin_type): - if condition(value.name()): - return value + for entry_point in entry_points: + loaded_plugin_type = entry_point.load() + if issubclass(loaded_plugin_type, plugin_type) & (loaded_plugin_type is not plugin_type): + if condition(loaded_plugin_type.name()): + return loaded_plugin_type - def _load_interface(self, potential_keys: list) -> Type[Interface]: - """ - TODO: - """ + return None - import cppython.plugins.interface + plugin_type = find_plugin_type(Generator, lambda name: name == interface.pyproject.cppython_data.generator) - return self._find_first_plugin(cppython.plugins.interface, Interface, lambda name: name in potential_keys) + if plugin_type is None: + raise ConfigError( + f"No generator plugin with the name '{interface.pyproject.cppython_data.generator}' was found." + ) - def _load_generator(self, generator: str) -> Type[Generator]: - """ - TODO: - """ + generator_data = interface.read_generator_data(plugin_type.data_type()) + self._generator = plugin_type(interface.pyproject, generator_data) + self._generator.install_generator() - import cppython.plugins.generator - - return self._find_first_plugin(cppython.plugins.generator, Generator, lambda name: name == generator) - - def load(self): - # Read the raw configuration data - pyproject_data = self._interface.read_pyproject() - cppython_data = self._parse_cppython_data(pyproject_data) - - # Load the generator type - generator_type = self._load_generator(cppython_data.generator) - - if generator_type is None: - raise ConfigError("") - - pep_621 = self._parse_PEP621_data(pyproject_data, self._interface) - generator_data = self._parse_generator_data(pyproject_data, generator_type) - - # Construct the generator - self._generator = generator_type(pep_621, cppython_data, generator_data) - - self.loaded = True - - """ - API Contract - """ + # API Contract def install(self) -> None: self._generator.install() diff --git a/cppython/schema.py b/cppython/schema.py index 6e7a49b..79d6c69 100644 --- a/cppython/schema.py +++ b/cppython/schema.py @@ -1,19 +1,28 @@ +""" +Data types for CPPython that encapsulate the requirements between the plugins and the core library +""" + from abc import ABC, abstractmethod -from pathlib import Path from enum import Enum +from pathlib import Path +from typing import Type, TypeVar -from pydantic import BaseModel, Field +from pydantic import BaseModel class TargetEnum(Enum): - exe = "executable" - static = "static" - shared = "shared" + """ + The C++ build target type + """ + + EXE = "executable" + STATIC = "static" + SHARED = "shared" class PEP621(BaseModel): """ - Subset of PEP 621 + PEP 621 conforming data The entirety of PEP 621 is not relevant for interface plugins Schema: https://www.python.org/dev/peps/pep-0621/ """ @@ -23,16 +32,24 @@ class PEP621(BaseModel): description: str = "" -class Metadata(BaseModel): +class CPPythonData(BaseModel): """ Data required by the tool """ - # TODO: Grab default from plugin without circular import - generator: str = "CMake" + generator: str target: TargetEnum - dependencies: dict[str, str] = [] - install_path: Path = Field(alias="install-path") + dependencies: dict[str, str] = {} + install_path: Path + + +class PyProject(BaseModel): + """ + pyproject.toml schema + """ + + pep_621: PEP621 + cppython_data: CPPythonData class API(ABC): @@ -42,14 +59,32 @@ class API(ABC): @abstractmethod def install(self) -> None: + """ + Called when dependencies need to be installed from a lock file. + + Raises: + NotImplementedError: [description] + """ raise NotImplementedError() @abstractmethod def update(self) -> None: + """ + Called when dependencies need to be updated and written to the lock file. + + Raises: + NotImplementedError: [description] + """ raise NotImplementedError() @abstractmethod def build(self) -> None: + """ + Called when the C++ target needs to be produced. + + Raises: + NotImplementedError: [description] + """ raise NotImplementedError() @@ -58,62 +93,65 @@ class Plugin(ABC): Abstract plugin type """ + @abstractmethod def __init__(self) -> None: pass @staticmethod @abstractmethod - def name(self) -> str: + def plugin_group() -> str: """ - The name of the generator + The plugin group name as used by 'setuptools' """ raise NotImplementedError() -class Interface(Plugin): +class GeneratorData(BaseModel): """ - Abstract type to be inherited by CPPython Interface plugins + Base class for the configuration data that will be read by the interface and given to the generator """ - def __init__(self) -> None: - pass - @staticmethod - def external_config() -> bool: - """ - True if the plugin can read its own configuration. - False otherwise - """ +GeneratorDataType = TypeVar("GeneratorDataType", bound=GeneratorData) - return True - @staticmethod - @abstractmethod - def parse_pep_621(data: dict) -> PEP621: +class Interface: + """ + Abstract type to be inherited by CPPython interfaces + """ + + def __init__(self, pyproject: PyProject) -> None: + super().__init__() + + self.pyproject = pyproject + + @property + def pyproject(self) -> PyProject: """ - Requests the plugin to read the available PEP 621 information. Only requested if the plugin is not the entrypoint + PyProject getter """ - raise NotImplementedError() + return self._pyproject - @abstractmethod - def pep_621(self) -> PEP621: + @pyproject.setter + def pyproject(self, value: PyProject): """ - Requests PEP 621 information from the pyproject - Probably uses 'parse_pep_621' internally + PyProject setter """ - raise NotImplementedError() + + self._pyproject = value @abstractmethod - def read_pyproject(self) -> dict: + def read_generator_data(self, generator_data_type: Type[GeneratorDataType]) -> GeneratorDataType: """ - Called when CPPoetry requires the content of pyproject.toml + Dynamic pyproject.toml data that is determined by the generator plugin requested by [tool.cppython.generator] + The Schema defined by 'generator_data_type' must be filled by the [tool.cppython.{generator_value}] slot. """ raise NotImplementedError() @abstractmethod def write_pyproject(self) -> None: """ - Called when CPPoetry requires the plugin to write out pyproject.toml changes + Called when CPPython requires the interface to write out pyproject.toml changes """ raise NotImplementedError() @@ -124,13 +162,35 @@ class Generator(Plugin, API): """ @abstractmethod - def __init__(self, pep_612: PEP621, cppython_data: Metadata, generator_data: dict) -> None: - pass + def __init__(self, pyproject: PyProject, generator_data: GeneratorData) -> None: + super().__init__() + + @staticmethod + def plugin_group() -> str: + """ + The plugin group name as used by 'setuptools' + """ + return "generator_plugins" @staticmethod @abstractmethod - def data_type(self): + def name() -> str: + """ + The string that is matched with the [tool.cppython.generator] string + """ + raise NotImplementedError() + + @staticmethod + @abstractmethod + def data_type() -> Type[GeneratorData]: """ Returns the pydantic type to cast the generator configuration data to """ raise NotImplementedError() + + @abstractmethod + def install_generator(self) -> bool: + """ + Installs the external tooling required by the generator if necessary + Returns whether anything was installed or not + """ diff --git a/pdm.lock b/pdm.lock index fa2ade7..681ab32 100644 --- a/pdm.lock +++ b/pdm.lock @@ -1,7 +1,7 @@ [[package]] name = "astroid" -version = "2.9.0" -requires_python = "~=3.6" +version = "2.9.3" +requires_python = ">=3.6.2" summary = "An abstract syntax tree for Python with inference support." dependencies = [ "lazy-object-proxy>=1.4.0", @@ -17,23 +17,21 @@ summary = "Atomic file writes." [[package]] name = "attrs" -version = "21.2.0" +version = "21.4.0" requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" summary = "Classes Without Boilerplate" [[package]] name = "black" -version = "21.12b0" +version = "22.1.0" requires_python = ">=3.6.2" summary = "The uncompromising code formatter." dependencies = [ - "click>=7.1.2", + "click>=8.0.0", "mypy-extensions>=0.4.3", - "pathspec<1,>=0.9.0", + "pathspec>=0.9.0", "platformdirs>=2", - "tomli<2.0.0,>=0.2.6", - "typing-extensions!=3.10.0.1; python_version >= \"3.10\"", - "typing-extensions>=3.10.0.0", + "tomli>=1.1.0", ] [[package]] @@ -47,7 +45,7 @@ dependencies = [ [[package]] name = "cmake" -version = "3.22.1" +version = "3.22.2" summary = "CMake is an open-source, cross-platform family of tools designed to build, test and package software" [[package]] @@ -58,27 +56,21 @@ summary = "Cross-platform colored terminal text." [[package]] name = "coverage" -version = "6.2" -requires_python = ">=3.6" +version = "6.3.1" +requires_python = ">=3.7" summary = "Code coverage measurement for Python" [[package]] name = "coverage" -version = "6.2" +version = "6.3.1" extras = ["toml"] -requires_python = ">=3.6" +requires_python = ">=3.7" summary = "Code coverage measurement for Python" dependencies = [ "coverage>=5.2.1", "tomli", ] -[[package]] -name = "execnet" -version = "1.9.0" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -summary = "execnet: rapid multi-Python deployment" - [[package]] name = "iniconfig" version = "1.1.1" @@ -122,8 +114,8 @@ summary = "Utility library for gitignore style pattern matching of file paths." [[package]] name = "platformdirs" -version = "2.4.0" -requires_python = ">=3.6" +version = "2.5.0" +requires_python = ">=3.7" summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." [[package]] @@ -140,7 +132,7 @@ summary = "library with cross-python path, ini-parsing, io, code, log facilities [[package]] name = "pydantic" -version = "1.8.2" +version = "1.9.0" requires_python = ">=3.6.1" summary = "Data validation and settings management using python 3.6 type hinting" dependencies = [ @@ -163,13 +155,13 @@ dependencies = [ [[package]] name = "pyparsing" -version = "3.0.6" +version = "3.0.7" requires_python = ">=3.6" summary = "Python parsing module" [[package]] name = "pytest" -version = "6.2.5" +version = "7.0.1" requires_python = ">=3.6" summary = "pytest: simple powerful testing with Python" dependencies = [ @@ -180,7 +172,7 @@ dependencies = [ "packaging", "pluggy<2.0,>=0.12", "py>=1.8.2", - "toml", + "tomli>=1.0.0", ] [[package]] @@ -193,40 +185,19 @@ dependencies = [ "pytest>=4.6", ] -[[package]] -name = "pytest-forked" -version = "1.4.0" -requires_python = ">=3.6" -summary = "run tests in isolated forked subprocesses" -dependencies = [ - "py", - "pytest>=3.10", -] - [[package]] name = "pytest-mock" -version = "3.6.1" -requires_python = ">=3.6" +version = "3.7.0" +requires_python = ">=3.7" summary = "Thin-wrapper around the mock package for easier use with pytest" dependencies = [ "pytest>=5.0", ] -[[package]] -name = "pytest-xdist" -version = "2.5.0" -requires_python = ">=3.6" -summary = "pytest xdist plugin for distributed testing and loop-on-failing modes" -dependencies = [ - "execnet>=1.1", - "pytest-forked", - "pytest>=6.2.0", -] - [[package]] name = "setuptools" -version = "59.6.0" -requires_python = ">=3.6" +version = "60.8.2" +requires_python = ">=3.7" summary = "Easily download, build, install, upgrade, and uninstall Python packages" [[package]] @@ -237,19 +208,19 @@ summary = "Python Library for Tom's Obvious, Minimal Language" [[package]] name = "tomli" -version = "1.2.3" -requires_python = ">=3.6" +version = "2.0.1" +requires_python = ">=3.7" summary = "A lil' TOML parser" [[package]] name = "tomlkit" -version = "0.7.2" -requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "0.9.2" +requires_python = ">=3.6,<4.0" summary = "Style preserving TOML library" [[package]] name = "typing-extensions" -version = "4.0.1" +version = "4.1.0" requires_python = ">=3.6" summary = "Backported and Experimental Type Hints for Python 3.6+" @@ -261,103 +232,114 @@ summary = "Module for decorators, wrappers and monkey patching." [metadata] lock_version = "3.1" -content_hash = "sha256:9c52d28eff0b966cb0ddf5369b3af743ec10571db88414c654993a1dba023c1e" +content_hash = "sha256:f18a6d6ee6b08697dc4b4ab33ecb41cf6cfe597cbf60877d816cb884f7544cfc" [metadata.files] -"astroid 2.9.0" = [ - {file = "astroid-2.9.0-py3-none-any.whl", hash = "sha256:776ca0b748b4ad69c00bfe0fff38fa2d21c338e12c84aa9715ee0d473c422778"}, - {file = "astroid-2.9.0.tar.gz", hash = "sha256:5939cf55de24b92bda00345d4d0659d01b3c7dafb5055165c330bc7c568ba273"}, +"astroid 2.9.3" = [ + {file = "astroid-2.9.3-py3-none-any.whl", hash = "sha256:506daabe5edffb7e696ad82483ad0228245a9742ed7d2d8c9cdb31537decf9f6"}, + {file = "astroid-2.9.3.tar.gz", hash = "sha256:1efdf4e867d4d8ba4a9f6cf9ce07cd182c4c41de77f23814feb27ca93ca9d877"}, ] "atomicwrites 1.4.0" = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] -"attrs 21.2.0" = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, -] -"black 21.12b0" = [ - {file = "black-21.12b0-py3-none-any.whl", hash = "sha256:a615e69ae185e08fdd73e4715e260e2479c861b5740057fde6e8b4e3b7dd589f"}, - {file = "black-21.12b0.tar.gz", hash = "sha256:77b80f693a569e2e527958459634f18df9b0ba2625ba4e0c2d5da5be42e6f2b3"}, +"attrs 21.4.0" = [ + {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"}, + {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"}, +] +"black 22.1.0" = [ + {file = "black-22.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1297c63b9e1b96a3d0da2d85d11cd9bf8664251fd69ddac068b98dc4f34f73b6"}, + {file = "black-22.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2ff96450d3ad9ea499fc4c60e425a1439c2120cbbc1ab959ff20f7c76ec7e866"}, + {file = "black-22.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e21e1f1efa65a50e3960edd068b6ae6d64ad6235bd8bfea116a03b21836af71"}, + {file = "black-22.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f69158a7d120fd641d1fa9a921d898e20d52e44a74a6fbbcc570a62a6bc8ab"}, + {file = "black-22.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:228b5ae2c8e3d6227e4bde5920d2fc66cc3400fde7bcc74f480cb07ef0b570d5"}, + {file = "black-22.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b1a5ed73ab4c482208d20434f700d514f66ffe2840f63a6252ecc43a9bc77e8a"}, + {file = "black-22.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35944b7100af4a985abfcaa860b06af15590deb1f392f06c8683b4381e8eeaf0"}, + {file = "black-22.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7835fee5238fc0a0baf6c9268fb816b5f5cd9b8793423a75e8cd663c48d073ba"}, + {file = "black-22.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dae63f2dbf82882fa3b2a3c49c32bffe144970a573cd68d247af6560fc493ae1"}, + {file = "black-22.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa1db02410b1924b6749c245ab38d30621564e658297484952f3d8a39fce7e8"}, + {file = "black-22.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c8226f50b8c34a14608b848dc23a46e5d08397d009446353dad45e04af0c8e28"}, + {file = "black-22.1.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2d6f331c02f0f40aa51a22e479c8209d37fcd520c77721c034517d44eecf5912"}, + {file = "black-22.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:742ce9af3086e5bd07e58c8feb09dbb2b047b7f566eb5f5bc63fd455814979f3"}, + {file = "black-22.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fdb8754b453fb15fad3f72cd9cad3e16776f0964d67cf30ebcbf10327a3777a3"}, + {file = "black-22.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5660feab44c2e3cb24b2419b998846cbb01c23c7fe645fee45087efa3da2d61"}, + {file = "black-22.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:6f2f01381f91c1efb1451998bd65a129b3ed6f64f79663a55fe0e9b74a5f81fd"}, + {file = "black-22.1.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:efbadd9b52c060a8fc3b9658744091cb33c31f830b3f074422ed27bad2b18e8f"}, + {file = "black-22.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8871fcb4b447206904932b54b567923e5be802b9b19b744fdff092bd2f3118d0"}, + {file = "black-22.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ccad888050f5393f0d6029deea2a33e5ae371fd182a697313bdbd835d3edaf9c"}, + {file = "black-22.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07e5c049442d7ca1a2fc273c79d1aecbbf1bc858f62e8184abe1ad175c4f7cc2"}, + {file = "black-22.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:373922fc66676133ddc3e754e4509196a8c392fec3f5ca4486673e685a421321"}, + {file = "black-22.1.0-py3-none-any.whl", hash = "sha256:3524739d76b6b3ed1132422bf9d82123cd1705086723bc3e235ca39fd21c667d"}, + {file = "black-22.1.0.tar.gz", hash = "sha256:a7c0192d35635f6fc1174be575cb7915e92e5dd629ee79fdaf0dcfa41a80afb5"}, ] "click 8.0.3" = [ {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, ] -"cmake 3.22.1" = [ - {file = "cmake-3.22.1-py2.py3-none-macosx_10_9_universal2.macosx_10_9_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:153ab8c7d8bb6a0b6741a247ea89c3f269105e91b52cf44d7c51394193a3a94f"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5135c2039fd5e147857ea3aceefea5de00cfdd9f911f94fc987f35cd5b0b71af"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:609fe01e8b8241f4190f28d3e71f189c2272e7d7739568443b35fe1b0dea6494"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:493e436ac33ddb39238999f5c04c5767a1eec9c15b2e1284222cff067d2a8901"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33d081e76237c38cf115f7eecdaa277d914e4a57afbeb93229de293fc1418cfd"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cd7a3a33f6b78cb211334e120ed8d22f80c614d349e2b93fd958e0e9b89f7e"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:360eb0ab90e5ba08ab651bf088e7bd56f2c41022e5cde5e9caef274f1466f133"}, - {file = "cmake-3.22.1-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:55e7d61e48492f9a7561b4849ef0287dd858c76dd70a22b47b5c71b8d8ebdd5c"}, - {file = "cmake-3.22.1-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:dc9339db41ca0c208c082df3fb8ecb2ef62e38af5a9ccc0fe3ce2d91aa8eb2e8"}, - {file = "cmake-3.22.1-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:aef8619108fe43abc92782faf63d26b63fc56a5ab956de9c8b5d72240c800512"}, - {file = "cmake-3.22.1-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:f4bd2d162d81419c8310062913b574836e5bb04edf639cc25b5a7d4020a3a572"}, - {file = "cmake-3.22.1-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:d6f78f6e6f728e08a9f330942d8175f8234051328f8e060e2e5155f12f6edf0a"}, - {file = "cmake-3.22.1-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:e33657f8c2e49e8dc4f1714a94c1fc6a74656001f1ee2187c4f7e9f1ed641860"}, - {file = "cmake-3.22.1-py2.py3-none-win32.whl", hash = "sha256:bf7718fe37c755a1430099149cd23099dc024868c42cab9db2b6c8fe8a11c881"}, - {file = "cmake-3.22.1-py2.py3-none-win_amd64.whl", hash = "sha256:1a8023e21b538520b75c0166236164ae9ae08ac0b3edcc2aeafd436030aaae0d"}, - {file = "cmake-3.22.1.tar.gz", hash = "sha256:75d1573037748d5be4c73a51ef1a338bf21757aaddef5b532abf33f4333cd3ae"}, +"cmake 3.22.2" = [ + {file = "cmake-3.22.2-py2.py3-none-macosx_10_9_universal2.macosx_10_9_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:7bc1c50c9131105b4892528183475d3fc564f3d611f0fe2f1b1bd184f7de1fd4"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccb57bf773fdc0d3d299da387f7d46f38b452608fdc3100aa294dbb25d216515"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0801156be44344de6b1427ee8e845850d113868001c4c5bd415caf8d44328b8f"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43b820c4b880e28c10ff78ea0189deed77d77ddc166bb3fd807fa848a2822a25"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:026edb77648e9d84e2f446534a964513cf5ea82f226996bbe6dc480fb8048cf9"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aff4053fb344dc3d89a3ebd4ef66dd6ba0c8bf0130a2fd3fb8c65baf7316518"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9bc25b9c8be9507f4fc2004931f0d2f680eeae7c00f6d21aa168839a8aee7432"}, + {file = "cmake-3.22.2-py2.py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e01697d8beefd3cb2224aa70139858b6f515fc74348447fe97ddef8b56bf1cb9"}, + {file = "cmake-3.22.2-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:457e4990e8459cacbe37df6fb1aaf9648d6d08788d8b5f526c46a19d3cd7b700"}, + {file = "cmake-3.22.2-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:29eecf8285be72db820a60fa4adfc7b1f4c2acc0f3181881d191587ac5272e8c"}, + {file = "cmake-3.22.2-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:87cce96f5bd40987741718462fa29138d17bb8dbd24cd2a3f0824d2210cac429"}, + {file = "cmake-3.22.2-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:a642208015f3ffbc95dce55c23058ee7c562d3dece0da398f8d3276f45f5ee34"}, + {file = "cmake-3.22.2-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:7f10f00b863f2c60b585ebb45ae048174d450982c2595f336fcbbd6695a50e19"}, + {file = "cmake-3.22.2-py2.py3-none-win32.whl", hash = "sha256:fd3168e2535ddd0bd9bfff0e4aeb921a61a8351c272654ba71b518da502b9ec2"}, + {file = "cmake-3.22.2-py2.py3-none-win_amd64.whl", hash = "sha256:9f5f563e89a3ee8873a4c48c69d8a32331749da3c3b657d0f0ac74b659e87954"}, + {file = "cmake-3.22.2.tar.gz", hash = "sha256:b5bd5eeb488b13cf64ec963800f3d979eaeb90b4382861b86909df503379e219"}, ] "colorama 0.4.4" = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] -"coverage 6.2" = [ - {file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"}, - {file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"}, - {file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"}, - {file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"}, - {file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"}, - {file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"}, - {file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"}, - {file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"}, - {file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"}, - {file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"}, - {file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"}, - {file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"}, - {file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"}, - {file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"}, - {file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"}, - {file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"}, - {file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"}, - {file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"}, - {file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"}, - {file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"}, - {file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"}, - {file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"}, - {file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"}, - {file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"}, - {file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"}, - {file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"}, - {file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"}, - {file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"}, - {file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"}, -] -"execnet 1.9.0" = [ - {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, - {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, +"coverage 6.3.1" = [ + {file = "coverage-6.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525"}, + {file = "coverage-6.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c"}, + {file = "coverage-6.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145"}, + {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce"}, + {file = "coverage-6.3.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167"}, + {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda"}, + {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27"}, + {file = "coverage-6.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e"}, + {file = "coverage-6.3.1-cp310-cp310-win32.whl", hash = "sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217"}, + {file = "coverage-6.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb"}, + {file = "coverage-6.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0"}, + {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793"}, + {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd"}, + {file = "coverage-6.3.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1"}, + {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554"}, + {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1"}, + {file = "coverage-6.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8"}, + {file = "coverage-6.3.1-cp37-cp37m-win32.whl", hash = "sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0"}, + {file = "coverage-6.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687"}, + {file = "coverage-6.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320"}, + {file = "coverage-6.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8"}, + {file = "coverage-6.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734"}, + {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4"}, + {file = "coverage-6.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975"}, + {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa"}, + {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b"}, + {file = "coverage-6.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a"}, + {file = "coverage-6.3.1-cp38-cp38-win32.whl", hash = "sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10"}, + {file = "coverage-6.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f"}, + {file = "coverage-6.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d"}, + {file = "coverage-6.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6"}, + {file = "coverage-6.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1"}, + {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c"}, + {file = "coverage-6.3.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba"}, + {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed"}, + {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f"}, + {file = "coverage-6.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38"}, + {file = "coverage-6.3.1-cp39-cp39-win32.whl", hash = "sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2"}, + {file = "coverage-6.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa"}, + {file = "coverage-6.3.1-pp36.pp37.pp38-none-any.whl", hash = "sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2"}, + {file = "coverage-6.3.1.tar.gz", hash = "sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8"}, ] "iniconfig 1.1.1" = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -422,9 +404,9 @@ content_hash = "sha256:9c52d28eff0b966cb0ddf5369b3af743ec10571db88414c654993a1db {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] -"platformdirs 2.4.0" = [ - {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, - {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, +"platformdirs 2.5.0" = [ + {file = "platformdirs-2.5.0-py3-none-any.whl", hash = "sha256:30671902352e97b1eafd74ade8e4a694782bd3471685e78c32d0fdfd3aa7e7bb"}, + {file = "platformdirs-2.5.0.tar.gz", hash = "sha256:8ec11dfba28ecc0715eb5fb0147a87b1bf325f349f3da9aab2cd6b50b96b692b"}, ] "pluggy 1.0.0" = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, @@ -434,77 +416,82 @@ content_hash = "sha256:9c52d28eff0b966cb0ddf5369b3af743ec10571db88414c654993a1db {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, ] -"pydantic 1.8.2" = [ - {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, - {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, - {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, - {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, - {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, - {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, - {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, - {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, - {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, - {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, +"pydantic 1.9.0" = [ + {file = "pydantic-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5"}, + {file = "pydantic-1.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4"}, + {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37"}, + {file = "pydantic-1.9.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25"}, + {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6"}, + {file = "pydantic-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c"}, + {file = "pydantic-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398"}, + {file = "pydantic-1.9.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65"}, + {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46"}, + {file = "pydantic-1.9.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c"}, + {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054"}, + {file = "pydantic-1.9.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed"}, + {file = "pydantic-1.9.0-cp36-cp36m-win_amd64.whl", hash = "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1"}, + {file = "pydantic-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070"}, + {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2"}, + {file = "pydantic-1.9.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1"}, + {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032"}, + {file = "pydantic-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6"}, + {file = "pydantic-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d"}, + {file = "pydantic-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7"}, + {file = "pydantic-1.9.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77"}, + {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9"}, + {file = "pydantic-1.9.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6"}, + {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145"}, + {file = "pydantic-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034"}, + {file = "pydantic-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f"}, + {file = "pydantic-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b"}, + {file = "pydantic-1.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c"}, + {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce"}, + {file = "pydantic-1.9.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3"}, + {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d"}, + {file = "pydantic-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721"}, + {file = "pydantic-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16"}, + {file = "pydantic-1.9.0-py3-none-any.whl", hash = "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3"}, + {file = "pydantic-1.9.0.tar.gz", hash = "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a"}, ] "pylint 2.12.2" = [ {file = "pylint-2.12.2-py3-none-any.whl", hash = "sha256:daabda3f7ed9d1c60f52d563b1b854632fd90035bcf01443e234d3dc794e3b74"}, {file = "pylint-2.12.2.tar.gz", hash = "sha256:9d945a73640e1fec07ee34b42f5669b770c759acd536ec7b16d7e4b87a9c9ff9"}, ] -"pyparsing 3.0.6" = [ - {file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"}, - {file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"}, +"pyparsing 3.0.7" = [ + {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, + {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, ] -"pytest 6.2.5" = [ - {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, - {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, +"pytest 7.0.1" = [ + {file = "pytest-7.0.1-py3-none-any.whl", hash = "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db"}, + {file = "pytest-7.0.1.tar.gz", hash = "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171"}, ] "pytest-cov 3.0.0" = [ {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, ] -"pytest-forked 1.4.0" = [ - {file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"}, - {file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"}, -] -"pytest-mock 3.6.1" = [ - {file = "pytest_mock-3.6.1-py3-none-any.whl", hash = "sha256:30c2f2cc9759e76eee674b81ea28c9f0b94f8f0445a1b87762cadf774f0df7e3"}, - {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, -] -"pytest-xdist 2.5.0" = [ - {file = "pytest_xdist-2.5.0-py3-none-any.whl", hash = "sha256:6fe5c74fec98906deb8f2d2b616b5c782022744978e7bd4695d39c8f42d0ce65"}, - {file = "pytest-xdist-2.5.0.tar.gz", hash = "sha256:4580deca3ff04ddb2ac53eba39d76cb5dd5edeac050cb6fbc768b0dd712b4edf"}, +"pytest-mock 3.7.0" = [ + {file = "pytest_mock-3.7.0-py3-none-any.whl", hash = "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231"}, + {file = "pytest-mock-3.7.0.tar.gz", hash = "sha256:5112bd92cc9f186ee96e1a92efc84969ea494939c3aead39c50f421c4cc69534"}, ] -"setuptools 59.6.0" = [ - {file = "setuptools-59.6.0-py3-none-any.whl", hash = "sha256:4ce92f1e1f8f01233ee9952c04f6b81d1e02939d6e1b488428154974a4d0783e"}, - {file = "setuptools-59.6.0.tar.gz", hash = "sha256:22c7348c6d2976a52632c67f7ab0cdf40147db7789f9aed18734643fe9cf3373"}, +"setuptools 60.8.2" = [ + {file = "setuptools-60.8.2-py3-none-any.whl", hash = "sha256:43a5575eea6d3459789316e1596a3d2a0d215260cacf4189508112f35c9a145b"}, + {file = "setuptools-60.8.2.tar.gz", hash = "sha256:66b8598da112b8dc8cd941d54cf63ef91d3b50657b374457eda5851f3ff6a899"}, ] "toml 0.10.2" = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] -"tomli 1.2.3" = [ - {file = "tomli-1.2.3-py3-none-any.whl", hash = "sha256:e3069e4be3ead9668e21cb9b074cd948f7b3113fd9c8bba083f48247aab8b11c"}, - {file = "tomli-1.2.3.tar.gz", hash = "sha256:05b6166bff487dc068d322585c7ea4ef78deed501cc124060e0f238e89a9231f"}, +"tomli 2.0.1" = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -"tomlkit 0.7.2" = [ - {file = "tomlkit-0.7.2-py2.py3-none-any.whl", hash = "sha256:173ad840fa5d2aac140528ca1933c29791b79a374a0861a80347f42ec9328117"}, - {file = "tomlkit-0.7.2.tar.gz", hash = "sha256:d7a454f319a7e9bd2e249f239168729327e4dd2d27b17dc68be264ad1ce36754"}, +"tomlkit 0.9.2" = [ + {file = "tomlkit-0.9.2-py3-none-any.whl", hash = "sha256:daf4f9c5f2fbf6b861d6adfc51940b98dee36c13e1d88749a6dc9fb280fff304"}, + {file = "tomlkit-0.9.2.tar.gz", hash = "sha256:ebd982d61446af95a1e082b103e250cb9e6d152eae2581d4a07d31a70b34ab0f"}, ] -"typing-extensions 4.0.1" = [ - {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, - {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, +"typing-extensions 4.1.0" = [ + {file = "typing_extensions-4.1.0-py3-none-any.whl", hash = "sha256:c13180fbaa7cd97065a4915ceba012bdb31dc34743e63ddee16360161d358414"}, + {file = "typing_extensions-4.1.0.tar.gz", hash = "sha256:ba97c5143e5bb067b57793c726dd857b1671d4b02ced273ca0538e71ff009095"}, ] "wrapt 1.13.3" = [ {file = "wrapt-1.13.3-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:e05e60ff3b2b0342153be4d1b597bbcfd8330890056b9619f4ad6b8d5c96a81a"}, diff --git a/pyproject.toml b/pyproject.toml index 7b28885..6763d49 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,10 +18,11 @@ dynamic = ["version"] requires-python = ">=3.10" dependencies = [ - "click~=8.0", - "cmake~=3.22", - "pydantic~=1.8", - "tomlkit~=0.7", + "click>=8.0.3", + "cmake>=3.22.2", + "pydantic>=1.9", + "tomlkit>=0.9", + "pytest>=7.0.0", # Required for testing injection ] [tool.pdm] @@ -29,41 +30,48 @@ version = {use_scm = true} [tool.pdm.dev-dependencies] lint = [ - "black<22,>=21.11b1", - "pylint~=2.12", + "black>=22.1.0", + "pylint>=2.12.2", + "isort>=5.10.1", ] test = [ - "pytest~=6.2", - "pytest-cov~=3.0", - "pytest-mock~=3.6", - "pytest-xdist~=2.5", + "pytest-cov>=3.0.0", + "pytest-mock>=3.7.0", ] [project.scripts] cppython = "cppython.plugins.interface.console:cli" -# Register the testing information with pytest +# CPPython plugins +[project.entry-points."cppython.generator_plugins"] +cmake = "cppython.plugins.generator.cmake:CMakeGenerator" + +[project.entry-points."cppython.interface_plugins"] +console = "cppython.plugins.interface.console:ConsoleInterface" + +# Pytest plugins [tool.entry-points.pytest11] pytest_cppython = "cppython.plugins.test.pytest" [tool.pytest.ini_options] -addopts = "-n auto" testpaths = [ "tests", ] [tool.black] line-length = 120 +preview = true + +[tool.isort] +profile = "black" [tool.pylint.messages_control] disable = "C0330, C0326" +extension-pkg-whitelist = "pydantic" [tool.pylint.format] max-line-length = "120" -[tool.pylint.'MESSAGES CONTROL'] -extension-pkg-whitelist = "pydantic" - [build-system] build-backend = "pdm.pep517.api" requires = ["pdm-pep517"] diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index ed5638c..0000000 --- a/tests/conftest.py +++ /dev/null @@ -1,17 +0,0 @@ -import pytest - -from pathlib import Path -from shutil import copytree - - -@pytest.fixture -def tmp_workspace(tmp_path): - """ - Load the dummy project to its initial state - """ - - template_directory = Path("tests/data/test_project").absolute() - directory = Path(tmp_path).absolute() - copytree(str(directory), str(template_directory), dirs_exist_ok=True) - - return directory diff --git a/tests/integration/test_cli.py b/tests/integration/test_cli.py deleted file mode 100644 index 34c7aa3..0000000 --- a/tests/integration/test_cli.py +++ /dev/null @@ -1,3 +0,0 @@ -class TestCLI: - def test_something(self): - pass diff --git a/tests/integration/test_generator.py b/tests/integration/test_generator.py new file mode 100644 index 0000000..d3ccd5f --- /dev/null +++ b/tests/integration/test_generator.py @@ -0,0 +1,26 @@ +""" +Test the integrations related to the internal generator implementation and the 'Generator' interface itself +""" + +import pytest + +from cppython.plugins.generator.cmake import CMakeData, CMakeGenerator +from cppython.plugins.test.data import default_pyproject +from cppython.plugins.test.pytest import GeneratorIntegrationTests + + +class TestCMakeGenerator(GeneratorIntegrationTests): + """ + The tests for our CMake generator + """ + + @pytest.fixture(name="generator") + def fixture_generator(self): + """ + Override of the plugin provided generator fixture. + + Returns: + CMakeGenerator -- The Generator object to use for the CPPython defined tests + """ + cmake_data = CMakeData() + return CMakeGenerator(default_pyproject, cmake_data) diff --git a/tests/integration/test_interface.py b/tests/integration/test_interface.py new file mode 100644 index 0000000..df10d42 --- /dev/null +++ b/tests/integration/test_interface.py @@ -0,0 +1,25 @@ +""" +Test the integrations related to the internal interface implementation and the 'Interface' interface itself +""" + +import pytest + +from cppython.plugins.interface.console import ConsoleInterface +from cppython.plugins.test.data import default_pyproject +from cppython.plugins.test.pytest import InterfaceIntegrationTests + + +class TestCLIInterface(InterfaceIntegrationTests): + """ + The tests for our CLI interface + """ + + @pytest.fixture(name="interface") + def fixture_interface(self): + """ + Override of the plugin provided interface fixture. + + Returns: + ConsoleInterface -- The Interface object to use for the CPPython defined tests + """ + return ConsoleInterface(default_pyproject) diff --git a/tests/integration/test_project.py b/tests/integration/test_project.py deleted file mode 100644 index 3d3a61c..0000000 --- a/tests/integration/test_project.py +++ /dev/null @@ -1,3 +0,0 @@ -class TestProjects: - def test_correct_project(self, tmp_workspace): - pass diff --git a/tests/unit/test_generator.py b/tests/unit/test_generator.py index 98e37d9..d8871fb 100644 --- a/tests/unit/test_generator.py +++ b/tests/unit/test_generator.py @@ -1,17 +1,26 @@ +""" +Test the functions related to the internal generator implementation and the 'Generator' interface itself +""" + import pytest -from cppython.plugins.test.pytest import BaseGenerator -from cppython.plugins.generator.cmake import CMakeGenerator +from cppython.plugins.generator.cmake import CMakeData, CMakeGenerator +from cppython.plugins.test.data import default_pyproject +from cppython.plugins.test.pytest import GeneratorUnitTests -@pytest.mark.parametrize("generator", [CMakeGenerator]) -class TestCMakeGenerator(BaseGenerator): +class TestCMakeGenerator(GeneratorUnitTests): """ The tests for our CMake generator """ - def test_name(self, generator): + @pytest.fixture(name="generator") + def fixture_generator(self) -> CMakeGenerator: """ - Tests that the generators name is expected + Override of the plugin provided generator fixture. + + Returns: + CMakeGenerator -- The Generator object to use for the CPPython defined tests """ - assert generator.name() == "cmake" + cmake_data = CMakeData() + return CMakeGenerator(default_pyproject, cmake_data) diff --git a/tests/unit/test_interface.py b/tests/unit/test_interface.py index f517cde..5cc74e9 100644 --- a/tests/unit/test_interface.py +++ b/tests/unit/test_interface.py @@ -1,32 +1,57 @@ -import pytest +""" +Test the functions related to the internal interface implementation and the 'Interface' interface itself +""" -from cppython.plugins.test.pytest import BaseInterface -from cppython.plugins.interface.console import ConsoleInterface, Config, cli -from cppython.project import Project +import pytest from click.testing import CliRunner +from pytest_mock.plugin import MockerFixture + +from cppython.plugins.interface.console import Config, ConsoleInterface, cli +from cppython.plugins.test.data import default_pyproject +from cppython.plugins.test.pytest import InterfaceUnitTests +from cppython.schema import API -@pytest.mark.parametrize("interface", [ConsoleInterface]) -class TestCLIInterface(BaseInterface): +class TestCLIInterface(InterfaceUnitTests): """ The tests for our CLI interface """ - @pytest.mark.parametrize("command", ["install", "update"]) - def test_command(self, interface, command, mocker): + @pytest.fixture(name="interface") + def fixture_interface(self) -> ConsoleInterface: + """ + Override of the plugin provided interface fixture. + + Returns: + ConsoleInterface -- The Interface object to use for the CPPython defined tests + """ + return ConsoleInterface(default_pyproject) + + # Grab the API methods and parameterize them for automatic testing of the entry_points + method_list = [func for func in dir(API) if callable(getattr(API, func)) and not func.startswith("__")] + + @pytest.mark.parametrize("command", method_list) + def test_command(self, command: str, mocker: MockerFixture): + """ + _summary_ - # Patch the project - mocker.patch("cppython.plugins.interface.console.Config.load") + Arguments: + command {str} -- The CLI command with the same name as the CPPython API call + mocker {MockerFixture} -- pytest-mock fixture + """ + # Patch the project initialization + mocker.patch("cppython.project.Project.__init__", return_value=None) - # Patch the file IO - mocker.patch("cppython.plugins.interface.console._read_data") + # Patch the reading of data + mocker.patch("cppython.plugins.interface.console._create_pyproject", return_value=default_pyproject) config = Config() - # Patch out the non-plugin implementation - mocker.patch(f"cppython.project.Project.{command}") + # Patch out the implementation + mocked_command = mocker.patch(f"cppython.project.Project.{command}") runner = CliRunner() result = runner.invoke(cli, [command], obj=config, catch_exceptions=False) assert result.exit_code == 0 + mocked_command.assert_called_once() diff --git a/tests/unit/test_plugin.py b/tests/unit/test_plugin.py deleted file mode 100644 index 5f28270..0000000 --- a/tests/unit/test_plugin.py +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/tests/unit/test_project.py b/tests/unit/test_project.py deleted file mode 100644 index 5f13681..0000000 --- a/tests/unit/test_project.py +++ /dev/null @@ -1,6 +0,0 @@ -from cppython.project import Project - - -class TestProject: - def test_something(self): - pass