3
3
import shutil
4
4
import sysconfig
5
5
import platform
6
+ import fnmatch
6
7
7
8
from setuptools import setup
8
9
from distutils .command .build_scripts import build_scripts as distutils_build_scripts
9
10
from setuptools .command .build_py import build_py as setuptools_build_py
10
- from setuptools .command .egg_info import egg_info as setuptools_egg_info
11
- from distutils .errors import ( DistutilsSetupError , DistutilsModuleError ,
12
- DistutilsOptionError )
11
+ from setuptools .command .editable_wheel import editable_wheel as setuptools_editable_wheel
12
+ from setuptools .errors import SetupError
13
+
13
14
14
15
class build_py (setuptools_build_py ):
15
16
16
17
def run (self ):
17
- DOT_SAGE = os .environ .get ('DOT_SAGE' , os .path .join (os .environ .get ('HOME' ), '.sage' ))
18
18
HERE = os .path .dirname (__file__ )
19
- with open (os .path .join (HERE , 'VERSION.txt' )) as f :
20
- sage_version = f .read ().strip ()
19
+ if self .editable_mode :
20
+ SAGE_ROOT = os .path .join (HERE , 'sage_root' )
21
+ else :
22
+ SAGE_ROOT = self ._create_writable_sage_root ()
23
+
21
24
# For convenience, set up the homebrew env automatically. This is a no-op if homebrew is not present.
22
- SETENV = '(. ./.homebrew-build-env 2> /dev/null || :)'
23
- # After #30534, SAGE_LOCAL no longer contains any Python. So we key the SAGE_ROOT only to Sage version
24
- # and architecture.
25
- system = platform .system ()
26
- machine = platform .machine ()
27
- arch_tag = f'{ system } -{ machine } '
28
- # TODO: These two should be user-configurable with options passed to "setup.py install"
29
- SAGE_ROOT = os .path .join (DOT_SAGE , f'sage-{ sage_version } -{ arch_tag } ' )
25
+ if os .environ .get ('CONDA_PREFIX' , '' ):
26
+ SETENV = ':'
27
+ else :
28
+ SETENV = '(. ./.homebrew-build-env 2> /dev/null || :)'
29
+
30
30
SAGE_LOCAL = os .path .join (SAGE_ROOT , 'local' )
31
+
31
32
if os .path .exists (os .path .join (SAGE_ROOT , 'config.status' )):
32
- print (f'Reusing SAGE_ROOT={ SAGE_ROOT } ' )
33
+ print (f'Reusing configured SAGE_ROOT={ SAGE_ROOT } ' )
33
34
else :
34
- # config.status and other configure output has to be writable.
35
- # So (until the Sage distribution supports VPATH builds - #21469), we have to make a copy of sage_root.
36
- try :
37
- shutil .copytree ('sage_root' , SAGE_ROOT ) # will fail if already exists
38
- except Exception :
39
- raise DistutilsSetupError (f"the directory SAGE_ROOT={ SAGE_ROOT } already exists but it is not configured. Please remove it and try again." )
40
35
cmd = f"cd { SAGE_ROOT } && { SETENV } && ./configure --prefix={ SAGE_LOCAL } --with-python={ sys .executable } --enable-build-as-root --enable-download-from-upstream-url --with-system-python3=force --with-sage-venv --disable-notebook --disable-sagelib --disable-sage_conf --disable-doc"
41
36
print (f"Running { cmd } " )
42
37
sys .stdout .flush ()
@@ -45,7 +40,18 @@ def run(self):
45
40
sys .stdout .flush ()
46
41
PREREQ_SPKG = "_prereq bzip2 xz libffi" # includes python3 SPKG_DEPCHECK packages
47
42
os .system (f'cd { SAGE_ROOT } && export SYSTEM=$(build/bin/sage-guess-package-system 2>/dev/null) && export PACKAGES="$(build/bin/sage-get-system-packages $SYSTEM { PREREQ_SPKG } )" && [ -n "$PACKAGES" ] && echo "You can install the required build prerequisites using the following shell command" && echo "" && build/bin/sage-print-system-package-command $SYSTEM --verbose --sudo install $PACKAGES && echo ""' )
48
- raise DistutilsSetupError ("configure failed" )
43
+ raise SetupError ("configure failed" )
44
+
45
+ # Copy over files generated by the configure script
46
+ # (see configure.ac AC_CONFIG_FILES)
47
+ if self .editable_mode :
48
+ pass # same file
49
+ else :
50
+ shutil .copyfile (os .path .join (SAGE_ROOT , 'pkgs' , 'sage-conf' , '_sage_conf' , '_conf.py' ),
51
+ os .path .join (HERE , '_sage_conf' , '_conf.py' ))
52
+ shutil .copyfile (os .path .join (SAGE_ROOT , 'src' , 'bin' , 'sage-env-config' ),
53
+ os .path .join (HERE , 'bin' , 'sage-env-config' ))
54
+
49
55
# Here we run "make build" -- which builds everything except for sagelib because we
50
56
# used configure --disable-sagelib
51
57
# Alternative:
@@ -61,13 +67,44 @@ def run(self):
61
67
if os .system (cmd ) != 0 :
62
68
raise DistutilsSetupError (f"make { TARGETS } failed" )
63
69
64
- # Install configuration
65
- shutil .copyfile (os .path .join (SAGE_ROOT , 'pkgs' , 'sage-conf' , '_sage_conf' , '_conf.py' ),
66
- os .path .join (HERE , '_sage_conf' , '_conf.py' ))
67
- shutil .copyfile (os .path .join (SAGE_ROOT , 'src' , 'bin' , 'sage-env-config' ),
68
- os .path .join (HERE , 'bin' , 'sage-env-config' ))
69
70
setuptools_build_py .run (self )
70
71
72
+ def _create_writable_sage_root (self ):
73
+ HERE = os .path .dirname (__file__ )
74
+ DOT_SAGE = os .environ .get ('DOT_SAGE' , os .path .join (os .environ .get ('HOME' ), '.sage' ))
75
+ with open (os .path .join (HERE , 'VERSION.txt' )) as f :
76
+ sage_version = f .read ().strip ()
77
+ # After #30534, SAGE_LOCAL no longer contains any Python. So we key the SAGE_ROOT only to Sage version
78
+ # and architecture.
79
+ system = platform .system ()
80
+ machine = platform .machine ()
81
+ arch_tag = f'{ system } -{ machine } '
82
+ # TODO: Should be user-configurable with config settings
83
+ SAGE_ROOT = os .path .join (DOT_SAGE , f'sage-{ sage_version } -{ arch_tag } ' )
84
+
85
+ def ignore (path , names ):
86
+ # exclude all embedded src trees
87
+ if fnmatch .fnmatch (path , f'*/build/pkgs/*' ):
88
+ return ['src' ]
89
+ ### ignore more stuff --- .tox etc.
90
+ return [name for name in names
91
+ if name in ('.tox' , '.git' , '__pycache__' ,
92
+ 'prefix' , 'local' , 'venv' , 'upstream' ,
93
+ 'config.status' , 'config.log' , 'logs' )]
94
+
95
+ if not os .path .exists (os .path .join (SAGE_ROOT , 'config.status' )):
96
+ # config.status and other configure output has to be writable.
97
+ # So (until the Sage distribution supports VPATH builds - #21469), we have to make a copy of sage_root.
98
+ try :
99
+ shutil .copytree ('sage_root' , SAGE_ROOT ,
100
+ ignore = ignore ) # will fail if already exists
101
+ except Exception as e :
102
+ raise SetupError (f"the directory SAGE_ROOT={ SAGE_ROOT } already exists but it is not configured ({ e } ). "
103
+ "Please either remove it and try again, or install in editable mode (pip install -e)." )
104
+
105
+ return SAGE_ROOT
106
+
107
+
71
108
class build_scripts (distutils_build_scripts ):
72
109
73
110
def run (self ):
@@ -76,6 +113,17 @@ def run(self):
76
113
self .entry_points = self .distribution .entry_points = dict ()
77
114
distutils_build_scripts .run (self )
78
115
116
+
117
+ class editable_wheel (setuptools_editable_wheel ):
118
+ r"""
119
+ Customized so that exceptions raised by our build_py
120
+ do not lead to the "Customization incompatible with editable install" message
121
+ """
122
+ _safely_run = setuptools_editable_wheel .run_command
123
+
124
+
79
125
setup (
80
- cmdclass = dict (build_py = build_py , build_scripts = build_scripts )
126
+ cmdclass = dict (build_py = build_py ,
127
+ build_scripts = build_scripts ,
128
+ editable_wheel = editable_wheel )
81
129
)
0 commit comments