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

[BUG] ModuleNotFoundError when using cmdclass option in PEP517-style build #3000

Closed
1 task done
zluudg opened this issue Jan 5, 2022 · 9 comments
Closed
1 task done

Comments

@zluudg
Copy link

zluudg commented Jan 5, 2022

setuptools version

setuptools===60.2.0

Python version

Python 3.8

OS

Ubuntu 20.04

Additional environment information

build 0.7.0

Description

Having the cmdclass option defined in setup.cfg causes python -m build to fail with a ModuleNotFoundError.

Expected behavior

I expect to be able to customize/override setuptools commands in a project with a PEP 517-style build system with no setup.py.

The code for the overriden/customized commands resides in a python module at the root of the repo and is being pointed out with the cmdclass option in setup.cfg.

How to Reproduce

  1. Download and unzip this minimal example: example.zip
  2. Move to the top folder of the unzipped contents
  3. Issue python -m build
  4. Behold, no source or wheel distribution gets built. All we get is a ModuleNotFoundError

Output

zluudg@computer > python3 -m build
/home/zluudg/.local/lib/python3.8/site-packages/setuptools/command/install.py:34: SetuptoolsDeprecationWarning: setup.py install is deprecated. Use build and pip and other standards-based tools.
  warnings.warn(
* Creating virtualenv isolated environment...
* Installing packages in isolated environment... (setuptools==60.2.0, wheel)
* Getting dependencies for sdist...
Traceback (most recent call last):
  File "/home/zluudg/.local/lib/python3.8/site-packages/pep517/in_process/_in_process.py", line 363, in <module>
    main()
  File "/home/zluudg/.local/lib/python3.8/site-packages/pep517/in_process/_in_process.py", line 345, in main
    json_out['return_val'] = hook(**hook_input['kwargs'])
  File "/home/zluudg/.local/lib/python3.8/site-packages/pep517/in_process/_in_process.py", line 297, in get_requires_for_build_sdist
    return hook(config_settings)
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/build_meta.py", line 167, in get_requires_for_build_sdist
    return self._get_build_requires(config_settings, requirements=[])
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/build_meta.py", line 143, in _get_build_requires
    self.run_setup()
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/build_meta.py", line 158, in run_setup
    exec(compile(code, __file__, 'exec'), locals())
  File "setup.py", line 1, in <module>
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/__init__.py", line 155, in setup
    return distutils.core.setup(**attrs)
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/_distutils/core.py", line 122, in setup
    dist.parse_config_files()
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/_virtualenv.py", line 21, in parse_config_files
    result = old_parse_config_files(self, *args, **kwargs)
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/dist.py", line 804, in parse_config_files
    parse_configuration(
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 150, in parse_configuration
    options.parse()
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 498, in parse
    section_parser_method(section_options)
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 469, in parse_section
    self[name] = value
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 222, in __setitem__
    value = parser(value)
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 654, in _parse_cmdclass
    return {k: resolve_class(v) for k, v in self._parse_dict(value).items()}
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 654, in <dictcomp>
    return {k: resolve_class(v) for k, v in self._parse_dict(value).items()}
  File "/tmp/build-env-dwvi2g6f/lib/python3.8/site-packages/setuptools/config.py", line 650, in resolve_class
    module = __import__(pkg_name)
ModuleNotFoundError: No module named 'custom_build'

ERROR Backend subproccess exited when trying to invoke get_requires_for_build_sdist

Code of Conduct

  • I agree to follow the PSF Code of Conduct
@zluudg zluudg added bug Needs Triage Issues that need to be evaluated for severity and status. labels Jan 5, 2022
@abravalheri
Copy link
Contributor

abravalheri commented Jan 5, 2022

Hi @zluudg, thank you very much for reporting this!

Unfortunately, this feature is not yet fully supported by setuptools via setup.cfg only via setup.py (also not part of the public API). The reason is that build_meta does not guarantee the project directory is appended to sys.path (only build_meta:legacy guarantees that).

As a workaround, you could try:

PYTHONPATH=$PWD python -m build

But the good news is that this problem might be solved in the near future (via #2970)

@abravalheri abravalheri added enhancement and removed bug Needs Triage Issues that need to be evaluated for severity and status. labels Jan 5, 2022
@zluudg
Copy link
Author

zluudg commented Jan 5, 2022

Thanks for the tips and for the quick reply! I think I'll go with the setup.py-approach for now while keeping an eye on your PR. Good luck with that!

@jaraco
Copy link
Member

jaraco commented Jan 8, 2022

Another option could be to supply the cmdclass as a plugin. If you were to implement custom_build as a library like lzuudgs_custom_build, then declare that dependency in your build-system.requires (pyproject.toml), then it would be available to the setup.cfg for PEP 517 builds.

@zluudg
Copy link
Author

zluudg commented Jan 10, 2022

That seems like an interesting option as well, @jaraco. But would I have to upload my custom_build library to PyPI? Or is there some way to keep it in the same repo as my project and still specify it as a dependency in pyproject.toml?

@jaraco
Copy link
Member

jaraco commented Jan 10, 2022

It would have to be on PyPI or otherwise discoverable by pip, so not a good solution if the implementation is local to this one project.

@zluudg
Copy link
Author

zluudg commented Jan 10, 2022

Ah, I see. I think I'll stick with my setup.py-approach for now since I have no hard requirements to be "pure PEP 517". But it's very good for me to know what options I have.

Thanks a lot for taking the time, @abravalheri and @jaraco. It's ok for me if you want to close this issue.

Cheers!

@abravalheri
Copy link
Contributor

Thanks @zluudg, I think it is ok to leave it open now as a reminder to add a test case if #2970 gets merged 😝

@zluudg
Copy link
Author

zluudg commented Jan 10, 2022

Sure, no probs!

@abravalheri
Copy link
Contributor

Ok, I revisited this issue and considering the changes in the mentioned PR, I think this specific problem will not be solved, but a similar problem will: when the cmdclass reside within the package being published. So I think the best options here are keep using setup.py or use Jason's suggestion.

abravalheri added a commit to abravalheri/setuptools that referenced this issue Mar 24, 2022
Although this situation is different from the one described in pypa#3000,
that issue served as inspiration behind this change.
abravalheri added a commit to abravalheri/setuptools that referenced this issue Mar 24, 2022
Although this situation is different from the one described in pypa#3000,
that issue served as inspiration behind this change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants