from i3pystatus.updates import Backend
import sys

# Remove first dir from sys.path to avoid shadowing dnf module from
# site-packages dir when this module executed directly on the CLI.
__module_dir = sys.path.pop(0)
try:
    import dnf
    HAS_DNF_BINDINGS = True
except ImportError:
    HAS_DNF_BINDINGS = False
finally:
    # Replace the directory we popped earlier
    sys.path.insert(0, __module_dir)


class Dnf(Backend):
    """
    Gets updates for RPM-based distributions using the `DNF API`_

    The notification body consists of the package name and version for each
    available update.

    .. _`DNF API`: http://dnf.readthedocs.io/en/latest/api.html
    """

    @property
    def updates(self):
        if HAS_DNF_BINDINGS:
            try:
                with dnf.Base() as base:
                    base.read_all_repos()
                    base.fill_sack()
                    upgrades = base.sack.query().upgrades().run()

                notif_body = ''.join([
                    '%s: %s-%s\n' % (pkg.name, pkg.version, pkg.release)
                    for pkg in upgrades
                ])
                return len(upgrades), notif_body
            except Exception as exc:
                self.logger.error('DNF update check failed', exc_info=True)
                return '?', exc.__str__()
        else:
            return '?', 'Failed to import DNF Python bindings'

Backend = Dnf

if __name__ == "__main__":
    """
    Call this module directly; Print the update count and notification body.
    """
    print("Updates: {}\n\n{}".format(*Backend().updates))

@@ -658,16 +658,952 @@
 api.html
+%0A%0A    .. note::%0A        Users running i3pystatus from a virtualenv may see the updates display%0A        as %60%60?%60%60 due to an inability to import the %60%60dnf%60%60 module. To ensure%0A        that i3pystatus can access the DNF Python bindings, the virtualenv%0A        should be created with %60%60--system-site-packages%60%60.%0A%0A        If using %60pyenv-virtualenv%60_, the virtualenv must additionally be%0A        created to use the system Python binary:%0A%0A        .. code-block:: bash%0A%0A            $ pyenv virtualenv --system-site-packages --python=/usr/bin/python3 pyenv_name%0A%0A        To invoke i3pystatus with this virtualenv, your %60%60bar%60%60 section in%0A        %60%60~/.config/i3/config%60%60 would look like this:%0A%0A        .. code-block:: bash%0A%0A            bar %7B%0A                position top%0A                status_command PYENV_VERSION=pyenv_name python /path/to/i3pystatus/script.py%0A            %7D%0A%0A    .. _%60pyenv-virtualenv%60: https://github.com/yyuu/pyenv-virtualenv
 %0A    %22%22%22

Add documentation about running in virtualenv