logilab-common #8849 Using plugins, options and .pylintrc crashes PyLint [resolved]

Laurent reported on python-projects

I am trying to create a plugin that declares its own options for use with the .pylintrc file. This only works when the plugin is auto-loaded from the pylint.checkers package. When the plugin is outside pylint.checkers (given by .pylintrc's load-plugins), I get the traceback:

Traceback (most recent call last):
File "D:\Apps\Python26\lib\runpy.py", line 121, in _run_module_as_main
  "__main__", fname, loader, pkg_name)
File "D:\Apps\Python26\lib\runpy.py", line 34, in _run_code
  exec code in run_globals
File "D:\Apps\Python26\lib\site-packages\pylint-0.18.0-py2.6.egg\pylint\lint.py", line 932, in <module>
  Run(sys.argv[1:])
File "D:\Apps\Python26\lib\site-packages\pylint-0.18.0-py2.6.egg\pylint\lint.py", line 854, in __init__
  linter.load_plugin_modules(plugins)
File "D:\Apps\Python26\lib\site-packages\pylint-0.18.0-py2.6.egg\pylint\lint.py", line 300, in load_plugin_modules
  module.register(self)
File "custom.py", line 15, in register
  linter.register_checker(CustomChecker(linter))
File "D:\Apps\Python26\lib\site-packages\pylint-0.18.0-py2.6.egg\pylint\lint.py", line 346, in register_checker
  self.register_options_provider(checker)
File "d:\apps\python26\lib\site-packages\logilab_common-0.39.0-py2.6.egg\logilab\common\configuration.py", line 385, in register_options_provider
  non_group_spec_options, provider)
File "d:\apps\python26\lib\site-packages\logilab_common-0.39.0-py2.6.egg\logilab\common\configuration.py", line 403, in add_option_group
  self._config_parser.add_section(group_name)
File "D:\Apps\Python26\lib\ConfigParser.py", line 245, in add_section
  raise DuplicateSectionError(section)
ConfigParser.DuplicateSectionError: Section 'CUSTOMCHECK' already exists

To recreate this configuration:

  1. Create the module custom.py, in a package other than pylint.checkers

  2. In this module, declare a checker with custom options:

    from pylint.checkers import BaseChecker
    from pylint.interfaces import IASTNGChecker
    class CustomChecker(BaseChecker):
      __implements__ = IASTNGChecker
      name = 'customcheck'
      priority = -1
      options = ( ('custom',
                {'default': ('value', ),
                 'type': 'csv',
                 'metavar': '<attributes>',
                 'help': 'Custom option' }), )
    
    def register(linter):
      print 'Registering custom checker'
      linter.register_checker(CustomChecker(linter))
    
  3. Create a custom.pylintrc file, that uses, loads and declares the checker's section:

    [MASTER]
    load-plugins=custom
    [MESSAGE CONTROL]
    enable-checker=customcheck
    [CUSTOMCHECK]
    custom=v1,v2
    
  4. Launch PyLint:

    python -m pylint.lint --rcfile=custom.pylintrc custom.py
    

Analysis:

This happens because, in lint.py, class Run, method __init__: a. Internal plugins are loaded (using linter.load_plugin_modules(self._plugins) b. The .pylintrc file is loaded (using linter.read_config_file(), this overrides already declared contents) c. External plugins are loaded (using linter.load_plugin_modules(plugins)).

This last step fails, as logilab-common is trying to (re-)add a section that already exists in the config file, loaded in b.

prioritynormal
typebug
done in0.45.1
load0.500
load left0.000
closed by<not specified>