ipython / traitlets

A lightweight Traits like module
https://traitlets.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
615 stars 201 forks source link

flake8 sees 'c' as an undefined name #502

Open cclauss opened 5 years ago

cclauss commented 5 years ago

From: https://traitlets.readthedocs.io/en/latest/config.html#python-configuration-files

A Config instance [...] is available inside the config file as c, and you simply set attributes on this.

This preestablishment of an external global variable is a bit of magic that causes linters (and sometimes humans) to scratch their heads. Would there be an OPTIONAL way to be explicit instead of implicit about the origins of c? Something OPTIONAL like like from ipython import c or from traitlets import c that would provide a quick hint as to where c came from.

flake8 testing of https://github.com/foo/bar on Python 3.7.0

$ flake8 . --count --select=E901,E999,F821,F822,F823 --show-source --statistics

./utils/bar.py:97:1: F821 undefined name 'c'
c.foo = 'bar'
^
1     F821 undefined name 'c'
1

Usually I would use global c to explain to humans and flake8 that 'c' is created in the global namespace by code that lies outside this file. However, global does not work in an un-indented code bloc which is where 'c' is usually used.

One solution would be to mark the code with a linter directive: c.foo = 'bar' # noqa: F821 but looks clunky and maintainers often resist adding linter-specific directives to their code. It is a shame when maintainers avoid linting a whole codebase because they do not know how to cleanly resolve one issue.

cclauss commented 5 years ago

Perhaps we could placate flake8 with:

from IPython import get_config()
c = get_config()
minrk commented 5 years ago

Yeah, I think a top-level traitlets.get_config would be useful for linting. For now, you can do:

c = get_config()  # noqa 

Since the get_config name is injected into the module namespace.

cclauss commented 5 years ago

It is the “injecting” that throws the linters — they tend to follow the Zen of Python: explicit is is better than implicit