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

Add an option to disable sys.path patching. #5235

Conversation

hmc-cs-mdrissi
Copy link
Contributor

Type of Changes

Type
βœ“ πŸ› Bug fix
βœ“ ✨ New feature

Description

Adds an option for disabling sys.path patching. This option is default to False and should have no impact on existing users.

This is helpful for implicit namespace packages where the current patching logic is incorrect and making patch logic correct in general case is difficult. Disabling sys.path patching means that pylint will work if running python on same files will work. Practically this means any files users want to check should either be checked from the package root directory or be installed first.

Closes #5226

@coveralls
Copy link

coveralls commented Oct 30, 2021

Pull Request Test Coverage Report for Build 1409090769

  • 7 of 7 (100.0%) changed or added relevant lines in 3 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 93.335%

Totals Coverage Status
Change from base Build 1404598281: 0.0%
Covered Lines: 13737
Relevant Lines: 14718

πŸ’› - Coveralls

@Pierre-Sassoulas Pierre-Sassoulas added Enhancement ✨ Improvement to a component Needs review πŸ” Needs to be reviewed by one or multiple more persons labels Oct 31, 2021
@Pierre-Sassoulas Pierre-Sassoulas added this to the 2.13.0 milestone Oct 31, 2021
Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't tested any namespace packages, but the change itself looks good. One small comment.

pylint/lint/pylinter.py Outdated Show resolved Hide resolved
pylint/pyreverse/main.py Outdated Show resolved Hide resolved
@cdce8p cdce8p modified the milestones: 2.13.0, 2.12.0 Oct 31, 2021
@cdce8p cdce8p removed the Needs review πŸ” Needs to be reviewed by one or multiple more persons label Oct 31, 2021
Copy link
Member

@cdce8p cdce8p left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks @hmc-cs-mdrissi πŸš€

Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding this option !I think this need to be documented so we have something to refer to when someone has trouble with sys.path patching (or even only for discoverability, I'm not sure user often use the--help).

@hmc-cs-mdrissi
Copy link
Contributor Author

hmc-cs-mdrissi commented Oct 31, 2021

Testing wise I tested this on my team's codebase that had import namespace package error and it fixed issue for us.

Documentation, @Pierre-Sassoulas where would you recommend me updating the documentation? The faq the run page with other global options or somewhere else? If I do the faq I could add a question under troubleshooting for namespace packages.

@Pierre-Sassoulas
Copy link
Member

In the faq is a really good idea :) Also if you have ideas about how to test that automatically with a minimum namespace package so we don't regress later on that would be great, but I'm sure this is quite complicated to do.

@hmc-cs-mdrissi
Copy link
Contributor Author

hmc-cs-mdrissi commented Nov 1, 2021

I wasn't sure if I could write a unit test, but I think I got a reasonable one to work using functional test. It does rely on pylint being installed when running test for disable path patching one to work or running from the repository root directory. So locally testing it with an editable pylint install it worked. I'm unsure if CI installs pylint before testing or not.

If that doesn't work on CI then I think CI will need a tweak.

I'll add documentation tomorrow.

I think best test though for this would be part of pylint primer and include some repository that uses namespace packages and require disable-path-patching to work correctly. Ideal repository is one with multiple python packages (monorepo) in it with at least one namespace package that overlaps in name with other package in repo if you ignore namespace part.

@Pierre-Sassoulas
Copy link
Member

I'm on mobile, so I can't link the issue but one of the last things we need to do for the 2.12 milestone is (convenientely) adding primer tests. Please feel free to suggest repositories that would be great to add on the relevant issue (you can click the milestone from here).

@cdce8p
Copy link
Member

cdce8p commented Nov 1, 2021

The issue regarding the primer tests Pierre mentioned

@hmc-cs-mdrissi
Copy link
Contributor Author

Test failure is interesting. The two functional tests I wrote pass individually, but fail when run together. Awkwardly once an import happens it impacts global state (sys.modules) and influences next test import resolution. Messy aspect is this can negatively impact an entirely unrelated test. My test that relied on import failure for namespace_package since it used checkers broke generated_members test because it also imported checkers.

After a couple tries I got it working with all tests and left a long comment in _fake.py about it.

@@ -0,0 +1,7 @@
"""This file is intended to only be used for testing namespace package importing.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should add file without purpose in pylint itself. pylint is not a namespace package so maybe we can create a fixture or it's not even required to have one ? Could we use a namespace that does not exists ? Or is this supposed to be in tests/functional/n/namespace_package/pylint/testutils/ ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought testutils was for files used in tests/? Are you fine with test file importing another test file? I don't think that's currently done by any of the tests and a future version of pytest will not allow that by default either.

https://docs.pytest.org/en/6.2.x/pythonpath.html#import-modes
For this reason this doesn’t require test module names to be unique at all, but also makes test modules non-importable by each other

So moving it to tests/functional/n/namespace_package will force you to disable an upcoming pytest change.

There's a second reason why it's better to avoid having the file in tests/. sys path disable mode has a requirement either files you import are installed or you run it from the right directory. tests folder is not included in pytest install. As a side effect if I move the file to tests this new test will only work as expected if run from the repository root directory. If a user tries to run pytest from a different directory for this test it won't work.

Because of those 2 reasons having the _fake file with tests/ will impose restrictions on pytest usage and I'd prefer to avoid. I can move it there, but the tests will become sensitive to where you run them and unsure that's a good trade off.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other option is drop this test entirely and make sys path logic is tested in future primer test.

The main issue for making this not directory sensitive is I need module I'm importing to be installed package in repo. The only choice for that is under pylint/ somewhere. I can make a folder _internal/ and actual location doesn't matter as long as it's in pylint.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I forgot to reply. We have some test with import in test_func.py which is the legacy functional test file. Maybe you could take add a test to it exceptionally ? I'm guessing we'll have to think about a system for those kind of tesst soon if pytest is going to make this impossible. But it will always be possible to call pylint on a directory, as an integration tests, right ? Sorry if this is not in this PR scope. I'm hesitant to drop the test as long as #5173 is not merged. Do you have a list of stable project that we could use to test this ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would putting it in tests/regrtest_data work? This is where I have been putting all data for tests that require additional files.
We should probably update the name of that directory though...

Copy link
Contributor Author

@hmc-cs-mdrissi hmc-cs-mdrissi Nov 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it would have same issue as anywhere outside pylint. The root issue is this line, https://github.com/PyCQA/pylint/blob/main/setup.cfg#L57

When pylint is installed as a package, it installs pylint directory. It does not install tests directory. Namespace package solution here works under one of 2 conditions, the imported modules are installed or you need to use right directory to run them from. The second condition means that for development tests will break depending on cd and will complicate test scripts. The first condition means I can't test this well if pylint separates test folder from the install.

Some codebases have a test structure of keeping tests in same folder as src and tests are included with a package install. https://docs.pytest.org/en/6.2.x/goodpractices.html#tests-as-part-of-application-code pytest discusses different test folder structures here. The structure of mixing tests with application code would work. It'd need a pr to refactor the test structure. You could in theory mix both test structures but it'd be fairly confusing if some tests lived in pylint/ and other tests lived in tests/. Having every user be forced to install all tests as part of pip install is a downside to this option.

For stable project to test with I'm unsure of repository that uses implicit namespace packages and would fail without this. Most repositories don't use namespace packages. For the ones that do I expect if they use pylint they have workarounds. My internal repo that needs this uses a workaround of never calling pylint on the whole repo and also has multiple setup.py in it which primer would struggle with. The primer I think is designed for repositories with single setup.py/cfg. Monorepo that has multiple separate packages (so separate setup.cfg/py) installed to same namespace I don't think mypy primer supports and that's situation most likely to need this.

I can make a toy repository for this that primer would work with.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. Reading the project,

When using multiple namespace packages within the same repository:

Because mynamespace doesn’t contain an init.py, setuptools.find_packages() won’t find the sub-package. You must use setuptools.find_namespace_packages() instead or explicitly list all packages in your setup.py. For example:

is true in readme, but the repository does not follow that itself.

https://github.com/madhavhugar/example-python-namespace-package/blob/master/setup.py#L11

I don't see any namespace module in that repository. Instead it looks like a repository that has 3 packages all in same repository and controlled by same setup.py, but no namespace that shares them.

I can make a simple example for the primer tomorrow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you much appreciated !

@hmc-cs-mdrissi
Copy link
Contributor Author

@Pierre-Sassoulas Thoughts on what I should do with the test? Main options I see are drop the test or keep a file somewhere in pylint/. I don't see a good way to test importing works with disable path on and having the files all in tests/ directory.

@Pierre-Sassoulas
Copy link
Member

Thoughts on what I should do with the test? Main options I see are drop the test or keep a file somewhere in pylint/. I don't see a good way to test importing works with disable path on and having the files all in tests/ directory.

Sorry for the delay. Imo we can drop the tests if we introduce a namespace repository with #5173

@Pierre-Sassoulas
Copy link
Member

@hmc-cs-mdrissi did you have the time to find an example of a namespace package ? We're trying to release 2.12 this week, and there's only this issue and the primer tests left :)

@Pierre-Sassoulas Pierre-Sassoulas modified the milestones: 2.12.0, 2.12.1, 2.12.2 Nov 21, 2021
@Pierre-Sassoulas Pierre-Sassoulas modified the milestones: 2.12.2, 2.13.0 Nov 29, 2021
@DanielNoord DanielNoord added the Waiting on author Indicate that maintainers are waiting for a message of the author label Dec 14, 2021
Copy link
Member

@Pierre-Sassoulas Pierre-Sassoulas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, we still need a namespace package for primer, a very small example should do if we don't find a serious one.

@DanielNoord
Copy link
Collaborator

@Pierre-Sassoulas
Copy link
Member

What about https://github.com/pypa/sample-namespace-packages?

Looks good πŸ‘ (We just need to check that it was failing previously)

@hmc-cs-mdrissi do you still want to work on this or should we take over ? I think this MR is very valuable and need to go in 2.13 :)

@DanielNoord
Copy link
Collaborator

@hmc-cs-mdrissi Sorry for pinging you again. As @Pierre-Sassoulas said previously this is likely a much appreciated function for many users. Do you think you have the time to write the small package for the primer you mentioned?

@Pierre-Sassoulas Pierre-Sassoulas self-assigned this Mar 15, 2022
@Pierre-Sassoulas Pierre-Sassoulas removed the Waiting on author Indicate that maintainers are waiting for a message of the author label Mar 15, 2022
@Pierre-Sassoulas Pierre-Sassoulas modified the milestones: 2.13.0, 2.14.0 Mar 23, 2022
CONTRIBUTORS.txt Outdated Show resolved Hide resolved
update changelog + contributors

Address comment to add default for option

Add unit test for namespace package sys patching

fix unit test to avoid global side effects from imports

Update faq to explain namespace package issue with imports
@Pierre-Sassoulas
Copy link
Member

Confirmed to fix namespace issue in #2648 (comment)

@Pierre-Sassoulas Pierre-Sassoulas added the Needs backport Needs to be cherry-picked on the current patch version by a pylint's maintainer label Apr 6, 2022
@Pierre-Sassoulas Pierre-Sassoulas modified the milestones: 2.14.0, 2.13.6 Apr 6, 2022
@DanielNoord
Copy link
Collaborator

@Pierre-Sassoulas I think I have found a solution for namespaces without this option. Using some of the import logic we have already made at astroid we can determine whether something is a namespace package is some cases. I tested #2648 and I could get astroid to tell us that we're dealing with a namespace.

Let's wait (again, I know...) with merging this...

@Pierre-Sassoulas Pierre-Sassoulas modified the milestones: 2.13.6, 2.15.0 Apr 20, 2022
@Pierre-Sassoulas Pierre-Sassoulas removed this from the 2.15.0 milestone May 2, 2022
@Pierre-Sassoulas
Copy link
Member

Closing in favor of #6405

@Pierre-Sassoulas
Copy link
Member

Thank you for working on this @hmc-cs-mdrissi, even if we did not merge the change in the end it would have been a great contribution and made us rethink the way we handle namespace in pylint.

@Pierre-Sassoulas Pierre-Sassoulas removed the Needs backport Needs to be cherry-picked on the current patch version by a pylint's maintainer label May 2, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement ✨ Improvement to a component
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support an Option to Disable sys.path patching
5 participants