Skip to content

Fix "has no attribute 'keys' error" #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

phresnel
Copy link

This fixes a strange error I get for Python 3.4.1 as well as Python 2.7.8.

It only appears on one of three test machines, all of which have the exact same Python versions, as well as the exact same uname -a.

The error I get for Python 3 is:

  File "./nocms.py", line 78, in compile
    extension_configs=extension_configs)
  File "/usr/lib/python3.4/site-packages/markdown/__init__.py", line 410, in markdown
    md = Markdown(*args, **kwargs)
  File "/usr/lib/python3.4/site-packages/markdown/__init__.py", line 137, in __init__
    configs=kwargs.get('extension_configs', {}))
  File "/usr/lib/python3.4/site-packages/markdown/__init__.py", line 165, in registerExtensions
    ext.extendMarkdown(self, globals())
  File "/usr/lib/python3.4/site-packages/markdown/extensions/math.py", line 37, in extendMarkdown
    configs = self.getConfigs()
  File "/usr/lib/python3.4/site-packages/markdown/extensions/__init__.py", line 28, in getConfigs
    return dict([(key, self.getConfig(key)) for key in self.config.keys()])
AttributeError: 'dict_items' object has no attribute 'keys'

For Python 2 I get:

** snip **
AttributeError: 'list' object has no attribute 'keys'

The strangeness lies in the irreproducibility on two of three near-identical Fedora machines. Here's my uname:

uname -a
Linux desktop 3.17.7-300.fc21.x86_64 #1 SMP Wed Dec 17 03:08:44 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

Possibly there was some change in python-markdown, but it seems that at least the python files for /usr/lib/python/.../markdown/extensions/init.py are the same.

In any case, this Pull Request should fix the error.

This constructor style corresponds to some other standard extensions' constructors (e.g. toc.py and codehilite.py)
@mitya57
Copy link
Owner

mitya57 commented Jan 16, 2015

Hi,

According to the documentation I am doing it the right way.

How are you trying to initialize the extension class? The valid ways are only MathExtension() and MathExtension(enable_dollar_delimiter=True).

The configuration is not a list, it is a dict.

@phresnel
Copy link
Author

The thing is, if I print config within __init__.py

def getConfigs(self):
        """ Return all configs settings as a dict. """
        print(self.config)
        return dict([(key, self.getConfig(key)) for key in self.config.keys()])

then it only prints an empty data structure. With my change, it is no longer empty. I will investigate this a bit more.

@phresnel
Copy link
Author

Wow. Even though my Fedora installations are almost identical, I have two totally different versions of extensions/__init__.py, which probably IS the root of the problem.

On the box that gives problems, the constructor goes like:

""" Base class for extensions to subclass. """
def __init__(self, configs = {}):
    """Create an instance of an Extention.

    Keyword arguments:

    * configs: A dict of configuration setting used by an Extension.
    """
    self.config = configs

And that code is older than February 2013 (https://github.com/waylan/Python-Markdown/blob/579288c5eb684dd09d1ef298929a566f40151205/markdown/extensions/__init__.py), I am not even sure if I used Python then already, but the Fedora install is just a few weeks old.

Whereas on the boxes that are good, it goes like:

def __init__(self, *args, **kwargs):
    """ Initiate Extension and set up configs. """

    # check for configs arg for backward compat.
    # (there only ever used to be one so we use arg[0])
    if len(args):
        self.setConfigs(args[0])
        warnings.warn('Extension classes accepting positional args is '
                      'pending Deprecation. Each setting should be '
                      'passed into the Class as a keyword. Positional '
                      'args will be deprecated in version 2.6 and raise '
                      'an error in version 2.7. See the Release Notes for '
                      'Python-Markdown version 2.5 for more info.',
                      PendingDeprecationWarning)
    # check for configs kwarg for backward compat.
    if 'configs' in kwargs.keys():
        self.setConfigs(kwargs.pop('configs', {}))
        warnings.warn('Extension classes accepting a dict on the single '
                      'keyword "config" is pending Deprecation. Each '
                      'setting should be passed into the Class as a '
                      'keyword directly. The "config" keyword will be '
                      'deprecated in version 2.6 and raise an error in '
                      'version 2.7. See the Release Notes for '
                      'Python-Markdown version 2.5 for more info.',
                      PendingDeprecationWarning)
    # finally, use kwargs
    self.setConfigs(kwargs)

i.e. the current version. No wonder the options were empty!

I am not sure whom to blame, but you are out of play. Thanks for contributing your plugin!

@phresnel
Copy link
Author

To close the topic and provide the final hint to anyone who came from the internet:

On the other boxes, I use pip, on my desktop, however, I used the distro's package manager for python-markdown installation. Mistake!

The problem was that my Linux Distro, Fedora 21, has an old version of python-markdown in the repositories, 2.4.1, whereas Python pip has 2.5.2.

Lesson to be learned: Use pip.

@phresnel phresnel closed this Jan 16, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants