@@ -28,19 +28,167 @@ for parsing top level args.
28
28
29
29
``Command `` then uses another ``ConfigOptionParser `` instance, to parse command-specific args.
30
30
31
- * TODO: How & where options are defined
32
- (cmdoptions, command-specific files).
31
+ Command structure
32
+ -----------------
33
33
34
- * TODO: How & where arguments are processed.
35
- (main_parser, command-specific parser)
34
+ This section shows the class hierarchy from which every command's class will inherit
35
+ from.
36
36
37
- * TODO: How processed arguments are accessed.
38
- (attributes on argument to ``Command.run() ``)
37
+ `base_command.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/base_command.py >`_
38
+ defines the base ``Command `` class, from which every other command will inherit directly or
39
+ indirectly (see the *command tree * at the end of this section).
39
40
40
- * TODO: How configuration and CLI "blend".
41
- (implemented in ``ConfigOptionParser ``)
41
+ Using the ``ConfigOptionParser `` (see `Configuration and CLI "blend" <Configuration and CLI "blend" _>`_),
42
+ this class adds the general options and instantiates the *cmd_opts * group, where every other specific
43
+ option will be added if needed on each command's class. For those commands that define specific
44
+ options, like ``--dry-run `` on ``pip install `` command, the options must be added to *cmd_opts *
45
+ this is the job of *add_options * method), which will be automatically called on ``Command ``'s initialization.
42
46
43
- * TODO: progress bars and spinners
47
+ The base ``Command `` has the following methods:
48
+
49
+ .. py :class :: Command
50
+
51
+ .. py :method :: main()
52
+
53
+ Main method of the class, it's always called (as can be seen in main.py's
54
+ `main <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/main.py#L46 >`_).
55
+ It's in charge of calling the specific ``run `` method of the class and handling the possible errors.
56
+
57
+ .. py :method :: run()
58
+
59
+ Abstract method where the actual action of a command is defined.
60
+
61
+ .. py :method :: add_options()
62
+
63
+ Optional method to insert additional options on a class, called on ``Command `` initialization.
64
+
65
+ Some commands have more specialized behavior, (see for example ``pip index ``).
66
+ These commands instead will inherit from ``IndexGroupCommand ``, which inherits from ``Command ``
67
+ and ``SessionCommandMixin `` to build build the pip session for the corresponding requests.
68
+
69
+ Lastly, ``RequirementCommand ``, which inherits from ``IndexGroupCommand `` is the base class
70
+ for those commands which make use of requirements in any form, like ``pip install ``.
71
+
72
+ In addition to the previous classes, a last mixin class must be mentioned, from which
73
+ ``Command `` as well as ``SessionCommandMixin `` inherit: ``CommandContextMixIn ``, in
74
+ charge of the command's context.
75
+
76
+ In the following command tree we can see the hierarchy defined for the different pip
77
+ commands, where each command is defined under the base class it inherits from:
78
+
79
+ | ``Command``
80
+ | ├─ ``cache``, ``check``, ``completion``, ``configuration``, ``debug``, ``freeze``, ``hash``, ``help``, ``inspect``, ``show``, ``search``, ``uninstall``
81
+ | └─ ``IndexGroupCommand``
82
+ | ├─ ``index``, ``list``
83
+ | └─ ``RequirementCommand``
84
+ | └─ ``wheel``, ``download``, ``install``
85
+
86
+
87
+ Option definition
88
+ -----------------
89
+
90
+ The set of shared options are defined in `cmdoptions.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/cmdoptions.py >`_
91
+ module, as well as the *general options * and *package index options * groups of options
92
+ we see when we call a command's help, or the ``pip index ``'s help message respectively.
93
+ All options are defined in terms of functions that return `optparse.Option <https://docs.python.org/3/library/optparse.html#optparse.Option >`_
94
+ instances once called, while specific groups of options, like *Config Options * for
95
+ ``pip config `` are defined in each specific command file (see for example the
96
+ `configuration.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/commands/configuration.py >`_).
97
+
98
+ Argument parsing
99
+ ----------------
100
+
101
+ The main entrypoint for the application is defined in the ``main `` function in the
102
+ `main.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/main.py >`_ module.
103
+ This function is in charge of the `autocompletion <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/autocompletion.py >`_,
104
+ calling the ``parse_command `` function and creating and running the subprograms
105
+ via ``create_command ``, on which the ``main `` method is called.
106
+
107
+ The ``parse_command `` is defined in the `main_parser.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/main_parser.py >`_
108
+ module, which defines the following two functions:
109
+
110
+ .. py :function :: parse_command()
111
+
112
+ Function in charge of the initial parse of ``pip ``'s program. Creates the main parser (see
113
+ the next function ``create_main_parser ``) to extract the general options
114
+ and the remaining arguments. For example, running ``pip --timeout=5 install --user INITools ``
115
+ will split ``['--timeout=5'] `` as general option and ``['install', '--user', 'INITools'] ``
116
+ as the remainder.
117
+
118
+ At this step the program deals with the options ``--python ``, ``--version ``, ``pip ``
119
+ or ``pip help ``. If neither of the previous options is found, it tries to extract the command
120
+ name and arguments.
121
+
122
+ .. py :function :: create_main_parser()
123
+
124
+ Creates the main parser (type ``pip `` in the console to see the description of the
125
+ program). The internal parser (`ConfigOptionParser <Configuration and CLI "blend" _>`_),
126
+ adds the general option group and the list of commands coming from ``cmdoptions.py ``
127
+ at this point.
128
+
129
+ After the initial parsing is done, ``create_command `` is in charge of creating the appropriate
130
+ command using the information stored in `commands_dict <https://github.com/pypa/pip/blob/main/src/pip/_internal/commands/__init__.py >`_
131
+ variable, and calling its ``main `` method (see `Command structure <Command structure >`_).
132
+
133
+ A second argument parsing is done at each specific command (defined in the base ``Command `` class),
134
+ again using the ``ConfigOptionParser ``.
135
+
136
+ Argument access
137
+ ---------------
138
+
139
+ To access all the options and arguments, ``Command.run() `` takes
140
+ the options as `optparse.Values <https://docs.python.org/3/library/optparse.html#optparse.Values >`_
141
+ and a list of strings for the arguments (parsed in ``Command.main() ``). The internal methods of
142
+ the base ``Command `` class are in charge of passing these variables after ``parse_args `` is
143
+ called for a specific command.
144
+
145
+ Configuration and CLI "blend"
146
+ -----------------------------
147
+
148
+ The base ``Command `` instantiates the class `ConfigOptionParser <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/parser.py >`_
149
+ which is in charge of the parsing process (via its parent class
150
+ `optparse.OptionParser <https://docs.python.org/3/library/optparse.html#optparse.OptionParser >`_).
151
+ Its main addition consists of the following function:
152
+
153
+ .. py :class :: ConfigOptionParser(OptionParser)
154
+
155
+ .. py :method :: get_default_values()
156
+
157
+ Overrides the original method to allow updating the defaults ater the instantiation of the
158
+ option parser.
159
+
160
+ It allows overriding the default options and arguments using the ``Configuration `` class
161
+ (more information can be found on :ref: `Configuration `) to include environment variables and
162
+ settings from configuration files.
163
+
164
+ Progress bars and spinners
165
+ --------------------------
166
+
167
+ There are two more modules in the ``cli `` subpackage in charge of showing the state of the
168
+ program.
169
+
170
+ * `progress_bars.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/progress_bars.py >`_
171
+
172
+ This module contains the following function:
173
+
174
+ .. py :function :: get_download_progress_renderer()
175
+
176
+ It uses `rich <https://rich.readthedocs.io/en/stable/reference/progress.html#module-rich.progress >`_
177
+ functionalities to render the download progress.
178
+
179
+ This function (used in `download.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/network/download.py >`_,
180
+ inside the ``Downloader `` class), allows watching the download process when running
181
+ ``pip install `` on *big * packages.
182
+
183
+ * `spinner.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/cli/spinners.py >`_
184
+
185
+ The main function of this module is:
186
+
187
+ .. py :function :: open_spinner()
188
+
189
+ It yields the appropriate type of spinner, which is used in ``call_subprocess ``
190
+ function, inside `subprocess.py <https://github.com/pypa/pip/blob/main/src/pip/_internal/utils/subprocess.py >`_
191
+ module, so the user can see there is a program running.
44
192
45
193
* TODO: quirks / standard practices / broad ideas.
46
194
(avoiding lists in option def'n, special cased option value types,
0 commit comments