Note: This is a public test instance of Red Hat Bugzilla. The data contained within is a snapshot of the live data so any changes you make will not be reflected in the production Bugzilla. Email is disabled so feel free to test any aspect of the site that you want. File any problems you find or give feedback at bugzilla.redhat.com.
Bug 1913619 - python-apprise fails to build with Python 3.10: AssertionError assert 1 == 3
Summary: python-apprise fails to build with Python 3.10: AssertionError assert 1 == 3
Keywords:
Status: CLOSED CURRENTRELEASE
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.10
TreeView+ depends on / blocked
 
Reported: 2021-01-07 09:22 UTC by Tomáš Hrnčiar
Modified: 2021-01-15 07:00 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2021-01-15 03:28:44 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Tomáš Hrnčiar 2021-01-07 09:22:29 UTC
python-apprise fails to build with Python 3.10.0a4.

=================================== FAILURES ===================================
___________________________ test_apprise_cli_nux_env ___________________________

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

    def test_apprise_cli_nux_env(tmpdir):
        """
        CLI: Nux Environment
    
        """
    
        class GoodNotification(NotifyBase):
            def __init__(self, *args, **kwargs):
                super(GoodNotification, self).__init__(*args, **kwargs)
    
            def notify(self, **kwargs):
                # Pretend everything is okay
                return True
    
            def url(self, *args, **kwargs):
                # Support url()
                return 'good://'
    
        class BadNotification(NotifyBase):
            def __init__(self, *args, **kwargs):
                super(BadNotification, self).__init__(*args, **kwargs)
    
            def notify(self, **kwargs):
                # Force a notification failure
                return False
    
            def url(self, *args, **kwargs):
                # Support url()
                return 'bad://'
    
        # Set up our notification types
        SCHEMA_MAP['good'] = GoodNotification
        SCHEMA_MAP['bad'] = BadNotification
    
        runner = CliRunner()
        result = runner.invoke(cli.main)
        # no servers specified; we return 1 (non-zero)
        assert result.exit_code == 1
    
        result = runner.invoke(cli.main, ['-v'])
        assert result.exit_code == 1
    
        result = runner.invoke(cli.main, ['-vv'])
        assert result.exit_code == 1
    
        result = runner.invoke(cli.main, ['-vvv'])
        assert result.exit_code == 1
    
        result = runner.invoke(cli.main, ['-vvvv'])
        assert result.exit_code == 1
    
        # Display version information and exit
        result = runner.invoke(cli.main, ['-V'])
        assert result.exit_code == 0
    
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'good://localhost',
        ])
        assert result.exit_code == 0
    
        # Run in synchronous mode
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'good://localhost',
            '--disable-async',
        ])
        assert result.exit_code == 0
    
        # Test Debug Mode (--debug)
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'good://localhost',
            '--debug',
        ])
        assert result.exit_code == 0
    
        # Test Debug Mode (-D)
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'good://localhost',
            '-D',
        ])
        assert result.exit_code == 0
    
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            'good://localhost',
        ], input='test stdin body\n')
        assert result.exit_code == 0
    
        # Run in synchronous mode
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            'good://localhost',
            '--disable-async',
        ], input='test stdin body\n')
        assert result.exit_code == 0
    
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'bad://localhost',
        ])
        assert result.exit_code == 1
    
        # Run in synchronous mode
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'bad://localhost',
            '-Da',
        ])
        assert result.exit_code == 1
    
        # Testing with the --dry-run flag reveals a successful response since we
        # don't actually execute the bad:// notification; we only display it
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            'bad://localhost',
            '--dry-run',
        ])
        assert result.exit_code == 0
    
        # Write a simple text based configuration file
        t = tmpdir.mkdir("apprise-obj").join("apprise")
        buf = """
        # Include ourselves
        include {}
    
        taga,tagb=good://localhost
        tagc=good://nuxref.com
        """.format(str(t))
        t.write(buf)
    
        # This will read our configuration and not send any notices at all
        # because we assigned tags to all of our urls and didn't identify
        # a specific match below.
    
        # 'include' reference in configuration file would have included the file a
        # second time (since recursion default is 1).
        result = runner.invoke(cli.main, [
            '-b', 'test config',
            '--config', str(t),
        ])
        # Even when recursion take place, tags are all honored
        # so 2 is returned because nothing was notified
        assert result.exit_code == 3
    
        # This will send out 1 notification because our tag matches
        # one of the entries above
        # translation: has taga
        result = runner.invoke(cli.main, [
            '-b', 'has taga',
            '--config', str(t),
            '--tag', 'taga',
        ])
        assert result.exit_code == 0
    
        # Test recursion
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            '--config', str(t),
            '--tag', 'tagc',
            # Invalid entry specified for recursion
            '-R', 'invalid',
        ])
        assert result.exit_code == 2
    
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            '--config', str(t),
            '--tag', 'tagc',
            # missing entry specified for recursion
            '--recursive-depth',
        ])
        assert result.exit_code == 2
    
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            '--config', str(t),
            '--tag', 'tagc',
            # Disable recursion (thus inclusion will be ignored)
            '-R', '0',
        ])
        assert result.exit_code == 0
    
        # Test recursion
        result = runner.invoke(cli.main, [
            '-t', 'test title',
            '-b', 'test body',
            '--config', str(t),
            '--tag', 'tagc',
            # Recurse up to 5 times
            '--recursion-depth', '5',
        ])
        assert result.exit_code == 0
    
        # This will send out 2 notifications because by specifying 2 tag
        # entries, we 'or' them together:
        # translation: has taga or tagb or tagd
        result = runner.invoke(cli.main, [
            '-b', 'has taga OR tagc OR tagd',
            '--config', str(t),
            '--tag', 'taga',
            '--tag', 'tagc',
            '--tag', 'tagd',
        ])
        assert result.exit_code == 0
    
        # Write a simple text based configuration file
        t = tmpdir.mkdir("apprise-obj2").join("apprise-test2")
        buf = """
        good://localhost/1
        good://localhost/2
        good://localhost/3
        good://localhost/4
        good://localhost/5
        myTag=good://localhost/6
        """
        t.write(buf)
    
        # This will read our configuration and send a notification to
        # the first 5 entries in the list, but not the one that has
        # the tag associated with it
        result = runner.invoke(cli.main, [
            '-b', 'test config',
            '--config', str(t),
        ])
        assert result.exit_code == 0
    
        # Test our notification type switch (it defaults to info) so we want to
        # try it as a different value. Should return without a problem
        result = runner.invoke(cli.main, [
            '-b', '# test config',
            '--config', str(t),
            '-n', 'success',
        ])
        assert result.exit_code == 0
    
        # Test our notification type switch when set to something unsupported
        result = runner.invoke(cli.main, [
            '-b', 'test config',
            '--config', str(t),
            '--notification-type', 'invalid',
        ])
        # An error code of 2 is returned if invalid input is specified on the
        # command line
        assert result.exit_code == 2
    
        # The notification type switch is case-insensitive
        result = runner.invoke(cli.main, [
            '-b', 'test config',
            '--config', str(t),
            '--notification-type', 'WARNING',
        ])
        assert result.exit_code == 0
    
        # Test our formatting switch (it defaults to text) so we want to try it as
        # a different value. Should return without a problem
        result = runner.invoke(cli.main, [
            '-b', '# test config',
            '--config', str(t),
            '-i', 'markdown',
        ])
        assert result.exit_code == 0
    
        # Test our formatting switch when set to something unsupported
        result = runner.invoke(cli.main, [
            '-b', 'test config',
            '--config', str(t),
            '--input-format', 'invalid',
        ])
        # An error code of 2 is returned if invalid input is specified on the
        # command line
        assert result.exit_code == 2
    
        # The formatting switch is not case sensitive
        result = runner.invoke(cli.main, [
            '-b', '# test config',
            '--config', str(t),
            '--input-format', 'HTML',
        ])
        assert result.exit_code == 0
    
        # As a way of ensuring we match the first 5 entries, we can run a
        # --dry-run against the same result set above and verify the output
        result = runner.invoke(cli.main, [
            '-b', 'test config',
            '--config', str(t),
            '--dry-run',
        ])
        assert result.exit_code == 0
        lines = re.split(r'[\r\n]', result.output.strip())
        # 5 lines of all good:// entries matched
        assert len(lines) == 5
        # Verify we match against the remaining good:// entries
        for i in range(0, 5):
            assert lines[i].endswith('good://')
    
        # This will fail because nothing matches mytag. It's case sensitive
        # and we would only actually match against myTag
        result = runner.invoke(cli.main, [
            '-b', 'has mytag',
            '--config', str(t),
            '--tag', 'mytag',
        ])
        assert result.exit_code == 3
    
        # Same command as the one identified above except we set the --dry-run
        # flag. This causes our list of matched results to be printed only.
        # However, since we don't match anything; we still fail with a return code
        # of 2.
        result = runner.invoke(cli.main, [
            '-b', 'has mytag',
            '--config', str(t),
            '--tag', 'mytag',
            '--dry-run'
        ])
        assert result.exit_code == 3
    
        # Here is a case where we get what was expected; we also attach a file
        result = runner.invoke(cli.main, [
            '-b', 'has myTag',
            '--config', str(t),
            '--attach', join(dirname(__file__), 'var', 'apprise-test.gif'),
            '--tag', 'myTag',
        ])
        assert result.exit_code == 0
    
        # Testing with the --dry-run flag reveals the same positive results
        # because there was at least one match
        result = runner.invoke(cli.main, [
            '-b', 'has myTag',
            '--config', str(t),
            '--tag', 'myTag',
            '--dry-run',
        ])
        assert result.exit_code == 0
    
        #
        # Test environment variables
        #
        # Write a simple text based configuration file
        t2 = tmpdir.mkdir("apprise-obj-env").join("apprise")
        buf = """
        # A general one
        good://localhost
    
        # A failure (if we use the fail tag)
        fail=bad://localhost
    
        # A normal one tied to myTag
        myTag=good://nuxref.com
        """
        t2.write(buf)
    
        with environ(APPRISE_URLS="good://localhost"):
            # This will load okay because we defined the environment
            # variable with a valid URL
            result = runner.invoke(cli.main, [
                '-b', 'test environment',
                # Test that we ignore our tag
                '--tag', 'mytag',
            ])
            assert result.exit_code == 0
    
            # Same action but without --tag
            result = runner.invoke(cli.main, [
                '-b', 'test environment',
            ])
            assert result.exit_code == 0
    
        with environ(APPRISE_URLS="      "):
            # An empty string is not valid and therefore not loaded
            # so the below fails
            result = runner.invoke(cli.main, [
                '-b', 'test environment',
            ])
>           assert result.exit_code == 3
E           assert 1 == 3
E             +1
E             -3

test/test_cli.py:440: AssertionError

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

For all our attempts to build python-apprise with Python 3.10, see:
https://copr.fedorainfracloud.org/coprs/g/python/python3.10/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.10:
https://copr.fedorainfracloud.org/coprs/g/python/python3.10/

Let us know here if you have any questions.

Python 3.10 will be included in Fedora 35. To make that update smoother, we're building Fedora packages with early pre-releases of Python 3.10.
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 2021-01-10 21:09:33 UTC
Hi, thanks for reporting the issue.  It's been fixed in this commit here: https://github.com/caronc/apprise/commit/5e002044a43c00243763af8d9e336ed67124ccd7

I'll see if i can just push a small patch to update the test from within the spec file

Comment 2 Chris Caron 2021-01-15 03:28:44 UTC
The issue has now been resolved
See: https://bodhi.fedoraproject.org/updates/FEDORA-2021-9a880d95ac

Comment 3 Tomáš Hrnčiar 2021-01-15 07:00:37 UTC
Thank you


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