1{
2 lib,
3 buildPythonPackage,
4 fetchFromGitHub,
5 pythonAtLeast,
6
7 # build-system
8 installShellFiles,
9 wheel,
10 setuptools,
11
12 # docs
13 sphinx,
14 sphinx-issues,
15
16 # checks
17 freezegun,
18 git,
19 mock,
20 scripttest,
21 virtualenv,
22 pretend,
23 proxy-py,
24 pytestCheckHook,
25 tomli-w,
26 werkzeug,
27
28 # coupled downstream dependencies
29 pip-tools,
30}:
31
32let
33 self = buildPythonPackage rec {
34 pname = "pip";
35 version = "25.0.1";
36 format = "pyproject";
37
38 src = fetchFromGitHub {
39 owner = "pypa";
40 repo = "pip";
41 tag = version;
42 hash = "sha256-V069rAL6U5KBnSc09LRCu0M7qQCH5NbMghVttlmIoRY=";
43 };
44
45 postPatch = ''
46 # Remove vendored Windows PE binaries
47 # Note: These are unused but make the package unreproducible.
48 find -type f -name '*.exe' -delete
49 '';
50
51 nativeBuildInputs = [
52 installShellFiles
53 setuptools
54 wheel
55 ]
56 ++ lib.optionals (pythonAtLeast "3.11") [
57 # docs
58 # (sphinx requires Python 3.11)
59 sphinx
60 sphinx-issues
61 ];
62
63 outputs = [
64 "out"
65 ]
66 ++ lib.optionals (pythonAtLeast "3.11") [
67 "man"
68 ];
69
70 # pip uses a custom sphinx extension and unusual conf.py location, mimic the internal build rather than attempting
71 # to fit sphinxHook see https://github.com/pypa/pip/blob/0778c1c153da7da457b56df55fb77cbba08dfb0c/noxfile.py#L129-L148
72 postBuild = lib.optionalString (pythonAtLeast "3.11") ''
73 cd docs
74
75 # remove references to sphinx extentions only required for html doc generation
76 # sphinx.ext.intersphinx requires network connection or packaged object.inv files for python and pypug
77 # sphinxcontrib.towncrier is not currently packaged
78 for ext in sphinx.ext.intersphinx sphinx_copybutton sphinx_inline_tabs sphinxcontrib.towncrier myst_parser; do
79 substituteInPlace html/conf.py --replace-fail '"'$ext'",' ""
80 done
81
82 PYTHONPATH=$src/src:$PYTHONPATH sphinx-build -v \
83 -d build/doctrees/man \
84 -c html \
85 -d build/doctrees/man \
86 -b man \
87 man \
88 build/man
89 cd ..
90 '';
91
92 doCheck = false;
93
94 nativeCheckInputs = [
95 freezegun
96 git
97 mock
98 scripttest
99 virtualenv
100 pretend
101 pytestCheckHook
102 proxy-py
103 tomli-w
104 werkzeug
105 ];
106
107 postInstall = ''
108 installManPage docs/build/man/*
109
110 installShellCompletion --cmd pip \
111 --bash <($out/bin/pip completion --bash --no-cache-dir) \
112 --fish <($out/bin/pip completion --fish --no-cache-dir) \
113 --zsh <($out/bin/pip completion --zsh --no-cache-dir)
114 '';
115
116 passthru.tests = {
117 inherit pip-tools;
118 pytest = self.overridePythonAttrs { doCheck = true; };
119 };
120
121 meta = {
122 description = "PyPA recommended tool for installing Python packages";
123 license = with lib.licenses; [ mit ];
124 homepage = "https://pip.pypa.io/";
125 changelog = "https://pip.pypa.io/en/stable/news/#v${lib.replaceStrings [ "." ] [ "-" ] version}";
126 };
127 };
128in
129self