Skip to content
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

Optparse conflict when invoking as module vs. via entry point #39

Open
sco1 opened this issue Jan 18, 2020 · 2 comments
Open

Optparse conflict when invoking as module vs. via entry point #39

sco1 opened this issue Jan 18, 2020 · 2 comments

Comments

@sco1
Copy link

sco1 commented Jan 18, 2020

Migrating this, as recommended, from a downstream flake8 issue. As the issue disappears with the latest flake8 version from the master branch (which has migrated away from entrypoints), it was suggested that this might be an issue with entrypoints. I've provided the reproduction steps from the downstream issue below, please let me know if there's something entrypoint-specific that would be more helpful for your triage.

I've installed a custom flake8 plugin into a fresh Python 3.8.1 virtualenv using the following setup.py and pip install -e .

from setuptools import setup


setup(
    name="flake8-test",
    version="1.0.0",
    description="Flake8 test",
    author="hello",
    entry_points={
        "flake8.extension": ["TST = flake8_test:TestChecker"]
    },
    install_requires=["flake8"],
)

Using the following skeleton (flake8_test.py):

from flake8.options.manager import OptionManager


class TestChecker:
    name = "flake8-test"
    version = "1.0.0"

    def __init__(self, tree, lines):
        self.lines = lines
        self.tree = tree

    def run(self):
        yield (1, 1, "This is a test", TestChecker)

    @classmethod
    def add_options(cls, parser) -> None:
        """Add custom configuration option(s) to flake8."""
        parser.add_option(
            "--test-config-option",
            default=False,
            action="store_true",
            parse_from_config=True,
            help="This is a test"
        )

    @classmethod
    def parse_options(cls, options) -> None:
        """Parse the custom configuration options given to flake8."""
        cls.test_config_option = options.test_config_option

I recieve the following when invoking as a module:

$ python -m flake8 setup.py
Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\runpy.py", line 193, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\test\.venv\lib\site-packages\flake8\__main__.py", line 4, in <module>
    cli.main()
  File "C:\test\.venv\lib\site-packages\flake8\main\cli.py", line 18, in main
    app.run(argv)
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 393, in run
    self._run(argv)
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 380, in _run
    self.initialize(argv)
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 364, in initialize
    self.register_plugin_options()
  File "C:\test\.venv\lib\site-packages\flake8\main\application.py", line 205, in register_plugin_options
    self.check_plugins.register_options(self.option_manager)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 489, in register_options
    list(self.manager.map(register_and_enable))
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 297, in map
    yield func(self.plugins[name], *args, **kwargs)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 485, in register_and_enable
    call_register_options(plugin)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 397, in generated_function
    return method(optmanager, *args, **kwargs)
  File "C:\test\.venv\lib\site-packages\flake8\plugins\manager.py", line 216, in register_options
    add_options(optmanager)
  File "C:\test\flake8_test.py", line 18, in add_options
    parser.add_option(
  File "C:\test\.venv\lib\site-packages\flake8\options\manager.py", line 231, in add_option
    self.parser.add_option(option.to_optparse())
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\optparse.py", line 1008, in add_option
    self._check_conflict(option)
  File "C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\optparse.py", line 980, in _check_conflict
    raise OptionConflictError(
optparse.OptionConflictError: option --test-config-option: conflicting option string(s): --test-config-option

While flake8 behaves as expected:

$ flake8 setup.py
setup.py:13:2: W292 no newline at end of file

For broader context, this is causing CI for my plugin (flake8-annotations) to fail (Azure) since we're invoking flake8 as a module rather than from the defined entry point.

@takluyver
Copy link
Owner

Is it possible that it finds more than one entry point with the name TST? I see flake8 was using get_group_all, which allows multiple entry points with the same name. It should still shadow correctly if it finds the same package installed in multiple places, but it's possible that could go wrong.

@sco1
Copy link
Author

sco1 commented Jan 19, 2020

Sorry, I cut this chunk out of the issue when I was moving it over. With the skeleton installed there's just the testing plugin installed in the environment so there's nothing being shadowed:

$ flake8 --version
3.7.9 (flake8-test: 1.0.0, mccabe: 0.6.1, pycodestyle: 2.5.0, pyflakes: 2.1.1) CPython 3.8.1 on Windows

vs.

$ python -m flake8 --version
<snipped, same traceback as OP>
line 980, in _check_conflict
    raise OptionConflictError(
optparse.OptionConflictError: option --test-config-option: conflicting option string(s): --test-config-option

The conflict occurs even if we change the entry point to something that's probably truly unique:

    entry_points={
        "flake8.extension": ["JANUARY192020 = flake8_test:TestChecker"]
    },

But again, only when invoking via python -m

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

No branches or pull requests

2 participants