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

Editable installs improvements #569

Merged
merged 6 commits into from
Feb 28, 2024

Conversation

dnicolodi
Copy link
Member

No description provided.

@dnicolodi dnicolodi marked this pull request as draft February 4, 2024 20:15
@dnicolodi dnicolodi force-pushed the editable-module-path branch 5 times, most recently from bf80201 to b989bae Compare February 4, 2024 21:39
@dnicolodi dnicolodi marked this pull request as ready for review February 4, 2024 21:40
@dnicolodi dnicolodi force-pushed the editable-module-path branch from b989bae to 3092827 Compare February 4, 2024 21:55
@dnicolodi dnicolodi force-pushed the editable-module-path branch 2 times, most recently from 075cd39 to 54dc58c Compare February 4, 2024 23:31
@lesteve
Copy link
Contributor

lesteve commented Feb 5, 2024

Thanks for this PR!

I gave in a go to see whether that would fix the issue we were seeing in scikit-learn where some of our tests are using pkgutil.walk_packages as I mentioned in #557 (comment).

Right now if I try to run the problematic test with pytest, I get an error AttributeError: 'MesonpyPathFinder' object has no attribute 'find_spec', see below for full stack-trace.

Let me know if I can provide additional information!

Full stack-trace
❯ pytest sklearn/tests/test_common.py -k are_importable
+ /home/lesteve/micromamba/envs/del/bin/ninja
ninja: no work to do.
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/pytest/__main__.py", line 5, in <module>
    raise SystemExit(pytest.console_main())
                     ^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 197, in console_main
    code = main()
           ^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 155, in main
    config = _prepareconfig(args, plugins)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 337, in _prepareconfig
    config = pluginmanager.hook.pytest_cmdline_parse(
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/pluggy/_hooks.py", line 501, in __call__
    return self._hookexec(self.name, self._hookimpls.copy(), kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/pluggy/_manager.py", line 119, in _hookexec
    return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/pluggy/_callers.py", line 138, in _multicall
    raise exception.with_traceback(exception.__traceback__)
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/pluggy/_callers.py", line 121, in _multicall
    teardown.throw(exception)  # type: ignore[union-attr]
    ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/helpconfig.py", line 104, in pytest_cmdline_parse
    config = yield
             ^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/pluggy/_callers.py", line 102, in _multicall
    res = hook_impl.function(*args)
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1094, in pytest_cmdline_parse
    self.parse(args)
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1446, in parse
    self._preparse(args, addopts=addopts)
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 1320, in _preparse
    self.pluginmanager.consider_preparse(args, exclude_only=False)
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 727, in consider_preparse
    self.consider_pluginarg(parg)
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 753, in consider_pluginarg
    self.import_plugin(arg, consider_entry_points=True)
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/config/__init__.py", line 801, in import_plugin
    __import__(importspec)
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1322, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1262, in _find_spec
  File "/home/lesteve/micromamba/envs/del/lib/python3.12/site-packages/_pytest/assertion/rewrite.py", line 104, in find_spec
    spec = self._find_spec(name, path)  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap_external>", line 1524, in find_spec
  File "<frozen importlib._bootstrap_external>", line 1498, in _get_spec
AttributeError: 'MesonpyPathFinder' object has no attribute 'find_spec'

@dnicolodi
Copy link
Member Author

Thanks for testing. I cut some corners in the implementation. It seems that pytest uses one of the interfaces I haven't implemented. I'll add it when I find a moment.

@lesteve
Copy link
Contributor

lesteve commented Feb 5, 2024

Great, let me know if there is something I can help with!

@dnicolodi dnicolodi force-pushed the editable-module-path branch 4 times, most recently from 5b21a86 to c9e3058 Compare February 5, 2024 21:26
Add support for the exclude_dirs and exclude_files arguments of
install_subdir() Meson function. Extend editable install tests to
cover this functionality and a more complex package layout.
@dnicolodi dnicolodi force-pushed the editable-module-path branch from c9e3058 to 8f19aec Compare February 5, 2024 21:27
@dnicolodi
Copy link
Member Author

@lesteve Can you try again, please?

@lesteve
Copy link
Contributor

lesteve commented Feb 5, 2024

Great! This seems to fix both #557 (comment) and #568.

@dnicolodi dnicolodi force-pushed the editable-module-path branch 2 times, most recently from 48f8a5f to e29e9a3 Compare February 6, 2024 21:27
@rgommers rgommers added the enhancement New feature or request label Feb 15, 2024
@rgommers rgommers self-requested a review February 15, 2024 09:55
@rgommers rgommers added this to the v0.16.0 milestone Feb 15, 2024
@lesteve
Copy link
Contributor

lesteve commented Feb 19, 2024

I just saw that this was added on the 0.16.0 milestone, which is great news, let me know if there is anything I can do to help move it forward!

@rgommers
Copy link
Contributor

Yes, I hope we can get this in and released soon. I need to finish testing and reviewing; holidays interfered a bit. I'll try to finalize my review in the next couple of days.

Copy link
Contributor

@rgommers rgommers left a comment

Choose a reason for hiding this comment

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

This is very close. I did a fair bit of testing; it's definitely a large improvement. For PyWavelets it fixed an issue, for NumPy and SciPy the tests got more accurate. There is one hiccup with pkgutil.walk_packages, I commented inline about what I think the problem is.

ispkg = True
if modname and '.' not in modname:
yielded.add(modname)
yield prefix + modname, ispkg
Copy link
Contributor

Choose a reason for hiding this comment

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

I've found one issue where pkgutil.walk_packages returns directories with files in it that get installed with install_subdir but don't have an __init__.py. According to the docs, only modules should be returned.

It looks like the condition here should include an is_dir part, and if it's a directory then ispkg must be True for this to be yielded. Although not sure if that will mess with namespace packages; this is handled in the find_spec function higher up, but not in this iter_modules.

I ran into this in both NumPy and SciPy, where the test_public_api.py::test_all_modules_are_expected tests turn up a few of these non-package directories.

Copy link
Member Author

Choose a reason for hiding this comment

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

You're right. My understanding was that namespace packages should be returned too. I even added test to check that this was the case. However, I've just tested and they are indeed not returned. Let me fix this.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the review @rgommers. The issue with namespace packages should be fixed now.

Copy link
Member Author

Choose a reason for hiding this comment

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

The test failures are due to mesonbuild/meson#12920

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! I can confirm that it works now with both numpy and scipy, and from some more debug printing it seems to function exactly as expected.

Test failures with Meson master shouldn't be blocking here, so let's get this in.

@dnicolodi dnicolodi force-pushed the editable-module-path branch from e29e9a3 to 063e6b7 Compare February 27, 2024 22:07
Set the __path__ module attribute to a placeholder path.  Because how
editable installs are implemented, this cannot correspond to the
filesystem path for the package.  And add a sys.path_hook that
recognizes this paths and returns a path loader that implements
iter_modules(). This allows pkgutil.iter_packages() to work properly.

Fixes mesonbuild#557.
Fixes mesonbuild#568.
@dnicolodi dnicolodi force-pushed the editable-module-path branch from 063e6b7 to 4924a5a Compare February 27, 2024 22:10
@rgommers rgommers merged commit d377bf7 into mesonbuild:main Feb 28, 2024
37 of 39 checks passed
agriyakhetarpal added a commit to agriyakhetarpal/pywt that referenced this pull request Apr 17, 2024
Since the mechanism for editable installations
was improved in mesonbuild/meson-python#569
and subsequently released in meson-python
v0.16.0, this bumps the minimum version for it
for use during compilation.
agriyakhetarpal added a commit to agriyakhetarpal/pywt that referenced this pull request Apr 18, 2024
Since the mechanism for editable installations
was improved in mesonbuild/meson-python#569
and subsequently released in meson-python
v0.16.0, this bumps the minimum version for it
for use during compilation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants