diff --git a/.github/workflows/ci-pr.yaml b/.github/workflows/ci-pr.yaml index 2c74ec0c..4ad3582a 100644 --- a/.github/workflows/ci-pr.yaml +++ b/.github/workflows/ci-pr.yaml @@ -17,7 +17,7 @@ jobs: steps: - name: Run nox - uses: frequenz-floss/gh-action-nox@v1.0.0 + uses: frequenz-floss/gh-action-nox@v1.0.1 with: python-version: "3.11" nox-session: ci_checks_max @@ -30,12 +30,12 @@ jobs: uses: frequenz-floss/gh-action-setup-git@v1.0.0 - name: Fetch sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 + uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.1 with: python-version: ${{ env.DEFAULT_PYTHON_VERSION }} dependencies: .[dev-mkdocs] diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 55dddda6..8f8355ae 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -45,7 +45,7 @@ jobs: steps: - name: Run nox - uses: frequenz-floss/gh-action-nox@v1.0.0 + uses: frequenz-floss/gh-action-nox@v1.0.1 with: python-version: ${{ matrix.python }} nox-session: ${{ matrix.nox-session }} @@ -79,12 +79,12 @@ jobs: uses: frequenz-floss/gh-action-setup-git@v1.0.0 - name: Fetch sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 + uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.1 with: python-version: ${{ env.DEFAULT_PYTHON_VERSION }} dependencies: build @@ -123,7 +123,7 @@ jobs: run: env - name: Download package - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: dist-packages path: dist @@ -143,7 +143,7 @@ jobs: > pyproject.toml - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 + uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.1 with: python-version: ${{ matrix.python }} dependencies: dist/*.whl @@ -177,12 +177,12 @@ jobs: uses: frequenz-floss/gh-action-setup-git@v1.0.0 - name: Fetch sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 + uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.1 with: python-version: ${{ env.DEFAULT_PYTHON_VERSION }} dependencies: .[dev-mkdocs] @@ -213,12 +213,12 @@ jobs: uses: frequenz-floss/gh-action-setup-git@v1.0.0 - name: Fetch sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: submodules: true - name: Setup Python - uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.0 + uses: frequenz-floss/gh-action-setup-python-with-deps@v1.0.1 with: python-version: ${{ env.DEFAULT_PYTHON_VERSION }} dependencies: .[dev-mkdocs] @@ -279,7 +279,7 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Download distribution files - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: dist-packages path: dist @@ -325,7 +325,7 @@ jobs: id-token: write steps: - name: Download distribution files - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: name: dist-packages path: dist diff --git a/pyproject.toml b/pyproject.toml index d3015749..4773d0a1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,8 +4,8 @@ [build-system] requires = [ "setuptools == 80.9.0", - "setuptools_scm[toml] == 8.3.1", - "frequenz-repo-config[lib] == 0.13.4", + "setuptools_scm[toml] == 9.2.0", + "frequenz-repo-config[lib] == 0.13.5", ] build-backend = "setuptools.build_meta" @@ -42,7 +42,6 @@ dependencies = [ "frequenz-client-common >= 0.3.2, < 0.4.0", "grpcio >= 1.63.0, < 2", "protobuf >= 5.26.1, < 7", - "timezonefinder >= 6.2.0, < 7", "typing-extensions >= 4.13.0, < 5", ] dynamic = ["version"] @@ -53,45 +52,45 @@ email = "floss@frequenz.com" [project.optional-dependencies] dev-flake8 = [ - "flake8 == 7.2.0", + "flake8 == 7.3.0", "flake8-docstrings == 1.7.0", "flake8-pyproject == 1.2.3", # For reading the flake8 config from pyproject.toml - "pydoclint == 0.6.6", + "pydoclint == 0.6.11", "pydocstyle == 6.3.0", ] dev-formatting = ["black == 25.1.0", "isort == 6.0.1"] dev-mkdocs = [ "black == 25.1.0", - "Markdown==3.8", + "Markdown==3.8.2", "mike == 2.1.3", "mkdocs-gen-files == 0.5.0", "mkdocs-literate-nav == 0.6.2", - "mkdocs-macros-plugin == 1.3.7", - "mkdocs-material == 9.6.14", - "mkdocstrings[python] == 0.29.1", - "mkdocstrings-python == 1.16.11", - "frequenz-repo-config[lib] == 0.13.4", + "mkdocs-macros-plugin == 1.3.9", + "mkdocs-material == 9.6.18", + "mkdocstrings[python] == 0.30.0", + "mkdocstrings-python == 1.18.2", + "frequenz-repo-config[lib] == 0.13.5", ] dev-mypy = [ - "mypy == 1.16.0", + "mypy == 1.17.1", "grpc-stubs == 1.53.0.6", - "types-Markdown == 3.8.0.20250415", - "types-protobuf == 6.30.2.20250516", + "types-Markdown == 3.8.0.20250809", + "types-protobuf == 6.30.2.20250822", # For checking the noxfile, docs/ script, and tests "frequenz-client-microgrid[dev-mkdocs,dev-noxfile,dev-pytest]", ] -dev-noxfile = ["nox == 2025.5.1", "frequenz-repo-config[lib] == 0.13.4"] +dev-noxfile = ["nox == 2025.5.1", "frequenz-repo-config[lib] == 0.13.5"] dev-pylint = [ - "pylint == 3.3.7", + "pylint == 3.3.8", # For checking the noxfile, docs/ script, and tests "frequenz-client-microgrid[dev-mkdocs,dev-noxfile,dev-pytest]", ] dev-pytest = [ - "pytest == 8.3.5", - "frequenz-repo-config[extra-lint-examples] == 0.13.4", + "pytest == 8.4.1", + "frequenz-repo-config[extra-lint-examples] == 0.13.5", "pytest-mock == 3.14.1", - "pytest-asyncio == 0.26.0", - "async-solipsism == 0.7", + "pytest-asyncio == 1.1.0", + "async-solipsism == 0.8", ] dev = [ "frequenz-client-microgrid[dev-mkdocs,dev-flake8,dev-formatting,dev-mkdocs,dev-mypy,dev-noxfile,dev-pylint,dev-pytest]", diff --git a/src/frequenz/client/microgrid/_metadata.py b/src/frequenz/client/microgrid/_metadata.py index 135dafca..b48c8fd6 100644 --- a/src/frequenz/client/microgrid/_metadata.py +++ b/src/frequenz/client/microgrid/_metadata.py @@ -7,9 +7,6 @@ from zoneinfo import ZoneInfo from frequenz.client.common.microgrid import MicrogridId -from timezonefinder import TimezoneFinder - -_timezone_finder = TimezoneFinder() @dataclass(frozen=True, kw_only=True) @@ -23,23 +20,7 @@ class Location: """The longitude of the microgrid in degree.""" timezone: ZoneInfo | None = None - """The timezone of the microgrid. - - If not passed during construction (or `None` is passed), and there is a `longitude` - and `latitude`, then the timezone wil be looked up in a database based on the - coordinates. This lookup could fail, in which case the timezone will still be - `None`. - """ - - def __post_init__(self) -> None: - """Initialize the timezone of the microgrid.""" - if self.latitude is None or self.longitude is None or self.timezone is not None: - return - - timezone = _timezone_finder.timezone_at(lat=self.latitude, lng=self.longitude) - if timezone: - # The dataclass is frozen, so it needs to use __setattr__ to set the timezone. - object.__setattr__(self, "timezone", ZoneInfo(key=timezone)) + """The timezone of the microgrid.""" @dataclass(frozen=True, kw_only=True) diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 1276d2b5..b14eb35f 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -3,8 +3,6 @@ """Tests for the microgrid metadata types.""" -from collections.abc import Iterator -from unittest.mock import MagicMock, patch from zoneinfo import ZoneInfo import pytest @@ -13,59 +11,20 @@ from frequenz.client.microgrid import Location, Metadata -@pytest.fixture -def timezone_finder() -> Iterator[MagicMock]: - """Return a mock timezone finder.""" - with patch( - "frequenz.client.microgrid._metadata._timezone_finder", autospec=True - ) as mock_timezone_finder: - yield mock_timezone_finder - - -@pytest.mark.parametrize( - "latitude, longitude, timezone", - [ - (None, None, None), - (52.52, None, None), - (None, 13.405, None), - (None, None, ZoneInfo(key="UTC")), - (52.52, None, ZoneInfo(key="UTC")), - (None, 13.405, ZoneInfo(key="UTC")), - (52.52, 13.405, ZoneInfo(key="UTC")), - ], - ids=str, -) -def test_location_timezone_not_looked_up_if_not_possible_or_necessary( - timezone_finder: MagicMock, +@pytest.mark.parametrize("latitude", [None, 52.52], ids=str) +@pytest.mark.parametrize("longitude", [None, 13.405], ids=str) +@pytest.mark.parametrize("timezone", [None, ZoneInfo(key="UTC")], ids=str) +def test_location_initialization( latitude: float | None, longitude: float | None, timezone: ZoneInfo | None, ) -> None: - """Test the location timezone is not looked up if is not necessary or possible.""" - timezone_finder.timezone_at.return_value = "Europe/Berlin" - + """Test location initialization with different combinations of parameters.""" location = Location(latitude=latitude, longitude=longitude, timezone=timezone) assert location.latitude == latitude assert location.longitude == longitude assert location.timezone == timezone - timezone_finder.timezone_at.assert_not_called() - - -@pytest.mark.parametrize("timezone", [None, "Europe/Berlin"], ids=str) -def test_location_timezone_lookup( - timezone_finder: MagicMock, timezone: str | None -) -> None: - """Test the location timezone is looked up if not provided and there is enough info.""" - timezone_finder.timezone_at.return_value = timezone - - location = Location(latitude=52.52, longitude=13.405) - - if timezone is None: - assert location.timezone is None - else: - assert location.timezone == ZoneInfo(key=timezone) - timezone_finder.timezone_at.assert_called_once_with(lat=52.52, lng=13.405) def test_metadata_initialization() -> None: @@ -81,11 +40,12 @@ def test_metadata_initialization() -> None: assert metadata.microgrid_id == microgrid_id assert metadata.location is None - # Test with only location + # Test with only location - timezone should be None even with lat/lng location = Location(latitude=52.52, longitude=13.405) metadata = Metadata(location=location) assert metadata.microgrid_id is None assert metadata.location == location + assert metadata.location.timezone is None # Test with both parameters metadata = Metadata(microgrid_id=microgrid_id, location=location)