From e53e91b1a2927828b1c8cb43ca0ebb53ed5fead9 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:10:46 +0200 Subject: [PATCH 01/43] Group dependabot updates and make them weekly Signed-off-by: Leandro Lucarella --- .github/dependabot.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index db6cfbd3d..7ddc4b9a7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,7 @@ updates: - package-ecosystem: "pip" directory: "/" schedule: - interval: "daily" + interval: "weekly" time: "07:00" labels: - "part:tooling" @@ -13,11 +13,28 @@ updates: versioning-strategy: auto # Allow up to 10 open pull requests for updates to dependency versions open-pull-requests-limit: 10 + # We group production and development ("optional" in the context of + # pyproject.toml) dependency updates when they are patch and minor updates, + # so we end up with less PRs being generated. + # Major updates are still managed, but they'll create one PR per + # dependency, as major updates are expected to be breaking, it is better to + # manage them individually. + groups: + required: + dependency-type: "production" + update-types: + - "minor" + - "patch" + optional: + dependency-type: "development" + update-types: + - "minor" + - "patch" - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "daily" + interval: "weekly" time: "06:00" labels: - "part:tooling" From c3aa3a39a105ece72cb9b4927f9c9a4c10e2b76a Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:11:29 +0200 Subject: [PATCH 02/43] ci: Add debug info and run `nox` sessions in parallel Signed-off-by: Leandro Lucarella --- .github/workflows/ci.yaml | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1cb82cd57..335c54280 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,9 +32,17 @@ jobs: - ubuntu-20.04 python: - "3.11" + nox-session: + # To speed things up a bit we use the special ci_checks_max session + # that uses the same venv to run multiple linting sessions + - "ci_checks_max" + - "pytest_min" runs-on: ${{ matrix.os }} steps: + - name: Print environment (debug) + run: env + - name: Fetch sources uses: actions/checkout@v3 with: @@ -50,11 +58,25 @@ jobs: run: | python -m pip install --upgrade pip python -m pip install -e .[dev-noxfile] + pip freeze + + - name: Create nox venv + env: + NOX_SESSION: ${{ matrix.nox-session }} + run: nox --install-only -e "$NOX_SESSION" + + - name: Print pip freeze for nox venv (debug) + env: + NOX_SESSION: ${{ matrix.nox-session }} + run: | + . ".nox/$NOX_SESSION/bin/activate" + pip freeze + deactivate - name: Run nox - # To speed things up a bit we use the special ci_checks_max session - # that uses the same venv to run multiple linting sessions - run: nox -e ci_checks_max pytest_min + env: + NOX_SESSION: ${{ matrix.nox-session }} + run: nox -R -e "$NOX_SESSION" timeout-minutes: 10 build: @@ -76,6 +98,7 @@ jobs: run: | python -m pip install -U pip python -m pip install -U build + pip freeze - name: Build the source and binary distribution run: python -m build @@ -135,6 +158,7 @@ jobs: run: | python -m pip install -U pip python -m pip install .[dev-mkdocs] + pip freeze - name: Generate the documentation env: @@ -217,6 +241,7 @@ jobs: run: | python -m pip install -U pip python -m pip install .[dev-mkdocs] + pip freeze - name: Fetch the gh-pages branch if: steps.mike-metadata.outputs.version From f61a546268c9dae3499752b8368a3e3fc1f4f52f Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:11:54 +0200 Subject: [PATCH 03/43] Remove `darglint` configuration Now `pydoclint` is used instead. Signed-off-by: Leandro Lucarella --- MANIFEST.in | 1 - 1 file changed, 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 1dc8c9d55..fc40ba9c5 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,4 @@ exclude .cookiecutter-replay.json -exclude .darglint exclude .editorconfig exclude .gitignore exclude CODEOWNERS From b1131f8d06a843beb34421a21513b9b6758cce1e Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:13:27 +0200 Subject: [PATCH 04/43] Remove transitive dependencies These are now installed via repo-config. Signed-off-by: Leandro Lucarella --- pyproject.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ff9157c64..50b1ad673 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,8 +86,6 @@ dev-pytest = [ "time-machine == 2.12.0", "async-solipsism == 0.5", # For checking docstring code examples - "sybil == 5.0.3", - "pylint == 2.17.5", "frequenz-sdk[dev-examples]", ] dev = [ From 18bf79b84d9c6ad1f5a9e4a69e02ff3dba445dce Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:14:57 +0200 Subject: [PATCH 05/43] Change docstrings dependencies to `flake8` Now `flake8` is used to check docstrings, so the optional depdendencies should match that. Also add the configuration for `flake8` and the plugins it runs. Signed-off-by: Leandro Lucarella --- pyproject.toml | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 50b1ad673..d663567fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,10 +49,12 @@ name = "Frequenz Energy-as-a-Service GmbH" email = "floss@frequenz.com" [project.optional-dependencies] -dev-docstrings = [ +dev-flake8 = [ + "flake8 == 6.1.0", + "flake8-docstrings == 1.7.0", + "flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml + "pydoclint == 0.3.1", "pydocstyle == 6.3.0", - "darglint == 1.8.1", - "tomli == 2.0.1", # Needed by pydocstyle to read pyproject.toml ] dev-examples = ["polars == 0.18.15"] dev-formatting = ["black == 23.7.0", "isort == 5.12.0"] @@ -89,7 +91,7 @@ dev-pytest = [ "frequenz-sdk[dev-examples]", ] dev = [ - "frequenz-sdk[dev-mkdocs,dev-docstrings,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]", + "frequenz-sdk[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]", ] [project.urls] @@ -108,6 +110,23 @@ profile = "black" line_length = 88 src_paths = ["benchmarks", "examples", "src", "tests"] +[tool.flake8] +# We give some flexibility to go over 88, there are cases like long URLs or +# code in documenation that have extra indentation. Black will still take care +# of making everything that can be 88 wide, 88 wide. +max-line-length = 100 +extend-ignore = [ + "E203", # Whitespace before ':' (conflicts with black) + "W503", # Line break before binary operator (conflicts with black) +] +# pydoclint options +style = "google" +allow-init-docstring = true +arg-type-hints-in-docstring = false +arg-type-hints-in-signature = true +check-return-types = false +check-yield-types = false + [tool.pylint.similarities] ignore-comments = ['yes'] ignore-docstrings = ['yes'] From 5cf27c067072a500485b88a1d31860bd6e75ad94 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:02:18 +0200 Subject: [PATCH 06/43] Ignore pylint errors that overlap with flake8 Flake8 runs much faster than pylint, so it is preferred. Signed-off-by: Leandro Lucarella --- pyproject.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index d663567fa..a61c7ce19 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,6 +142,10 @@ disable = [ # pylint's unsubscriptable check is buggy and is not needed because # it is a type-check, for which we already have mypy. "unsubscriptable-object", + # Checked by flake8 + "line-too-long", + "unused-variable", + "unnecessary-lambda-assignment", ] [tool.pylint.design] From d5a43a68296810c34d65ebcb0a4168959b605b3c Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:15:19 +0200 Subject: [PATCH 07/43] Add `mypy` configuration to `pyproject.toml` Adds command-line options and also adds the stub dependencies. Signed-off-by: Leandro Lucarella --- pyproject.toml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a61c7ce19..167f39c88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -69,8 +69,15 @@ dev-mkdocs = [ ] dev-mypy = [ "mypy == 1.5.1", - "grpc-stubs == 1.24.12", # This dependency introduces breaking changes in patch releases + "grpc-stubs == 1.24.12", # This dependency introduces breaking changes in patch releases + "types-Markdown == 3.4.2.10", + "types-PyYAML == 6.0.12.11", + "types-Pygments == 2.16.0.0", + "types-colorama == 0.4.15.12", "types-protobuf == 4.24.0.1", + "types-python-dateutil == 2.8.19.14", + "types-pytz == 2023.3.0.1", + "types-setuptools == 68.1.0.0", # For checking the noxfile, docs/ script, and tests "frequenz-sdk[dev-mkdocs,dev-noxfile,dev-pytest]", ] From 0467495949e12b92468d1f5f576c5eccee02b3f7 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 12:52:01 +0200 Subject: [PATCH 08/43] Document *args and **kwargs properly Collected positional and keyword argument should be documented using also the asterisks. Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/actor/_run_utils.py | 2 +- src/frequenz/sdk/timeseries/_quantities.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frequenz/sdk/actor/_run_utils.py b/src/frequenz/sdk/actor/_run_utils.py index 5cc547c8d..27a9c50bc 100644 --- a/src/frequenz/sdk/actor/_run_utils.py +++ b/src/frequenz/sdk/actor/_run_utils.py @@ -16,7 +16,7 @@ async def run(*actors: Actor) -> None: """Await the completion of all actors. Args: - actors: the actors to be awaited. + *actors: the actors to be awaited. """ _logger.info("Starting %s actor(s)...", len(actors)) diff --git a/src/frequenz/sdk/timeseries/_quantities.py b/src/frequenz/sdk/timeseries/_quantities.py index d5dd0147b..15bda6673 100644 --- a/src/frequenz/sdk/timeseries/_quantities.py +++ b/src/frequenz/sdk/timeseries/_quantities.py @@ -374,8 +374,8 @@ def __call__(cls, *_args: Any, **_kwargs: Any) -> NoReturn: """Raise a TypeError when the default constructor is called. Args: - _args: ignored positional arguments. - _kwargs: ignored keyword arguments. + *_args: ignored positional arguments. + **_kwargs: ignored keyword arguments. Raises: TypeError: Always. From 86151ef6d1e2f1e019a0f4a46cd5b426d38d1d71 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 12:53:39 +0200 Subject: [PATCH 09/43] Remove documented exceptions that are not really raised Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/microgrid/client/_client.py | 3 --- .../sdk/timeseries/_periodic_feature_extractor.py | 3 --- src/frequenz/sdk/timeseries/_quantities.py | 9 --------- .../sdk/timeseries/battery_pool/_component_metrics.py | 3 --- .../sdk/timeseries/battery_pool/_metric_calculator.py | 3 --- 5 files changed, 21 deletions(-) diff --git a/src/frequenz/sdk/microgrid/client/_client.py b/src/frequenz/sdk/microgrid/client/_client.py index 210c46b92..fd75f1368 100644 --- a/src/frequenz/sdk/microgrid/client/_client.py +++ b/src/frequenz/sdk/microgrid/client/_client.py @@ -335,9 +335,6 @@ async def _component_data_task( transform: A method for transforming raw component data into the desired output type. sender: A channel sender, to send the component data to. - - Raises: - AioRpcError: if connection to Microgrid API cannot be established """ retry_spec: RetryStrategy = self._retry_spec.copy() while True: diff --git a/src/frequenz/sdk/timeseries/_periodic_feature_extractor.py b/src/frequenz/sdk/timeseries/_periodic_feature_extractor.py index 66a954f57..fea3073c5 100644 --- a/src/frequenz/sdk/timeseries/_periodic_feature_extractor.py +++ b/src/frequenz/sdk/timeseries/_periodic_feature_extractor.py @@ -250,9 +250,6 @@ def _get_relative_positions( Returns: The relative positions of the start, end and next samples. - - Raises: - ValueError: If the start timestamp is after the end timestamp. """ # The number of usable windows can change, when the current position of # the ringbuffer is inside one of the windows inside the MovingWindow. diff --git a/src/frequenz/sdk/timeseries/_quantities.py b/src/frequenz/sdk/timeseries/_quantities.py index 15bda6673..287646fa1 100644 --- a/src/frequenz/sdk/timeseries/_quantities.py +++ b/src/frequenz/sdk/timeseries/_quantities.py @@ -544,9 +544,6 @@ def __mul__(self, other: Percentage | timedelta) -> Self | Energy: Returns: A power or energy. - - Raises: - TypeError: If the given value is not a percentage or duration. """ if isinstance(other, Percentage): return super().__mul__(other) @@ -681,9 +678,6 @@ def __mul__(self, other: Percentage | Voltage) -> Self | Power: Returns: A current or power. - - Raises: - TypeError: If the given value is not a percentage or voltage. """ if isinstance(other, Percentage): return super().__mul__(other) @@ -799,9 +793,6 @@ def __mul__(self, other: Percentage | Current) -> Self | Power: Returns: The calculated voltage or power. - - Raises: - TypeError: If the given value is not a percentage or current. """ if isinstance(other, Percentage): return super().__mul__(other) diff --git a/src/frequenz/sdk/timeseries/battery_pool/_component_metrics.py b/src/frequenz/sdk/timeseries/battery_pool/_component_metrics.py index afc6b2735..09781635b 100644 --- a/src/frequenz/sdk/timeseries/battery_pool/_component_metrics.py +++ b/src/frequenz/sdk/timeseries/battery_pool/_component_metrics.py @@ -55,9 +55,6 @@ def get(self, metric: ComponentMetricId) -> float | None: Args: metric: metric id - Raises: - KeyError: If given metric is not stored in the object. - Returns: Value of the metric. """ diff --git a/src/frequenz/sdk/timeseries/battery_pool/_metric_calculator.py b/src/frequenz/sdk/timeseries/battery_pool/_metric_calculator.py index ceb730e0d..67b880be0 100644 --- a/src/frequenz/sdk/timeseries/battery_pool/_metric_calculator.py +++ b/src/frequenz/sdk/timeseries/battery_pool/_metric_calculator.py @@ -457,9 +457,6 @@ def __init__( Args: batteries: What batteries should be used for calculation. - - Raises: - ValueError: If no battery has adjacent inverter. """ self._bat_inv_map = battery_inverter_mapping(batteries) used_batteries = set(self._bat_inv_map.keys()) From de86e5f55653b8ee258f0377bcfbddcacd15b9b4 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 12:54:59 +0200 Subject: [PATCH 10/43] Add missing returns documentation Signed-off-by: Leandro Lucarella --- .../microgrid/component/_component_data.py | 3 ++ src/frequenz/sdk/timeseries/_quantities.py | 30 +++++++++++++++++++ .../sdk/timeseries/_ringbuffer/buffer.py | 6 ++++ 3 files changed, 39 insertions(+) diff --git a/src/frequenz/sdk/microgrid/component/_component_data.py b/src/frequenz/sdk/microgrid/component/_component_data.py index a3e29c3dc..2a44207d7 100644 --- a/src/frequenz/sdk/microgrid/component/_component_data.py +++ b/src/frequenz/sdk/microgrid/component/_component_data.py @@ -53,6 +53,9 @@ def from_proto(cls, raw: microgrid_pb.ComponentData) -> ComponentData: Args: raw: raw component data as decoded from the wire. + + Returns: + The instance created from the protobuf message. """ diff --git a/src/frequenz/sdk/timeseries/_quantities.py b/src/frequenz/sdk/timeseries/_quantities.py index 287646fa1..71898c2e8 100644 --- a/src/frequenz/sdk/timeseries/_quantities.py +++ b/src/frequenz/sdk/timeseries/_quantities.py @@ -526,6 +526,9 @@ def __mul__(self, other: Percentage) -> Self: Args: other: The percentage to multiply by. + + Returns: + The scaled power. """ @overload @@ -534,6 +537,9 @@ def __mul__(self, other: timedelta) -> Energy: Args: other: The duration to multiply by. + + Returns: + The calculated energy. """ def __mul__(self, other: Percentage | timedelta) -> Self | Energy: @@ -560,6 +566,9 @@ def __truediv__(self, other: Current) -> Voltage: Args: other: The current to divide by. + + Returns: + A voltage from dividing this power by the a current. """ @overload @@ -568,6 +577,9 @@ def __truediv__(self, other: Voltage) -> Current: Args: other: The voltage to divide by. + + Returns: + A current from dividing this power by a voltage. """ def __truediv__(self, other: Current | Voltage) -> Voltage | Current: @@ -660,6 +672,9 @@ def __mul__(self, other: Percentage) -> Self: Args: other: The percentage to multiply by. + + Returns: + The scaled current. """ @overload @@ -668,6 +683,9 @@ def __mul__(self, other: Voltage) -> Power: Args: other: The voltage. + + Returns: + The calculated power. """ def __mul__(self, other: Percentage | Voltage) -> Self | Power: @@ -775,6 +793,9 @@ def __mul__(self, other: Percentage) -> Self: Args: other: The percentage to multiply by. + + Returns: + The scaled voltage. """ @overload @@ -783,6 +804,9 @@ def __mul__(self, other: Current) -> Power: Args: other: The current to multiply the voltage with. + + Returns: + The calculated power. """ def __mul__(self, other: Percentage | Current) -> Self | Power: @@ -894,6 +918,9 @@ def __truediv__(self, other: timedelta) -> Power: Args: other: The duration to divide by. + + Returns: + A power from dividing this energy by the given duration. """ @overload @@ -902,6 +929,9 @@ def __truediv__(self, other: Power) -> timedelta: Args: other: The power to divide by. + + Returns: + A duration from dividing this energy by the given power. """ def __truediv__(self, other: timedelta | Power) -> Power | timedelta: diff --git a/src/frequenz/sdk/timeseries/_ringbuffer/buffer.py b/src/frequenz/sdk/timeseries/_ringbuffer/buffer.py index a1616d616..1a087022e 100644 --- a/src/frequenz/sdk/timeseries/_ringbuffer/buffer.py +++ b/src/frequenz/sdk/timeseries/_ringbuffer/buffer.py @@ -488,6 +488,9 @@ def __getitem__(self, index_or_slice: SupportsIndex) -> float: Args: index_or_slice: Index of the requested data. + + Returns: + The requested value. """ @overload @@ -499,6 +502,9 @@ def __getitem__(self, index_or_slice: slice) -> FloatArray: Args: index_or_slice: Slice specification of where the requested data is. + + Returns: + The requested slice. """ def __getitem__(self, index_or_slice: SupportsIndex | slice) -> float | FloatArray: From 7aec399a2bbc70091966246ea62c4279ea449789 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 12:55:29 +0200 Subject: [PATCH 11/43] Fix wrong order in documented arguments Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py index 62321fa74..b0e3aff09 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_engine.py @@ -281,8 +281,8 @@ async def run() -> None: ``` Args: - receiver: A receiver that streams `Sample`s. name: A name for the formula engine. + receiver: A receiver that streams `Sample`s. create_method: A method to generate the output `Sample` value with, e.g. `Power.from_watts`. nones_are_zeros: If `True`, `None` values in the receiver are treated as 0. From 573669f0037b0fb0f5628f66bf36e1ee9b09e9f9 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 12:58:22 +0200 Subject: [PATCH 12/43] Make exception documentation more generic This exception is being raised indirectly, and the function raising it was updated and now it raises the exception in different conditions. Keeping the documentation of both functions in sync is costly and having outdated documentation is confusing, so we just make the exception documentation more general, hoping that it keeps being truth for longer. Signed-off-by: Leandro Lucarella --- .../_formula_engine/_formula_generators/_pv_power_formula.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py index cce41f00d..acbba6bde 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py @@ -24,7 +24,7 @@ def generate(self) -> FormulaEngine[Power]: A formula engine that will calculate PV power production values. Raises: - ComponentNotFound: if there are no PV inverters in the component graph. + ComponentNotFound: if there is a problem finding the needed components. """ builder = self._get_builder( "pv-power", ComponentMetricId.ACTIVE_POWER, Power.from_watts From fb8b0748e4d6f3837f26f8e89f730c5d2a48a549 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 12:59:09 +0200 Subject: [PATCH 13/43] Add missing indirectly raised exceptions Since this code was already documenting indirectly raised exceptions, we update it to include other exceptions raised by the same internal call. Signed-off-by: Leandro Lucarella --- .../_formula_engine/_formula_generators/_pv_power_formula.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py index acbba6bde..b956d9166 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py @@ -25,6 +25,8 @@ def generate(self) -> FormulaEngine[Power]: Raises: ComponentNotFound: if there is a problem finding the needed components. + RuntimeError: if the grid component has no PV inverters or meters as + successors. """ builder = self._get_builder( "pv-power", ComponentMetricId.ACTIVE_POWER, Power.from_watts From 3a163a4470632d30e1feaeb0aaa1df8ab40db99f Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 13:00:18 +0200 Subject: [PATCH 14/43] Fix wrong raises documentation The raises documentation needs to have `ExceptionType: description` form. Also improve the documentation slightly. Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/timeseries/_ringbuffer/serialization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py b/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py index 9bfb7cd68..60c408ac7 100644 --- a/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py +++ b/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py @@ -58,7 +58,7 @@ def dump( file_format_version: Version of the file format, optional. Raises: - I/O related exceptions when the file cannot be written. + OSError: When the file cannot be opened or written. """ with open(path, mode="wb+") as fileobj: pickle.dump((file_format_version, ringbuffer), fileobj) From fda7a763ee34f9978852c2a2621f6bb0bdc0c3ba Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 13:08:30 +0200 Subject: [PATCH 15/43] Improve overloads for quantity scaling by Percentage Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/timeseries/_quantities.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/frequenz/sdk/timeseries/_quantities.py b/src/frequenz/sdk/timeseries/_quantities.py index 71898c2e8..0c4b9918e 100644 --- a/src/frequenz/sdk/timeseries/_quantities.py +++ b/src/frequenz/sdk/timeseries/_quantities.py @@ -262,13 +262,13 @@ def __sub__(self, other: Self) -> Self: return difference def __mul__(self, percent: Percentage) -> Self: - """Return the product of this quantity and a percentage. + """Scale this quantity by a percentage. Args: - percent: The percentage. + percent: The percentage by which to scale this quantity. Returns: - The product of this quantity and a percentage. + The scaled quantity. """ if not isinstance(percent, Percentage): return NotImplemented @@ -522,10 +522,10 @@ def as_megawatts(self) -> float: @overload # type: ignore def __mul__(self, other: Percentage) -> Self: - """Return a power from multiplying this power by the given percentage. + """Scale this power by a percentage. Args: - other: The percentage to multiply by. + other: The percentage by which to scale this power. Returns: The scaled power. @@ -668,10 +668,10 @@ def as_milliamperes(self) -> float: @overload # type: ignore def __mul__(self, other: Percentage) -> Self: - """Return a power from multiplying this power by the given percentage. + """Scale this current by a percentage. Args: - other: The percentage to multiply by. + other: The percentage by which to scale this current. Returns: The scaled current. @@ -789,10 +789,10 @@ def as_kilovolts(self) -> float: @overload # type: ignore def __mul__(self, other: Percentage) -> Self: - """Return a power from multiplying this power by the given percentage. + """Scale this voltage by a percentage. Args: - other: The percentage to multiply by. + other: The percentage by which to scale this voltage. Returns: The scaled voltage. From 2f17593306ab4dcdd34644672c299c81ae010808 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Thu, 24 Aug 2023 13:10:22 +0200 Subject: [PATCH 16/43] Add ignore rules and document indirectly raised exceptions The documentation linting expects functions to have a `raise` statement for each documented exception, so we need to add ignore rules when we want to document exceptions that are raised indirectly by other functions called in the implementation. Signed-off-by: Leandro Lucarella --- .../sdk/actor/power_distributing/_battery_pool_status.py | 2 +- src/frequenz/sdk/microgrid/client/_client.py | 8 ++++---- .../_formula_generators/_chp_power_formula.py | 4 +++- .../_formula_generators/_grid_current_formula.py | 4 +++- .../_formula_generators/_grid_power_formula.py | 2 +- .../_formula_generators/_pv_power_formula.py | 5 ++++- src/frequenz/sdk/timeseries/_ringbuffer/serialization.py | 2 +- .../timeseries/battery_pool/_component_metric_fetcher.py | 4 ++-- 8 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/frequenz/sdk/actor/power_distributing/_battery_pool_status.py b/src/frequenz/sdk/actor/power_distributing/_battery_pool_status.py index 669e41180..57a627ab5 100644 --- a/src/frequenz/sdk/actor/power_distributing/_battery_pool_status.py +++ b/src/frequenz/sdk/actor/power_distributing/_battery_pool_status.py @@ -70,7 +70,7 @@ class BatteryPoolStatus: Send set of working and uncertain batteries, when the any battery change status. """ - def __init__( + def __init__( # noqa: DOC502 (RuntimeError is raised indirectly by BatteryStatus) self, battery_ids: Set[int], battery_status_sender: Sender[BatteryStatus], diff --git a/src/frequenz/sdk/microgrid/client/_client.py b/src/frequenz/sdk/microgrid/client/_client.py index fd75f1368..15fc0ef9c 100644 --- a/src/frequenz/sdk/microgrid/client/_client.py +++ b/src/frequenz/sdk/microgrid/client/_client.py @@ -443,7 +443,7 @@ async def _expect_category( f", not a {expected_category}." ) - async def meter_data( + async def meter_data( # noqa: DOC502 (ValueError is raised indirectly by _expect_category) self, component_id: int, maxsize: int = RECEIVER_MAX_SIZE, @@ -473,7 +473,7 @@ async def meter_data( MeterData.from_proto, ).new_receiver(maxsize=maxsize) - async def battery_data( + async def battery_data( # noqa: DOC502 (ValueError is raised indirectly by _expect_category) self, component_id: int, maxsize: int = RECEIVER_MAX_SIZE, @@ -503,7 +503,7 @@ async def battery_data( BatteryData.from_proto, ).new_receiver(maxsize=maxsize) - async def inverter_data( + async def inverter_data( # noqa: DOC502 (ValueError is raised indirectly by _expect_category) self, component_id: int, maxsize: int = RECEIVER_MAX_SIZE, @@ -533,7 +533,7 @@ async def inverter_data( InverterData.from_proto, ).new_receiver(maxsize=maxsize) - async def ev_charger_data( + async def ev_charger_data( # noqa: DOC502 (ValueError is raised indirectly by _expect_category) self, component_id: int, maxsize: int = RECEIVER_MAX_SIZE, diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_chp_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_chp_power_formula.py index d202a88c3..948d77640 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_chp_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_chp_power_formula.py @@ -25,7 +25,9 @@ class CHPPowerFormula(FormulaGenerator[Power]): """Formula generator for CHP Power.""" - def generate(self) -> FormulaEngine[Power]: + def generate( # noqa: DOC502 (FormulaGenerationError is raised indirectly by _get_chp_meters) + self, + ) -> FormulaEngine[Power]: """Make a formula for the cumulative CHP power of a microgrid. The calculation is performed by adding the active power measurements from diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py index 63e2ba98d..c6d940017 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py @@ -14,7 +14,9 @@ class GridCurrentFormula(FormulaGenerator[Current]): """Create a formula engine from the component graph for calculating grid current.""" - def generate(self) -> FormulaEngine3Phase[Current]: + def generate( # noqa: DOC502 (ComponentNotFound is raised indirectly by _get_grid_component_successors) + self, + ) -> FormulaEngine3Phase[Current]: """Generate a formula for calculating grid current from the component graph. Returns: diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py index 489bf8bdb..085a24245 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py @@ -12,7 +12,7 @@ class GridPowerFormula(FormulaGenerator[Power]): """Creates a formula engine from the component graph for calculating grid power.""" - def generate( + def generate( # noqa: DOC502 (ComponentNotFound is raised indirectly by _get_grid_component_successors) self, ) -> FormulaEngine[Power]: """Generate a formula for calculating grid power from the component graph. diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py index b956d9166..b812555ec 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py @@ -17,7 +17,10 @@ class PVPowerFormula(FormulaGenerator[Power]): """Creates a formula engine for calculating the PV power production.""" - def generate(self) -> FormulaEngine[Power]: + def generate( # noqa: DOC502 (ComponentNotFound and RuntimeError are raised + # indirectly by _get_pv_power_components) + self, + ) -> FormulaEngine[Power]: """Make a formula for the PV power production of a microgrid. Returns: diff --git a/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py b/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py index 60c408ac7..169e5fe2d 100644 --- a/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py +++ b/src/frequenz/sdk/timeseries/_ringbuffer/serialization.py @@ -45,7 +45,7 @@ def load(path: str) -> OrderedRingBuffer[FloatArray] | None: return instance -def dump( +def dump( # noqa: DOC502 (OSError is raised indirectly by open and pickle.dump) ringbuffer: OrderedRingBuffer[FloatArray], path: str, file_format_version: int = FILE_FORMAT_VERSION, diff --git a/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py b/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py index a2d24dedd..cb9170539 100644 --- a/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py +++ b/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py @@ -169,7 +169,7 @@ class LatestBatteryMetricsFetcher(LatestMetricsFetcher[BatteryData]): """Subscribe for the latest battery data using MicrogridApiClient.""" @classmethod - async def async_new( + async def async_new( # noqa: DOC502 (ValueError is raised indirectly super.async_new) cls, component_id: int, metrics: Iterable[ComponentMetricId], @@ -220,7 +220,7 @@ class LatestInverterMetricsFetcher(LatestMetricsFetcher[InverterData]): """Subscribe for the latest inverter data using MicrogridApiClient.""" @classmethod - async def async_new( + async def async_new( # noqa: DOC502 (ValueError is raised indirectly by super.async_new) cls, component_id: int, metrics: Iterable[ComponentMetricId], From 05ab761ff75d599e4b65b3f4a2476dbd19048417 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 12:45:38 +0200 Subject: [PATCH 17/43] Fix typing of Self The method always returned a `ComponentMetricFetcher` (or `LatestMetricsFetcher`), even for subclasses, which is not what `Self` is. To make sure that an instance of the subclass is returned we just use `cls` to call `__new__` instead of `ComponentMetricFetcher` (and fix the type hint for `LatestMetricsFetcher`). Signed-off-by: Leandro Lucarella --- .../sdk/timeseries/battery_pool/_component_metric_fetcher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py b/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py index cb9170539..3c7e6b1a4 100644 --- a/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py +++ b/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py @@ -57,7 +57,7 @@ async def async_new( Returns: This class instance. """ - self: ComponentMetricFetcher = ComponentMetricFetcher.__new__(cls) + self: Self = cls.__new__(cls) self._component_id = component_id self._metrics = metrics return self @@ -94,7 +94,7 @@ async def async_new( Returns: This class instance """ - self: LatestMetricsFetcher[T] = await super().async_new(component_id, metrics) + self: Self = await super().async_new(component_id, metrics) for metric in metrics: # pylint: disable=protected-access From a28d0c4e05546cfd9c597cb94fc10a1c32d32dbd Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:09:14 +0200 Subject: [PATCH 18/43] Replace `not x in y` with `x not in y` Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/actor/power_distributing/power_distributing.py | 2 +- src/frequenz/sdk/timeseries/_quantities.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frequenz/sdk/actor/power_distributing/power_distributing.py b/src/frequenz/sdk/actor/power_distributing/power_distributing.py index 492f96c35..670551b29 100644 --- a/src/frequenz/sdk/actor/power_distributing/power_distributing.py +++ b/src/frequenz/sdk/actor/power_distributing/power_distributing.py @@ -217,7 +217,7 @@ async def _send_result(self, namespace: str, result: Result) -> None: namespace: namespace of the sender, to identify the result channel with. result: Result to send out. """ - if not namespace in self._result_senders: + if namespace not in self._result_senders: self._result_senders[namespace] = self._channel_registry.new_sender( namespace ) diff --git a/src/frequenz/sdk/timeseries/_quantities.py b/src/frequenz/sdk/timeseries/_quantities.py index 0c4b9918e..9dac8e6ac 100644 --- a/src/frequenz/sdk/timeseries/_quantities.py +++ b/src/frequenz/sdk/timeseries/_quantities.py @@ -61,7 +61,7 @@ def __init_subclass__(cls, exponent_unit_map: dict[int, str]) -> None: ValueError: If the given exponent_unit_map does not contain a base unit (exponent 0). """ - if not 0 in exponent_unit_map: + if 0 not in exponent_unit_map: raise ValueError("Expected a base unit for the type (for exponent 0)") cls._exponent_unit_map = exponent_unit_map super().__init_subclass__() From 939e5d027a6d1b020b3a65be38d91448bdfe49af Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:21:46 +0200 Subject: [PATCH 19/43] Import (Async)Iterator directly `pydoclint` doesn't resolve basic types, so for the type-checking to be able to match the yield statement we need to use the plain name. More info at: https://jsh9.github.io/pydoclint/notes_for_users.html#2-cases-that-pydoclint-is-not-designed-to-handle Signed-off-by: Leandro Lucarella --- tests/conftest.py | 8 ++++---- tests/timeseries/test_periodic_feature_extractor.py | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 348741f79..631360209 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,8 +2,8 @@ # Copyright © 2022 Frequenz Energy-as-a-Service GmbH """Setup for all the tests.""" -import collections.abc import contextlib +from collections.abc import Iterator from datetime import timedelta import pytest @@ -16,7 +16,7 @@ @contextlib.contextmanager -def actor_restart_limit(limit: int) -> collections.abc.Iterator[None]: +def actor_restart_limit(limit: int) -> Iterator[None]: """Temporarily set the actor restart limit to a given value. Example: @@ -41,14 +41,14 @@ def actor_restart_limit(limit: int) -> collections.abc.Iterator[None]: @pytest.fixture(scope="session", autouse=True) -def disable_actor_auto_restart() -> collections.abc.Iterator[None]: +def disable_actor_auto_restart() -> Iterator[None]: """Disable auto-restart of actors while running tests.""" with actor_restart_limit(0): yield @pytest.fixture -def actor_auto_restart_once() -> collections.abc.Iterator[None]: +def actor_auto_restart_once() -> Iterator[None]: """Make actors restart only once.""" with actor_restart_limit(1): yield diff --git a/tests/timeseries/test_periodic_feature_extractor.py b/tests/timeseries/test_periodic_feature_extractor.py index 7320db130..3525d7c9a 100644 --- a/tests/timeseries/test_periodic_feature_extractor.py +++ b/tests/timeseries/test_periodic_feature_extractor.py @@ -3,8 +3,8 @@ """Tests for the timeseries averager.""" -import collections.abc import contextlib +from collections.abc import AsyncIterator from datetime import datetime, timedelta, timezone from typing import List @@ -28,7 +28,7 @@ @contextlib.asynccontextmanager async def init_feature_extractor( data: List[float], period: timedelta -) -> collections.abc.AsyncIterator[PeriodicFeatureExtractor]: +) -> AsyncIterator[PeriodicFeatureExtractor]: """ Initialize a PeriodicFeatureExtractor with a `MovingWindow` that contains the data. @@ -36,7 +36,7 @@ async def init_feature_extractor( data: The data that is pushed into the moving window. period: The distance between two successive windows. - Returns: + Yields: PeriodicFeatureExtractor """ window, sender = init_moving_window(timedelta(seconds=len(data))) @@ -48,14 +48,14 @@ async def init_feature_extractor( @contextlib.asynccontextmanager async def init_feature_extractor_no_data( period: int, -) -> collections.abc.AsyncIterator[PeriodicFeatureExtractor]: +) -> AsyncIterator[PeriodicFeatureExtractor]: """ Initialize a PeriodicFeatureExtractor with a `MovingWindow` that contains no data. Args: period: The distance between two successive windows. - Returns: + Yields: PeriodicFeatureExtractor """ # We only need the moving window to initialize the PeriodicFeatureExtractor class. From 75e1a285f3732607b3d69d8e2d34fad8c44ff645 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:22:35 +0200 Subject: [PATCH 20/43] Add missing `Self` import Signed-off-by: Leandro Lucarella --- .../timeseries/battery_pool/_component_metric_fetcher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py b/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py index 3c7e6b1a4..ddf5a62d1 100644 --- a/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py +++ b/src/frequenz/sdk/timeseries/battery_pool/_component_metric_fetcher.py @@ -10,7 +10,7 @@ import math from abc import ABC, abstractmethod from datetime import datetime, timezone -from typing import Any, Generic, Iterable, Optional, Set, TypeVar +from typing import Any, Generic, Iterable, Optional, Self, Set, TypeVar from frequenz.channels import ChannelClosedError, Receiver @@ -44,7 +44,7 @@ class ComponentMetricFetcher(AsyncConstructible, ABC): @classmethod async def async_new( cls, component_id: int, metrics: Iterable[ComponentMetricId] - ) -> Self: # type: ignore[name-defined] # pylint: disable=undefined-variable + ) -> Self: """Create an instance of this class. Subscribe for the given component metrics and return them if method @@ -78,7 +78,7 @@ async def async_new( cls, component_id: int, metrics: Iterable[ComponentMetricId], - ) -> Self: # type: ignore[name-defined] # pylint: disable=undefined-variable: + ) -> Self: """Create instance of this class. Subscribe for the requested component data and fetch only the latest component From 7626774ff14663e4f36315547ee7cb4c4adbe4f2 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:36:25 +0200 Subject: [PATCH 21/43] Remove type specifications from docstrings Signed-off-by: Leandro Lucarella --- tests/actor/test_actor.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/actor/test_actor.py b/tests/actor/test_actor.py index 7d266cbbb..7b2cbd3e6 100644 --- a/tests/actor/test_actor.py +++ b/tests/actor/test_actor.py @@ -122,9 +122,9 @@ def __init__( """Create an `EchoActor` instance. Args: - name (str): Name of the actor. - recv1 (Receiver[bool]): A channel receiver for test boolean data. - recv2 (Receiver[bool]): A channel receiver for test boolean data. + name: Name of the actor. + recv1: A channel receiver for test boolean data. + recv2: A channel receiver for test boolean data. """ super().__init__(name=name) self._recv1 = recv1 @@ -135,7 +135,7 @@ async def _run(self) -> None: """Do computations depending on the selected input message. Args: - output (Sender[OT]): A channel sender, to send actor's results to. + output: A channel sender, to send actor's results to. """ print(f"{self} started") self.inc_restart_count() From 232ebe2aad7c2a80ef8f83d2d7b0aff7ade5af10 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:56:31 +0200 Subject: [PATCH 22/43] Remove inexistent arguments from docstrings Signed-off-by: Leandro Lucarella --- benchmarks/power_distribution/power_distributor.py | 1 - benchmarks/timeseries/periodic_feature_extractor.py | 1 - tests/actor/test_actor.py | 6 +----- tests/utils/mock_microgrid_client.py | 1 - 4 files changed, 1 insertion(+), 8 deletions(-) diff --git a/benchmarks/power_distribution/power_distributor.py b/benchmarks/power_distribution/power_distributor.py index bd4a147d3..6f16ccbb4 100644 --- a/benchmarks/power_distribution/power_distributor.py +++ b/benchmarks/power_distribution/power_distributor.py @@ -36,7 +36,6 @@ async def send_requests(batteries: Set[int], request_num: int) -> List[Result]: """Send requests to the PowerDistributingActor and wait for the response. Args: - user: user that should send request batteries: set of batteries where the power should be set request_num: number of requests that should be send diff --git a/benchmarks/timeseries/periodic_feature_extractor.py b/benchmarks/timeseries/periodic_feature_extractor.py index 9be937e23..a5ab2651e 100644 --- a/benchmarks/timeseries/periodic_feature_extractor.py +++ b/benchmarks/timeseries/periodic_feature_extractor.py @@ -64,7 +64,6 @@ def _calculate_avg_window( feature_extractor: The instance of the PeriodicFeatureExtractor to use. window: The window to calculate the average over. window_size: The size of the window to calculate the average over. - weights: The weights to use for the average calculation. Returns: The averaged window. diff --git a/tests/actor/test_actor.py b/tests/actor/test_actor.py index 7b2cbd3e6..bfe473851 100644 --- a/tests/actor/test_actor.py +++ b/tests/actor/test_actor.py @@ -132,11 +132,7 @@ def __init__( self._output = output async def _run(self) -> None: - """Do computations depending on the selected input message. - - Args: - output: A channel sender, to send actor's results to. - """ + """Do computations depending on the selected input message.""" print(f"{self} started") self.inc_restart_count() diff --git a/tests/utils/mock_microgrid_client.py b/tests/utils/mock_microgrid_client.py index 32c390b8c..aa977146e 100644 --- a/tests/utils/mock_microgrid_client.py +++ b/tests/utils/mock_microgrid_client.py @@ -229,7 +229,6 @@ def _create_mock_api( """Create mock of MicrogridApiClient. Args: - components: set of components. bat_channel: battery channels to be returned from MicrogridApiClient.battery_data. inv_channel: inverter channels to be returned from From 4eb29c302139cccafac7293a8e16de01b164b644 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:58:17 +0200 Subject: [PATCH 23/43] Add missing arguments to docstrings Signed-off-by: Leandro Lucarella --- benchmarks/timeseries/periodic_feature_extractor.py | 1 + tests/actor/test_actor.py | 2 ++ tests/actor/test_battery_status.py | 1 + tests/timeseries/mock_microgrid.py | 1 + tests/utils/graph_generator.py | 1 + tests/utils/mock_microgrid_client.py | 8 ++++++++ 6 files changed, 14 insertions(+) diff --git a/benchmarks/timeseries/periodic_feature_extractor.py b/benchmarks/timeseries/periodic_feature_extractor.py index a5ab2651e..b22e7e793 100644 --- a/benchmarks/timeseries/periodic_feature_extractor.py +++ b/benchmarks/timeseries/periodic_feature_extractor.py @@ -112,6 +112,7 @@ def _num_windows( Args: window: The buffer that is used for the average calculation. window_size: The size of the window in samples. + period: The distance between two succeeding intervals in samples. Returns: The number of windows that are fully contained in the MovingWindow. diff --git a/tests/actor/test_actor.py b/tests/actor/test_actor.py index bfe473851..2f44ee3c2 100644 --- a/tests/actor/test_actor.py +++ b/tests/actor/test_actor.py @@ -125,6 +125,7 @@ def __init__( name: Name of the actor. recv1: A channel receiver for test boolean data. recv2: A channel receiver for test boolean data. + output: A channel sender for output test boolean data. """ super().__init__(name=name) self._recv1 = recv1 @@ -203,6 +204,7 @@ async def test_restart_on_unhandled_exception( Args: restart_limit: The restart limit to use. + caplog: The log capture fixture. """ caplog.set_level("DEBUG", logger="frequenz.sdk.actor._actor") caplog.set_level("DEBUG", logger="frequenz.sdk.actor._run_utils") diff --git a/tests/actor/test_battery_status.py b/tests/actor/test_battery_status.py index 375ebf64b..fcd46a0f3 100644 --- a/tests/actor/test_battery_status.py +++ b/tests/actor/test_battery_status.py @@ -59,6 +59,7 @@ def battery_data( # pylint: disable=too-many-arguments component_state: Component state. Defaults to BatteryState.COMPONENT_STATE_CHARGING. errors: List of the components error. By default empty list will be created. + capacity: Battery capacity. Returns: BatteryData with given arguments. diff --git a/tests/timeseries/mock_microgrid.py b/tests/timeseries/mock_microgrid.py index 3d97f3969..c2c2439d5 100644 --- a/tests/timeseries/mock_microgrid.py +++ b/tests/timeseries/mock_microgrid.py @@ -304,6 +304,7 @@ def add_chps(self, count: int, no_meters: bool = False) -> None: Args: count: number of CHPs to add. + no_meters: if True, do not add a meter for each CHP. """ for _ in range(count): meter_id = self._id_increment * 10 + self.meter_id_suffix diff --git a/tests/utils/graph_generator.py b/tests/utils/graph_generator.py index 912a5f6dc..75ff275ea 100644 --- a/tests/utils/graph_generator.py +++ b/tests/utils/graph_generator.py @@ -185,6 +185,7 @@ def _to_graph( """Convert a list of components to a graph. Args: + parent: the parent component. components: the components to convert to a graph. Returns: diff --git a/tests/utils/mock_microgrid_client.py b/tests/utils/mock_microgrid_client.py index aa977146e..0545008bd 100644 --- a/tests/utils/mock_microgrid_client.py +++ b/tests/utils/mock_microgrid_client.py @@ -233,6 +233,10 @@ def _create_mock_api( MicrogridApiClient.battery_data. inv_channel: inverter channels to be returned from MicrogridApiClient.inverter_data. + meter_channels: meter channels to be returned from + MicrogridApiClient.meter_data. + ev_charger_channels: ev_charger channels to be returned from + MicrogridApiClient.ev_charger_data. Returns: Magic mock instance of MicrogridApiClient. @@ -274,6 +278,7 @@ def _get_battery_receiver( Args: component_id: component_id channels: Broadcast channels + maxsize: Max size of the channel Returns: Receiver from the given channels. @@ -293,6 +298,7 @@ def _get_meter_receiver( Args: component_id: component_id channels: Broadcast channels + maxsize: Max size of the channel Returns: Receiver from the given channels. @@ -312,6 +318,7 @@ def _get_ev_charger_receiver( Args: component_id: component_id channels: Broadcast channels + maxsize: Max size of the channel Returns: Receiver from the given channels. @@ -331,6 +338,7 @@ def _get_inverter_receiver( Args: component_id: component_id channels: Broadcast channels + maxsize: Max size of the channel Returns: Receiver from the given channels. From 3a1ea065996913fb286bffed62dc7bd59d0ad11d Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 13:59:39 +0200 Subject: [PATCH 24/43] Fix wrong arguments in docstrings Signed-off-by: Leandro Lucarella --- benchmarks/timeseries/periodic_feature_extractor.py | 4 ++-- .../test_distribution_algorithm.py | 10 +++------- tests/actor/test_battery_pool_status.py | 2 +- tests/actor/test_battery_status.py | 13 ++++++------- tests/timeseries/_battery_pool/test_battery_pool.py | 8 ++++---- tests/timeseries/mock_microgrid.py | 2 +- tests/utils/graph_generator.py | 2 +- tests/utils/mock_microgrid_client.py | 4 ++-- 8 files changed, 20 insertions(+), 25 deletions(-) diff --git a/benchmarks/timeseries/periodic_feature_extractor.py b/benchmarks/timeseries/periodic_feature_extractor.py index b22e7e793..04791fc01 100644 --- a/benchmarks/timeseries/periodic_feature_extractor.py +++ b/benchmarks/timeseries/periodic_feature_extractor.py @@ -168,7 +168,7 @@ def run_avg_np( The return value is discarded such that it can be used by timit. Args: - a: The array containing all data. + array: The array containing all data. window_size: The size of the window. feature_extractor: An instance of the PeriodicFeatureExtractor. """ @@ -185,7 +185,7 @@ def run_avg_py( The return value is discarded such that it can be used by timit. Args: - a: The array containing all data. + array: The array containing all data. window_size: The size of the window. feature_extractor: An instance of the PeriodicFeatureExtractor. """ diff --git a/tests/actor/power_distributing/test_distribution_algorithm.py b/tests/actor/power_distributing/test_distribution_algorithm.py index 87c2badf8..b827d5053 100644 --- a/tests/actor/power_distributing/test_distribution_algorithm.py +++ b/tests/actor/power_distributing/test_distribution_algorithm.py @@ -50,8 +50,7 @@ def battery_msg( # pylint: disable=too-many-arguments component_id: id of that component capacity: capacity soc: soc - power_supply: supply bound - power_consumption: consumption bound + power: power bounds timestamp: timestamp of the message Returns: @@ -80,8 +79,7 @@ def inverter_msg( Args: component_id: id of that component - power_supply: Supply bound - power_consumption: Consumption bound inverter + power: Power bounds timestamp: Timestamp from the message Returns: @@ -109,9 +107,7 @@ def create_components( num: Number of components capacity: Capacity for each battery soc: SoC for each battery - soc_bounds: SoC bounds for each battery - supply_bounds: Supply bounds for each battery and inverter - consumption_bounds: Consumption bounds for each battery and inverter + power: Power bounds for each battery and inverter Returns: List of the components diff --git a/tests/actor/test_battery_pool_status.py b/tests/actor/test_battery_pool_status.py index 4e0f40475..3963a40d4 100644 --- a/tests/actor/test_battery_pool_status.py +++ b/tests/actor/test_battery_pool_status.py @@ -28,7 +28,7 @@ async def test_batteries_status(self, mocker: MockerFixture) -> None: BatteryStatusTracker is more tested in its own unit tests. Args: - mock_microgrid: mock microgrid client + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) diff --git a/tests/actor/test_battery_status.py b/tests/actor/test_battery_status.py index fcd46a0f3..1a538ffc2 100644 --- a/tests/actor/test_battery_status.py +++ b/tests/actor/test_battery_status.py @@ -155,7 +155,7 @@ async def test_sync_update_status_with_messages( Otherwise we would have lots of async calls and waiting. Args: - mock_microgrid: mock_microgrid fixture + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) @@ -317,7 +317,7 @@ async def test_sync_blocking_feature(self, mocker: MockerFixture) -> None: Otherwise we would have lots of async calls and waiting. Args: - mock_microgrid: mock_microgrid fixture + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) @@ -434,7 +434,7 @@ async def test_sync_blocking_interrupted_with_with_max_data( Otherwise we would have lots of async calls and waiting. Args: - mock_microgrid: mock_microgrid fixture + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) @@ -485,7 +485,7 @@ async def test_sync_blocking_interrupted_with_invalid_message( Otherwise we would have lots of async calls and waiting. Args: - mock_microgrid: mock_microgrid fixture + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) @@ -545,8 +545,7 @@ async def test_timers(self, mocker: MockerFixture) -> None: Otherwise we would have lots of async calls and waiting. Args: - mock_microgrid: mock_microgrid fixture - mocker: pytest mocker instance + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) @@ -608,7 +607,7 @@ async def test_async_battery_status(self, mocker: MockerFixture) -> None: """Test if status changes. Args: - mock_microgrid: mock_microgrid fixture + mocker: Pytest mocker fixture. """ mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(3) diff --git a/tests/timeseries/_battery_pool/test_battery_pool.py b/tests/timeseries/_battery_pool/test_battery_pool.py index 34923e855..2706600ff 100644 --- a/tests/timeseries/_battery_pool/test_battery_pool.py +++ b/tests/timeseries/_battery_pool/test_battery_pool.py @@ -301,7 +301,7 @@ async def test_battery_pool_capacity(setup_batteries_pool: SetupArgs) -> None: """Test capacity metric for battery pool with subset of components in the microgrid. Args: - setup_all_batteries: Fixture that creates needed microgrid tools. + setup_batteries_pool: Fixture that creates needed microgrid tools. """ await run_capacity_test(setup_batteries_pool) @@ -319,7 +319,7 @@ async def test_battery_pool_soc(setup_batteries_pool: SetupArgs) -> None: """Test soc metric for battery pool with subset of components in the microgrid. Args: - setup_all_batteries: Fixture that creates needed microgrid tools. + setup_batteries_pool: Fixture that creates needed microgrid tools. """ await run_soc_test(setup_batteries_pool) @@ -337,7 +337,7 @@ async def test_battery_pool_power_bounds(setup_batteries_pool: SetupArgs) -> Non """Test power bounds metric for battery pool with subset of components in the microgrid. Args: - setup_all_batteries: Fixture that creates needed microgrid tools. + setup_batteries_pool: Fixture that creates needed microgrid tools. """ await run_power_bounds_test(setup_batteries_pool) @@ -355,7 +355,7 @@ async def test_battery_pool_temperature(setup_batteries_pool: SetupArgs) -> None """Test temperature for battery pool with subset of components in the microgrid. Args: - setup_all_batteries: Fixture that creates needed microgrid tools. + setup_batteries_pool: Fixture that creates needed microgrid tools. """ await run_temperature_test(setup_batteries_pool) diff --git a/tests/timeseries/mock_microgrid.py b/tests/timeseries/mock_microgrid.py index c2c2439d5..7000a386a 100644 --- a/tests/timeseries/mock_microgrid.py +++ b/tests/timeseries/mock_microgrid.py @@ -465,7 +465,7 @@ async def send_battery_data(self, socs: list[float]) -> None: """Send raw battery data from the mock microgrid. Args: - values: list of soc values for each battery. + socs: list of soc values for each battery. """ assert len(socs) == len(self.battery_ids) timestamp = datetime.now(tz=timezone.utc) diff --git a/tests/utils/graph_generator.py b/tests/utils/graph_generator.py index 75ff275ea..49cb43e5f 100644 --- a/tests/utils/graph_generator.py +++ b/tests/utils/graph_generator.py @@ -186,7 +186,7 @@ def _to_graph( Args: parent: the parent component. - components: the components to convert to a graph. + children: the children components. Returns: a tuple containing the components and connections of the graph. diff --git a/tests/utils/mock_microgrid_client.py b/tests/utils/mock_microgrid_client.py index 0545008bd..364267825 100644 --- a/tests/utils/mock_microgrid_client.py +++ b/tests/utils/mock_microgrid_client.py @@ -229,9 +229,9 @@ def _create_mock_api( """Create mock of MicrogridApiClient. Args: - bat_channel: battery channels to be returned from + bat_channels: battery channels to be returned from MicrogridApiClient.battery_data. - inv_channel: inverter channels to be returned from + inv_channels: inverter channels to be returned from MicrogridApiClient.inverter_data. meter_channels: meter channels to be returned from MicrogridApiClient.meter_data. From 9bb63b3f7e2b2a04fa7e4bbe0a48e12261a195b2 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:00:23 +0200 Subject: [PATCH 25/43] Add missing Returns and Raises to docstrings Signed-off-by: Leandro Lucarella --- benchmarks/timeseries/ringbuffer_serialization.py | 3 +++ tests/timeseries/mock_microgrid.py | 3 +++ tests/utils/graph_generator.py | 3 +++ 3 files changed, 9 insertions(+) diff --git a/benchmarks/timeseries/ringbuffer_serialization.py b/benchmarks/timeseries/ringbuffer_serialization.py index 101387a7f..02edac2ff 100644 --- a/benchmarks/timeseries/ringbuffer_serialization.py +++ b/benchmarks/timeseries/ringbuffer_serialization.py @@ -45,6 +45,9 @@ def benchmark_serialization( Args: ringbuffer: Ringbuffer to benchmark to serialize. iterations: amount of iterations to run. + + Returns: + Average time to dump and load the ringbuffer. """ total = 0.0 for _ in range(iterations): diff --git a/tests/timeseries/mock_microgrid.py b/tests/timeseries/mock_microgrid.py index 7000a386a..0f2ef3be0 100644 --- a/tests/timeseries/mock_microgrid.py +++ b/tests/timeseries/mock_microgrid.py @@ -75,6 +75,9 @@ def __init__( # pylint: disable=too-many-arguments different namespaces. graph: optional, a graph of components to use instead of the default grid layout. If specified, grid_meter must be None. + + Raises: + ValueError: if both grid_meter and graph are specified. """ if grid_meter is not None and graph is not None: raise ValueError("grid_meter and graph are mutually exclusive") diff --git a/tests/utils/graph_generator.py b/tests/utils/graph_generator.py index 49cb43e5f..d04d983bd 100644 --- a/tests/utils/graph_generator.py +++ b/tests/utils/graph_generator.py @@ -190,6 +190,9 @@ def _to_graph( Returns: a tuple containing the components and connections of the graph. + + Raises: + ValueError: if the input is invalid. """ def inverter_type(category: ComponentCategory) -> InverterType | None: From b1aa0101a909af0ffd0b8f9be863cf7037258bde Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:00:42 +0200 Subject: [PATCH 26/43] Ignore indirect raises in Raises specification Signed-off-by: Leandro Lucarella --- .../_formula_generators/_producer_power_formula.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_producer_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_producer_power_formula.py index bd51d969d..84bbca7c4 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_producer_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_producer_power_formula.py @@ -21,7 +21,11 @@ class ProducerPowerFormula(FormulaGenerator[Power]): which are CHP and PV. """ - def generate(self) -> FormulaEngine[Power]: + def generate( # noqa: DOC502 + # * ComponentNotFound is raised indirectly by _get_grid_component() + # * RuntimeError is raised indirectly by connection_manager.get() + self, + ) -> FormulaEngine[Power]: """Generate formula for calculating producer power from the component graph. Returns: From b57b2ac916dd8030ed55a017966876dca980dc42 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:42:38 +0200 Subject: [PATCH 27/43] Add missing ending full stop to docstrings. Signed-off-by: Leandro Lucarella --- .../test_distribution_algorithm.py | 8 ++++---- .../test_power_distributing.py | 4 ++-- tests/actor/test_actor.py | 6 +++--- tests/actor/test_battery_pool_status.py | 2 +- tests/actor/test_battery_status.py | 6 +++--- tests/actor/test_config_manager.py | 15 +++++++------- tests/config/test_config.py | 20 +++++++++---------- tests/microgrid/test_microgrid_api.py | 3 ++- tests/microgrid/test_timeout.py | 6 +++--- tests/test_sdk.py | 10 ++++------ .../_battery_pool/test_battery_pool.py | 2 +- tests/timeseries/test_moving_window.py | 14 ++++++------- .../test_periodic_feature_extractor.py | 4 +--- tests/timeseries/test_quantities.py | 4 ++-- tests/timeseries/test_resampling.py | 4 +--- 15 files changed, 51 insertions(+), 57 deletions(-) diff --git a/tests/actor/power_distributing/test_distribution_algorithm.py b/tests/actor/power_distributing/test_distribution_algorithm.py index b827d5053..4b4c212b3 100644 --- a/tests/actor/power_distributing/test_distribution_algorithm.py +++ b/tests/actor/power_distributing/test_distribution_algorithm.py @@ -23,7 +23,7 @@ @dataclass class Bound: - """Class to create protobuf Bound""" + """Class to create protobuf Bound.""" lower: float upper: float @@ -31,7 +31,7 @@ class Bound: @dataclass class Metric: - """Class to create protobuf Metric""" + """Class to create protobuf Metric.""" now: Optional[float] bound: Optional[Bound] = None @@ -277,7 +277,7 @@ def test_distribute_power_three_batteries_2(self) -> None: assert result.remaining_power == approx(0.0) def test_distribute_power_three_batteries_3(self) -> None: - """Test with batteries with no capacity""" + """Test with batteries with no capacity.""" capacity: List[float] = [0, 49000, 0] components = self.create_components_with_capacity(3, capacity) @@ -568,7 +568,7 @@ def test_consumption_three_batteries_4(self) -> None: assert result.remaining_power == approx(200.0) def test_consumption_three_batteries_5(self) -> None: - """Test what if some batteries has invalid SoC and capacity""" + """Test what if some batteries has invalid SoC and capacity.""" capacity: List[Metric] = [Metric(98000), Metric(49000), Metric(0.0)] soc: List[Metric] = [ Metric(80.0, Bound(0, 50)), diff --git a/tests/actor/power_distributing/test_power_distributing.py b/tests/actor/power_distributing/test_power_distributing.py index a1db2bcf0..f6f92960c 100644 --- a/tests/actor/power_distributing/test_power_distributing.py +++ b/tests/actor/power_distributing/test_power_distributing.py @@ -1,7 +1,7 @@ # License: MIT # Copyright © 2023 Frequenz Energy-as-a-Service GmbH -"""Tests power distributor""" +"""Tests power distributor.""" from __future__ import annotations @@ -41,7 +41,7 @@ class TestPowerDistributingActor: # pylint: disable=protected-access - """Test tool to distribute power""" + """Test tool to distribute power.""" _namespace = "power_distributor" diff --git a/tests/actor/test_actor.py b/tests/actor/test_actor.py index 2f44ee3c2..b60ccbffb 100644 --- a/tests/actor/test_actor.py +++ b/tests/actor/test_actor.py @@ -47,7 +47,7 @@ def __init__(self) -> None: super().__init__(name="test") async def _run(self) -> None: - """Start the actor and crash upon receiving a message""" + """Start the actor and crash upon receiving a message.""" print(f"{self} started") self.inc_restart_count() print(f"{self} done") @@ -69,7 +69,7 @@ def __init__( self._recv = recv async def _run(self) -> None: - """Start the actor and crash upon receiving a message""" + """Start the actor and crash upon receiving a message.""" print(f"{self} started") self.inc_restart_count() async for msg in self._recv: @@ -94,7 +94,7 @@ def __init__( self._recv = recv async def _run(self) -> None: - """Start the actor and crash upon receiving a message""" + """Start the actor and crash upon receiving a message.""" print(f"{self} started") self.inc_restart_count() async for _ in self._recv: diff --git a/tests/actor/test_battery_pool_status.py b/tests/actor/test_battery_pool_status.py index 3963a40d4..e9fc6b544 100644 --- a/tests/actor/test_battery_pool_status.py +++ b/tests/actor/test_battery_pool_status.py @@ -20,7 +20,7 @@ # pylint: disable=protected-access class TestBatteryPoolStatus: - """Tests for BatteryPoolStatus""" + """Tests for BatteryPoolStatus.""" async def test_batteries_status(self, mocker: MockerFixture) -> None: """Basic tests for BatteryPoolStatus. diff --git a/tests/actor/test_battery_status.py b/tests/actor/test_battery_status.py index 1a538ffc2..f66f4b001 100644 --- a/tests/actor/test_battery_status.py +++ b/tests/actor/test_battery_status.py @@ -149,7 +149,7 @@ class TestBatteryStatus: async def test_sync_update_status_with_messages( self, mocker: MockerFixture ) -> None: - """Test if messages changes battery status/ + """Test if messages changes battery status. Tests uses FakeSelect to test status in sync way. Otherwise we would have lots of async calls and waiting. @@ -539,7 +539,7 @@ async def test_sync_blocking_interrupted_with_invalid_message( @time_machine.travel("2022-01-01 00:00 UTC", tick=False) async def test_timers(self, mocker: MockerFixture) -> None: - """Test if messages changes battery status/ + """Test if messages changes battery status. Tests uses FakeSelect to test status in sync way. Otherwise we would have lots of async calls and waiting. @@ -689,7 +689,7 @@ class TestBatteryStatusRecovery: async def setup_tracker( self, mocker: MockerFixture ) -> AsyncIterator[tuple[MockMicrogrid, Receiver[Status]]]: - """Setup a BatteryStatusTracker instance to run tests with.""" + """Set a BatteryStatusTracker instance up to run tests with.""" mock_microgrid = MockMicrogrid(grid_meter=True) mock_microgrid.add_batteries(1) await mock_microgrid.start(mocker) diff --git a/tests/actor/test_config_manager.py b/tests/actor/test_config_manager.py index 3e70c4f09..bd2d3513c 100644 --- a/tests/actor/test_config_manager.py +++ b/tests/actor/test_config_manager.py @@ -1,7 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -"""Test for ConfigManager""" +"""Test for ConfigManager.""" import pathlib import pytest @@ -15,7 +15,7 @@ class Item(BaseModel): - """Test item""" + """Test item.""" item_id: int name: str @@ -31,7 +31,7 @@ def create_content(number: int) -> str: class TestActorConfigManager: - """Test for ConfigManager""" + """Test for ConfigManager.""" conf_path = "sdk/config.toml" conf_content = """ @@ -71,11 +71,12 @@ def real_config_file( return file_path async def test_update(self, config_file: pathlib.Path) -> None: - """ - Test ConfigManager by checking if: + """Test ConfigManager. + + Check if: + - the initial content of the content file is correct - - the config file modifications are picked up and the new content - is correct + - the config file modifications are picked up and the new content is correct """ config_channel: Broadcast[Config] = Broadcast( "Config Channel", resend_latest=True diff --git a/tests/config/test_config.py b/tests/config/test_config.py index 2a890983b..f8a21bf36 100644 --- a/tests/config/test_config.py +++ b/tests/config/test_config.py @@ -1,7 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -"""Test for Config""" +"""Test for Config.""" import pathlib import re @@ -16,14 +16,14 @@ class Item(BaseModel): - """Test item""" + """Test item.""" item_id: int name: str class TestConfig: - """Test for Config""" + """Test for Config.""" conf_path = "sdk/config.toml" conf_content = """ @@ -61,7 +61,7 @@ def conf_vars(self, config_file: pathlib.Path) -> dict[str, Any]: return tomllib.load(file) def test_get(self, conf_vars: dict[str, Any]) -> None: - """Test get function""" + """Test get function.""" config = Config(conf_vars=conf_vars) assert config.get("logging_lvl") == "DEBUG" @@ -70,7 +70,7 @@ def test_get(self, conf_vars: dict[str, Any]) -> None: assert config.get("var2", default=0) == 0 def test_getitem(self, conf_vars: dict[str, Any]) -> None: - """Test getitem function""" + """Test getitem function.""" config = Config(conf_vars=conf_vars) assert config["logging_lvl"] == "DEBUG" @@ -79,7 +79,7 @@ def test_getitem(self, conf_vars: dict[str, Any]) -> None: assert config["var2"] def test_contains(self, conf_vars: dict[str, Any]) -> None: - """Test contains function""" + """Test contains function.""" config = Config(conf_vars=conf_vars) assert "logging_lvl" in config @@ -116,7 +116,7 @@ def test_contains(self, conf_vars: dict[str, Any]) -> None: def test_get_as_success( self, key: str, expected_type: Any, value: Any, conf_vars: dict[str, Any] ) -> None: - """Test get_as function with proper arguments""" + """Test get_as function with proper arguments.""" config = Config(conf_vars=conf_vars) result = config.get_as(key, expected_type) @@ -136,7 +136,7 @@ def test_get_as_success( def test_get_as_validation_error( self, key: str, expected_type: Any, conf_vars: dict[str, Any] ) -> None: - """Test get_as function which raise ValidationError""" + """Test get_as function which raise ValidationError.""" config = Config(conf_vars=conf_vars) err_msg = ( @@ -161,7 +161,7 @@ def test_get_dict_values_success( value: Any, conf_vars: dict[str, Any], ) -> None: - """Test get_as function with proper arguments""" + """Test get_as function with proper arguments.""" config = Config(conf_vars=conf_vars) result = config.get_dict(key_prefix, expected_values_type) @@ -178,7 +178,7 @@ def test_get_dict_values_success( def test_get_dict_success( self, key_prefix: str, expected_values_type: Any, conf_vars: dict[str, Any] ) -> None: - """Test get_as function with proper arguments""" + """Test get_as function with proper arguments.""" config = Config(conf_vars=conf_vars) diff --git a/tests/microgrid/test_microgrid_api.py b/tests/microgrid/test_microgrid_api.py index 7f93dc416..ad681baf7 100644 --- a/tests/microgrid/test_microgrid_api.py +++ b/tests/microgrid/test_microgrid_api.py @@ -1,7 +1,8 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -"""Tests of MicrogridApi""" +"""Tests of MicrogridApi.""" + import asyncio from asyncio.tasks import ALL_COMPLETED from typing import List diff --git a/tests/microgrid/test_timeout.py b/tests/microgrid/test_timeout.py index 21edddf99..af9c4affd 100644 --- a/tests/microgrid/test_timeout.py +++ b/tests/microgrid/test_timeout.py @@ -39,7 +39,7 @@ "frequenz.sdk.microgrid.client._client.DEFAULT_GRPC_CALL_TIMEOUT", GRPC_CALL_TIMEOUT ) async def test_components_timeout(mocker: MockerFixture) -> None: - """Test if the components() method properly raises AioRpcError""" + """Test if the components() method properly raises AioRpcError.""" servicer = MockMicrogridServicer() def mock_list_components( @@ -66,7 +66,7 @@ def mock_list_components( "frequenz.sdk.microgrid.client._client.DEFAULT_GRPC_CALL_TIMEOUT", GRPC_CALL_TIMEOUT ) async def test_connections_timeout(mocker: MockerFixture) -> None: - """Test if the connections() method properly raises AioRpcError""" + """Test if the connections() method properly raises AioRpcError.""" servicer = MockMicrogridServicer() def mock_list_connections( @@ -93,7 +93,7 @@ def mock_list_connections( "frequenz.sdk.microgrid.client._client.DEFAULT_GRPC_CALL_TIMEOUT", GRPC_CALL_TIMEOUT ) async def test_set_power_timeout(mocker: MockerFixture) -> None: - """Test if the set_power() method properly raises AioRpcError""" + """Test if the set_power() method properly raises AioRpcError.""" servicer = MockMicrogridServicer() def mock_set_power( diff --git a/tests/test_sdk.py b/tests/test_sdk.py index 707bab2bf..46167abb5 100644 --- a/tests/test_sdk.py +++ b/tests/test_sdk.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Top level tests for the `frequenz.sdk` pacakge -""" +"""Top level tests for the `frequenz.sdk` pacakge.""" import frequenz.sdk from frequenz.sdk import config @@ -11,15 +9,15 @@ def test_sdk_import() -> None: - """Checks that `import frequenz.sdk` works""" + """Checks that `import frequenz.sdk` works.""" assert frequenz.sdk is not None def test_sdk_import_config() -> None: - """Checks that `import frequenz.sdk` works""" + """Checks that `import frequenz.sdk` works.""" assert config is not None def test_sdk_import_config_manager() -> None: - """Checks that `import frequenz.sdk` works""" + """Checks that `import frequenz.sdk` works.""" assert ConfigManagingActor is not None diff --git a/tests/timeseries/_battery_pool/test_battery_pool.py b/tests/timeseries/_battery_pool/test_battery_pool.py index 2706600ff..2f4753d2d 100644 --- a/tests/timeseries/_battery_pool/test_battery_pool.py +++ b/tests/timeseries/_battery_pool/test_battery_pool.py @@ -62,7 +62,7 @@ def event_loop() -> Iterator[async_solipsism.EventLoop]: def get_components( mock_microgrid: MockMicrogridClient, component_category: ComponentCategory ) -> set[int]: - """Get components of given category from mock microgrid + """Get components of given category from mock microgrid. Args: mock_microgrid: mock microgrid diff --git a/tests/timeseries/test_moving_window.py b/tests/timeseries/test_moving_window.py index 7635d49b8..132fc4041 100644 --- a/tests/timeseries/test_moving_window.py +++ b/tests/timeseries/test_moving_window.py @@ -57,8 +57,7 @@ async def push_logical_meter_data( def init_moving_window( size: timedelta, ) -> Tuple[MovingWindow, Sender[Sample[Quantity]]]: - """ - Initialize the moving window with given shape + """Initialize the moving window with given shape. Args: size: The size of the `MovingWindow` @@ -73,7 +72,7 @@ def init_moving_window( async def test_access_window_by_index() -> None: - """Test indexing a window by integer index""" + """Test indexing a window by integer index.""" window, sender = init_moving_window(timedelta(seconds=1)) async with window: await push_logical_meter_data(sender, [1]) @@ -81,7 +80,7 @@ async def test_access_window_by_index() -> None: async def test_access_window_by_timestamp() -> None: - """Test indexing a window by timestamp""" + """Test indexing a window by timestamp.""" window, sender = init_moving_window(timedelta(seconds=1)) async with window: await push_logical_meter_data(sender, [1]) @@ -89,8 +88,7 @@ async def test_access_window_by_timestamp() -> None: async def test_access_window_by_int_slice() -> None: - """ - Test accessing a subwindow with an integer slice + """Test accessing a subwindow with an integer slice. Note that the second test is overwriting the data of the first test. since the push_lm_data function is starting with the same initial timestamp. @@ -106,7 +104,7 @@ async def test_access_window_by_int_slice() -> None: async def test_access_window_by_ts_slice() -> None: - """Test accessing a subwindow with a timestamp slice""" + """Test accessing a subwindow with a timestamp slice.""" window, sender = init_moving_window(timedelta(seconds=5)) async with window: await push_logical_meter_data(sender, range(0, 5)) @@ -116,7 +114,7 @@ async def test_access_window_by_ts_slice() -> None: async def test_access_empty_window() -> None: - """Test accessing an empty window, should throw IndexError""" + """Test accessing an empty window, should throw IndexError.""" window, _ = init_moving_window(timedelta(seconds=5)) async with window: with pytest.raises(IndexError, match=r"^The buffer is empty\.$"): diff --git a/tests/timeseries/test_periodic_feature_extractor.py b/tests/timeseries/test_periodic_feature_extractor.py index 3525d7c9a..ad1e3154a 100644 --- a/tests/timeseries/test_periodic_feature_extractor.py +++ b/tests/timeseries/test_periodic_feature_extractor.py @@ -74,9 +74,7 @@ async def init_feature_extractor_no_data( async def test_interval_shifting() -> None: - """ - Test if a interval is properly shifted into a moving window - """ + """Test if a interval is properly shifted into a moving window.""" async with init_feature_extractor( [1, 2, 2, 1, 1, 1, 2, 2, 1, 1], timedelta(seconds=5) ) as feature_extractor: diff --git a/tests/timeseries/test_quantities.py b/tests/timeseries/test_quantities.py index c9e5311bd..824c13215 100644 --- a/tests/timeseries/test_quantities.py +++ b/tests/timeseries/test_quantities.py @@ -407,7 +407,7 @@ def test_neg() -> None: def test_inf() -> None: - """Test proper formating when using inf in quantities""" + """Test proper formating when using inf in quantities.""" assert f"{Power.from_watts(float('inf'))}" == "inf W" assert f"{Power.from_watts(float('-inf'))}" == "-inf W" @@ -428,7 +428,7 @@ def test_inf() -> None: def test_nan() -> None: - """Test proper formating when using nan in quantities""" + """Test proper formating when using nan in quantities.""" assert f"{Power.from_watts(float('nan'))}" == "nan W" assert f"{Voltage.from_volts(float('nan'))}" == "nan V" assert f"{Current.from_amperes(float('nan'))}" == "nan A" diff --git a/tests/timeseries/test_resampling.py b/tests/timeseries/test_resampling.py index 6f8ab5a6e..7e8e1bd15 100644 --- a/tests/timeseries/test_resampling.py +++ b/tests/timeseries/test_resampling.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the `TimeSeriesResampler` -""" +"""Tests for the `TimeSeriesResampler` class.""" from __future__ import annotations From d16d434317354576454d0232ab802e31582a3db9 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:43:33 +0200 Subject: [PATCH 28/43] Don't leave an empty line between docstrings and code Signed-off-by: Leandro Lucarella --- tests/actor/power_distributing/test_distribution_algorithm.py | 1 - tests/actor/test_battery_status.py | 3 --- tests/actor/test_resampling.py | 2 -- tests/actor/test_run_utils.py | 2 -- tests/config/test_config.py | 3 --- tests/microgrid/test_datapipeline.py | 1 - tests/microgrid/test_grid.py | 1 - tests/microgrid/test_microgrid_api.py | 1 - tests/timeseries/test_ev_charger_pool.py | 1 - tests/timeseries/test_formula_engine.py | 1 - 10 files changed, 16 deletions(-) diff --git a/tests/actor/power_distributing/test_distribution_algorithm.py b/tests/actor/power_distributing/test_distribution_algorithm.py index 4b4c212b3..3229d4a32 100644 --- a/tests/actor/power_distributing/test_distribution_algorithm.py +++ b/tests/actor/power_distributing/test_distribution_algorithm.py @@ -129,7 +129,6 @@ def create_components_with_capacity( self, num: int, capacity: List[float] ) -> List[InvBatPair]: """Create components with given capacity.""" - components: List[InvBatPair] = [] for i in range(0, num): battery_data = BatteryDataWrapper( diff --git a/tests/actor/test_battery_status.py b/tests/actor/test_battery_status.py index f66f4b001..4ddd25f13 100644 --- a/tests/actor/test_battery_status.py +++ b/tests/actor/test_battery_status.py @@ -64,7 +64,6 @@ def battery_data( # pylint: disable=too-many-arguments Returns: BatteryData with given arguments. """ - return BatteryDataWrapper( component_id=component_id, capacity=capacity, @@ -98,7 +97,6 @@ def inverter_data( Returns: InverterData with given arguments. """ - return InverterDataWrapper( component_id=component_id, timestamp=datetime.now(tz=timezone.utc) if timestamp is None else timestamp, @@ -887,7 +885,6 @@ async def test_critical_error( setup_tracker: tuple[MockMicrogrid, Receiver[Status]], ) -> None: """Test recovery after critical error.""" - mock_microgrid, status_receiver = setup_tracker await self._send_healthy_inverter(mock_microgrid) diff --git a/tests/actor/test_resampling.py b/tests/actor/test_resampling.py index 752ce479b..7e1d39884 100644 --- a/tests/actor/test_resampling.py +++ b/tests/actor/test_resampling.py @@ -115,7 +115,6 @@ async def test_single_request( fake_time: time_machine.Coordinates, ) -> None: """Run main functions that initializes and creates everything.""" - channel_registry = ChannelRegistry(name="test") data_source_req_chan = Broadcast[ComponentMetricRequest]("data-source-req") data_source_req_recv = data_source_req_chan.new_receiver() @@ -159,7 +158,6 @@ async def test_duplicate_request( fake_time: time_machine.Coordinates, ) -> None: """Run main functions that initializes and creates everything.""" - channel_registry = ChannelRegistry(name="test") data_source_req_chan = Broadcast[ComponentMetricRequest]("data-source-req") data_source_req_recv = data_source_req_chan.new_receiver() diff --git a/tests/actor/test_run_utils.py b/tests/actor/test_run_utils.py index 3d93e2429..7324626dd 100644 --- a/tests/actor/test_run_utils.py +++ b/tests/actor/test_run_utils.py @@ -77,7 +77,6 @@ async def _run(self) -> None: # pylint: disable=redefined-outer-name async def test_all_actors_done(fake_time: time_machine.Coordinates) -> None: """Test the completion of all actors.""" - sleepy_actor_1 = SleepyActor("sleepy_actor_1", sleep_duration=1.0) sleepy_actor_2 = SleepyActor("sleepy_actor_2", sleep_duration=2.0) @@ -110,7 +109,6 @@ async def test_all_actors_done(fake_time: time_machine.Coordinates) -> None: async def test_actors_cancelled() -> None: """Test the completion of actors being cancelled.""" - faulty_actors = [FaultyActor(f"faulty_actor_{idx}") for idx in range(5)] await asyncio.wait_for(run(*faulty_actors), timeout=1.0) diff --git a/tests/config/test_config.py b/tests/config/test_config.py index f8a21bf36..786c432d6 100644 --- a/tests/config/test_config.py +++ b/tests/config/test_config.py @@ -117,7 +117,6 @@ def test_get_as_success( self, key: str, expected_type: Any, value: Any, conf_vars: dict[str, Any] ) -> None: """Test get_as function with proper arguments.""" - config = Config(conf_vars=conf_vars) result = config.get_as(key, expected_type) assert result == value @@ -162,7 +161,6 @@ def test_get_dict_values_success( conf_vars: dict[str, Any], ) -> None: """Test get_as function with proper arguments.""" - config = Config(conf_vars=conf_vars) result = config.get_dict(key_prefix, expected_values_type) assert result == value @@ -179,7 +177,6 @@ def test_get_dict_success( self, key_prefix: str, expected_values_type: Any, conf_vars: dict[str, Any] ) -> None: """Test get_as function with proper arguments.""" - config = Config(conf_vars=conf_vars) err_msg_re = ( diff --git a/tests/microgrid/test_datapipeline.py b/tests/microgrid/test_datapipeline.py index 029d49d63..9c715961d 100644 --- a/tests/microgrid/test_datapipeline.py +++ b/tests/microgrid/test_datapipeline.py @@ -30,7 +30,6 @@ def event_loop() -> Iterator[async_solipsism.EventLoop]: async def test_actors_started(mocker: MockerFixture) -> None: """Test that the datasourcing, resampling and power distributing actors are started.""" - datapipeline = _DataPipeline( resampler_config=ResamplerConfig(resampling_period=timedelta(seconds=1)) ) diff --git a/tests/microgrid/test_grid.py b/tests/microgrid/test_grid.py index b401266c4..0475f378c 100644 --- a/tests/microgrid/test_grid.py +++ b/tests/microgrid/test_grid.py @@ -14,7 +14,6 @@ async def test_grid() -> None: """Test the grid connection module.""" - # The tests here need to be in this exact sequence, because the grid connection # is a singleton. Once it gets created, it stays in memory for the duration of # the tests, unless we explicitly delete it. diff --git a/tests/microgrid/test_microgrid_api.py b/tests/microgrid/test_microgrid_api.py index ad681baf7..7c9a41df9 100644 --- a/tests/microgrid/test_microgrid_api.py +++ b/tests/microgrid/test_microgrid_api.py @@ -165,7 +165,6 @@ async def test_connection_manager_another_method( components: components connections: connections """ - microgrid_client = MagicMock() microgrid_client.components = AsyncMock(return_value=[]) microgrid_client.connections = AsyncMock(return_value=[]) diff --git a/tests/timeseries/test_ev_charger_pool.py b/tests/timeseries/test_ev_charger_pool.py index 32ba8970f..1c3c7c60d 100644 --- a/tests/timeseries/test_ev_charger_pool.py +++ b/tests/timeseries/test_ev_charger_pool.py @@ -27,7 +27,6 @@ class TestEVChargerPool: async def test_state_updates(self, mocker: MockerFixture) -> None: """Test ev charger state updates are visible.""" - mockgrid = MockMicrogrid( grid_meter=False, api_client_streaming=True, sample_rate_s=0.01 ) diff --git a/tests/timeseries/test_formula_engine.py b/tests/timeseries/test_formula_engine.py index 17db38ac3..9f0595851 100644 --- a/tests/timeseries/test_formula_engine.py +++ b/tests/timeseries/test_formula_engine.py @@ -643,7 +643,6 @@ class TestConstantValue: async def test_constant_value(self) -> None: """Test using constant values in formulas.""" - channel_1 = Broadcast[Sample[Quantity]]("channel_1") channel_2 = Broadcast[Sample[Quantity]]("channel_2") From ccc1beea8732e5a36febf8379a3feba227ac03bc Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:44:47 +0200 Subject: [PATCH 29/43] Fit one-line docstrings in one line. Also do some rephrasing as needed. Signed-off-by: Leandro Lucarella --- tests/actor/test_data_sourcing.py | 4 +--- tests/microgrid/test_client.py | 4 +--- tests/microgrid/test_component.py | 4 +--- tests/microgrid/test_component_data.py | 4 +--- tests/microgrid/test_connection.py | 4 +--- tests/microgrid/test_graph.py | 4 +--- tests/microgrid/test_grid.py | 4 +--- tests/microgrid/test_mock_api.py | 4 +--- tests/timeseries/test_moving_window.py | 4 ++-- tests/timeseries/test_ringbuffer.py | 4 ++-- 10 files changed, 12 insertions(+), 28 deletions(-) diff --git a/tests/actor/test_data_sourcing.py b/tests/actor/test_data_sourcing.py index 4d70fe5cb..377a5859a 100644 --- a/tests/actor/test_data_sourcing.py +++ b/tests/actor/test_data_sourcing.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the DataSourcingActor. -""" +"""Tests for the DataSourcingActor.""" from frequenz.api.common import components_pb2 as components_pb from frequenz.channels import Broadcast diff --git a/tests/microgrid/test_client.py b/tests/microgrid/test_client.py index 8b38e72bb..199279bcb 100644 --- a/tests/microgrid/test_client.py +++ b/tests/microgrid/test_client.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the microgrid client thin wrapper. -""" +"""Tests for the microgrid client thin wrapper.""" import asyncio diff --git a/tests/microgrid/test_component.py b/tests/microgrid/test_component.py index 3d8ff2773..1dda260c2 100644 --- a/tests/microgrid/test_component.py +++ b/tests/microgrid/test_component.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the microgrid component wrapper. -""" +"""Tests for the microgrid component wrapper.""" import frequenz.api.common.components_pb2 as components_pb import pytest diff --git a/tests/microgrid/test_component_data.py b/tests/microgrid/test_component_data.py index bc8b9d2ea..6670512d9 100644 --- a/tests/microgrid/test_component_data.py +++ b/tests/microgrid/test_component_data.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the microgrid component data. -""" +"""Tests for the microgrid component data.""" from datetime import datetime, timezone diff --git a/tests/microgrid/test_connection.py b/tests/microgrid/test_connection.py index 63eb42142..fc4898eeb 100644 --- a/tests/microgrid/test_connection.py +++ b/tests/microgrid/test_connection.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the microgrid Connection type. -""" +"""Tests for the microgrid Connection type.""" from frequenz.sdk.microgrid import client diff --git a/tests/microgrid/test_graph.py b/tests/microgrid/test_graph.py index 7d6f35640..0fd8219ac 100644 --- a/tests/microgrid/test_graph.py +++ b/tests/microgrid/test_graph.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the microgrid component graph. -""" +"""Tests for the microgrid component graph.""" # pylint: disable=too-many-lines,use-implicit-booleaness-not-comparison # pylint: disable=invalid-name,missing-function-docstring,too-many-statements diff --git a/tests/microgrid/test_grid.py b/tests/microgrid/test_grid.py index 0475f378c..ad451a931 100644 --- a/tests/microgrid/test_grid.py +++ b/tests/microgrid/test_grid.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2023 Frequenz Energy-as-a-Service GmbH -""" -Tests for the `Grid` module. -""" +"""Tests for the `Grid` module.""" from frequenz.sdk import microgrid from frequenz.sdk.microgrid.component import Component, ComponentCategory, GridMetadata diff --git a/tests/microgrid/test_mock_api.py b/tests/microgrid/test_mock_api.py index 9d1ffa18c..b9fb5726e 100644 --- a/tests/microgrid/test_mock_api.py +++ b/tests/microgrid/test_mock_api.py @@ -1,9 +1,7 @@ # License: MIT # Copyright © 2022 Frequenz Energy-as-a-Service GmbH -""" -Tests for the microgrid mock api. -""" +"""Tests for the microgrid mock api.""" # pylint: disable=missing-function-docstring,use-implicit-booleaness-not-comparison # pylint: disable=invalid-name,no-name-in-module,no-member diff --git a/tests/timeseries/test_moving_window.py b/tests/timeseries/test_moving_window.py index 132fc4041..4f37eea84 100644 --- a/tests/timeseries/test_moving_window.py +++ b/tests/timeseries/test_moving_window.py @@ -38,8 +38,8 @@ def fake_time() -> Iterator[time_machine.Coordinates]: async def push_logical_meter_data( sender: Sender[Sample[Quantity]], test_seq: Sequence[float] ) -> None: - """ - Push data in the passed sender to mock `LogicalMeter` behaviour. + """Push data in the passed sender to mock `LogicalMeter` behaviour. + Starting with the First of January 2023. Args: diff --git a/tests/timeseries/test_ringbuffer.py b/tests/timeseries/test_ringbuffer.py index f1b4e6708..ee2344989 100644 --- a/tests/timeseries/test_ringbuffer.py +++ b/tests/timeseries/test_ringbuffer.py @@ -393,8 +393,8 @@ def test_cleanup_oldest_gap_timestamp() -> None: def test_delete_oudated_gap() -> None: - """ - Update the buffer such that the gap is no longer valid. + """Test updating the buffer such that the gap is no longer valid. + We introduce two gaps and check that the oldest is removed. """ buffer = OrderedRingBuffer( From 110a3a19ad64b6934a6163582bfdde844addc93e Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:45:28 +0200 Subject: [PATCH 30/43] Add missing docstrings Signed-off-by: Leandro Lucarella --- tests/api_client/test_api_client.py | 13 +++++++++++++ tests/microgrid/test_client.py | 10 ++++++++++ tests/microgrid/test_graph.py | 18 ++++++++++++++++++ tests/microgrid/test_mock_api.py | 2 ++ 4 files changed, 43 insertions(+) diff --git a/tests/api_client/test_api_client.py b/tests/api_client/test_api_client.py index 4cab18628..12a587477 100644 --- a/tests/api_client/test_api_client.py +++ b/tests/api_client/test_api_client.py @@ -14,6 +14,11 @@ class FakeApiClient(ApiClient): @classmethod def api_major_version(cls) -> int: + """Return the major version of the API supported by the client. + + Returns: + The major version of the API supported by the client. + """ # Specifying the targeted API version here. return 1 @@ -42,16 +47,20 @@ class FakeGrpcClient(FakeApiClient): @classmethod def api_type(cls) -> ApiProtocol: + """Return the API type.""" # Specifying the API protocol here as gRPC. return ApiProtocol.GRPC async def connect(self, connection_params: str) -> None: + """Connect to the API.""" self.is_connected = True async def disconnect(self) -> None: + """Disconnect from the API.""" self.is_connected = False def get_data(self) -> str: + """Get data from the API.""" return "grpc data" @@ -62,16 +71,20 @@ class FakeRestClient(FakeApiClient): @classmethod def api_type(cls) -> ApiProtocol: + """Return the API type.""" # Same as `FakeGrpcClient`, but targeting REST protocol here. return ApiProtocol.REST async def connect(self, connection_params: str) -> None: + """Connect to the API.""" self.is_connected = True async def disconnect(self) -> None: + """Disconnect from the API.""" self.is_connected = False def get_data(self) -> str: + """Get data from the API.""" return "rest data" diff --git a/tests/microgrid/test_client.py b/tests/microgrid/test_client.py index 199279bcb..a22d991e9 100644 --- a/tests/microgrid/test_client.py +++ b/tests/microgrid/test_client.py @@ -34,8 +34,11 @@ class TestMicrogridGrpcClient: + """Tests for the microgrid client thin wrapper.""" + @staticmethod def create_client(port: int) -> client.MicrogridApiClient: + """Create a client for the mock API server.""" return client.MicrogridGrpcClient( grpc.aio.insecure_channel(f"[::]:{port}"), f"[::]:{port}", @@ -43,6 +46,7 @@ def create_client(port: int) -> client.MicrogridApiClient: ) async def test_components(self) -> None: + """Test the components() method.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57899) await server.start() @@ -165,6 +169,7 @@ async def test_components(self) -> None: assert await server.graceful_shutdown() async def test_connections(self) -> None: + """Test the connections() method.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57898) await server.start() @@ -390,6 +395,7 @@ def ListAllComponents( assert await server.graceful_shutdown() async def test_meter_data(self) -> None: + """Test the meter_data() method.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57899) await server.start() @@ -422,6 +428,7 @@ async def test_meter_data(self) -> None: assert latest.component_id == 83 async def test_battery_data(self) -> None: + """Test the battery_data() method.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57899) await server.start() @@ -454,6 +461,7 @@ async def test_battery_data(self) -> None: assert latest.component_id == 83 async def test_inverter_data(self) -> None: + """Test the inverter_data() method.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57899) await server.start() @@ -486,6 +494,7 @@ async def test_inverter_data(self) -> None: assert latest.component_id == 83 async def test_ev_charger_data(self) -> None: + """Test the ev_charger_data() method.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57899) await server.start() @@ -563,6 +572,7 @@ async def test_discharge(self) -> None: assert await server.graceful_shutdown() async def test_set_bounds(self) -> None: + """Check if set_bounds is able to set bounds for component.""" servicer = mock_api.MockMicrogridServicer() server = mock_api.MockGrpcServer(servicer, port=57899) await server.start() diff --git a/tests/microgrid/test_graph.py b/tests/microgrid/test_graph.py index 0fd8219ac..d8fa83d1a 100644 --- a/tests/microgrid/test_graph.py +++ b/tests/microgrid/test_graph.py @@ -64,6 +64,7 @@ class TestComponentGraph: @pytest.fixture() def sample_input_components(self) -> Set[Component]: + """Create a sample set of components for testing purposes.""" return { Component(11, ComponentCategory.GRID), Component(21, ComponentCategory.METER), @@ -74,6 +75,7 @@ def sample_input_components(self) -> Set[Component]: @pytest.fixture() def sample_input_connections(self) -> Set[Connection]: + """Create a sample set of connections for testing purposes.""" return { Connection(11, 21), Connection(21, 41), @@ -95,6 +97,7 @@ def sample_graph( return _graph_implementation def test_without_filters(self) -> None: + """Test the graph component query without filters.""" _graph_implementation = gr._MicrogridComponentGraph() graph: gr.ComponentGraph = _graph_implementation @@ -210,6 +213,7 @@ def test_without_filters(self) -> None: def test_filter_graph_components_by_id( self, sample_graph: gr.ComponentGraph, ids: Set[int], expected: Set[Component] ) -> None: + """Test the graph component query with component ID filter.""" # with component_id filter specified, we get back only components whose ID # matches one of the specified values assert len(sample_graph.components(component_id=ids)) == len(expected) @@ -260,6 +264,7 @@ def test_filter_graph_components_by_type( types: Set[ComponentCategory], expected: Set[Component], ) -> None: + """Test the graph component query with component category filter.""" # with component_id filter specified, we get back only components whose ID # matches one of the specified values assert len(sample_graph.components(component_category=types)) == len(expected) @@ -292,6 +297,7 @@ def test_filter_graph_components_with_composite_filter( types: Set[ComponentCategory], expected: Set[Component], ) -> None: + """Test the graph component query with composite filter.""" # when both filters are applied, they are combined via AND logic, i.e. # the component must have one of the specified IDs and be of one of # the specified types @@ -306,11 +312,13 @@ def test_filter_graph_components_with_composite_filter( def test_components_without_filters( self, sample_input_components: Set[Component], sample_graph: gr.ComponentGraph ) -> None: + """Test the graph component query without filters.""" # without any filter applied, we get back all the components in the graph assert len(sample_graph.components()) == len(sample_input_components) assert sample_graph.components() == sample_input_components def test_connection_filters(self) -> None: + """Test the graph connection query with filters.""" _graph_implementation = gr._MicrogridComponentGraph( components={ Component(1, ComponentCategory.GRID), @@ -528,6 +536,7 @@ class Test_MicrogridComponentGraph: """ def test___init__(self) -> None: + """Test the constructor.""" # it is possible to instantiate an empty graph, but # it will not be considered valid until it has been # populated with components and connections @@ -604,6 +613,7 @@ def test___init__(self) -> None: ) def test_refresh_from(self) -> None: + """Test the refresh_from method.""" graph = gr._MicrogridComponentGraph() assert set(graph.components()) == set() assert list(graph.connections()) == [] @@ -765,6 +775,7 @@ def pretend_to_correct_errors(_g: gr._MicrogridComponentGraph) -> None: graph.validate() async def test_refresh_from_api(self) -> None: + """Test the refresh_from_api method.""" graph = gr._MicrogridComponentGraph() assert graph.components() == set() assert graph.connections() == set() @@ -885,6 +896,7 @@ async def test_refresh_from_api(self) -> None: assert await server.graceful_shutdown() def test_validate(self) -> None: + """Test the validate method.""" # `validate` will fail if any of the following are the case: # # * the graph data is not valid @@ -953,6 +965,7 @@ def test_validate(self) -> None: graph.validate() def test__validate_graph(self) -> None: + """Test the _validate_graph method.""" # to ensure clean testing of the individual method, # we cheat by setting underlying graph data directly @@ -1003,6 +1016,7 @@ def test__validate_graph(self) -> None: graph._validate_graph() def test__validate_graph_root(self) -> None: + """Test the _validate_graph_root method.""" # to ensure clean testing of the individual method, # we cheat by setting underlying graph data directly @@ -1125,6 +1139,7 @@ def test__validate_graph_root(self) -> None: graph._validate_graph_root() def test__validate_grid_endpoint(self) -> None: + """Test the _validate_grid_endpoint method.""" # to ensure clean testing of the individual method, # we cheat by setting underlying graph data directly @@ -1194,6 +1209,7 @@ def test__validate_grid_endpoint(self) -> None: graph._validate_grid_endpoint() def test__validate_intermediary_components(self) -> None: + """Test the _validate_intermediary_components method.""" # to ensure clean testing of the individual method, # we cheat by setting underlying graph data directly @@ -1247,6 +1263,7 @@ def test__validate_intermediary_components(self) -> None: graph._validate_intermediary_components() def test__validate_leaf_components(self) -> None: + """Test the _validate_leaf_components method.""" # to ensure clean testing of the individual method, # we cheat by setting underlying graph data directly @@ -1336,6 +1353,7 @@ def test__validate_leaf_components(self) -> None: graph._validate_leaf_components() def test_graph_correction(self) -> None: + """Test the graph correction functionality.""" # Simple test cases for our built-in graph correction # functionality. We test only with `refresh_from`: # for `refresh_from_api` it suffices to test that any diff --git a/tests/microgrid/test_mock_api.py b/tests/microgrid/test_mock_api.py index b9fb5726e..814161636 100644 --- a/tests/microgrid/test_mock_api.py +++ b/tests/microgrid/test_mock_api.py @@ -23,6 +23,7 @@ def test_MockMicrogridServicer() -> None: + """Test the MockMicrogridServicer.""" api = mock_api.MockMicrogridServicer() service_context_mock = Mock(spec=grpc.ServicerContext) assert ( @@ -211,6 +212,7 @@ def test_MockMicrogridServicer() -> None: async def test_MockGrpcServer() -> None: + """Test the MockGrpcServer.""" servicer1 = mock_api.MockMicrogridServicer( components=[ (1, ComponentCategory.COMPONENT_CATEGORY_GRID), From 6aa39e5aad35d199f3e409fc0ac3f8287a6c6bff Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:45:50 +0200 Subject: [PATCH 31/43] Use imperative for function docstring Signed-off-by: Leandro Lucarella --- tests/actor/test_config_manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/actor/test_config_manager.py b/tests/actor/test_config_manager.py index bd2d3513c..7190a77a5 100644 --- a/tests/actor/test_config_manager.py +++ b/tests/actor/test_config_manager.py @@ -22,7 +22,7 @@ class Item(BaseModel): def create_content(number: int) -> str: - """Utility function to create content to be written to a config file.""" + """Create content to be written to a config file.""" return f""" logging_lvl = "ERROR" var1 = "0" From 902446a5cc49184e941d4664a652888d891d53d4 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:46:05 +0200 Subject: [PATCH 32/43] Remove empty file Signed-off-by: Leandro Lucarella --- tests/config/test_config_manager.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 tests/config/test_config_manager.py diff --git a/tests/config/test_config_manager.py b/tests/config/test_config_manager.py deleted file mode 100644 index e69de29bb..000000000 From a67ad5517acf7f4e5b8c6b05551dd23ea0758789 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 14:46:27 +0200 Subject: [PATCH 33/43] Rephrase comment to make the summary fit in one line Signed-off-by: Leandro Lucarella --- tests/timeseries/test_periodic_feature_extractor.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/timeseries/test_periodic_feature_extractor.py b/tests/timeseries/test_periodic_feature_extractor.py index ad1e3154a..a84d22340 100644 --- a/tests/timeseries/test_periodic_feature_extractor.py +++ b/tests/timeseries/test_periodic_feature_extractor.py @@ -236,9 +236,10 @@ async def test_011( async def test_profiler_calculate_np() -> None: - """ - Test the calculation of the average using a numpy array and compare it - against the pure python method with the same functionality. + """Test calculating the average with numpy and a pure python version. + + Calculate the average using a numpy array and compare the run time against the pure + python method with the same functionality. """ data = np.array([2, 2.5, 1, 1, 1, 2]) async with init_feature_extractor_no_data(4) as feature_extractor: From a792ba5128feb42dafd96562d9fd42880d11a32e Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:28:29 +0200 Subject: [PATCH 34/43] Use `_` symbol for unused variable Signed-off-by: Leandro Lucarella --- benchmarks/timeseries/benchmark_ringbuffer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benchmarks/timeseries/benchmark_ringbuffer.py b/benchmarks/timeseries/benchmark_ringbuffer.py index 4615f009f..23839b940 100644 --- a/benchmarks/timeseries/benchmark_ringbuffer.py +++ b/benchmarks/timeseries/benchmark_ringbuffer.py @@ -39,8 +39,7 @@ def test_days(days: int, buffer: OrderedRingBuffer[Any]) -> None: basetime = datetime(2022, 1, 1, tzinfo=timezone.utc) for day in range(days): - # pylint: disable=unused-variable - minutes = buffer.window( + _ = buffer.window( basetime + timedelta(days=day), basetime + timedelta(days=day + 1) ) From 8ee926daa1a83ad9276521f741a409088962fc2b Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:29:17 +0200 Subject: [PATCH 35/43] Shorten long lines Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/microgrid/client/_client.py | 6 ++++-- .../_formula_generators/_grid_current_formula.py | 3 ++- .../_formula_generators/_grid_power_formula.py | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/frequenz/sdk/microgrid/client/_client.py b/src/frequenz/sdk/microgrid/client/_client.py index 15fc0ef9c..742f4d98b 100644 --- a/src/frequenz/sdk/microgrid/client/_client.py +++ b/src/frequenz/sdk/microgrid/client/_client.py @@ -621,12 +621,14 @@ async def set_bounds( if lower > 0: raise ValueError(f"Lower bound {upper} must be less than or equal to 0.") + target_metric = ( + microgrid_pb.SetBoundsParam.TargetMetric.TARGET_METRIC_POWER_ACTIVE + ) try: self.api.AddInclusionBounds( microgrid_pb.SetBoundsParam( component_id=component_id, - # pylint: disable=no-member,line-too-long - target_metric=microgrid_pb.SetBoundsParam.TargetMetric.TARGET_METRIC_POWER_ACTIVE, + target_metric=target_metric, bounds=metrics_pb.Bounds(lower=lower, upper=upper), ), ) diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py index c6d940017..b6f7e1b54 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_current_formula.py @@ -14,7 +14,8 @@ class GridCurrentFormula(FormulaGenerator[Current]): """Create a formula engine from the component graph for calculating grid current.""" - def generate( # noqa: DOC502 (ComponentNotFound is raised indirectly by _get_grid_component_successors) + def generate( # noqa: DOC502 + # ComponentNotFound is raised indirectly by _get_grid_component_successors self, ) -> FormulaEngine3Phase[Current]: """Generate a formula for calculating grid current from the component graph. diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py index 085a24245..5cbc4a8e4 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_grid_power_formula.py @@ -12,7 +12,8 @@ class GridPowerFormula(FormulaGenerator[Power]): """Creates a formula engine from the component graph for calculating grid power.""" - def generate( # noqa: DOC502 (ComponentNotFound is raised indirectly by _get_grid_component_successors) + def generate( # noqa: DOC502 + # * ComponentNotFound is raised indirectly by _get_grid_component_successors self, ) -> FormulaEngine[Power]: """Generate a formula for calculating grid power from the component graph. From 66f05e833bdb773c161f99b2a3ba24b433852231 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:29:53 +0200 Subject: [PATCH 36/43] Use only one `#` for comments Signed-off-by: Leandro Lucarella --- .../test_power_distributing.py | 6 +++--- tests/microgrid/test_client.py | 16 ++++++++-------- tests/timeseries/test_ev_charger_pool.py | 8 ++++---- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/actor/power_distributing/test_power_distributing.py b/tests/actor/power_distributing/test_power_distributing.py index f6f92960c..09bf33451 100644 --- a/tests/actor/power_distributing/test_power_distributing.py +++ b/tests/actor/power_distributing/test_power_distributing.py @@ -191,7 +191,7 @@ async def test_power_distributor_exclusion_bounds( channel_registry=channel_registry, battery_status_sender=battery_status_channel.new_sender(), ): - ## zero power requests should pass through despite the exclusion bounds. + # zero power requests should pass through despite the exclusion bounds. request = Request( namespace=self._namespace, power=Power.zero(), @@ -216,8 +216,8 @@ async def test_power_distributor_exclusion_bounds( assert result.excess_power.isclose(Power.zero(), abs_tol=1e-9) assert result.request == request - ## non-zero power requests that fall within the exclusion bounds should be - ## rejected. + # non-zero power requests that fall within the exclusion bounds should be + # rejected. request = Request( namespace=self._namespace, power=Power.from_watts(300.0), diff --git a/tests/microgrid/test_client.py b/tests/microgrid/test_client.py index a22d991e9..c09766818 100644 --- a/tests/microgrid/test_client.py +++ b/tests/microgrid/test_client.py @@ -411,11 +411,11 @@ async def test_meter_data(self) -> None: ) with pytest.raises(ValueError): - ## should raise a ValueError for missing component_id + # should raise a ValueError for missing component_id await microgrid.meter_data(20) with pytest.raises(ValueError): - ## should raise a ValueError for wrong component category + # should raise a ValueError for wrong component category await microgrid.meter_data(38) peekable = (await microgrid.meter_data(83)).into_peekable() await asyncio.sleep(0.2) @@ -444,11 +444,11 @@ async def test_battery_data(self) -> None: ) with pytest.raises(ValueError): - ## should raise a ValueError for missing component_id + # should raise a ValueError for missing component_id await microgrid.meter_data(20) with pytest.raises(ValueError): - ## should raise a ValueError for wrong component category + # should raise a ValueError for wrong component category await microgrid.meter_data(38) peekable = (await microgrid.battery_data(83)).into_peekable() await asyncio.sleep(0.2) @@ -477,11 +477,11 @@ async def test_inverter_data(self) -> None: ) with pytest.raises(ValueError): - ## should raise a ValueError for missing component_id + # should raise a ValueError for missing component_id await microgrid.meter_data(20) with pytest.raises(ValueError): - ## should raise a ValueError for wrong component category + # should raise a ValueError for wrong component category await microgrid.meter_data(38) peekable = (await microgrid.inverter_data(83)).into_peekable() await asyncio.sleep(0.2) @@ -510,11 +510,11 @@ async def test_ev_charger_data(self) -> None: ) with pytest.raises(ValueError): - ## should raise a ValueError for missing component_id + # should raise a ValueError for missing component_id await microgrid.meter_data(20) with pytest.raises(ValueError): - ## should raise a ValueError for wrong component category + # should raise a ValueError for wrong component category await microgrid.meter_data(38) peekable = (await microgrid.ev_charger_data(83)).into_peekable() await asyncio.sleep(0.2) diff --git a/tests/timeseries/test_ev_charger_pool.py b/tests/timeseries/test_ev_charger_pool.py index 1c3c7c60d..dc2a80b5c 100644 --- a/tests/timeseries/test_ev_charger_pool.py +++ b/tests/timeseries/test_ev_charger_pool.py @@ -46,26 +46,26 @@ async def check_states( for comp_id, exp_state in expected.items(): assert state_tracker.get(comp_id) == exp_state - ## check that all chargers are in idle state. + # check that all chargers are in idle state. expected_states = {evc_id: EVChargerState.IDLE for evc_id in mockgrid.evc_ids} assert len(expected_states) == 5 await check_states(expected_states) - ## check that EV_PLUGGED state gets set + # check that EV_PLUGGED state gets set evc_2_id = mockgrid.evc_ids[2] mockgrid.evc_cable_states[evc_2_id] = EVChargerCableState.EV_PLUGGED mockgrid.evc_component_states[evc_2_id] = EVChargerComponentState.READY expected_states[evc_2_id] = EVChargerState.EV_PLUGGED await check_states(expected_states) - ## check that EV_LOCKED state gets set + # check that EV_LOCKED state gets set evc_3_id = mockgrid.evc_ids[3] mockgrid.evc_cable_states[evc_3_id] = EVChargerCableState.EV_LOCKED mockgrid.evc_component_states[evc_3_id] = EVChargerComponentState.READY expected_states[evc_3_id] = EVChargerState.EV_LOCKED await check_states(expected_states) - ## check that ERROR state gets set + # check that ERROR state gets set evc_1_id = mockgrid.evc_ids[1] mockgrid.evc_cable_states[evc_1_id] = EVChargerCableState.EV_LOCKED mockgrid.evc_component_states[evc_1_id] = EVChargerComponentState.ERROR From 40a6ed6d8785d2f721ed94dec299a0af5a511404 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:30:03 +0200 Subject: [PATCH 37/43] Remove unused import Signed-off-by: Leandro Lucarella --- tests/microgrid/mock_api.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/microgrid/mock_api.py b/tests/microgrid/mock_api.py index 3e07b3824..72fde7a6b 100644 --- a/tests/microgrid/mock_api.py +++ b/tests/microgrid/mock_api.py @@ -45,7 +45,6 @@ ConnectionFilter, ConnectionList, MicrogridMetadata, - PowerLevelParam, SetBoundsParam, SetPowerActiveParam, SetPowerReactiveParam, From a2c85adfc8982a53f10bbd2068f9d2c31e72f312 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:30:17 +0200 Subject: [PATCH 38/43] Convert lamda to a function Signed-off-by: Leandro Lucarella --- tests/microgrid/test_client.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/microgrid/test_client.py b/tests/microgrid/test_client.py index c09766818..eb3c27a74 100644 --- a/tests/microgrid/test_client.py +++ b/tests/microgrid/test_client.py @@ -604,8 +604,11 @@ async def test_set_bounds(self) -> None: assert len(expected_bounds) == len(servicer.get_bounds()) - # pylint:disable=unnecessary-lambda-assignment - sort_key = lambda bound: bound.target_metric + def sort_key( + bound: microgrid_pb.SetBoundsParam, + ) -> microgrid_pb.SetBoundsParam.TargetMetric.ValueType: + return bound.target_metric + assert sorted(servicer.get_bounds(), key=sort_key) == sorted( expected_bounds, key=sort_key ) From 1f996a146ada7dd72666763c7d12205845c34a8b Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:30:30 +0200 Subject: [PATCH 39/43] Remove unused variable Signed-off-by: Leandro Lucarella --- tests/microgrid/test_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/microgrid/test_graph.py b/tests/microgrid/test_graph.py index d8fa83d1a..07599aa8f 100644 --- a/tests/microgrid/test_graph.py +++ b/tests/microgrid/test_graph.py @@ -1184,7 +1184,7 @@ def test__validate_grid_endpoint(self) -> None: match=r"Grid endpoint 1 has graph predecessors: \[Component" r"\(component_id=99, category=, " r"type=None, metadata=None\)\]", - ) as _err_predecessors: + ): graph._validate_grid_endpoint() # grid endpoint has no successors From 3792906f4cd9649c6693ab06ab3d825494c64a2b Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 15:46:45 +0200 Subject: [PATCH 40/43] Ignore unused import error These imports are used to break circular imports in a very convoluted set of circular dependencies. To do that some types need to be specified as strings and use `typing.TYPE_CHECKING` to conditionally add imports, and it seems like flake8 doesn't detect those strings as types being used. Signed-off-by: Leandro Lucarella --- src/frequenz/sdk/microgrid/_data_pipeline.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frequenz/sdk/microgrid/_data_pipeline.py b/src/frequenz/sdk/microgrid/_data_pipeline.py index fb0c6a5a4..325fea6d7 100644 --- a/src/frequenz/sdk/microgrid/_data_pipeline.py +++ b/src/frequenz/sdk/microgrid/_data_pipeline.py @@ -33,7 +33,7 @@ DataSourcingActor, ResamplerConfig, ) - from ..actor.power_distributing import ( + from ..actor.power_distributing import ( # noqa: F401 (imports used by string type hints) BatteryStatus, PowerDistributingActor, Request, From a6aae235ea7c689bd74d1fd1b2fa3cbf6a5c28e4 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 30 Aug 2023 21:00:25 +0200 Subject: [PATCH 41/43] Make sure that the returned grid is not None `microgrid.grid.get()` returns `Grid | None`, so before accessing any attributes from `grid` we need to make sure it is not `None`. Signed-off-by: Leandro Lucarella --- tests/microgrid/test_grid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/microgrid/test_grid.py b/tests/microgrid/test_grid.py index ad451a931..eb1bddfe6 100644 --- a/tests/microgrid/test_grid.py +++ b/tests/microgrid/test_grid.py @@ -55,6 +55,7 @@ async def test_grid() -> None: microgrid.grid.initialize(components) grid = microgrid.grid.get() + assert grid is not None expected_fuse_current = Current.from_amperes(123.0) expected_fuse = Fuse(expected_fuse_current) From 0aa3c8a76e94fb296f9dbad9a7cd67d5963c963c Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 29 Aug 2023 15:50:23 +0200 Subject: [PATCH 42/43] Bump dependency for repo-config to v0.6.1 Signed-off-by: Leandro Lucarella --- pyproject.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 167f39c88..6362431f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = [ "setuptools == 68.1.0", "setuptools_scm[toml] == 7.1.0", - "frequenz-repo-config[lib] == 0.5.2", + "frequenz-repo-config[lib] == 0.6.1", ] build-backend = "setuptools.build_meta" @@ -65,7 +65,7 @@ dev-mkdocs = [ "mkdocs-material == 9.2.5", "mkdocs-section-index == 0.3.5", "mkdocstrings[python] == 0.22.0", - "frequenz-repo-config[lib] == 0.5.2", + "frequenz-repo-config[lib] == 0.6.1", ] dev-mypy = [ "mypy == 1.5.1", @@ -81,7 +81,7 @@ dev-mypy = [ # For checking the noxfile, docs/ script, and tests "frequenz-sdk[dev-mkdocs,dev-noxfile,dev-pytest]", ] -dev-noxfile = ["nox == 2023.4.22", "frequenz-repo-config[lib] == 0.5.2"] +dev-noxfile = ["nox == 2023.4.22", "frequenz-repo-config[lib] == 0.6.1"] dev-pylint = [ "pylint == 2.17.5", # For checking the noxfile, docs/ script, and tests @@ -89,7 +89,7 @@ dev-pylint = [ ] dev-pytest = [ "pytest == 7.4.0", - "frequenz-repo-config[extra-lint-examples] == 0.5.2", + "frequenz-repo-config[extra-lint-examples] == 0.6.1", "pytest-mock == 3.11.1", "pytest-asyncio == 0.21.1", "time-machine == 2.12.0", From 5e879be33cb629a44399395907958e9446a8a23c Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Mon, 4 Sep 2023 12:12:52 +0200 Subject: [PATCH 43/43] Use a consistent format for comments for `noqa: DOC502` Co-authored-by: daniel-zullo-frequenz <120166726+daniel-zullo-frequenz@users.noreply.github.com> Signed-off-by: Leandro Lucarella --- .../_formula_engine/_formula_generators/_pv_power_formula.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py index b812555ec..50a6e7e1a 100644 --- a/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py +++ b/src/frequenz/sdk/timeseries/_formula_engine/_formula_generators/_pv_power_formula.py @@ -17,8 +17,9 @@ class PVPowerFormula(FormulaGenerator[Power]): """Creates a formula engine for calculating the PV power production.""" - def generate( # noqa: DOC502 (ComponentNotFound and RuntimeError are raised - # indirectly by _get_pv_power_components) + def generate( # noqa: DOC502 + # * ComponentNotFound is raised indirectly by _get_pv_power_components + # * RuntimeError is also raised indirectly by _get_pv_power_components self, ) -> FormulaEngine[Power]: """Make a formula for the PV power production of a microgrid.