From 19afcd966afd87d8932b856773870227c927e735 Mon Sep 17 00:00:00 2001 From: Asher Norland Date: Sun, 17 Apr 2022 14:38:41 -0400 Subject: [PATCH] Integrate Initial Logger Support --- cppython/console.py | 11 ++--- cppython/project.py | 95 ++++++++++++++++++++++++++---------- pdm.lock | 21 ++++---- pyproject.toml | 4 +- tests/unit/test_interface.py | 2 +- tests/unit/test_project.py | 17 +++++-- 6 files changed, 100 insertions(+), 50 deletions(-) diff --git a/cppython/console.py b/cppython/console.py index 4f94e0d..62f1bb1 100644 --- a/cppython/console.py +++ b/cppython/console.py @@ -2,9 +2,9 @@ A click CLI for CPPython interfacing """ +from logging import Logger from pathlib import Path from typing import Any, Type -from xmlrpc.client import Boolean import click import tomlkit @@ -54,13 +54,13 @@ def create_project(self) -> Project: @click.group() -@click.option("-v", "--verbose", is_flag=True, help="Print additional output") +@click.option("-v", "--verbose", count=True, help="Print additional output") @pass_config -def cli(config, verbose: Boolean): +def cli(config, verbose: int): """ entry_point group for the CLI commands """ - config.configuration.verbose = verbose + config.configuration.verbosity = verbose @cli.command() @@ -118,8 +118,7 @@ def write_pyproject(self) -> None: Write output """ - def print(self, string: str) -> None: + def register_logger(self, logger: Logger) -> None: """ TODO """ - click.echo(string) diff --git a/cppython/project.py b/cppython/project.py index 9d07313..64cb7bd 100644 --- a/cppython/project.py +++ b/cppython/project.py @@ -2,16 +2,16 @@ The central delegation of the CPPython project """ +import logging from dataclasses import dataclass from importlib import metadata -from pathlib import Path from typing import Any, Type, TypeVar -from xmlrpc.client import Boolean from cppython_core.schema import ( API, CPPythonData, Generator, + GeneratorConfiguration, Interface, Plugin, PyProject, @@ -26,7 +26,21 @@ class ProjectConfiguration: TODO """ - verbose: Boolean = False + _verbosity: int = 0 + + @property + def verbosity(self) -> int: + """ + TODO + """ + return self._verbosity + + @verbosity.setter + def verbosity(self, value: int) -> None: + """ + TODO + """ + self._verbosity = min(max(value, 0), 2) class ProjectBuilder: @@ -79,13 +93,15 @@ def generate_model(self, plugins: list[Type[Generator]]) -> Type[PyProject]: __base__=PyProject, ) - def create_generators(self, plugins: list[Type[Generator]], pyproject: PyProject) -> list[Generator]: + def create_generators( + self, plugins: list[Type[Generator]], configuration: GeneratorConfiguration, pyproject: PyProject + ) -> list[Generator]: """ TODO """ _generators = [] for plugin_type in plugins: - _generators.append(plugin_type(pyproject)) + _generators.append(plugin_type(configuration, pyproject)) return _generators @@ -100,39 +116,69 @@ def __init__( ) -> None: self._enabled = False - self.configuration = configuration + self._configuration = configuration + self._pyproject = None + + levels = [logging.WARNING, logging.INFO, logging.DEBUG] + + self._logger = logging.getLogger("cppython") + self._logger.setLevel(levels[configuration.verbosity]) - if self.configuration.verbose: - interface.print("Starting CPPython project initialization") + interface.register_logger(self._logger) + + self._logger.info("Initializing project") builder = ProjectBuilder(self.configuration) plugins = builder.gather_plugins(Generator) if not plugins: - if self.configuration.verbose: - interface.print("No generator plugin was found.") + self._logger.info("No generator plugin was found") return extended_pyproject_type = builder.generate_model(plugins) - self.pyproject = extended_pyproject_type(**pyproject_data) + self._pyproject = extended_pyproject_type(**pyproject_data) + + if self.pyproject is None: + self._logger.info("Data is not defined") + return if self.pyproject.tool is None: - if self.configuration.verbose: - interface.print("Table [tool] is not defined") + self._logger.info("Table [tool] is not defined") return if self.pyproject.tool.cppython is None: - if self.configuration.verbose: - interface.print("Table [tool.cppython] is not defined") + self._logger.info("Table [tool.cppython] is not defined") return self._enabled = True self._interface = interface - self._generators = builder.create_generators(plugins, self.pyproject) - if self.configuration.verbose: - interface.print("CPPython project initialized") + generator_configuration = GeneratorConfiguration(self._logger) + self._generators = builder.create_generators(plugins, generator_configuration, self.pyproject) + + self._logger.info("Initialized project") + + @property + def enabled(self) -> bool: + """ + TODO + """ + return self._enabled + + @property + def configuration(self) -> ProjectConfiguration: + """ + TODO + """ + return self._configuration + + @property + def pyproject(self) -> PyProject | None: + """ + TODO + """ + return self._pyproject def download(self): """ @@ -148,18 +194,17 @@ def download(self): path.mkdir(parents=True, exist_ok=True) if not generator.generator_downloaded(path): - self._interface.print(f"Downloading the {generator.name()} tool") + self._logger.info(f"Downloading the {generator.name()} tool") # TODO: Make async with progress bar generator.download_generator(path) - self._interface.print("Download complete") + self._logger.info("Download complete") # API Contract def install(self) -> None: if self._enabled: - if self.configuration.verbose: - self._interface.print("CPPython: Installing...") + self._logger.info("Installing project") self.download() for generator in self._generators: @@ -167,16 +212,14 @@ def install(self) -> None: def update(self) -> None: if self._enabled: - if self.configuration.verbose: - self._interface.print("CPPython: Updating...") + self._logger.info("Updating project") for generator in self._generators: generator.update() def build(self) -> None: if self._enabled: - if self.configuration.verbose: - self._interface.print("CPPython: Building...") + self._logger.info("Building project") for generator in self._generators: generator.build() diff --git a/pdm.lock b/pdm.lock index ba8bfba..fefa5a8 100644 --- a/pdm.lock +++ b/pdm.lock @@ -68,10 +68,11 @@ dependencies = [ [[package]] name = "cppython-core" -version = "0.2.1" +version = "0.3.2" requires_python = ">=3.10" summary = "Data definitions for CPPython" dependencies = [ + "packaging>=21.3", "pydantic>=1.9", ] @@ -199,11 +200,11 @@ dependencies = [ [[package]] name = "pytest-cppython" -version = "0.1.4" +version = "0.1.6" requires_python = ">=3.10" summary = "A pytest plugin that imports CPPython testing types" dependencies = [ - "cppython-core>=0.2.1", + "cppython-core>=0.3.2", "pydantic>=1.9.0", ] @@ -248,7 +249,7 @@ summary = "Module for decorators, wrappers and monkey patching." [metadata] lock_version = "3.1" -content_hash = "sha256:df6c31dc4b507acddb260891407183bb5d4b0f4c62c8fbb39623d64f2a24ff2c" +content_hash = "sha256:fd1d9812a5b77dc7e8b93ed0d0f723d7d03a1fec4fc66f6b19ec2158fb2ffbf7" [metadata.files] "astroid 2.11.2" = [ @@ -339,9 +340,9 @@ content_hash = "sha256:df6c31dc4b507acddb260891407183bb5d4b0f4c62c8fbb39623d64f2 {file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"}, {file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"}, ] -"cppython-core 0.2.1" = [ - {file = "cppython_core-0.2.1-py3-none-any.whl", hash = "sha256:d5f7be4815b89c53bfd7bbc7653e1fc66e1cde022edebe78afc86f5b0d6a1de4"}, - {file = "cppython-core-0.2.1.tar.gz", hash = "sha256:001fb049a1d62c584eb1a2bcc8c4e4acad461ff583e875bb44ab5df9249b37b7"}, +"cppython-core 0.3.2" = [ + {file = "cppython_core-0.3.2-py3-none-any.whl", hash = "sha256:bd7ee3988fe73206476c7d3979392279f203ed696e2920e00075163b00a5aea9"}, + {file = "cppython-core-0.3.2.tar.gz", hash = "sha256:65da9e2cac0db22c8e061978bd910137560ad1bbb0c28f240797e0b8a7b5d6fa"}, ] "dill 0.3.4" = [ {file = "dill-0.3.4-py2.py3-none-any.whl", hash = "sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f"}, @@ -475,9 +476,9 @@ content_hash = "sha256:df6c31dc4b507acddb260891407183bb5d4b0f4c62c8fbb39623d64f2 {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-cppython 0.1.4" = [ - {file = "pytest_cppython-0.1.4-py3-none-any.whl", hash = "sha256:b0c04961114872fc1cb472b31d0028c958140682b4769a3da15b66c6299880ff"}, - {file = "pytest-cppython-0.1.4.tar.gz", hash = "sha256:4cfdf36f6c7f767a13f407ca48d65b3848d89b1f676e3fe74872bae3d3b05675"}, +"pytest-cppython 0.1.6" = [ + {file = "pytest_cppython-0.1.6-py3-none-any.whl", hash = "sha256:bfdced9e41d40b2fcf9d74dc92c3029bb08aa9147b0530db3c96250b02b47587"}, + {file = "pytest-cppython-0.1.6.tar.gz", hash = "sha256:38743eb491ba068b87b55e56d343ced1905e22ed50025b9964b4ced3c60106b2"}, ] "pytest-mock 3.7.0" = [ {file = "pytest_mock-3.7.0-py3-none-any.whl", hash = "sha256:6cff27cec936bf81dc5ee87f07132b807bcda51106b5ec4b90a04331cba76231"}, diff --git a/pyproject.toml b/pyproject.toml index 744a2b4..f6ef25b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ requires-python = ">=3.10" dependencies = [ "click>=8.1.2", "tomlkit>=0.10.1", - "cppython-core>=0.2.1", + "cppython-core>=0.3.2", "pydantic>=1.9.0", ] @@ -40,7 +40,7 @@ test = [ "pytest>=7.1.1", "pytest-cov>=3.0.0", "pytest-mock>=3.7.0", - "pytest-cppython>=0.1.4", + "pytest-cppython>=0.1.6", ] [project.scripts] diff --git a/tests/unit/test_interface.py b/tests/unit/test_interface.py index 079a455..657ae71 100644 --- a/tests/unit/test_interface.py +++ b/tests/unit/test_interface.py @@ -75,4 +75,4 @@ def test_verbosity(self): assert result.exit_code == 0 - assert config.configuration.verbose + assert config.configuration.verbosity diff --git a/tests/unit/test_project.py b/tests/unit/test_project.py index 40bb2ac..4d8d5a1 100644 --- a/tests/unit/test_project.py +++ b/tests/unit/test_project.py @@ -2,9 +2,14 @@ Test the functions related to the internal interface implementation and the 'Interface' interface itself """ -from pathlib import Path - -from cppython_core.schema import Generator, GeneratorData, PyProject +import logging + +from cppython_core.schema import ( + Generator, + GeneratorConfiguration, + GeneratorData, + PyProject, +) from pytest_mock import MockerFixture from cppython.data import default_pyproject @@ -85,11 +90,13 @@ def test_generator_creation(self, mocker: MockerFixture): configuration = ProjectConfiguration() builder = ProjectBuilder(configuration) - generators = builder.create_generators([], default_pyproject) + + generator_configuration = GeneratorConfiguration(logging.getLogger(__name__)) + generators = builder.create_generators([], generator_configuration, default_pyproject) assert not generators generator = mocker.Mock(spec=Generator) - generators = builder.create_generators([generator], default_pyproject) + generators = builder.create_generators([generator], generator_configuration, default_pyproject) assert len(generators) == 1