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 building of pyodide universal wheels #918

Merged
merged 10 commits into from
Aug 10, 2024
Merged

Add building of pyodide universal wheels #918

merged 10 commits into from
Aug 10, 2024

Conversation

twiecki
Copy link
Member

@twiecki twiecki commented Jul 10, 2024

Closes #285 and #360.

These require pure-python wheels which does not work if we ship a cython-version of scan, so this build does not include this extension module.

.github/workflows/pypi.yml Outdated Show resolved Hide resolved
@maresb
Copy link
Contributor

maresb commented Jul 10, 2024

Looks pretty straightforward. Does anyone know offhand it a platform-specific wheel takes precedence over a universal one? I'd hope it does.

@twiecki
Copy link
Member Author

twiecki commented Jul 10, 2024

Looks pretty straightforward. Does anyone know offhand it a platform-specific wheel takes precedence over a universal one? I'd hope it does.

Yes, they take precedence. And since we have wheels for all major platforms, the universal one should really only ever be installed when installed through pyodide.

setup.py Outdated Show resolved Hide resolved
setup.py Show resolved Hide resolved
Copy link

codecov bot commented Jul 10, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.69%. Comparing base (7fffec6) to head (19cf45e).
Report is 93 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main     #918   +/-   ##
=======================================
  Coverage   81.69%   81.69%           
=======================================
  Files         182      182           
  Lines       47585    47585           
  Branches    11584    11584           
=======================================
  Hits        38875    38875           
- Misses       6518     6520    +2     
+ Partials     2192     2190    -2     

see 2 files with indirect coverage changes

@ricardoV94
Copy link
Member

ricardoV94 commented Jul 10, 2024

To clarify, did this PR addressed the concerns here: #285 (comment) ?

@maresb
Copy link
Contributor

maresb commented Jul 10, 2024

We can't make pytensor behave as a universal wheel because it has a cython extension.

I believe the idea here is to sidestep the issue by omitting the cython extension. (I don't understand the implications of omitting it.)

@maresb maresb requested a review from lucianopaz July 11, 2024 08:23
@twiecki
Copy link
Member Author

twiecki commented Jul 11, 2024

To clarify, did this PR addressed the concerns here: #285 (comment) ?

I think so, yes. Ultimately, having a cython-extension really only makes sense if using the c-backend. For the python backend there shouldn't be any dependency that's related to compilation.

@twiecki
Copy link
Member Author

twiecki commented Jul 11, 2024

Thanks for the assist @maresb!

@maresb
Copy link
Contributor

maresb commented Jul 11, 2024

I don't think we're testing the universal dist. Probably we should in order to avoid potentially uploading corrupt wheels.

Also, while trying to determine whether or not we're testing, I see that we're using the sloppy old versions for artifact upload/download, see #560, #580.

@maresb
Copy link
Contributor

maresb commented Jul 17, 2024

@lucianopaz, I'm very interested to get your thoughts on this approach. Is it viable to simply omit the extension when building a universal wheel?

Copy link
Contributor

@lucianopaz lucianopaz left a comment

Choose a reason for hiding this comment

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

As far as I understand, the code here should work. It will produce a universal wheel without the cython extension for scan. I think that the setup.py could be improved so that it doesn't rely on environment variables but that is more of a detail.
My bigger concern is the same that I said originally: building a universal wheel with reduced capabilities will do more harm than good in the long run. As pointed out here, universal wheels will be preferred by pip over platform specific wheels. This means that, any installation will need to require a platform specific version of pytensor manually to avoid getting the universal wheel. The correct way to deal with this is to get pytensor built using the pyodide build toolchain so that we have a platform specific version that can run on the browser.

Comment on lines +19 to +31
if is_pyodide:
# For pyodide we build a universal wheel that must be pure-python
# so we must omit the cython-version of scan.
ext_modules = []
else:
ext_modules = [
Extension(
name="pytensor.scan.scan_perform",
sources=["pytensor/scan/scan_perform.pyx"],
include_dirs=[numpy.get_include()],
),
]
Copy link
Contributor

Choose a reason for hiding this comment

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

Depending on an environment variable to conditionally include an extension is very unorthodox and I don't think that it will be robust in the future. As far as I know, there is no canonical way to conditionally include an extension or not when using pyproject.toml or the older setup.py. However, there is a way to get platform conditional requirements following this pep. Maybe we could look at the sys information to identify that python is running from the browser instead of having is_pyodide conditioned on the environment?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm extremely pro-declarative config, so I'd really like to do this better.

Unfortunately after taking a brief look through the environment markers, I don't see any particular variables that can help in our situation. This feels not so surprising to me since "universal" vs "platform-specific" seems more like a "build" parameter than an "environment" parameter, making it something to be handled at the build-backend (setuptools) level rather than the project-config level. On the same note, the pyproject.toml standard doesn't seem to support ext_modules. So I don't have any ideas for how we could do this better.

Also, unfortunately using ext_modules seems to marry us to setuptools which I loathe, but that's out-of-scope for this PR.

@maresb
Copy link
Contributor

maresb commented Jul 17, 2024

My reading of the stack overflow answer is that the priority is:

platform-specific compatible wheel > universal wheel > sdist

@twiecki
Copy link
Member Author

twiecki commented Jul 17, 2024

As pointed out here, universal wheels will be preferred by pip over platform specific wheels.

I don't think that's the case. And I have confirmed that non-pyodide installs work the same across all major platforms.

I don't think the risk is that high to give this a try. We can test to make sure we don't break anything on existing platforms.

@lucianopaz
Copy link
Contributor

My reading of the stack overflow answer is that the priority is:

platform-specific compatible wheel > universal wheel > sdist

Oh! You’re right, I misread the last sentence

This is not all that common however, as a universal wheel would be preferred over a source distribution!

So platform specific wheels will be preferred, then universal wheels and finally source distributions. I take back what I said about the risks then. This should be mostly fine.

@twiecki
Copy link
Member Author

twiecki commented Jul 18, 2024

Thanks @lucianopaz. Can we get an approval?

@maresb
Copy link
Contributor

maresb commented Jul 18, 2024

I'm a bit uncomfortable that we're not testing the universal wheel. Maybe I can finish off #560 right now...

@twiecki
Copy link
Member Author

twiecki commented Aug 9, 2024

FAILED tests/test_config.py::test_config_pickling - AssertionError: Regex pattern did not match.
 Regex: "Can't pickle local object"
 Input: "Can't get local object 'test_config_pickling.<locals>.<lambda>'"
= 1 failed, 807 passed, 69 skipped, 4 xfailed, 33 warnings in 248.68s (0:04:08) =
Error: Process completed with exit code 1.

what might this be about?

.github/workflows/pypi.yml Outdated Show resolved Hide resolved
@twiecki twiecki merged commit 29183c7 into main Aug 10, 2024
59 of 60 checks passed
Ch0ronomato pushed a commit to Ch0ronomato/pytensor that referenced this pull request Aug 15, 2024
* Add building of pyodide universal wheels

* precommit

* Fix precommit. Readd comment.

* Fix precommit2

* Minor improvement to ext_modules conditional definition

* Bump Python version so that tomllib is included

This way versioneer can read pyproject.toml

* Add wheel package to build dependencies

* Update .github/workflows/pypi.yml

* Revert unnecessary

* ruff

---------

Co-authored-by: Ben Mares <[email protected]>
@ricardoV94 ricardoV94 deleted the universal_wheel branch November 14, 2024 06:44
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

Successfully merging this pull request may close these issues.

Provide pyodide packages
4 participants