Skip to content

Conversation

@nkr0
Copy link
Contributor

@nkr0 nkr0 commented Oct 7, 2025

Pull Request Checklist

  • Ensured tests pass and (if applicable) updated functional test output
  • Conformed to code style guidelines by running appropriate linting tools
  • Added tests for changed code
  • Updated documentation for changed code

A test fails on Debian (forky), and therefore probably on Ubuntu, when tzdata (python package) is not installed. I do have tzdata debian package installed (this is not a python package, but still a dependency of python). Perhaps it passes in CI because setup-python includes tzdata. ?

$ pytest pelican/tests/test_utils.py::TestUtils::test_get_date
=============================================================================================== test session starts ================================================================================================
platform linux -- Python 3.13.7, pytest-8.4.2, pluggy-1.6.0
rootdir: pelican
configfile: tox.ini
plugins: cov-7.0.0, xdist-3.8.0, anyio-4.11.0
2 workers [1 item]      
F                                                                                                                                                                                                            [100%]
===================================================================================================== FAILURES =====================================================================================================
_____________________________________________________________________________________________ TestUtils.test_get_date ______________________________________________________________________________________________
[gw0] linux -- Python 3.13.7 /usr/bin/python3

key = 'EST'

    def load_tzdata(key):
        from importlib import resources
    
        components = key.split("/")
        package_name = ".".join(["tzdata.zoneinfo"] + components[:-1])
        resource_name = components[-1]
    
        try:
>           path = resources.files(package_name).joinpath(resource_name)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

/usr/lib/python3.13/zoneinfo/_common.py:12: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/python3.13/importlib/resources/_common.py:46: in wrapper
    return func(anchor)
           ^^^^^^^^^^^^
/usr/lib/python3.13/importlib/resources/_common.py:56: in files
    return from_package(resolve(anchor))
                        ^^^^^^^^^^^^^^^
/usr/lib/python3.13/functools.py:934: in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/usr/lib/python3.13/importlib/resources/_common.py:82: in _
    return importlib.import_module(cand)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

name = 'tzdata.zoneinfo', package = None

    def import_module(name, package=None):
        """Import a module.
    
        The 'package' argument is required when performing a relative import. It
        specifies the package to use as the anchor point from which to resolve the
        relative import to an absolute import.
    
        """
        level = 0
        if name.startswith('.'):
            if not package:
                raise TypeError("the 'package' argument is required to perform a "
                                f"relative import for {name!r}")
            for character in name:
                if character != '.':
                    break
                level += 1
>       return _bootstrap._gcd_import(name[level:], package, level)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
E       ModuleNotFoundError: No module named 'tzdata'

/usr/lib/python3.13/importlib/__init__.py:88: ModuleNotFoundError

During handling of the above exception, another exception occurred:

self = <pelican.tests.test_utils.TestUtils testMethod=test_get_date>

    def test_get_date(self):
        # valid ones
        date = utils.SafeDatetime(year=2012, month=11, day=22)
        date_hour = utils.SafeDatetime(year=2012, month=11, day=22, hour=22, minute=11)
        date_hour_z = utils.SafeDatetime(
            year=2012, month=11, day=22, hour=22, minute=11, tzinfo=timezone.utc
        )
        date_hour_est = utils.SafeDatetime(
>           year=2012, month=11, day=22, hour=22, minute=11, tzinfo=ZoneInfo("EST")
                                                                    ^^^^^^^^^^^^^^^
        )

pelican/tests/test_utils.py:68: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

key = 'EST'

    def load_tzdata(key):
        from importlib import resources
    
        components = key.split("/")
        package_name = ".".join(["tzdata.zoneinfo"] + components[:-1])
        resource_name = components[-1]
    
        try:
            path = resources.files(package_name).joinpath(resource_name)
            # gh-85702: Prevent PermissionError on Windows
            if path.is_dir():
                raise IsADirectoryError
            return path.open("rb")
        except (ImportError, FileNotFoundError, UnicodeEncodeError, IsADirectoryError):
            # There are four types of exception that can be raised that all amount
            # to "we cannot find this key":
            #
            # ImportError: If package_name doesn't exist (e.g. if tzdata is not
            #   installed, or if there's an error in the folder name like
            #   Amrica/New_York)
            # FileNotFoundError: If resource_name doesn't exist in the package
            #   (e.g. Europe/Krasnoy)
            # UnicodeEncodeError: If package_name or resource_name are not UTF-8,
            #   such as keys containing a surrogate character.
            # IsADirectoryError: If package_name without a resource_name specified.
>           raise ZoneInfoNotFoundError(f"No time zone found with key {key}")
E           zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key EST'

/usr/lib/python3.13/zoneinfo/_common.py:29: ZoneInfoNotFoundError
============================================================================================= short test summary info ==============================================================================================
FAILED pelican/tests/test_utils.py::TestUtils::test_get_date - zoneinfo._common.ZoneInfoNotFoundError: 'No time zone found with key EST'

Is there a reason to explicitly mark this dependency as only for Windows?

@nkr0
Copy link
Contributor Author

nkr0 commented Oct 7, 2025

Looks like the issue is related to a change in Debian. So this should pop in Ubuntu as well.
python-kasa/python-kasa#1579
https://www.debian.org/releases/trixie/release-notes/issues.en.html#timezones-split-off-into-tzdata-legacy-package
Instead of adding a dependency, I now change the test to use Asia/Jakarta. This works in old and new Debian/Ubuntu versions. To avoid tests from breaking due to daylight savings, a city closer to the equator and that does not use daylight savings is selected.

@nkr0 nkr0 changed the title tzdata dependency for linux Oct 7, 2025
@minchinweb
Copy link
Contributor

The test was probably marked as "Windows only" because Linux platforms tended to have a timezone database installed at a system level and available to Pelican, whereas on Windows the most straightforward way to have the timezone database was to install Python's tzdata package.

@nkr0
Copy link
Contributor Author

nkr0 commented Oct 17, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants