-
Notifications
You must be signed in to change notification settings - Fork 382
Add buildpack for pyproject.toml to configure container image #1444
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
base: main
Are you sure you want to change the base?
Conversation
83b5f11 to
577cb1b
Compare
|
577cb1b implements a minimal working version. It was tested with https://github.com/rgaiacs/binder-examples-pyproject. Required changes before merge
Changes that can be done in another pull request
|
|
All tests are passing after support to Python < 3.11 was dropped. |
I've got a PR that refactors the handling of runtime.txt |
ad70986 to
974a559
Compare
|
I rebased this pull request and I made minor changes to reduce the code duplication. It need to be reviewed again. |
|
Can we merge this? Or should we talk about it in jupyterhub/team-compass#814? |
We can depend on try:
import tomllib
except ImportError:
import tomli as tomllibwithout losing any supported environments. I think reverting the baseline version change and depending on tomli, and fixing detection of pyproject.toml contents, I think this should be all set. |
974a559 to
1a393bb
Compare
|
I addressed the comments from @minrk
I also added
I suggest to add more tests in another pull request. |
minrk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This implementation looks great to me. My only comment is that I don't think we necessarily need a new buildpack to do this - the assemble steps, etc. should be identical to when setup.py is present. The only effect it should have is detecting the Python version, so it seems to me that it would be simpler to keep everything consistent if this logic is added to the python buildpack, rather than a whole new buildpack that should do all the same things.
But we can also do that as a simplification later. What do you think?
I don't like code duplication but my line of thoughts was "when we decided to drop support to Tomorrow, I will refactor the code so that there are only one Python buildpack. |
We don't have a setup.py buildpack. setup.py is one small part of the So the real change here ought to be changing the "should we run pip install ." in the Python buildpack from "setup.py exists" to a more general "is it a python package?" which checks:
Then the only other change is detecting Python version from project info, I think, at a lower priority than runtime.txt, binder dir, etc. The rest of |
85a9e6c to
b755b7a
Compare
|
I'm not sure I quite follow - The We could isolate this into a single This is because |
8472f26 to
f3d2e06
Compare
|
Sorry for the delay to pick this one again.
We should wait the end of JupyterCon to merge this. |
because now repo2docker requires Python >= 3.11 given the requirement of tomllib.
de8027f to
512f37c
Compare
512f37c to
6183e4f
Compare
yuvipanda
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excited for this to land, and it looks pretty good to me! Do you think your last comments have been fully addressed, @minrk?
minrk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So sorry, I wrote this review 2 weeks ago, but failed to submit it. I think it's almost there, but we need to always check the contents of pyproject.toml before using it, which isn't quite done yet.
| if name != "python" or not version: | ||
| # Either not specified, or not a Python runtime (e.g. R, which subclasses this) | ||
| if name is not None and name != "python": | ||
| # Either not a Python runtime (e.g. R, which subclasses this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # Either not a Python runtime (e.g. R, which subclasses this) | |
| # Runtime specified, but not Python (e.g. R, which subclasses this) |
| if not self.binder_dir and os.path.exists(setup_py): | ||
| assemble_scripts.append(("${NB_USER}", f"{pip} install --no-cache-dir .")) | ||
| for _configuration_file in ("pyproject.toml", "setup.py"): | ||
| if not self.binder_dir and os.path.exists(_configuration_file): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still needs to check for [build-system].
I think it's probably a good idea to have a cached method:
@lru_cache
def _is_python_package(self):
if self.binder_dir:
return False
if os.path.exists("setup.py"):
return True
if os.path.exists("pyproject.toml"):
with open(pyproject_toml, "rb") as _pyproject_file:
pyproject = tomllib.load(_pyproject_file)
if (
("project" in pyproject)
and ("build-system" in pyproject)
):
return True
return Falsebecause we need the exact same check in a few places, and they aren't currently in sync.
| pyproject["project"]["requires-python"] | ||
| ) | ||
|
|
||
| if runtime_version not in pyproject_python_specifier: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the default version doesn't satisfy, we should probably pick the lowest version available rather than error, right? But only if runtime.txt is not specified?
# pseudocode
if runtime_version not in pyproject_python_specifier:
if version:
raise ValueError(
f"Python version {version} in runtime.txt does not satisfy {pyproject_python_specifier} in pyproject.toml."
)
else:
# version not specified in runtime.txt, pick the lowest available satisfying version
for python in sorted(self.major_pythons):
if python in pyproject_python_specifier:
runtime_version = python
break
else:
raise ValueError(f"Unable to find a supported Python version satisfying {pyproject_python_specifier}")There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this part can be a later refinement, if it seems too complex to address right now. This isn't a regression, at least.
| if name is None or version is None: | ||
| self._python_version = self.major_pythons["3"] | ||
| runtime_version = Version(self.major_pythons["3"]) | ||
| self.log.warning( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we decide to go with my suggestion below, we should perhaps only show this warning if we don't end up picking a version based on pyproject.toml.
Related to #1427
This is not yet ready for review!The code is based on the Pipfile buildpack. We probably want to refactor some portions to avoid code duplication.