Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

Python_Appendix.txt 20 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  1. = Additional Python Guidelines
  2. :last-reviewed: 2020-01-01
  3. Here are some additional Python-related guidelines, moved here in order to keep the main page manageable.
  4. == Python 2 packages
  5. If your package needs to build for Python 2 only,
  6. follow the xref:Python_201x.adoc[201x-era Python guidelines],
  7. except substitute 3 for 2.
  8. For example instead of `+%{python3_sitearch}+`,
  9. use `+%{python2_sitearch}+`.
  10. Special emphasis on the rule that packages MUST NOT use `+/usr/bin/python+`.
  11. === Naming
  12. The source package for a Python library MUST be named with the python- prefix except for a specific case bellow. A built package must include the Python major version in the name, using the python2- prefix. This is accomplished by adding a subpackage.
  13. If you need to package the python2 module as a separate source package (usually because upstream has dropped Python 2 support in newer versions but still supports the last version that works with Python 2), you MUST name the source package using the python2- prefix instead of creating a subpackage.
  14. === Common spec files for python3 and python2
  15. It is possible to create both python3 and python2 subpackage from one common spec file.
  16. The following is a very simple spec file for a module building for both python2
  17. and python3. It builds both versions in the same directory; this is possible
  18. because the build products for different versions of Python usually do not conflict.
  19. There are cases where it is not possible to build in a single directory. Most
  20. commonly this happens when the sources are modified during the build process to
  21. convert them from python2 to python3 using the the `+2to3+` tool (see bellow).
  22. As you can see in the `+%install+` section below, the order in which
  23. you do the python2 versus python3 install can sometimes matter. You need to be
  24. aware of when the install is writing to the same file in both packages (in this
  25. example, a script in `+%{_bindir}+`) and make sure that you're getting
  26. the version you expect.
  27. ....
  28. %global srcname example
  29. Name: python-%{srcname}
  30. Version: 1.2.3
  31. Release: 1%{?dist}
  32. Summary: An example python module
  33. License: MIT
  34. URL: https://pypi.python.org/pypi/%{srcname}
  35. Source: %pypi_source
  36. BuildArch: noarch
  37. %global _description %{expand:
  38. A python module which provides a convenient example.}
  39. %description %_description
  40. %package -n python2-%{srcname}
  41. Summary: %{summary}
  42. BuildRequires: python2-devel
  43. %description -n python2-%{srcname} %_description
  44. %package -n python3-%{srcname}
  45. Summary: %{summary}
  46. BuildRequires: python3-devel
  47. %description -n python3-%{srcname} %_description
  48. %prep
  49. %autosetup -n %{srcname}-%{version}
  50. %build
  51. %py2_build
  52. %py3_build
  53. %install
  54. # Must do the python2 install first because the scripts in /usr/bin are
  55. # overwritten with every setup.py install, and in general we want the
  56. # python3 version to be the default.
  57. %py2_install
  58. %py3_install
  59. %check
  60. %{python2} setup.py test
  61. %{python3} setup.py test
  62. # Note that there is no %%files section for the unversioned python module if we are building for several python runtimes
  63. %files -n python2-%{srcname}
  64. %license COPYING
  65. %doc README.rst
  66. %{python2_sitelib}/%{srcname}/
  67. %{python2_sitelib}/%{srcname}-*.egg-info/
  68. %files -n python3-%{srcname}
  69. %license COPYING
  70. %doc README.rst
  71. %{python3_sitelib}/%{srcname}/
  72. %{python3_sitelib}/%{srcname}-*.egg-info/
  73. %{_bindir}/sample-exec
  74. %changelog
  75. ....
  76. === Using separate build directories
  77. Sometimes is it impossible to build both versions from the same source directory. Most often this happens when sources are "translated" to python3 in the source directory and made incompatible with python2 in the process. This used to be fairly common, but is fortunately much rarer now. Some things to look for are:
  78. * Sources are not Python 3 compatible (`+print+` without parentheses is used, old module names like `+ConfigParser+` are imported),
  79. * `+six+` module is not used,
  80. * `+2to3+` is run in `+setup.py+` without creating a separate build directory.
  81. Our method in building from the same code to make the two separate modules is to keep each build as independent as possible. To do that, we copy the source tree to python3 so that the python 2 sources are entirely independent from the python 3 sources.
  82. Some things to watch out for:
  83. * Make sure that you are copying the correct code. The example is copying the code from within the top directory of the untarred source. If the `+%prep+` has changed directory you will need to change back to the tarball location.
  84. * Patching the source code is done before copying to `+python3+`. Since you have both a python2 and a python3 directory you might be tempted to patch each one separately. *Resist!* Upstream for your package has chosen to distribute a single source tree that builds for both python2 and python3. For your patches to https://docs.fedoraproject.org/en-US/package-maintainers/Staying_Close_to_Upstream_Projects/[get into upstream], you need to write patches that work with both as well.
  85. `+rpmbuild+` resets the directory at the end of each phase, so you don't need to restore the directory at the end of `+%prep+`.
  86. ....
  87. %prep
  88. %setup -qc
  89. mv %{srcname}-%{version} python2
  90. pushd python2
  91. %patch0 -p1 -b .testfix
  92. find -name '*.txt' | xargs chmod -x
  93. # copy common doc files to top dir
  94. cp -pr docs psfl.txt zpl.txt ../
  95. popd
  96. cp -a python2 python3
  97. find python3 -name '*.py' | xargs sed -i '1s|^#!.*|#!%{python3}|'
  98. find python2 -name '*.py' | xargs sed -i '1s|^#!.*|#!%{python2}|'
  99. %build
  100. pushd python2
  101. %py2_build
  102. popd
  103. pushd python3
  104. %py3_build
  105. popd
  106. %install
  107. # Must do the python2 install first because the scripts in /usr/bin are
  108. # overwritten with every setup.py install, and in general we want the
  109. # python3 version to be the default.
  110. pushd python2
  111. %py2_install
  112. popd
  113. pushd python3
  114. %py3_install
  115. popd
  116. %check
  117. pushd python2
  118. %{python2} setup.py test
  119. popd
  120. pushd python3
  121. %{python3} setup.py test
  122. popd
  123. ....
  124. You'll notice that the `+%build+`, `+%install+`, and `+%check+` sections again follow a pattern similar to the previous example. They switch to the python2 directory and do the normal steps for building the python2 module, and then switch to the python3 directory and run the same steps for python3. The usage of `+pushd/popd+` commands will ensure that the directories are logged.
  125. === Conditionalizing the Python 2 parts
  126. If the maintainer wishes to support a similar specfile across several Fedora releases,
  127. sometimes the Python 2 packages are only appropriate for the older ones.
  128. Conditionalizing the Python 2 parts of the specfile (if applicable)
  129. SHOULD be done with the following bcond:
  130. ....
  131. %bcond_with python2 # to disable python2 by default, or:
  132. %bcond_without python2 # to enable python2 by default
  133. %if %{with python2}
  134. ...
  135. %endif
  136. ....
  137. See the following example for reference:
  138. ....
  139. %global srcname example
  140. # Disable python2 by default
  141. %bcond_with python2
  142. Name: python-%{srcname}
  143. Version: 1.2.3
  144. Release: 1%{?dist}
  145. Summary: An example python module
  146. License: MIT
  147. URL: https://pypi.python.org/pypi/%{srcname}
  148. Source: %pypi_source
  149. BuildArch: noarch
  150. %global _description %{expand:
  151. A python module which provides a convenient example.}
  152. %description %_description
  153. %if %{with python2}
  154. %package -n python2-%{srcname}
  155. Summary: %{summary}
  156. BuildRequires: python2-devel
  157. %description -n python2-%{srcname} %_description
  158. %endif
  159. %package -n python3-%{srcname}
  160. Summary: %{summary}
  161. BuildRequires: python3-devel
  162. %description -n python3-%{srcname} %_description
  163. %prep
  164. %autosetup -n %{srcname}-%{version}
  165. %build
  166. %if %{with python2}
  167. %py2_build
  168. %endif
  169. %py3_build
  170. %install
  171. # Must do the python2 install first because the scripts in /usr/bin are
  172. # overwritten with every setup.py install, and in general we want the
  173. # python3 version to be the default.
  174. %if %{with python2}
  175. %py2_install
  176. %endif
  177. %py3_install
  178. %check
  179. %if %{with python2}
  180. %{python2} setup.py test
  181. %endif
  182. %{python3} setup.py test
  183. %if %{with python2}
  184. %files -n python2-%{srcname}
  185. %license COPYING
  186. %doc README.rst
  187. %{python2_sitelib}/%{srcname}/
  188. %{python2_sitelib}/%{srcname}-*.egg-info/
  189. %endif
  190. %files -n python3-%{srcname}
  191. %license COPYING
  192. %doc README.rst
  193. %{python3_sitelib}/%{srcname}/
  194. %{python3_sitelib}/%{srcname}-*.egg-info/
  195. %{_bindir}/sample-exec
  196. %changelog
  197. ....
  198. === Avoiding collisions between the python 2 and python 3 stacks
  199. The python 2 and python 3 stacks are intended to be fully-installable in parallel. When generalizing the package for both python 2 and python 3, it is important to ensure that two different built packages do not attempt to place different payloads into the same path.
  200. ==== Executables in `+/usr/bin+`
  201. Many existing python packages install executables into `+/usr/bin+`.
  202. For example if we have a `+console_scripts+` in a `+setup.py+` shared between
  203. python 2 and python 3 builds: these will spit out files in `+/usr/bin/+`,
  204. and these will collide.
  205. For example `+python-coverage+` has a `+setup.py+` that contains:
  206. ....
  207. entry_points = {
  208. 'console_scripts': [
  209. 'coverage = coverage:main',
  210. ]
  211. },
  212. ....
  213. which thus generates a `+/usr/bin/coverage+` executable (this is a python
  214. script that runs another python script whilst generating code-coverage
  215. information on the latter).
  216. Similarly for the 'scripts' clause; see e.g. `+python-pygments+`:
  217. `+Pygments-1.1.1/setup.py+` has:
  218. ....
  219. scripts = ['pygmentize'],
  220. ....
  221. which generates a `+/usr/bin/pygmentize+` (this is a python script that leverages the pygments syntax-highlighting module, giving a simple command-line interface for generating syntax-highlighted files)
  222. If the executables provide the same functionality independent of whether they are run on top of Python 2 or Python 3, then only the Python 3 version of the executable SHOULD be packaged, the python2 version MUST NOT be packaged.
  223. Examples of this:
  224. * `+/usr/bin/pygmentize+` ought to generate the same output regardless of whether it's implemented via Python 2 or Python 3, so only one version needs to be shipped.
  225. If the executables provide different functionality for Python 2 and Python 3, then Python 2 version MAY be packaged.
  226. Examples of this:
  227. * `+/usr/bin/coverage+` runs a python script, augmenting the interpreter with code-coverage information. Given that the interpreter itself is the thing being worked with, it's reasonable to package both versions of the executable.
  228. * `+/usr/bin/bpython+` augments the interpreter with a "curses" interface. Again, it's reasonable to package both versions of this.
  229. * `+/usr/bin/easy_install+` installs a module into one of the Python runtimes: we need a version for each runtime.
  230. ==== Naming
  231. Many executables already contain a "-MAJOR.MINOR" suffix, for example `+/usr/bin/easy_install-3.4+`. These obviously can be used as-is, as they won't conflict.
  232. For other executables, the general rule is:
  233. * If only one executable is to be shipped, then it owns its own slot and should use /usr/bin/python3.
  234. * If executables are to be shipped for both python 2 and python 3:
  235. ** Both python 2 and python 3 variants MUST provide symlinks with a '-X' and '-X.Y' suffix (python runtime major version, or python runtime major.minor version), unless upstream already provides appropriately versioned executables without the dash.
  236. ** The unversioned executable MUST be the python3 version.
  237. ** For example, the python3 version of "twisted" MUST ship executables `+/usr/bin/twistd-3+` and `+/usr/bin/twistd-3.7+` (assuming python3 is currently version 3.7) and `+/usr/bin/twistd+`; while the python2 version MUST provide `+/usr/bin/twistd-2+` and `+/usr/bin/twistd-2.7+`.
  238. ** For compatibility packages, the Python version is appended *after* the specific package version, for example `+/usr/bin/coverage-v1.2-3+` and `+/usr/bin/coverage-v1.2-3.4+` for python3-coverage1.2 compat package.
  239. === Running 2to3 from the spec file
  240. Sometimes, upstream hasn't integrated running 2to3 on the code into their build scripts but they support making a python3 module from it if you manually run 2to3 on the source. This is the case when it's documented on the upstream's website, in a file in the tarball, or even when email with the module's author has instructions for building a python3 module from the python2 source and the authors are willing to support the result. In these cases it's usually just a matter of the upstream not having written the build script that can turn the python2 source into python3. When this happens you can run `+2to3+` from the spec file. Once you have it working, you can also help upstream integrate it into their build scripts which will benefit everyone in the long term.
  241. You should usually follow upstream's directions on how to run `+2to3+` and build the python3 module in these cases but there's a few things you should check to make sure upstream is doing it correctly.
  242. * Since the code is being built from a unified source, you need to copy the code to a new directory before invoking 2to3 just like the link:#Building_more_than_once[ building more than once] method.
  243. * If the `+2to3+` program is invoked instead of using the `+lib2to3+` library functions, make sure it's invoked with `+--write --nobackups+`. `+--write+` is needed to make `+2to3+` actually change the files. `+--nobackups+` avoids leaving `+foo.py.bak+` files in the module directories that then make it into the final package payload.
  244. * Be sure to run 2to3 on the correct directory. When you run `+2to3+` you need to run it on the whole tree. A common mistake here for distutils packages has been to run it on the directory below `+setup.py+`, missing the `+setup.py+` file itself. This leads to errors when `+python3+` tries to execute `+setup.py+`
  245. * If you need to run `+2to3+` to fix code, use `+2to3+` or `+/usr/bin/2to3+`. At the moment, this program is coming from the `+python-tools+` rpm. Using `+2to3+` means that you'll be using a name that is supported upstream and across distros rather than `+/usr/bin/python3-2to3+` which we have renamed in Fedora to avoid filesystem conflicts. This also makes it easier for us to test and eventually change from using the python2 `+2to3+` to the python3 `+2to3+`. We just need to change the python3 package to provide the `+/usr/bin/2to3+` program instead of python and all of our python packages will start using that version instead.
  246. * If `+2to3+` runs into a problem, please https://bugzilla.redhat.com/enter_bug.cgi?component=python&product=Fedora[file a Fedora bug]. Please try to isolate a minimal test case that reproduces the problem when doing so.
  247. [#manual-bytecompilation]
  248. == Manual byte compilation
  249. NOTE: This section only applies for the 201x-era guidelines.
  250. In the new guidelines, see the
  251. xref:Python.adoc#manual-bytecompilation[Manual byte compilation] section.
  252. When byte compiling a .py file, python embeds a magic number in the byte compiled files that correspond to the runtime. Files in `+%{python?_sitelib}+` and `+%{python?_sitearch}+` MUST correspond to the runtime for which they were built. For instance, a pure Python module compiled for the 3.4 runtime MUST be below `+%{_usr}/lib/python3.4/site-packages+`
  253. The `+brp-python-bytecompile+` script tries to figure this out for you.
  254. The script determines which interpreter to use when byte compiling the module
  255. by checking what directory the file is installed in.
  256. If it's `+/usr/lib{,64}/pythonX.Y+`,
  257. then `+pythonX.Y+` is used to byte compile the module.
  258. If `+pythonX.Y+` is not installed,
  259. then an error is returned and the rpm build process will exit on an error
  260. so remember to `+BuildRequire+` the proper python package.
  261. If you have `+*.py+` files outside of the `+/usr/lib(64)?/pythonX.Y/+` directories
  262. and you require those files to be byte compiled
  263. (e.g. it's an importable Python module)
  264. you MUST compile them explicitly using the `+%py_byte_compile+` macro.
  265. Note that not all Python files are importable Python modules;
  266. when in doubt, grep the sources for the appropriate import statement.
  267. An example for a package that has both Python versions:
  268. ....
  269. # Buildrequire both python2 and python3
  270. BuildRequires: python2-devel python3-devel
  271. %install
  272. # Installs a python2 private module into %{buildroot}%{_datadir}/mypackage/foo
  273. # and installs a python3 private module into %{buildroot}%{_datadir}/mypackage/bar
  274. make install DESTDIR=%{buildroot}
  275. # Manually invoke the python byte compile macro for each path that needs byte
  276. # compilation.
  277. %py_byte_compile %{python2} %{buildroot}%{_datadir}/mypackage/foo
  278. %py_byte_compile %{python3} %{buildroot}%{_datadir}/mypackage/bar
  279. ....
  280. The `+%py_byte_compile+` macro takes two arguments.
  281. The first is the python interpreter to use for byte compiling.
  282. The second is a file or directory to byte compile.
  283. If the second argument is a directory,
  284. the macro will recursively byte compile any *.py file in the directory.
  285. == Manual byte compilation for EPEL 6 and 7
  286. The script interpreter defined in `+%{__python}+` is used to compile the modules outside of `+/usr/lib(64)?/pythonX.Y/+` directories. This defaults to `+/usr/bin/python+` (that's Python 2.6 or on EPEL 6 and 2.7 on EPEL 7). If you need to compile the modules for python3, set it to `+/usr/bin/python3+` instead:
  287. ....
  288. %global __python %{python3}
  289. ....
  290. Doing this is useful when you have a python3 application that's installing a private module into its own directory. For instance, if the foobar application installs a module for use only by the command line application in `+%{_datadir}/foobar+`. Since these files are not in one of the python3 library paths (i.e., `+/usr/lib/python3.6+`) you have to override `+%{__python}+` to tell `+brp-python-bytecompile+` to use the python3 interpreter for byte compiling.
  291. These settings are enough to properly byte compile any package that builds Python modules in `+%{python?_sitelib}+` or `+%{python?_sitearch}+` or builds for only a single Python interpreter. However, if the application you're packaging needs to build with both python2 and python3 and install into a private module directory (perhaps because it provides one utility written in python2 and a second utility written in python3) then you need to do this manually. Here's a sample spec file snippet that shows what to do:
  292. ....
  293. # Turn off the brp-python-bytecompile script
  294. %global __os_install_post %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$!!g')
  295. # Buildrequire both python2 and python3
  296. BuildRequires: python2-devel python3-devel
  297. [...]
  298. %install
  299. # Installs a python2 private module into %{buildroot}%{_datadir}/mypackage/foo
  300. # and installs a python3 private module into %{buildroot}%{_datadir}/mypackage/bar
  301. make install DESTDIR=%{buildroot}
  302. # Manually invoke the python byte compile macro for each path that needs byte
  303. # compilation.
  304. %py_byte_compile %{python2} %{buildroot}%{_datadir}/mypackage/foo
  305. %py_byte_compile %{python3} %{buildroot}%{_datadir}/mypackage/bar
  306. ....
  307. Note that this *does disable* the compilation of files in `+/usr/lib(64)?/pythonX.Y/+`.
  308. == Byte compilation reproducibility
  309. For two Python files with the exact same content and metadata,
  310. byte compilation might produce different results.
  311. The resulting `.pyc` files are functionally identical but are not bit-by-bit identical.
  312. In most cases,
  313. internal Python reference counter is here to blame because it might have a different internal state during each byte compilation.
  314. If you want a deeper explanation,
  315. take a look at https://bugzilla.redhat.com/show_bug.cgi?id=1686078#c2[this Bugzilla comment].
  316. This inconvenience might cause a problem in Koji where noarch packages built as a part of an arch build might be rejected because they have different content.
  317. To workaround this issue,
  318. BuildRequire marshalparser `BuildRequires: /usr/bin/marshalparser`
  319. (a tool that makes `.pyc` files more reproducible)
  320. and instruct it to process the `.pyc` files in certain paths by setting the `+%py_reproducible_pyc_path+` macro:
  321. ....
  322. %global py_reproducible_pyc_path %{buildroot}%{_datadir}/llamafarm/plugins
  323. ....
  324. With that setting,
  325. marshalparser recursively finds all byte-compiled Python files in `+%{buildroot}%{_datadir}/llamafarm/plugins+` and attempts to fix them.
  326. This happens at the very end of the build process when all previous byte compilation steps are finished.
  327. If marshalparser cannot parse some of the cache files,
  328. the build fails.
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...