1{ lib, stdenv, fetchurl, fetchpatch
2, bzip2
3, expat
4, libffi
5, gdbm
6, xz
7, mailcap, mimetypesSupport ? true
8, ncurses
9, openssl
10, readline
11, sqlite
12, tcl ? null, tk ? null, tix ? null, libX11 ? null, xorgproto ? null, x11Support ? false
13, bluez ? null, bluezSupport ? false
14, zlib
15, tzdata ? null
16, libxcrypt
17, self
18, configd
19, autoreconfHook
20, autoconf-archive
21, pkg-config
22, python-setup-hook
23, nukeReferences
24# For the Python package set
25, packageOverrides ? (self: super: {})
26, pkgsBuildBuild
27, pkgsBuildHost
28, pkgsBuildTarget
29, pkgsHostHost
30, pkgsTargetTarget
31, sourceVersion
32, sha256
33, passthruFun
34, bash
35, stripConfig ? false
36, stripIdlelib ? false
37, stripTests ? false
38, stripTkinter ? false
39, rebuildBytecode ? true
40, stripBytecode ? true
41, includeSiteCustomize ? true
42, static ? stdenv.hostPlatform.isStatic
43, enableOptimizations ? false
44# enableNoSemanticInterposition is a subset of the enableOptimizations flag that doesn't harm reproducibility.
45# clang starts supporting `-fno-sematic-interposition` with version 10
46, enableNoSemanticInterposition ? (!stdenv.cc.isClang || (stdenv.cc.isClang && lib.versionAtLeast stdenv.cc.version "10"))
47# enableLTO is a subset of the enableOptimizations flag that doesn't harm reproducibility.
48# enabling LTO on 32bit arch causes downstream packages to fail when linking
49# enabling LTO on *-darwin causes python3 to fail when linking.
50, enableLTO ? stdenv.is64bit && stdenv.isLinux
51, reproducibleBuild ? false
52, pythonAttr ? "python${sourceVersion.major}${sourceVersion.minor}"
53} @ inputs:
54
55# Note: this package is used for bootstrapping fetchurl, and thus
56# cannot use fetchpatch! All mutable patches (generated by GitHub or
57# cgit) that are needed here should be included directly in Nixpkgs as
58# files.
59
60assert x11Support -> tcl != null
61 && tk != null
62 && xorgproto != null
63 && libX11 != null;
64
65assert bluezSupport -> bluez != null;
66
67assert lib.assertMsg (reproducibleBuild -> stripBytecode)
68 "Deterministic builds require stripping bytecode.";
69
70assert lib.assertMsg (reproducibleBuild -> (!enableOptimizations))
71 "Deterministic builds are not achieved when optimizations are enabled.";
72
73assert lib.assertMsg (reproducibleBuild -> (!rebuildBytecode))
74 "Deterministic builds are not achieved when (default unoptimized) bytecode is created.";
75
76with lib;
77
78let
79 buildPackages = pkgsBuildHost;
80 inherit (passthru) pythonForBuild;
81
82 tzdataSupport = tzdata != null && passthru.pythonAtLeast "3.9";
83
84 passthru = let
85 # When we override the interpreter we also need to override the spliced versions of the interpreter
86 inputs' = lib.filterAttrs (n: v: ! lib.isDerivation v && n != "passthruFun") inputs;
87 override = attr: let python = attr.override (inputs' // { self = python; }); in python;
88 in passthruFun rec {
89 inherit self sourceVersion packageOverrides;
90 implementation = "cpython";
91 libPrefix = "python${pythonVersion}";
92 executable = libPrefix;
93 pythonVersion = with sourceVersion; "${major}.${minor}";
94 sitePackages = "lib/${libPrefix}/site-packages";
95 inherit hasDistutilsCxxPatch pythonAttr;
96 pythonOnBuildForBuild = override pkgsBuildBuild.${pythonAttr};
97 pythonOnBuildForHost = override pkgsBuildHost.${pythonAttr};
98 pythonOnBuildForTarget = override pkgsBuildTarget.${pythonAttr};
99 pythonOnHostForHost = override pkgsHostHost.${pythonAttr};
100 pythonOnTargetForTarget = if lib.hasAttr pythonAttr pkgsTargetTarget then (override pkgsTargetTarget.${pythonAttr}) else {};
101 };
102
103 version = with sourceVersion; "${major}.${minor}.${patch}${suffix}";
104
105 nativeBuildInputs = optionals (!stdenv.isDarwin) [
106 autoreconfHook
107 pkg-config
108 autoconf-archive # needed for AX_CHECK_COMPILE_FLAG
109 ] ++ [
110 nukeReferences
111 ] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
112 buildPackages.stdenv.cc
113 pythonForBuild
114 ] ++ optionals (stdenv.cc.isClang && (!stdenv.hostPlatform.useAndroidPrebuilt or false) && (enableLTO || enableOptimizations)) [
115 stdenv.cc.cc.libllvm.out
116 ];
117
118 buildInputs = filter (p: p != null) ([
119 zlib bzip2 expat xz libffi gdbm sqlite readline ncurses openssl ]
120 ++ optionals x11Support [ tcl tk libX11 xorgproto ]
121 ++ optionals (bluezSupport && stdenv.isLinux) [ bluez ]
122 ++ optionals stdenv.isDarwin [ configd ])
123 ++ optionals tzdataSupport [ tzdata ]; # `zoneinfo` module
124
125 hasDistutilsCxxPatch = !(stdenv.cc.isGNU or false);
126
127 pythonForBuildInterpreter = if stdenv.hostPlatform == stdenv.buildPlatform then
128 "$out/bin/python"
129 else pythonForBuild.interpreter;
130
131 # The CPython interpreter contains a _sysconfigdata_<platform specific suffix>
132 # module that is imported by the sysconfig and distutils.sysconfig modules.
133 # The sysconfigdata module is generated at build time and contains settings
134 # required for building Python extension modules, such as include paths and
135 # other compiler flags. By default, the sysconfigdata module is loaded from
136 # the currently running interpreter (ie. the build platform interpreter), but
137 # when cross-compiling we want to load it from the host platform interpreter.
138 # This can be done using the _PYTHON_SYSCONFIGDATA_NAME environment variable.
139 # The _PYTHON_HOST_PLATFORM variable also needs to be set to get the correct
140 # platform suffix on extension modules. The correct values for these variables
141 # are not documented, and must be derived from the configure script (see links
142 # below).
143 sysconfigdataHook = with stdenv.hostPlatform; with passthru; let
144 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L428
145 # The configure script uses "arm" as the CPU name for all 32-bit ARM
146 # variants when cross-compiling, but native builds include the version
147 # suffix, so we do the same.
148 pythonHostPlatform = let
149 cpu = {
150 # According to PEP600, Python's name for the Power PC
151 # architecture is "ppc", not "powerpc". Without the Rosetta
152 # Stone below, the PEP600 requirement that "${ARCH} matches
153 # the return value from distutils.util.get_platform()" fails.
154 # https://peps.python.org/pep-0600/
155 powerpc = "ppc";
156 powerpcle = "ppcle";
157 powerpc64 = "ppc64";
158 powerpc64le = "ppc64le";
159 }.${parsed.cpu.name} or parsed.cpu.name;
160 in "${parsed.kernel.name}-${cpu}";
161
162 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L724
163 multiarchCpu =
164 if isAarch32 then
165 if parsed.cpu.significantByte.name == "littleEndian" then "arm" else "armeb"
166 else if isx86_32 then "i386"
167 else parsed.cpu.name;
168 pythonAbiName =
169 # python's build doesn't differentiate between musl and glibc in its
170 # abi detection, our wrapper should match.
171 if stdenv.hostPlatform.isMusl then
172 replaceStrings [ "musl" ] [ "gnu" ] parsed.abi.name
173 else parsed.abi.name;
174 multiarch =
175 if isDarwin then "darwin"
176 else "${multiarchCpu}-${parsed.kernel.name}-${pythonAbiName}";
177
178 abiFlags = optionalString (isPy36 || isPy37) "m";
179
180 # https://github.com/python/cpython/blob/e488e300f5c01289c10906c2e53a8e43d6de32d8/configure.ac#L78
181 pythonSysconfigdataName = "_sysconfigdata_${abiFlags}_${parsed.kernel.name}_${multiarch}";
182 in ''
183 sysconfigdataHook() {
184 if [ "$1" = '${placeholder "out"}' ]; then
185 export _PYTHON_HOST_PLATFORM='${pythonHostPlatform}'
186 export _PYTHON_SYSCONFIGDATA_NAME='${pythonSysconfigdataName}'
187 fi
188 }
189
190 addEnvHooks "$hostOffset" sysconfigdataHook
191 '';
192
193in with passthru; stdenv.mkDerivation {
194 pname = "python3";
195 inherit version;
196
197 inherit nativeBuildInputs;
198 buildInputs = [ bash ] ++ buildInputs; # bash is only for patchShebangs
199
200 src = fetchurl {
201 url = with sourceVersion; "https://www.python.org/ftp/python/${major}.${minor}.${patch}/Python-${version}.tar.xz";
202 inherit sha256;
203 };
204
205 prePatch = optionalString stdenv.isDarwin ''
206 substituteInPlace configure --replace '`/usr/bin/arch`' '"i386"'
207 '' + optionalString (pythonOlder "3.9" && stdenv.isDarwin && x11Support) ''
208 # Broken on >= 3.9; replaced with ./3.9/darwin-tcl-tk.patch
209 substituteInPlace setup.py --replace /Library/Frameworks /no-such-path
210 '';
211
212 patches = [
213 # Disable the use of ldconfig in ctypes.util.find_library (since
214 # ldconfig doesn't work on NixOS), and don't use
215 # ctypes.util.find_library during the loading of the uuid module
216 # (since it will do a futile invocation of gcc (!) to find
217 # libuuid, slowing down program startup a lot).
218 (./. + "/${sourceVersion.major}.${sourceVersion.minor}/no-ldconfig.patch")
219 # Make sure that the virtualenv activation scripts are
220 # owner-writable, so venvs can be recreated without permission
221 # errors.
222 ./virtualenv-permissions.patch
223 ] ++ optionals mimetypesSupport [
224 # Make the mimetypes module refer to the right file
225 ./mimetypes.patch
226 ] ++ optionals (isPy35 || isPy36) [
227 # Determinism: Write null timestamps when compiling python files.
228 ./3.5/force_bytecode_determinism.patch
229 ] ++ optionals isPy35 [
230 # Backports support for LD_LIBRARY_PATH from 3.6
231 ./3.5/ld_library_path.patch
232 ] ++ optionals (isPy35 || isPy36 || isPy37) [
233 # Backport a fix for discovering `rpmbuild` command when doing `python setup.py bdist_rpm` to 3.5, 3.6, 3.7.
234 # See: https://bugs.python.org/issue11122
235 ./3.7/fix-hardcoded-path-checking-for-rpmbuild.patch
236 # The workaround is for unittests on Win64, which we don't support.
237 # It does break aarch64-darwin, which we do support. See:
238 # * https://bugs.python.org/issue35523
239 # * https://github.com/python/cpython/commit/e6b247c8e524
240 ./3.7/no-win64-workaround.patch
241 ] ++ optionals (pythonAtLeast "3.7" && pythonOlder "3.11") [
242 # Fix darwin build https://bugs.python.org/issue34027
243 ./3.7/darwin-libutil.patch
244 ] ++ optionals (pythonAtLeast "3.11") [
245 ./3.11/darwin-libutil.patch
246 ] ++ optionals (pythonOlder "3.8") [
247 # Backport from CPython 3.8 of a good list of tests to run for PGO.
248 (
249 if isPy36 || isPy37 then
250 ./3.6/profile-task.patch
251 else
252 ./3.5/profile-task.patch
253 )
254 ] ++ optionals (pythonAtLeast "3.9" && pythonOlder "3.11" && stdenv.isDarwin) [
255 # Stop checking for TCL/TK in global macOS locations
256 ./3.9/darwin-tcl-tk.patch
257 ] ++ optionals (isPy3k && hasDistutilsCxxPatch) [
258 # Fix for http://bugs.python.org/issue1222585
259 # Upstream distutils is calling C compiler to compile C++ code, which
260 # only works for GCC and Apple Clang. This makes distutils to call C++
261 # compiler when needed.
262 (
263 if isPy35 then
264 ./3.5/python-3.x-distutils-C++.patch
265 else if pythonAtLeast "3.7" && pythonOlder "3.11" then
266 ./3.7/python-3.x-distutils-C++.patch
267 else if pythonAtLeast "3.11" then
268 ./3.11/python-3.x-distutils-C++.patch
269 else
270 fetchpatch {
271 url = "https://bugs.python.org/file48016/python-3.x-distutils-C++.patch";
272 sha256 = "1h18lnpx539h5lfxyk379dxwr8m2raigcjixkf133l4xy3f4bzi2";
273 }
274 )
275 ] ++ [
276 # LDSHARED now uses $CC instead of gcc. Fixes cross-compilation of extension modules.
277 ./3.8/0001-On-all-posix-systems-not-just-Darwin-set-LDSHARED-if.patch
278 # Use sysconfigdata to find headers. Fixes cross-compilation of extension modules.
279 (
280 if isPy36 then
281 ./3.6/fix-finding-headers-when-cross-compiling.patch
282 else
283 ./3.7/fix-finding-headers-when-cross-compiling.patch
284 )
285 ] ++ optionals (isPy36) [
286 # Backport a fix for ctypes.util.find_library.
287 ./3.6/find_library.patch
288 ];
289
290 postPatch = ''
291 substituteInPlace Lib/subprocess.py \
292 --replace "'/bin/sh'" "'${bash}/bin/sh'"
293 '' + optionalString mimetypesSupport ''
294 substituteInPlace Lib/mimetypes.py \
295 --replace "@mime-types@" "${mailcap}"
296 '' + optionalString (x11Support && (tix != null)) ''
297 substituteInPlace "Lib/tkinter/tix.py" --replace "os.environ.get('TIX_LIBRARY')" "os.environ.get('TIX_LIBRARY') or '${tix}/lib'"
298 '';
299
300 CPPFLAGS = concatStringsSep " " (map (p: "-I${getDev p}/include") buildInputs);
301 LDFLAGS = concatStringsSep " " (map (p: "-L${getLib p}/lib") buildInputs);
302 LIBS = "${optionalString (!stdenv.isDarwin) "-lcrypt"}";
303 NIX_LDFLAGS = lib.optionalString (stdenv.cc.isGNU && !stdenv.hostPlatform.isStatic) ({
304 "glibc" = "-lgcc_s";
305 "musl" = "-lgcc_eh";
306 }."${stdenv.hostPlatform.libc}" or "");
307 # Determinism: We fix the hashes of str, bytes and datetime objects.
308 PYTHONHASHSEED=0;
309
310 configureFlags = [
311 "--without-ensurepip"
312 "--with-system-expat"
313 "--with-system-ffi"
314 ] ++ optionals (!static) [
315 "--enable-shared"
316 ] ++ optionals enableOptimizations [
317 "--enable-optimizations"
318 ] ++ optionals enableLTO [
319 "--with-lto"
320 ] ++ optionals (pythonOlder "3.7") [
321 # This is unconditionally true starting in CPython 3.7.
322 "--with-threads"
323 ] ++ optionals (sqlite != null && isPy3k) [
324 "--enable-loadable-sqlite-extensions"
325 ] ++ optionals (openssl != null) [
326 "--with-openssl=${openssl.dev}"
327 ] ++ optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
328 "ac_cv_buggy_getaddrinfo=no"
329 # Assume little-endian IEEE 754 floating point when cross compiling
330 "ac_cv_little_endian_double=yes"
331 "ac_cv_big_endian_double=no"
332 "ac_cv_mixed_endian_double=no"
333 "ac_cv_x87_double_rounding=yes"
334 "ac_cv_tanh_preserves_zero_sign=yes"
335 # Generally assume that things are present and work
336 "ac_cv_posix_semaphores_enabled=yes"
337 "ac_cv_broken_sem_getvalue=no"
338 "ac_cv_wchar_t_signed=yes"
339 "ac_cv_rshift_extends_sign=yes"
340 "ac_cv_broken_nice=no"
341 "ac_cv_broken_poll=no"
342 "ac_cv_working_tzset=yes"
343 "ac_cv_have_long_long_format=yes"
344 "ac_cv_have_size_t_format=yes"
345 "ac_cv_computed_gotos=yes"
346 "ac_cv_file__dev_ptmx=yes"
347 "ac_cv_file__dev_ptc=yes"
348 ] ++ optionals stdenv.hostPlatform.isLinux [
349 # Never even try to use lchmod on linux,
350 # don't rely on detecting glibc-isms.
351 "ac_cv_func_lchmod=no"
352 ] ++ optionals (libxcrypt != null) [
353 "CFLAGS=-I${libxcrypt}/include"
354 "LIBS=-L${libxcrypt}/lib"
355 ] ++ optionals tzdataSupport [
356 "--with-tzpath=${tzdata}/share/zoneinfo"
357 ] ++ optional static "LDFLAGS=-static";
358
359 preConfigure = ''
360 for i in /usr /sw /opt /pkg; do # improve purity
361 substituteInPlace ./setup.py --replace $i /no-such-path
362 done
363 '' + optionalString stdenv.isDarwin ''
364 # Override the auto-detection in setup.py, which assumes a universal build
365 export PYTHON_DECIMAL_WITH_MACHINE=${if stdenv.isAarch64 then "uint128" else "x64"}
366 '' + optionalString (isPy3k && pythonOlder "3.7") ''
367 # Determinism: The interpreter is patched to write null timestamps when compiling Python files
368 # so Python doesn't try to update the bytecode when seeing frozen timestamps in Nix's store.
369 export DETERMINISTIC_BUILD=1;
370 '' + optionalString stdenv.hostPlatform.isMusl ''
371 export NIX_CFLAGS_COMPILE+=" -DTHREAD_STACK_SIZE=0x100000"
372 '' +
373
374 # enableNoSemanticInterposition essentially sets that CFLAG -fno-semantic-interposition
375 # which changes how symbols are looked up. This essentially means we can't override
376 # libpython symbols via LD_PRELOAD anymore. This is common enough as every build
377 # that uses --enable-optimizations has the same "issue".
378 #
379 # The Fedora wiki has a good article about their journey towards enabling this flag:
380 # https://fedoraproject.org/wiki/Changes/PythonNoSemanticInterpositionSpeedup
381 optionalString enableNoSemanticInterposition ''
382 export CFLAGS_NODIST="-fno-semantic-interposition"
383 '';
384
385 setupHook = python-setup-hook sitePackages;
386
387 postInstall = let
388 # References *not* to nuke from (sys)config files
389 keep-references = concatMapStringsSep " " (val: "-e ${val}") ([
390 (placeholder "out") libxcrypt
391 ] ++ optionals tzdataSupport [
392 tzdata
393 ]);
394 in ''
395 # needed for some packages, especially packages that backport functionality
396 # to 2.x from 3.x
397 for item in $out/lib/${libPrefix}/test/*; do
398 if [[ "$item" != */test_support.py*
399 && "$item" != */test/support
400 && "$item" != */test/libregrtest
401 && "$item" != */test/regrtest.py* ]]; then
402 rm -rf "$item"
403 else
404 echo $item
405 fi
406 done
407 touch $out/lib/${libPrefix}/test/__init__.py
408
409 ln -s "$out/include/${executable}m" "$out/include/${executable}"
410
411 # Determinism: Windows installers were not deterministic.
412 # We're also not interested in building Windows installers.
413 find "$out" -name 'wininst*.exe' | xargs -r rm -f
414
415 # Use Python3 as default python
416 ln -s "$out/bin/idle3" "$out/bin/idle"
417 ln -s "$out/bin/pydoc3" "$out/bin/pydoc"
418 ln -s "$out/bin/python3" "$out/bin/python"
419 ln -s "$out/bin/python3-config" "$out/bin/python-config"
420 ln -s "$out/lib/pkgconfig/python3.pc" "$out/lib/pkgconfig/python.pc"
421
422 # Get rid of retained dependencies on -dev packages, and remove
423 # some $TMPDIR references to improve binary reproducibility.
424 # Note that the .pyc file of _sysconfigdata.py should be regenerated!
425 for i in $out/lib/${libPrefix}/_sysconfigdata*.py $out/lib/${libPrefix}/config-${sourceVersion.major}${sourceVersion.minor}*/Makefile; do
426 sed -i $i -e "s|$TMPDIR|/no-such-path|g"
427 done
428
429 # Further get rid of references. https://github.com/NixOS/nixpkgs/issues/51668
430 find $out/lib/python*/config-* -type f -print -exec nuke-refs ${keep-references} '{}' +
431 find $out/lib -name '_sysconfigdata*.py*' -print -exec nuke-refs ${keep-references} '{}' +
432
433 # Make the sysconfigdata module accessible on PYTHONPATH
434 # This allows build Python to import host Python's sysconfigdata
435 mkdir -p "$out/${sitePackages}"
436 ln -s "$out/lib/${libPrefix}/"_sysconfigdata*.py "$out/${sitePackages}/"
437 '' + optionalString stripConfig ''
438 rm -R $out/bin/python*-config $out/lib/python*/config-*
439 '' + optionalString stripIdlelib ''
440 # Strip IDLE (and turtledemo, which uses it)
441 rm -R $out/bin/idle* $out/lib/python*/{idlelib,turtledemo}
442 '' + optionalString stripTkinter ''
443 rm -R $out/lib/python*/tkinter
444 '' + optionalString stripTests ''
445 # Strip tests
446 rm -R $out/lib/python*/test $out/lib/python*/**/test{,s}
447 '' + optionalString includeSiteCustomize ''
448 # Include a sitecustomize.py file
449 cp ${../sitecustomize.py} $out/${sitePackages}/sitecustomize.py
450
451 '' + optionalString stripBytecode ''
452 # Determinism: deterministic bytecode
453 # First we delete all old bytecode.
454 find $out -type d -name __pycache__ -print0 | xargs -0 -I {} rm -rf "{}"
455 '' + optionalString rebuildBytecode ''
456 # Python 3.7 implements PEP 552, introducing support for deterministic bytecode.
457 # compileall uses the therein introduced checked-hash method by default when
458 # `SOURCE_DATE_EPOCH` is set.
459 # We exclude lib2to3 because that's Python 2 code which fails
460 # We build 3 levels of optimized bytecode. Note the default level, without optimizations,
461 # is not reproducible yet. https://bugs.python.org/issue29708
462 # Not creating bytecode will result in a large performance loss however, so we do build it.
463 find $out -name "*.py" | ${pythonForBuildInterpreter} -m compileall -q -f -x "lib2to3" -i -
464 find $out -name "*.py" | ${pythonForBuildInterpreter} -O -m compileall -q -f -x "lib2to3" -i -
465 find $out -name "*.py" | ${pythonForBuildInterpreter} -OO -m compileall -q -f -x "lib2to3" -i -
466 '' + ''
467 # *strip* shebang from libpython gdb script - it should be dual-syntax and
468 # interpretable by whatever python the gdb in question is using, which may
469 # not even match the major version of this python. doing this after the
470 # bytecode compilations for the same reason - we don't want bytecode generated.
471 mkdir -p $out/share/gdb
472 sed '/^#!/d' Tools/gdb/libpython.py > $out/share/gdb/libpython.py
473 '';
474
475 preFixup = lib.optionalString (stdenv.hostPlatform != stdenv.buildPlatform) ''
476 # Ensure patch-shebangs uses shebangs of host interpreter.
477 export PATH=${lib.makeBinPath [ "$out" ]}:$PATH
478 '';
479
480 # Add CPython specific setup-hook that configures distutils.sysconfig to
481 # always load sysconfigdata from host Python.
482 postFixup = lib.optionalString (!stdenv.hostPlatform.isDarwin) ''
483 cat << "EOF" >> "$out/nix-support/setup-hook"
484 ${sysconfigdataHook}
485 EOF
486 '';
487
488 # Enforce that we don't have references to the OpenSSL -dev package, which we
489 # explicitly specify in our configure flags above.
490 disallowedReferences =
491 lib.optionals (openssl != null && !static) [ openssl.dev ]
492 ++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
493 # Ensure we don't have references to build-time packages.
494 # These typically end up in shebangs.
495 pythonForBuild buildPackages.bash
496 ];
497
498 separateDebugInfo = true;
499
500 inherit passthru;
501
502 enableParallelBuilding = true;
503
504 meta = {
505 homepage = "http://python.org";
506 description = "A high-level dynamically-typed programming language";
507 longDescription = ''
508 Python is a remarkably powerful dynamic programming language that
509 is used in a wide variety of application domains. Some of its key
510 distinguishing features include: clear, readable syntax; strong
511 introspection capabilities; intuitive object orientation; natural
512 expression of procedural code; full modularity, supporting
513 hierarchical packages; exception-based error handling; and very
514 high level dynamic data types.
515 '';
516 license = licenses.psfl;
517 platforms = with platforms; linux ++ darwin;
518 maintainers = with maintainers; [ fridh ];
519 };
520}