Bug 2433807

Summary: python-apprise fails to build with Python 3.15: AssertionError: test_apprise_cli_persistent_storage
Product: [Fedora] Fedora Reporter: Karolina Surma <ksurma>
Component: python-appriseAssignee: Chris Caron <lead2gold>
Status: CLOSED RAWHIDE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: rawhideCC: ksurma, lead2gold, mhroncok
Target Milestone: ---Keywords: Reopened
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: 1.9.9-1 Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2026-03-31 17:29:21 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2412434    

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.

Comment 2 Chris Caron 2026-02-13 21:36:36 UTC
Typo in my last comment; ticket is: https://github.com/caronc/apprise/issues/1506

I've updated the repo to build against Python v3.15 with changes pending here: https://github.com/caronc/apprise/pull/1516

If all passes, I'll close this ticket.

Comment 3 Chris Caron 2026-02-15 13:33:52 UTC
Issue has been resolved upstream; will appear in next release.

Comment 4 Karolina Surma 2026-02-19 12:32:30 UTC
Thank you. Let me reopen it for now, so that my automation doesn't try to create new tickets. Let's close it once it's in Fedora.

Comment 5 Chris Caron 2026-03-31 14:18:49 UTC
We should be good to go now; https://src.fedoraproject.org/rpms/python-apprise

Will await your confirmation before closing