partis-pyproj 0.1.4__tar.gz → 0.1.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- partis_pyproj-0.1.6/PKG-INFO +500 -0
- partis_pyproj-0.1.6/README.md +475 -0
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/pyproject.toml +26 -63
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/__init__.py +9 -1
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/_legacy_setup.py +11 -11
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/_nonprintable.py +4 -3
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/backend.py +44 -37
- partis_pyproj-0.1.6/src/pyproj/builder/builder.py +351 -0
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/builder/cargo.py +2 -2
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/builder/cmake.py +9 -15
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/builder/meson.py +5 -13
- partis_pyproj-0.1.6/src/pyproj/builder/process.py +42 -0
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/__init__.py +1 -1
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/dist_base.py +75 -86
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/dist_binary.py +6 -24
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/dist_copy.py +7 -18
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/dist_source.py +4 -21
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/dist_targz.py +5 -12
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/dist_file/dist_zip.py +5 -14
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/file.py +2 -1
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/legacy.py +3 -2
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/load_module.py +7 -6
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/norms.py +35 -31
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/path/__init__.py +2 -1
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/path/match.py +42 -35
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/path/pattern.py +60 -54
- partis_pyproj-0.1.6/src/pyproj/path/utils.py +94 -0
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/pep.py +36 -35
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/pkginfo.py +7 -16
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/pptoml.py +125 -120
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/pyproj.py +47 -36
- partis_pyproj-0.1.6/src/pyproj/template.py +229 -0
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/validate.py +273 -268
- partis_pyproj-0.1.4/PKG-INFO +0 -53
- partis_pyproj-0.1.4/README.rst +0 -4
- partis_pyproj-0.1.4/doc/__init__.py +0 -0
- partis_pyproj-0.1.4/doc/__main__.py +0 -16
- partis_pyproj-0.1.4/doc/conf.py +0 -13
- partis_pyproj-0.1.4/doc/glossary.rst +0 -12
- partis_pyproj-0.1.4/doc/index.rst +0 -553
- partis_pyproj-0.1.4/doc/src/backend.rst +0 -4
- partis_pyproj-0.1.4/doc/src/builder.rst +0 -9
- partis_pyproj-0.1.4/doc/src/dist_file.rst +0 -34
- partis_pyproj-0.1.4/doc/src/index.rst +0 -17
- partis_pyproj-0.1.4/doc/src/load_module.rst +0 -4
- partis_pyproj-0.1.4/doc/src/norms.rst +0 -4
- partis_pyproj-0.1.4/doc/src/path.rst +0 -8
- partis_pyproj-0.1.4/doc/src/pep.rst +0 -4
- partis_pyproj-0.1.4/doc/src/pkginfo.rst +0 -27
- partis_pyproj-0.1.4/doc/src/pptoml.rst +0 -4
- partis_pyproj-0.1.4/doc/src/pyproj.rst +0 -4
- partis_pyproj-0.1.4/doc/src/validate.rst +0 -4
- partis_pyproj-0.1.4/setup.py +0 -211
- partis_pyproj-0.1.4/src/pyproj/builder/builder.py +0 -267
- partis_pyproj-0.1.4/src/pyproj/builder/process.py +0 -75
- partis_pyproj-0.1.4/src/pyproj/path/utils.py +0 -40
- partis_pyproj-0.1.4/test/__init__.py +0 -0
- partis_pyproj-0.1.4/test/__main__.py +0 -32
- partis_pyproj-0.1.4/test/noxfile.py +0 -122
- partis_pyproj-0.1.4/test/pkg_bad_1/pyproject.toml +0 -69
- partis_pyproj-0.1.4/test/pkg_bad_1/src/test_pkg/pure_mod/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_1/src/test_pkg/sub_mod/sub_sub_mod/bad_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_1/src/test_pkg/sub_mod/sub_sub_mod/good_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_2/pkgaux/__init__.py +0 -15
- partis_pyproj-0.1.4/test/pkg_bad_2/pyproject.toml +0 -69
- partis_pyproj-0.1.4/test/pkg_bad_2/src/test_pkg/pure_mod/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_2/src/test_pkg/sub_mod/sub_sub_mod/bad_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_2/src/test_pkg/sub_mod/sub_sub_mod/good_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_3/pyproject.toml +0 -27
- partis_pyproj-0.1.4/test/pkg_bad_4/pkgaux/__init__.py +0 -23
- partis_pyproj-0.1.4/test/pkg_bad_4/pyproject.toml +0 -58
- partis_pyproj-0.1.4/test/pkg_bad_4/src/test_pkg/pure_mod/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_4/src/test_pkg/sub_mod/sub_sub_mod/bad_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_4/src/test_pkg/sub_mod/sub_sub_mod/good_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_5/pkgaux/__init__.py +0 -15
- partis_pyproj-0.1.4/test/pkg_bad_5/pyproject.toml +0 -46
- partis_pyproj-0.1.4/test/pkg_bad_5/src/test_pkg/pure_mod/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_5/src/test_pkg/sub_mod/sub_sub_mod/bad_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_bad_5/src/test_pkg/sub_mod/sub_sub_mod/good_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_base/pkgaux/__init__.py +0 -23
- partis_pyproj-0.1.4/test/pkg_base/pyproject.toml +0 -69
- partis_pyproj-0.1.4/test/pkg_base/src/test_pkg/pure_mod/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_base/src/test_pkg/sub_mod/bad_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_base/src/test_pkg/sub_mod/good_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_base/src/test_pkg/sub_mod/sub_sub_mod/bad_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_base/src/test_pkg/sub_mod/sub_sub_mod/good_file.py +0 -0
- partis_pyproj-0.1.4/test/pkg_cmake_1/CMakeLists.txt +0 -15
- partis_pyproj-0.1.4/test/pkg_cmake_1/pyproject.toml +0 -56
- partis_pyproj-0.1.4/test/pkg_cmake_1/src/test_pkg/CMakeLists.txt +0 -11
- partis_pyproj-0.1.4/test/pkg_cmake_1/src/test_pkg/plat_mod.pyx +0 -4
- partis_pyproj-0.1.4/test/pkg_cmake_1/src/test_pkg/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_meson_1/meson.build +0 -24
- partis_pyproj-0.1.4/test/pkg_meson_1/meson_options.txt +0 -11
- partis_pyproj-0.1.4/test/pkg_meson_1/pyproject.toml +0 -63
- partis_pyproj-0.1.4/test/pkg_meson_1/src/test_pkg/plat_mod.pyx +0 -4
- partis_pyproj-0.1.4/test/pkg_meson_1/src/test_pkg/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_meson_2/meson.build +0 -24
- partis_pyproj-0.1.4/test/pkg_meson_2/meson_options.txt +0 -11
- partis_pyproj-0.1.4/test/pkg_meson_2/pyproject.toml +0 -63
- partis_pyproj-0.1.4/test/pkg_meson_2/src/test_pkg/plat_mod.pyx +0 -4
- partis_pyproj-0.1.4/test/pkg_meson_2/src/test_pkg/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/bad_link/meson.build +0 -24
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/bad_link/meson_options.txt +0 -11
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/bad_link/pyproject.toml +0 -63
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/bad_link/src/test_pkg/plat_mod.pyx +0 -4
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/bad_link/src/test_pkg/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/meson.build +0 -24
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/meson_options.txt +0 -11
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/pyproject.toml +0 -65
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/src/test_pkg/plat_mod.pyx +0 -4
- partis_pyproj-0.1.4/test/pkg_meson_bad_1/src/test_pkg/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_min/pure_mod.py +0 -0
- partis_pyproj-0.1.4/test/pkg_min/pyproject.toml +0 -26
- partis_pyproj-0.1.4/test/sitecustom/partis-sitecustom.pth +0 -26
- partis_pyproj-0.1.4/test/sitecustom/pyproject.toml +0 -26
- partis_pyproj-0.1.4/test/test_00_validate.py +0 -498
- partis_pyproj-0.1.4/test/test_01_norms.py +0 -520
- partis_pyproj-0.1.4/test/test_02_path.py +0 -302
- partis_pyproj-0.1.4/test/test_03_dist.py +0 -315
- partis_pyproj-0.1.4/test/test_04_load_module.py +0 -25
- partis_pyproj-0.1.4/test/test_05_pkginfo.py +0 -208
- partis_pyproj-0.1.4/test/test_06_pyproj.py +0 -284
- partis_pyproj-0.1.4/test/test_07_backend.py +0 -57
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/LICENSE.txt +0 -0
- {partis_pyproj-0.1.4 → partis_pyproj-0.1.6}/src/pyproj/builder/__init__.py +0 -0
@@ -0,0 +1,500 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: partis-pyproj
|
3
|
+
Version: 0.1.6
|
4
|
+
Requires-Python: >=3.8
|
5
|
+
Author-email: "Nanohmics Inc." <software.support@nanohmics.com>
|
6
|
+
Maintainer-email: "Nanohmics Inc." <software.support@nanohmics.com>
|
7
|
+
Summary: Minimal set of Python project utilities (PEP-517/621)
|
8
|
+
License-File: LICENSE.txt
|
9
|
+
Classifier: License :: OSI Approved :: BSD License
|
10
|
+
Classifier: Intended Audience :: Developers
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Topic :: Software Development :: Build Tools
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
14
|
+
Classifier: Programming Language :: Python
|
15
|
+
Classifier: Operating System :: POSIX :: Linux
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
17
|
+
Provides-Extra: meson
|
18
|
+
Provides-Extra: cmake
|
19
|
+
Requires-Dist: tomli>=2.0.1
|
20
|
+
Requires-Dist: packaging>=24.2
|
21
|
+
Requires-Dist: meson>=0.61.3; extra == "meson"
|
22
|
+
Requires-Dist: ninja>=1.10.2.3; extra == "meson"
|
23
|
+
Requires-Dist: cmake>=3.24.3; extra == "cmake"
|
24
|
+
Requires-Dist: ninja>=1.10.2.3; extra == "cmake"
|
25
|
+
Description-Content-Type: text/markdown
|
26
|
+
|
27
|
+
[](https://github.com/kcdodd/partis-pyproj/actions/workflows/tests.yaml)
|
28
|
+
|
29
|
+
The ``partis.pyproj`` package aims to be a minimal and
|
30
|
+
transparent implementation of a [PEP-517](https://www.python.org/dev/peps/pep-0517) build back-end.
|
31
|
+
The guiding principles adopted for ``partis.pyproj`` are:
|
32
|
+
|
33
|
+
* Stateless and agnostic to project structure and management, focused on the
|
34
|
+
stages of preparing a distribution.
|
35
|
+
* Avoid inspecting or inferring "desired behavior" from the contents of the package
|
36
|
+
being distributed / installed, and provide as much control as possible over the
|
37
|
+
entire process.
|
38
|
+
* All configuration of ``partis.pyproj`` contained in ``pyproject.toml``
|
39
|
+
* A distribution is simply a collection of files,
|
40
|
+
plus package meta-data for either source or binary (wheel) distribution formats.
|
41
|
+
|
42
|
+
The process of building a source or binary distribution is broken down into
|
43
|
+
three general stages:
|
44
|
+
|
45
|
+
- **prepare** - Actions required to start the process of creating a distribution.
|
46
|
+
The 'prep' may be any custom function the developer wants to occur before files
|
47
|
+
are copied into the distribution, such as filling in dynamic metadata.
|
48
|
+
- **build** - If needed, running one or more build stages using third-party
|
49
|
+
or custom methods. ``partis.pyproj`` provides some standard structure to this
|
50
|
+
configuration, but otherwise avoids taking on the responsibility of a full build system.
|
51
|
+
- **copy** - Copy files into the distribution.
|
52
|
+
|
53
|
+
|
54
|
+
The sequence of actions for a distribution is roughly:
|
55
|
+
|
56
|
+
- `tool.pyproj.prep`: Run before anything else, used to fill in dynamic metadata or
|
57
|
+
update to `build_requires` list for binary distributions (front-end to install build requirements).
|
58
|
+
- `tool.pyproj.dist.prep`: Run for both source and binary distributions to prepare
|
59
|
+
or configure initial files.
|
60
|
+
- `tool.pyproj.dist.source.prep`: Runs before copying files to a source distribution.
|
61
|
+
- `tool.pyproj.targets`: Run build targets, in order, where `enabled` evaluates to true
|
62
|
+
(conditions based on [environment markers](https://packaging.pypa.io/en/stable/markers.html)).
|
63
|
+
- `tool.pyproj.dist.binary.prep`: Run before copying files to a binary distribution
|
64
|
+
(after all enabled build targets complete).
|
65
|
+
Can also customize compatibility tags for the binary distribution as per [PEP 425](https://peps.python.org/pep-0425/).
|
66
|
+
|
67
|
+
### Copy Operations
|
68
|
+
|
69
|
+
The majority of ``partis.pyproj`` is devoted to copying files into a distribution.
|
70
|
+
This logic is the most complicated, but derives from a combination of existing
|
71
|
+
formats and behaviors.
|
72
|
+
|
73
|
+
**Source and destination**
|
74
|
+
|
75
|
+
* Each item listed in a `copy` is treated like `copyfile` or `copytree`, depending on whether the `src` is a file or a directory.
|
76
|
+
* All `src` must exist within the root of the project, any external or generated
|
77
|
+
files must be prepared before the copy operation.
|
78
|
+
* If `src` is a directory, all files are copied recursively unless they
|
79
|
+
match an ignore pattern for that distribution type.
|
80
|
+
* If an item is a single path, it is expanded as ``dst = src``.
|
81
|
+
* `dst` is relative, specifically depending on whether it is a source or binary (wheel) distribution and which install scheme is desired (`purelib`, `platlib`, etc.).
|
82
|
+
* Destination file paths are constructed from matched source paths roughly equivalent
|
83
|
+
to `{scheme}/dst/match.relative_to(src)`.
|
84
|
+
|
85
|
+
**Include patterns**
|
86
|
+
|
87
|
+
* An `include` list is used to filter files or directories to be copied, expanded
|
88
|
+
to zero or more matches relative to `src`.
|
89
|
+
* `glob` follows the format of [Path.glob](https://docs.python.org/3/library/pathlib.html#pathlib.Path.glob), with recursion.
|
90
|
+
* `rematch` may further discriminate files (already matched by `glob`) using [Regular Expression Syntax](https://docs.python.org/3/library/re.html#regular-expression-syntax).
|
91
|
+
* `replace` can change destination filenames using
|
92
|
+
[Format String Syntax](https://docs.python.org/3/library/string.html#format-string-syntax), with values supplied by any groups defined in `rematch`.
|
93
|
+
|
94
|
+
**Ignore patterns**
|
95
|
+
|
96
|
+
* An `ignore` list follows the format of [git-ignore](https://git-scm.com/docs/gitignore#_pattern_format).
|
97
|
+
* Individual *files* explicitly listed as a `src` will be copied, even if it
|
98
|
+
matches one of the `ignore` patterns.
|
99
|
+
* The `ignore` patterns may be specified at different levels of distributions in
|
100
|
+
``tool.pyproj.dist``, ``tool.pyproj.dist.source``, ``tool.pyproj.dist.binary``,or individual copy operations ``{ src = '...', dst = '...', ignore = [...] }``.
|
101
|
+
The ignore patterns are inherited at each level of specificity.
|
102
|
+
* If an ignore pattern **does not contain** any path separators, it is matched to
|
103
|
+
the **base-name** of every file or directory being considered (E.G. `foo` is
|
104
|
+
equivalent to ``**/foo``).
|
105
|
+
* If an ignore pattern **does contain** a path separator, then it is matched to the
|
106
|
+
**full path** relative to either the project root (for distribution-level ignores)
|
107
|
+
or `src` (for copy-level ignores).
|
108
|
+
|
109
|
+
|
110
|
+
Individual copy operations have the following structure, but there are also
|
111
|
+
shorthands where the rest are default. A semi-formal description of this configuration follows:
|
112
|
+
|
113
|
+
```
|
114
|
+
copy: copy_item | array{copy_item}
|
115
|
+
copy_item: PATH | table{"src =" PATH, "dst =" PATH?, "include =" include?, "ignore =" ignore?}
|
116
|
+
include: GLOB | array{include_item}
|
117
|
+
include_item: GLOB | table{"glob =" GLOB, "rematch =" REGEX?, "replace =" FORMAT?}
|
118
|
+
ignore: IGNORE | array{IGNORE}
|
119
|
+
|
120
|
+
PATH: < POSIX path, implicitly relative to project root >
|
121
|
+
GLOB: < https://docs.python.org/3/library/glob.html#glob.glob >
|
122
|
+
REGEX: < https://docs.python.org/3/library/re.html#regular-expression-syntax >
|
123
|
+
FORMAT: < https://docs.python.org/3/library/string.html#formatstrings >
|
124
|
+
IGNORE: < https://git-scm.com/docs/gitignore#_pattern_format >
|
125
|
+
```
|
126
|
+
|
127
|
+
**Example**
|
128
|
+
|
129
|
+
```toml
|
130
|
+
# pyproject.toml
|
131
|
+
[tool.pyproj.dist]
|
132
|
+
ignore = [
|
133
|
+
'__pycache__',
|
134
|
+
'doc/_build' ]
|
135
|
+
|
136
|
+
[tool.pyproj.dist.source]
|
137
|
+
|
138
|
+
ignore = [
|
139
|
+
'*.so' ]
|
140
|
+
|
141
|
+
copy = [
|
142
|
+
'src',
|
143
|
+
'doc',
|
144
|
+
'pyproject.toml' ]
|
145
|
+
|
146
|
+
[[tool.pyproj.dist.binary.purelib.copy]]
|
147
|
+
src = 'src/my_project'
|
148
|
+
include = '**/*.py'
|
149
|
+
dst = 'my_project'
|
150
|
+
ignore = [
|
151
|
+
'bad_file.py',
|
152
|
+
'./config_file.py']
|
153
|
+
|
154
|
+
[[tool.pyproj.dist.binary.platlib.copy]]
|
155
|
+
src = 'src/my_project'
|
156
|
+
include = '**/*.so'
|
157
|
+
dst = 'my_project'
|
158
|
+
```
|
159
|
+
|
160
|
+
|
161
|
+
##### Source Distribution (``.tar.gz``)
|
162
|
+
|
163
|
+
| Result | File Path |
|
164
|
+
|--------|-----------|
|
165
|
+
| **Included** | ``pyproject.toml`` |
|
166
|
+
| **Included** | ``doc/index.rst`` |
|
167
|
+
| **Included** | ``src/my_project/__init__.py`` |
|
168
|
+
| **Included** | ``src/doc/_build`` |
|
169
|
+
| *Ignored* | ``doc/_build`` |
|
170
|
+
| *Ignored* | ``doc/__pycache__`` |
|
171
|
+
| *Ignored* | `__pycache__` |
|
172
|
+
| *Ignored* | ``src/__pycache__`` |
|
173
|
+
| *Ignored* | ``src/my_project/mylib.so`` |
|
174
|
+
|
175
|
+
|
176
|
+
##### Binary Distribution (``.whl``)
|
177
|
+
|
178
|
+
| Result | File Path |
|
179
|
+
|--------|-----------|
|
180
|
+
| **Included** | ``src/my_project/__init__.py`` |
|
181
|
+
| **Included** | ``src/my_project/sub_dir/__init__.py`` |
|
182
|
+
| **Included** | ``src/my_project/sub_dir/config_file.py`` |
|
183
|
+
| **Included** | ``src/my_project/mylib.so`` |
|
184
|
+
| *Ignored* | ``src/my_project/bad_file.py`` |
|
185
|
+
| *Ignored* | ``src/my_project/config_file.py`` |
|
186
|
+
| *Ignored* | ``src/my_project/sub_dir/bad_file.py`` |
|
187
|
+
|
188
|
+
|
189
|
+
Preparation Hooks
|
190
|
+
-----------------
|
191
|
+
|
192
|
+
The backend provides a mechanism to perform an arbitrary operation before any
|
193
|
+
files are copied into either the source or binary distribution:
|
194
|
+
|
195
|
+
Each hook must be a python module (a directory with an
|
196
|
+
``__init__.py`` file), either directly importable or relative to the 'pyproject.toml'.
|
197
|
+
The hook is specified according to the `entry_points` specification, and
|
198
|
+
must resolve to a function that takes the instance of the build system and
|
199
|
+
a logger.
|
200
|
+
Keyword arguments may also be defined to be passed to the function,
|
201
|
+
configured in the same section of the 'pyproject.toml'.
|
202
|
+
|
203
|
+
```toml
|
204
|
+
# pyproject.toml
|
205
|
+
[tool.pyproj.dist.binary.prep]
|
206
|
+
# hook defined in a python module
|
207
|
+
entry = "a_custom_prep_module:a_prep_function"
|
208
|
+
|
209
|
+
[tool.pyproj.dist.binary.prep.kwargs]
|
210
|
+
# define keyword argument values to be passed to the pre-processing hook
|
211
|
+
a_custom_argument = 'some value'
|
212
|
+
```
|
213
|
+
|
214
|
+
This will be treated by the backend **equivalent to the
|
215
|
+
following code** run from the `pyproject.toml` directory:
|
216
|
+
|
217
|
+
```python
|
218
|
+
# equivalent backend
|
219
|
+
import a_custom_prep_module
|
220
|
+
|
221
|
+
a_custom_prep_module.a_prep_function(
|
222
|
+
backend,
|
223
|
+
logger,
|
224
|
+
a_custom_argument = 'some value' )
|
225
|
+
```
|
226
|
+
|
227
|
+
> :warning: Only those requirements listed in `build-system.requires`
|
228
|
+
> will be importable during `tool.pyproj.prep`, and only those added to
|
229
|
+
> `backend.build_requires` will be available in subsequent hooks.
|
230
|
+
|
231
|
+
Dynamic Metadata
|
232
|
+
----------------
|
233
|
+
|
234
|
+
As described in [PEP-621](https://www.python.org/dev/peps/pep-0621), field values in the `project` table may be deferred
|
235
|
+
to the backend by listing the keys in `project.dynamic`, which must be set by the `tool.pyproj.prep` processing hook.
|
236
|
+
|
237
|
+
```toml
|
238
|
+
# pyproject.toml
|
239
|
+
[project]
|
240
|
+
name = "my_pkg"
|
241
|
+
dynamic = ["version"]
|
242
|
+
|
243
|
+
[tool.pyproj.prep]
|
244
|
+
entry = "pkgaux:prep"
|
245
|
+
```
|
246
|
+
|
247
|
+
The hook should set values for all keys of the `project` table listed
|
248
|
+
in ``project.dynamic``.
|
249
|
+
|
250
|
+
```python
|
251
|
+
def prep( backend, logger ):
|
252
|
+
backend.project.version = "1.2.3"
|
253
|
+
```
|
254
|
+
|
255
|
+
#### Build Targets
|
256
|
+
|
257
|
+
Methods of compiling extensions (or anything else) is delegated to third-party
|
258
|
+
build systems specified in the 'pyproject.toml' array ``tool.pyproj.targets``.
|
259
|
+
This means that, unlike with setuptools, detailed configuration of the build itself
|
260
|
+
would likely be stored in separate files like ``meson.build`` with Meson,
|
261
|
+
or ``CMakeLists.txt`` with CMake.
|
262
|
+
|
263
|
+
In case different options are needed depending on the environment, the `enabled`
|
264
|
+
field can be a [PEP-508](https://www.python.org/dev/peps/pep-0508) [environment marker](https://packaging.pypa.io/en/stable/markers.html),
|
265
|
+
or can also be set manually (True/False) by an earlier 'prep' stage.
|
266
|
+
Each third-party build system is given by the `entry`, which is an entry-point
|
267
|
+
to a function that takes in the arguments and options given in the table
|
268
|
+
for that build.
|
269
|
+
|
270
|
+
**standard config**
|
271
|
+
```
|
272
|
+
entry: ENTRY_POINT # entry-point specification of builder to use
|
273
|
+
work_dir: PATH # directory from which the builder will be run
|
274
|
+
src_dir: PATH # directory of source code
|
275
|
+
build_dir: PATH # directory for temporary build files (cleaned on exit)
|
276
|
+
prefix: PATH # directory which distribution files should be staged (cleaned on exit)
|
277
|
+
setup_args: array{STRING} # 3-stage build
|
278
|
+
compile_args: array{STRING} # 3-stage build
|
279
|
+
install_args: array{STRING} # 3-stage build
|
280
|
+
options: table{STRING|BOOL}? # options passed to builder from pyproject.toml
|
281
|
+
build_clean: BOOL? # control cleanup (ie for development builds)
|
282
|
+
enabled: (BOOL|MARKER)? # environment marker
|
283
|
+
```
|
284
|
+
|
285
|
+
There are several entry points available as-is:
|
286
|
+
|
287
|
+
- `partis.pyproj.builder:meson` - Support for [Meson Build system](https://mesonbuild.com/) with the 'extra' ``partis-pyproj[meson]``
|
288
|
+
- `partis.pyproj.builder:cmake` - Support for [CMake](https://cmake.org/) with the 'extra' ``partis-pyproj[cmake]``
|
289
|
+
- `partis.pyproj.builder:process` - Support for running arbitrary command line executable
|
290
|
+
|
291
|
+
In this example, the source directory must contain appropriate `meson.build` files,
|
292
|
+
since the 'pyproject.toml' configuration only provides a way of running
|
293
|
+
``meson setup`` and ``meson compile``.
|
294
|
+
For example:
|
295
|
+
|
296
|
+
```toml
|
297
|
+
# pyproject.toml
|
298
|
+
[[tool.pyproj.targets]]
|
299
|
+
|
300
|
+
entry = 'partis.pyproj.builder:meson'
|
301
|
+
|
302
|
+
# location to create temporary build files (optional)
|
303
|
+
build_dir = 'tmp/build'
|
304
|
+
# location to place final build targets
|
305
|
+
prefix = 'tmp/prefix'
|
306
|
+
|
307
|
+
[tool.pyproj.targets.options]
|
308
|
+
# Custom build options (e.g. passing to meson -Dcustom_feature=enabled)
|
309
|
+
custom_feature = 'enabled'
|
310
|
+
|
311
|
+
[tool.pyproj.dist.binary.platlib]
|
312
|
+
# binary distribution platform specific install path
|
313
|
+
copy = [
|
314
|
+
{ src = 'tmp/prefix/lib', dst = 'my_project' } ]
|
315
|
+
```
|
316
|
+
|
317
|
+
The `src_dir` and `prefix` paths are always relative to the project
|
318
|
+
root directory, and default to ``src_dir = '.'`` and ``prefix = './build'``.
|
319
|
+
Currently these must all be a sub-directory relative to the 'pyproject.toml'
|
320
|
+
(e.g. a specified temporary directory).
|
321
|
+
|
322
|
+
The result should be equivalent to running the following commands in a custom
|
323
|
+
defined builder:
|
324
|
+
|
325
|
+
```python
|
326
|
+
|
327
|
+
def custom_builder(
|
328
|
+
backend,
|
329
|
+
logger: logging.Logger,
|
330
|
+
options: dict,
|
331
|
+
work_dir: Path,
|
332
|
+
src_dir: Path,
|
333
|
+
build_dir: Path,
|
334
|
+
prefix: Path,
|
335
|
+
setup_args: list[str],
|
336
|
+
compile_args: list[str],
|
337
|
+
install_args: list[str],
|
338
|
+
build_clean: bool,
|
339
|
+
runner: ProcessRunner):
|
340
|
+
|
341
|
+
runner.run(['meson', 'setup', *setup_args, '--prefix', prefix, build_dir src_dir])
|
342
|
+
runner.run(['meson', 'compile', *compile_args, '-C', build_dir])
|
343
|
+
runner.run(['meson', 'install', *install_args, '-C', build_dir])
|
344
|
+
```
|
345
|
+
|
346
|
+
All files in 'build/lib' are then copied into the binary distribution's 'platlib' install path.
|
347
|
+
|
348
|
+
A custom 'builder' for the entry-point can also be used, and is simply a callable
|
349
|
+
with the correct signature.
|
350
|
+
|
351
|
+
**Template substitution**
|
352
|
+
|
353
|
+
The paths and options in build targets may contain template substitutions to more
|
354
|
+
easily pass environment-dependent information to the third-party build system.
|
355
|
+
The substitution rule is specialized to `partis-pyproj`, but derives from
|
356
|
+
Python [Template string](https://docs.python.org/3/library/string.html#template-strings) with additions to support nested identifiers and construction of paths. The commonality is:
|
357
|
+
|
358
|
+
- `$$` is an escape; it is replaced with a single `$`.
|
359
|
+
- `${identifier}` names a substitution placeholder matching a mapping key of "identifier".
|
360
|
+
|
361
|
+
However, `$identifier` (without braces) is not supported, instead allowing more expressive substitutions.
|
362
|
+
|
363
|
+
```
|
364
|
+
substitution: "${" (variable|literal|SEP)+ "}"
|
365
|
+
variable: IDENTIFIER ("." IDENTIFIER | "[" INTEGER "]")*
|
366
|
+
SEP: "/"
|
367
|
+
literal: "'" CHAR+ "'"
|
368
|
+
IDENTIFIER: < python identifier >
|
369
|
+
INTEGER: < integer >
|
370
|
+
CHAR: < ascii letter, number (not leading), or underscore >
|
371
|
+
```
|
372
|
+
|
373
|
+
Variable names can reference most of the content of the original 'pyproject.toml',
|
374
|
+
as well as values already substituted in the build target or earlier targets.
|
375
|
+
If the substitution contains any separators the result is interpreted as a path, converted to platform-specific filesystem format, and resolved to project directory.
|
376
|
+
|
377
|
+
**Example**
|
378
|
+
|
379
|
+
The value of `options.some_option` in the example below would be substituted with a filesystem equivalent path for `{root}/build/something/my_pkg/xyz/abc.so`:
|
380
|
+
|
381
|
+
|
382
|
+
```toml
|
383
|
+
# pyproject.toml
|
384
|
+
[project]
|
385
|
+
name = "my_pkg"
|
386
|
+
|
387
|
+
[[tool.pyproj.targets]]
|
388
|
+
prefix = "build/something"
|
389
|
+
options = {some_option = "${prefix/project.name/'xyz'/'abc.so'}"}
|
390
|
+
```
|
391
|
+
|
392
|
+
Binary distribution install paths
|
393
|
+
---------------------------------
|
394
|
+
|
395
|
+
If there are some binary distribution files that need to be installed to a
|
396
|
+
location according to a local installation scheme
|
397
|
+
these can be specified within sub-tables.
|
398
|
+
Available install scheme keys, and **example** corresponding install locations, are:
|
399
|
+
|
400
|
+
- `purelib` ("pure" library Python path): ``{prefix}/lib/python{X}.{Y}/site-packages/``
|
401
|
+
- `platlib` (platform specific Python path): ``{prefix}/lib{platform}/python{X}.{Y}/site-packages/``
|
402
|
+
Both `purelib` and `platlib` install to the base 'site-packages'
|
403
|
+
directory, so any files copied to these paths should be placed within a
|
404
|
+
desired top-level package directory.
|
405
|
+
|
406
|
+
- `headers` (INCLUDE search paths): ``{prefix}/include/{site}/python{X}.{Y}{abiflags}/{distname}/``
|
407
|
+
- `scripts` (executable search path): ``{prefix}/bin/``
|
408
|
+
Even though any files added to the `scripts` path will be installed to
|
409
|
+
the `bin` directory, there is often an issue with the 'execute' permission
|
410
|
+
being set correctly by the installer (e.g. `pip`).
|
411
|
+
The only verified way of ensuring an executable in the 'bin' directory is to
|
412
|
+
use the ``[project.scripts]`` section to add an entry point that will then
|
413
|
+
run the desired executable as a sub-process.
|
414
|
+
|
415
|
+
- `data` (generic data path): ``{prefix}/``
|
416
|
+
|
417
|
+
```toml
|
418
|
+
# pyproject.toml
|
419
|
+
[tool.pyproj.dist.binary.purelib]
|
420
|
+
copy = [
|
421
|
+
{ src = 'build/my_project.py', dst = 'my_project/my_project.py'} ]
|
422
|
+
|
423
|
+
[tool.pyproj.dist.binary.platlib]
|
424
|
+
copy = [
|
425
|
+
{ src = 'build/my_project.so', dst = 'my_project/my_project.so'} ]
|
426
|
+
|
427
|
+
[tool.pyproj.dist.binary.headers]
|
428
|
+
copy = [
|
429
|
+
{ src = 'build/header.hpp', dst = 'header.hpp' } ]
|
430
|
+
|
431
|
+
[tool.pyproj.dist.binary.scripts]
|
432
|
+
copy = [
|
433
|
+
{ src = 'build/script.py', dst = 'script.py'} ]
|
434
|
+
|
435
|
+
[tool.pyproj.dist.binary.data]
|
436
|
+
copy = [
|
437
|
+
{ src = 'build/data.dat', dst = 'data.dat' } ]
|
438
|
+
```
|
439
|
+
|
440
|
+
Config Settings
|
441
|
+
---------------
|
442
|
+
|
443
|
+
As described in [PEP-517](https://www.python.org/dev/peps/pep-0517),
|
444
|
+
an installer front-end may implement support for
|
445
|
+
passing additional options to the backend
|
446
|
+
(e.g. ``--config-settings`` in `pip`).
|
447
|
+
These options may be defined in the ``tool.pyproj.config`` table, which is used
|
448
|
+
to validate the allowed options, fill in default values, and cast to
|
449
|
+
desired types.
|
450
|
+
These settings, updated by any values passed from the front-end installer,
|
451
|
+
are available in any processing hook.
|
452
|
+
Combined with an entry-point `kwargs`, these can be used to keep all
|
453
|
+
conditional dependencies listed in ``pyproject.toml``.
|
454
|
+
|
455
|
+
|
456
|
+
The type is derived from the value parsed from ``pyproject.toml``.
|
457
|
+
For example, the value of `3` is parsed as an integer, while ``3.0`` is parsed
|
458
|
+
as a float.
|
459
|
+
Additionally, the ``tool.pyproj.config`` table may **not** contain nested tables,
|
460
|
+
since it must be able to map 1:1 with arguments passed on
|
461
|
+
the command line.
|
462
|
+
A single-level list may be set as a value to restrict the allowed value to
|
463
|
+
one of those in the list, with the first item in the list being used as the
|
464
|
+
default value.
|
465
|
+
|
466
|
+
Boolean values passed to ``--config-settings`` are parsed by comparing to
|
467
|
+
string values ``['true', 'True', 'yes', 'y', 'enable', 'enabled']``
|
468
|
+
or ``['false', 'False', 'no', 'n', 'disable', 'disabled']``.
|
469
|
+
|
470
|
+
```toml
|
471
|
+
|
472
|
+
[tool.pyproj.config]
|
473
|
+
a_cfg_option = false
|
474
|
+
another_option = ["foo", "bar"]
|
475
|
+
|
476
|
+
[tool.pyproj.prep]
|
477
|
+
entry = "pkgaux:prep"
|
478
|
+
kwargs = { deps = ["additional_build_dep >= 1.2.3"] }
|
479
|
+
```
|
480
|
+
|
481
|
+
```python
|
482
|
+
# pkgaux/__init__.py
|
483
|
+
|
484
|
+
def prep( backend, logger, deps ):
|
485
|
+
|
486
|
+
if backend.config_settings.a_cfg_option:
|
487
|
+
backend.build_requires |= set(deps)
|
488
|
+
|
489
|
+
if backend.config_settings.another_option == 'foo':
|
490
|
+
...
|
491
|
+
|
492
|
+
elif backend.config_settings.another_option == 'bar':
|
493
|
+
...
|
494
|
+
```
|
495
|
+
|
496
|
+
In this example, the command
|
497
|
+
``pip install --config-settings a_cfg_option=true ...`` will cause the
|
498
|
+
'additional_build_dep' to be installed before the build occurs.
|
499
|
+
The value of `another_option` may be either `foo` or `bar`,
|
500
|
+
and all other values will raise an exception before reaching the entry-point.
|