1+ """Buildpack for Git repositories with pyproject.toml
2+
3+ Support to pyproject.toml was added to pip v10.0,
4+ see https://pip.pypa.io/en/latest/reference/build-system/pyproject-toml/.
5+ """
6+
7+ import os
8+ import re
9+ import tomllib
10+
11+ from ..conda import CondaBuildPack
12+
13+ VERSION_PAT = re .compile (r"\d+(\.\d+)*" )
14+
15+
16+ class PyprojectBuildPack (CondaBuildPack ):
17+ """Setup Python with pyproject.toml for use with a repository."""
18+
19+ @property
20+ def python_version (self ):
21+ """
22+ Detect the Python version declared in a `pyproject.toml`.
23+ Will return 'x.y' if version is found (e.g '3.6'),
24+ or a Falsy empty string '' if not found.
25+ """
26+
27+ if hasattr (self , "_python_version" ):
28+ return self ._python_version
29+
30+ pyproject_file = self .binder_path ("pyproject.toml" )
31+ with open (pyproject_file , "rb" ) as _pyproject_file :
32+ pyproject_toml = tomllib .load (_pyproject_file )
33+
34+ if "project" in pyproject_toml :
35+ if "requires-python" in pyproject_toml ["project" ]:
36+ raw_version = pyproject_toml ["project" ]["requires-python" ]
37+
38+ match = VERSION_PAT .match (raw_version )
39+ if match :
40+ return match .group ()
41+
42+ return ""
43+
44+ @lru_cache
45+ def get_preassemble_script_files (self ):
46+ """Return files needed for preassembly"""
47+ files = super ().get_preassemble_script_files ()
48+ path = self .binder_path ("pyproject.toml" )
49+ if os .path .exists (path ):
50+ files [path ] = path
51+ return files
52+
53+ @lru_cache
54+ def get_preassemble_scripts (self ):
55+ """scripts to run prior to staging the repo contents"""
56+ scripts = super ().get_preassemble_scripts ()
57+ # install pipenv to install dependencies within Pipfile.lock or Pipfile
58+ if V (self .python_version ) < V ("3.6" ):
59+ # last pipenv version to support 2.7, 3.5
60+ pipenv_version = "2021.5.29"
61+ else :
62+ pipenv_version = "2022.1.8"
63+ scripts .append (
64+ (
65+ "${NB_USER}" ,
66+ f"${{KERNEL_PYTHON_PREFIX}}/bin/pip install --no-cache-dir pipenv=={ pipenv_version } " ,
67+ )
68+ )
69+ return scripts
70+
71+ @lru_cache
72+ def get_assemble_scripts (self ):
73+ """Return series of build-steps specific to this repository."""
74+ # If we have pyproject.toml declare the
75+ # use of Python 2, Python 2.7 will be made available in the *kernel*
76+ # environment. The notebook servers environment on the other hand
77+ # requires Python 3 but may require something additional installed in it
78+ # still such as `nbgitpuller`. For this purpose, a "requirements3.txt"
79+ # file will be used to install dependencies for the notebook servers
80+ # environment, if Python 2 had been specified for the kernel
81+ # environment.
82+ assemble_scripts = super ().get_assemble_scripts ()
83+
84+ if self .separate_kernel_env :
85+ # using legacy Python (e.g. 2.7) as a kernel
86+
87+ # requirements3.txt allows for packages to be installed to the
88+ # notebook servers Python environment
89+ nb_requirements_file = self .binder_path ("requirements3.txt" )
90+ if os .path .exists (nb_requirements_file ):
91+ assemble_scripts .append (
92+ (
93+ "${NB_USER}" ,
94+ f'${{NB_PYTHON_PREFIX}}/bin/pip install --no-cache-dir -r "{ nb_requirements_file } "' ,
95+ )
96+ )
97+
98+ assemble_scripts .append (
99+ (
100+ "${NB_USER}" ,
101+ """(cd && \\
102+ PATH="${{KERNEL_PYTHON_PREFIX}}/bin:$PATH" \\
103+ pip install --no-cache-dir --editable {working_directory}
104+ )""" .format (
105+ working_directory = working_directory ,
106+ ),
107+ )
108+ )
109+
110+ return assemble_scripts
111+
112+ def detect (self ):
113+ """Check if current repo should be built with the pyproject.toml buildpack."""
114+ # first make sure python is not explicitly unwanted
115+ runtime_txt = self .binder_path ("runtime.txt" )
116+ if os .path .exists (runtime_txt ):
117+ with open (runtime_txt ) as f :
118+ runtime = f .read ().strip ()
119+ if not runtime .startswith ("python-" ):
120+ return False
121+
122+ pyproject_file = self .binder_path ("pyproject.toml" )
123+
124+ return os .path .exists (pyproject_file )
0 commit comments