Bug 2433807 - python-apprise fails to build with Python 3.15: AssertionError: test_apprise_cli_persistent_storage
Summary: python-apprise fails to build with Python 3.15: AssertionError: test_apprise_...
Keywords:
Status: ASSIGNED
Alias: None
Product: Fedora
Classification: Fedora
Component: python-apprise
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Chris Caron
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: PYTHON3.15
TreeView+ depends on / blocked
 
Reported: 2026-01-28 13:23 UTC by Karolina Surma
Modified: 2026-02-03 14:17 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Karolina Surma 2026-01-28 13:23:04 UTC
python-apprise fails to build with Python 3.15.0a5.

_____________________ test_apprise_cli_persistent_storage ______________________

tmpdir = local('/tmp/pytest-of-mockbuild/pytest-0/test_apprise_cli_persistent_st0')

    @pytest.mark.skipif(
        sys.platform == "win32", reason="Unreliable results to be determined"
    )
    def test_apprise_cli_persistent_storage(tmpdir):
        """
        CLI: test persistent storage
    
        """
    
        # This is a made up class that is just used to verify
        class NoURLIDNotification(NotifyBase):
            """A no URL ID."""
    
            # Update URL identifier
            url_identifier = False
    
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
    
            def send(self, **kwargs):
    
                # Pretend everything is okay
                return True
    
            def url(self, *args, **kwargs):
                # Support URL
                return "noper://"
    
            def parse_url(self, *args, **kwargs):
                # parse our url
                return {"schema": "noper"}
    
        # This is a made up class that is just used to verify
        class TestNotification(NotifyBase):
            """A Testing Script."""
    
            def __init__(self, *args, **kwargs):
                super().__init__(*args, **kwargs)
    
            def send(self, **kwargs):
    
                # Test our persistent settings
                self.store.set("key", "value")
                assert self.store.get("key") == "value"
    
                # Pretend everything is okay
                return True
    
            def url(self, *args, **kwargs):
                # Support URL
                return "test://"
    
            def parse_url(self, *args, **kwargs):
                # parse our url
                return {"schema": "test"}
    
        # assign test:// to our  notification defined above
        N_MGR["test"] = TestNotification
        N_MGR["noper"] = NoURLIDNotification
    
        # Write a simple text based configuration file
        config = tmpdir.join("apprise.cfg")
        buf = cleandoc("""
        # Create a config file we can source easily
        test=test://
        noper=noper://
    
        # Define a second test URL that will
        two-urls=test://
    
        # Create another entry that has no tag associatd with it
        test://?entry=2
        """)
        config.write(buf)
    
        runner = CliRunner()
    
        # Generate notification that creates persistent data
        result = runner.invoke(
            cli.main,
            [
                "--storage-path",
                str(tmpdir),
                "--config",
                str(config),
                "storage",
                "list",
            ],
        )
        # list our entries
        assert result.exit_code == 0
    
        # our persist storage has not been created yet
        _stdout = result.stdout.strip()
        assert re.match(
            r"^1\.\s+[a-z0-9]{8}\s+0\.00B\s+unused\s+-\s+test://\s*",
            _stdout,
            re.MULTILINE,
        )
    
        # An invalid mode specified
        result = runner.invoke(
            cli.main,
            [
                "--storage-path",
                str(tmpdir),
                "--storage-mode",
                "invalid",
                "--config",
                str(config),
                "-g",
                "test",
                "-t",
                "title",
                "-b",
                "body",
            ],
        )
        # Bad mode specified
        assert result.exit_code == 2
    
        # Invalid uid lenth specified
        result = runner.invoke(
            cli.main,
            [
                "--storage-path",
                str(tmpdir),
                "--storage-mode",
                "flush",
                "--storage-uid-length",
                1,
                "--config",
                str(config),
                "-g",
                "test",
                "-t",
                "title",
                "-b",
                "body",
            ],
        )
        # storage uid length to small
        assert result.exit_code == 2
    
        # No files written yet; just config file exists
        dir_content = os.listdir(str(tmpdir))
        assert len(dir_content) == 1
        assert "apprise.cfg" in dir_content
    
        # Generate notification that creates persistent data
        result = runner.invoke(
            cli.main,
            [
                "--storage-path",
                str(tmpdir),
                "--storage-mode",
                "flush",
                "--config",
                str(config),
                "-t",
                "title",
                "-b",
                "body",
                "-g",
                "test",
            ],
        )
        # We parsed our data accordingly
        assert result.exit_code == 0
    
        dir_content = os.listdir(str(tmpdir))
        assert len(dir_content) == 2
        assert "apprise.cfg" in dir_content
        assert "ea482db7" in dir_content
    
        # Have a look at our storage listings
        result = runner.invoke(
            cli.main,
            [
                "--storage-path",
                str(tmpdir),
                "--config",
                str(config),
                "storage",
                "list",
            ],
        )
        # list our entries
        assert result.exit_code == 0
    
        _stdout = result.stdout.strip()
>       assert re.match(
            r"^1\.\s+[a-z0-9_-]{8}\s+81\.00B\s+active\s+-\s+test://$",
            _stdout,
            re.MULTILINE,
        )
E       AssertionError: assert None
E        +  where None = <function match at 0x7f6ebe9e1c70>('^1\\.\\s+[a-z0-9_-]{8}\\s+81\\.00B\\s+active\\s+-\\s+test://$', '1. ea482db7                                             84.00B   active\n      - test://\n      tags: test\n      - test://\n      tags: two-urls\n      - test://', re.MULTILINE)
E        +    where <function match at 0x7f6ebe9e1c70> = re.match
E        +    and   re.MULTILINE = re.MULTILINE

https://docs.python.org/3.15/whatsnew/3.15.html

For the build logs, see:
https://copr-be.cloud.fedoraproject.org/results/@python/python3.15/fedora-rawhide-x86_64/10056729-python-apprise/

For all our attempts to build python-apprise with Python 3.15, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.15/package/python-apprise/

Testing and mass rebuild of packages is happening in copr.
You can follow these instructions to test locally in mock if your package builds with Python 3.15:
https://copr.fedorainfracloud.org/coprs/g/python/python3.15/

Let us know here if you have any questions.

Python 3.15 is planned to be included in Fedora 45.
To make that update smoother, we're building Fedora packages with all pre-releases of Python 3.15.
A build failure prevents us from testing all dependent packages (transitive [Build]Requires),
so if this package is required a lot, it's important for us to get it fixed soon.

We'd appreciate help from the people who know this package best,
but if you don't want to work on this now, let us know so we can try to work around it on our side.

Comment 1 Chris Caron 2026-02-03 14:17:56 UTC
I have created https://github.com/caronc/apprise/issues/1500;  I'll do my best to debug this, but if you are able to help assist with this earlier, I would very much appreciate it.  At this time I do not know what was introduced in v3.15 that would break this.


Note You need to log in before you can comment on or make changes to this bug.