|
1 | | -<!-- ### Build tools for Python packages with complex build steps |
2 | | -If your package is not pure Python, or it has complex build steps (or build |
3 | | -steps that you need to customize), then you should consider using: |
4 | 1 |
|
5 | | -* Setuptools |
6 | | -* Hatch |
7 | | -* PDM |
8 | | -
|
9 | | -These tools allow you to customize your workflow with build steps needed |
10 | | -to compile code. --> |
11 | | - |
12 | | -<!-- From stefan: build, run tests on built version, load the built version into |
13 | | -Python (?how is this different from install??), make editable install, build |
14 | | -wheel, build sdist --> |
15 | | - |
16 | | -<!-- |
17 | | -The example below is taken from [this thread in GitHub](https://github.com/py-pkgs/py-pkgs/issues/95#issuecomment-1035584750). |
18 | | -
|
19 | | -```toml |
20 | | -[tool.poetry.dependencies] |
21 | | -python = ">=3.6" # This is muddled in as a dependency, while it's not like the others |
22 | | -numpy = ">=1.13.3" |
23 | | -typing_extensions = { version = ">=3.7", python = "<3.8" } |
24 | | -
|
25 | | -sphinx = {version = "^4.0", optional = true} |
26 | | -sphinx_book_theme = { version = ">=0.0.40", optional = true } |
27 | | -sphinx_copybutton = { version = ">=0.3.1", optional = true } |
28 | | -pytest = { version = ">=6", optional = true } |
29 | | -importlib_metadata = { version = ">=1.0", optional = true, python = "<3.8" } # TOML error to add an ending comma or new line, even if this gets long |
30 | | -boost-histogram = { version = ">=1.0", optional = true } |
31 | | -
|
32 | | -[tool.poetry.dev-dependencies] |
33 | | -pytest = ">=5.2" # All the optional stuff above doesn't help here! |
34 | | -importlib_metadata = {version = ">=1.0", python = "<3.8" } |
35 | | -boost_histogram = ">=1.0" |
36 | | -
|
37 | | -[tool.poetry.extras] |
38 | | -docs = ["sphinx", "sphinx_book_theme", "sphinx_copybutton"] |
39 | | -test = ["pytest", "importlib_metadata", "boost_histogram" ] |
40 | | -``` |
41 | | -
|
42 | | -vs PDM |
43 | | -
|
44 | | -```toml |
45 | | -[project] |
46 | | -requires-python = ">=3.6" |
47 | | -dependencies = [ |
48 | | - "numpy>=1.13.3", |
49 | | - "typing-extensions>=3.7; python_version<'3.8'", |
50 | | -] |
51 | | -
|
52 | | -# Only needed for extras |
53 | | -[project.optional-dependencies] |
54 | | -docs = [ |
55 | | - "sphinx>=4.0", |
56 | | - "sphinx-book-theme>=0.0.40", |
57 | | - "sphinx-copybutton>=0.3.1", |
58 | | -] |
59 | | -test = [ |
60 | | - "pytest>=6", |
61 | | - "importlib-metadata>=1.0; python_version<'3.8'", |
62 | | - "boost-histogram>=1.0", |
63 | | -] |
64 | | -
|
65 | | -# Only needed for "dev" installs |
66 | | -[tool.pdm.dev-dependencies] |
67 | | -dev = [ |
68 | | - "pytest>=6", |
69 | | - "importlib-metadata>=1.0; python_version<'3.8'", |
70 | | - "boost-histogram>=1.0", |
71 | | -] |
72 | | -``` |
73 | | -
|
74 | | -From Eli: |
75 | | -
|
76 | | -poetry: supports it (c extensions), but is undocumented and uses setuptools under the hood, they plan to change how this works and then document it |
77 | | -pdm-back-end: supports it, and documents it -- and also uses setuptools under the hood |
78 | | -hatchling: permits you to define hooks for you to write your own custom build steps, including to build C++ extensions |
79 | | -
|
80 | | -
|
81 | | -**PDM** does have some support for `C`/[`Cython`](https://cython.org/) extensions. [Click here to |
82 | | -learn more.](https://pdm.fming.dev/latest/pyproject/build/#build-platform-specific-wheels). This functionality uses setuptools "under the |
83 | | -hood". |
84 | | -
|
85 | | -
|
86 | | ---> |
87 | | - |
88 | | -<!-- |
89 | | -### Build front-ends |
90 | | -
|
91 | | -Build front-ends have a user-friendly interface that allow you to perform |
92 | | -common Python packaging tasks such as building your package, creating an |
93 | | -environment to run package tests and build documentation, and pushing to PyPI. |
94 | | -
|
95 | | -For instance, you can use **Flit**, **Hatch**, **Poetry** and **PDM** to both build your |
96 | | -package and to publish your package to PyPI (or test PyPI). However, if you |
97 | | -want a tool that also support environment management and versioning your package, |
98 | | -then you might prefer to use **Hatch**, **Poetry** or **PDM**. |
99 | | -
|
100 | | -Using a tool like **Flit**, **Hatch**, **Poetry** or **PDM** will simplify your workflow. |
101 | | -
|
102 | | -Example to build your package with **Flit**: |
103 | | -
|
104 | | -`flit build` |
105 | | -
|
106 | | -Example to publish to PyPI: |
107 | | -`flit publish --repository testpypi` |
108 | | -
|
109 | | -In the Python package build space **setuptools** is |
110 | | -the "OG" -the original tool that everyone used to use. |
111 | | -With a tool like `setuptools` you have the flexibility |
112 | | -to publish python pure python packages and packages with custom build steps. However, you will also need to use other tools. For example, you will use `twine` to publish to PyPI. |
113 | | -
|
114 | | -## An ecosystem of Python build tools |
115 | | -
|
116 | | -Below we introduce several of the most commonly used |
117 | | -Python packaging build tools. Each tool has various |
118 | | -features that might make you chose to use it |
119 | | -or not use it. There is no right or wrong tool to use |
120 | | -as far as pyOpenSci is concerned. We are just trying to |
121 | | -help you find the tool that works best for |
122 | | -your workflow. |
123 | | -Example build steps using setuptools: |
124 | | -======= --> |
125 | | - |
126 | | -<!-- TODO: create build tool selection diagram - https://www.canva.com/design/DAFawXrierc/O7DTnqW5fmMEZ31ao-TK9w/edit --> |
127 | | - |
128 | | -<!-- |
129 | | -On this page, we will focus on using front-end tools to package pure python |
130 | | -packages. We will note if a package does have the flexibility to support other |
131 | | -back-ends and in turn more complex builds (*mentioned in #2 and #3 above*). --> |
132 | | -<!-- |
133 | | -## COmbine the two sets of statement below... |
134 | | -ELI: |
135 | | -PDM supports C/Cython extensions too: https://pdm.fming.dev/latest/pyproject/build/#build-platform-specific-wheels |
136 | | -
|
137 | | -It does this by allowing you to write a python script that gets injected into a setuptools build process :) so that's not necessarily the greatest choice. It's a bit like using setuptools directly. ;) |
138 | | -
|
139 | | -Ralf: |
140 | | -Hatch only supports pure Python packages as of now. setuptools is still a very reasonable choice, and okay if all you have is a few C/Cython extensions. But I'd say you should probably recommend meson-python and scikit-build-core as the two best tools for building packages containing compiled extensions. |
141 | | -
|
142 | | -
|
143 | | -* link to ralf's blog and book on complex builds |
144 | | -* keep this page high level so we don't get weight downsides |
145 | | -* can use the examplePy repo stefan and I are working on that will test various build combinations |
146 | | -
|
147 | | -***** |
148 | | -
|
149 | | -ELI: It would be more accurate to say that PDM supports using PDM and setuptools at the same time, so you run setuptools to produce the C extensions and then PDM receives the compiled extension files (.so, .pyd) and packages it up alongside the pure python files. |
150 | | -
|
151 | | -Hatch - https://hatch.pypa.io/latest/config/build/#build-hooks uild hooks |
152 | | -
|
153 | | -Ralf - |
154 | | -Hatch has the worst take on building compiled code by some distance. Unless its author starts developing an understanding of build systems / needs, and implements support for PEP 517 build back-end hooks in pyproject.toml, it's pretty much a dead end. |
155 | | -**** |
156 | | -
|
157 | | -
|
158 | | - HEnry: Poetry will move to PEP 621 configuration in version 2. |
159 | | -
|
160 | | -* pdm, hatch and poetry all have "ways" of supporting c extensions via pdm-backend, hatchling and poetry's build back-end. |
161 | | -* poetry's support for C extensions is not fully developed and documented (yet). * Poetry doesn't offer a way to facilitate "communication" between poetry front end and another back-end like meson to build via a build hook. so while some have used it with other back-end builds it's not ideal for this application |
162 | | -* pdm and poetry both rely on setuptools for C extensions. pdm's support claims to be fully developed and documented. poetry claims nothing, and doesn't document it. |
163 | | -* hatch both offers a plugin type approach to support custom build steps |
164 | | -PDM (right now) is the only tool that supports other back-ends (hatch is working on this - 2 minor releases away) |
165 | | -At some point a build becomes so complex that you need to use a tool like scikit or meson to support that complexity. |
166 | | -
|
167 | | -
|
168 | | -
|
169 | | -**Setuptools** is the oldest tool in the above list. While it doesn't have a |
170 | | -friendly user front end, because "OG" tool that has been used for Python packaging for over a decade, we discuss it here. |
171 | | -
|
172 | | -**Hatch** and PDM are newer, more modern tool that support customization of any |
173 | | -part of your packaging steps. These tools also support some C and C++ |
174 | | -extensions. |
175 | | -
|
176 | | -
|
177 | | -OFEK - Why use hatchlin vs pdm back-end - |
178 | | -File inclusion is more configurable and easier by default |
179 | | -There is already a rich ecosystem of plugins and a well-thought-out interface |
180 | | -Consistency since the official Python packaging tutorial uses Hatchling by default |
181 | | -
|
182 | | -
|
183 | | -Henry - |
184 | | -The scikit-hep cookie provides 11 back-ends including flit-core and hatchling, and I've moved packaging to flit-core, and lots of other things to hatchling, and I can say that hatching's defaults are much nicer than flit-core's. Hatching uses .gitignore to decide what to put in the sdist. Flit-core basically tries to keep its hands off of adding defaults, so you have to configure everything manually. To make it even more confusing, if you use flit instead of a standard tool like build, it will switch to using VCS and those ignored files won't be added - meaning it is really easy to have a project that doesn't support build, including various GitHub Actions. Hatchling wins this by a ton. |
185 | | -
|
186 | | -<!-- TODO: add - compatible with other build back-ends eg pdm can work with hatchling |
187 | | -
|
188 | | -Eli: |
189 | | -poetry: supports it, but is undocumented and uses setuptools under the hood, they plan to change how this works and then document it |
190 | | -pdm-back-end: supports it, and documents it -- and also uses setuptools under the hood |
191 | | -hatchling: permits you to define hooks for you to write your own custom build steps, including to build C++ extensions |
192 | | -
|
193 | | ---> |
194 | | - |
195 | | -<!-- from eli about pdm |
196 | | -It would be more accurate to say that PDM supports using PDM and setuptools at the same time, so you run setuptools to produce the C extensions and then PDM receives the compiled extension files (.so, .pyd) and packages it up alongside the pure Python files. |
197 | | -
|
198 | | -Comment about hatch. |
199 | | -https://github.com/pyOpenSci/python-package-guide/pull/23#discussion_r1081108118 |
200 | | -
|
201 | | -From ralf: There are no silver bullets here yet, no workflow tool is complete. Both Hatch and PDM are single-author tools, which is another concern. @eli-schwartz's assessment is unfortunately correct here I believe (at a high level at least, not sure about details). Hatch has the worst take on building compiled code by some distance. Unless its author starts developing an understanding of build systems / needs, and implements support for PEP 517 build back-end hooks in pyproject.toml, it's pretty much a dead end. |
202 | | -
|
203 | | ---> |
204 | | - |
205 | | -<!--TODO Add examples of builds using each of the tools below? |
206 | | -
|
207 | | -pdm, hatch and poetry all have "ways" of supporting c extensions via pdm-build, hatchling and poetry's build back-end. |
208 | | -poetry's support for C extensions is not fully developed and documented (yet). Poetry doesn't offer a way to facilitate "communication" between poetry front end and another back-end like meson to build via a build hook. |
209 | | -PDM and hatch both offer a plugin type approach to support custom build steps |
210 | | -PDM (right now) is the only tool that supports other back-ends (hatch is working on this - 2 minor releases away) |
211 | | -At some point a build becomes so complex that you need to use a tool like scikit or meson to support that complexity. |
212 | | -
|
213 | | -CORRECTIONS: |
214 | | -pdm doesn't use plugins. Hatch does. |
215 | | -pdm and poetry both rely on setuptools for C extensions. pdm's support claims to be fully developed and documented. poetry claims nothing, and doesn't document it. |
216 | | -
|
217 | | -
|
218 | | -?? |
219 | | -Poetry supports extensions written in other languages but this functionality is |
220 | | -currently undocumented. |
221 | | -
|
222 | | -Tools such as Setuptools, PDM, Hatch and Poetry all have some level of support |
223 | | -for C and C++ extensions. |
224 | | -Some Python packaging tools, |
225 | | -such as **Flit** and the **flit-core** build back-end only support pure-Python |
226 | | -package builds. |
227 | | -Some front-end packaging tools, such as PDM, allow you to use other |
228 | | -build back-ends such as **meson** and **scikit-build**. |
229 | | -
|
230 | | -
|
231 | | -me: |
232 | | -pdm, hatch and poetry all have "ways" of supporting c extensions via pdm-build, hatchling and poetry's build back-end. |
233 | | -poetry's support for C extensions is not fully developed and documented (yet). Poetry doesn't offer a way to facilitate "communication" between poetry front end and another back-end like meson to build via a build hook. |
234 | | -PDM and hatch both offer a plugin type approach to support custom build steps |
235 | | -PDM (right now) is the only tool that supports other back-ends (hatch is working on this - 2 minor releases away) |
236 | | -At some point a build becomes so complex that you need to use a tool like scikit or meson to support that complexity. |
237 | | -@eli-schwartz eli-schwartz 3 weeks ago |
238 | | -PDM and hatch both offer a plugin type approach to support custom build steps |
239 | | -
|
240 | | -ELI: |
241 | | -pdm doesn't use plugins. Hatch does. |
242 | | -pdm and poetry both rely on setuptools for C extensions. pdm's support claims to be fully developed and documented. poetry claims nothing, and doesn't document it. |
243 | | -
|
244 | | -
|
245 | | -https://pdm.fming.dev/latest/pyproject/build/#build-platform-specific-wheels |
246 | | ---> |
247 | | - |
248 | | -<!-- https://github.com/pyOpenSci/python-package-guide/pull/23#discussion_r1071541329 |
249 | | -ELI: A complex build could mean running a python script that processes some data file and produces a pure python module file. |
250 | | -
|
251 | | -Probably not common in the scientific community specifically, but I've seen quite a few setup.py files that contain custom build stages which e.g. build gettext locale catalogs. |
252 | | -
|
253 | | -The main point is that it is more "complex" than simply copying files or directories as-is into the built wheel. |
254 | | ---> |
255 | | - |
256 | | -<!-- |
257 | | -COMMENTED OUT TEXT TO BE MOVED |
258 | | -
|
259 | | -
|
260 | | -# TODO LINK TO CI BUILDS FOR Documentation> |
261 | | -Maybe we can curate a list of CI builds that people can use??? or is that moving too close to a cookie cutter situation |
262 | | -
|
263 | | -The text below is being moved to the packaging infrastructure section which |
264 | | -doesn't exist YET... but will soon . |
265 | | -pyOpenSci packages must: |
266 | | -
|
267 | | -- Contain full documentation for any user-facing functions. |
268 | | -- Have a test suite that covers the major functionality of the package. |
269 | | -- Use continuous integration. |
270 | | -- Use an OSI approved software license. |
271 | | -
|
272 | | -
|
273 | | -## Other recommendations |
274 | | -### Python version support |
275 | | -You should always be explicit about which versions of Python your package supports. |
276 | | -Keeping compatibility with old Python versions can be difficult as functionality changes. |
277 | | -A good rule of thumb is that the package should support, at least, |
278 | | -the latest three Python versions (e.g., 3.8, 3.7, 3.6). |
279 | | -
|
280 | | -### Code Style |
281 | | -pyOpenSci encourages authors to consult [PEP 8](https://www.python.org/dev/peps/pep-0008/) for information on how to style your code. |
282 | | -
|
283 | | -### Linting |
284 | | -An automatic linter (e.g. flake8) can help ensure your code is clean and free of syntax errors. These can be integrated with your CI. |
285 | | -
|
286 | | ---> |
287 | | - |
288 | | -<!-- |
289 | | -```{tip} |
290 | | -### Python packaging resources that we love |
291 | | -
|
292 | | -We think the resources below are excellent but each have particular opinions |
293 | | -that you may or may not find in our packaging guide. For instance, the PyPA |
294 | | -guide encourages users to store their package in a `src/package-name` directory. |
295 | | -While we accept that approach many of our community members prefer to not use |
296 | | -the `src` directory. |
297 | | -
|
298 | | -* [Python packaging for research software engineers](https://merely-useful.tech/py-rse/) |
299 | | -* [PyPA packaging guide](https://packaging.python.org/en/latest/) |
300 | | -``` |
301 | | ---> |
302 | | - |
303 | | -<!-- |
304 | | -* one of the benefits of wheel is pretty much avoiding setup.py which |
305 | | -has code mixed in. makes you more vulnerable to a code injection on install. |
306 | | -
|
307 | | -assuming this means if the package is already pre-built than setup.py isn't running anything on install because install is just moving files across to the machine to be run. |
308 | | -
|
309 | | -And having metadata separate allows someone to view the metadata without |
310 | | -running any python code as it's a machine and human readable format. |
311 | | -
|
312 | | -https://scikit-hep.org/developer/pep621 |
313 | | ---> |
0 commit comments