ยปCore Development>Code coverage>Lib/packaging/command/cmd.py

Python code coverage for Lib/packaging/command/cmd.py

#countcontent
1n/a"""Base class for commands."""
2n/a
3n/aimport os
4n/aimport re
5n/afrom shutil import copyfile, move, make_archive
6n/afrom packaging import util
7n/afrom packaging import logger
8n/afrom packaging.errors import PackagingOptionError
9n/a
10n/a
11n/aclass Command:
12n/a """Abstract base class for defining command classes, the "worker bees"
13n/a of Packaging. A useful analogy for command classes is to think of
14n/a them as subroutines with local variables called "options". The options
15n/a are "declared" in 'initialize_options()' and "defined" (given their
16n/a final values, aka "finalized") in 'finalize_options()', both of which
17n/a must be defined by every command class. The distinction between the
18n/a two is necessary because option values might come from the outside
19n/a world (command line, config file, ...), and any options dependent on
20n/a other options must be computed *after* these outside influences have
21n/a been processed -- hence 'finalize_options()'. The "body" of the
22n/a subroutine, where it does all its work based on the values of its
23n/a options, is the 'run()' method, which must also be implemented by every
24n/a command class.
25n/a """
26n/a
27n/a # 'sub_commands' formalizes the notion of a "family" of commands,
28n/a # eg. "install_dist" as the parent with sub-commands "install_lib",
29n/a # "install_headers", etc. The parent of a family of commands
30n/a # defines 'sub_commands' as a class attribute; it's a list of
31n/a # (command_name : string, predicate : unbound_method | string | None)
32n/a # tuples, where 'predicate' is a method of the parent command that
33n/a # determines whether the corresponding command is applicable in the
34n/a # current situation. (Eg. we "install_headers" is only applicable if
35n/a # we have any C header files to install.) If 'predicate' is None,
36n/a # that command is always applicable.
37n/a #
38n/a # 'sub_commands' is usually defined at the *end* of a class, because
39n/a # predicates can be unbound methods, so they must already have been
40n/a # defined. The canonical example is the "install_dist" command.
41n/a sub_commands = []
42n/a
43n/a # Pre and post command hooks are run just before or just after the command
44n/a # itself. They are simple functions that receive the command instance. They
45n/a # are specified as callable objects or dotted strings (for lazy loading).
46n/a pre_hook = None
47n/a post_hook = None
48n/a
49n/a # -- Creation/initialization methods -------------------------------
50n/a
51n/a def __init__(self, dist):
52n/a """Create and initialize a new Command object. Most importantly,
53n/a invokes the 'initialize_options()' method, which is the real
54n/a initializer and depends on the actual command being instantiated.
55n/a """
56n/a # late import because of mutual dependence between these classes
57n/a from packaging.dist import Distribution
58n/a
59n/a if not isinstance(dist, Distribution):
60n/a raise TypeError("dist must be an instance of Distribution, not %r"
61n/a % type(dist))
62n/a if self.__class__ is Command:
63n/a raise RuntimeError("Command is an abstract class")
64n/a
65n/a self.distribution = dist
66n/a self.initialize_options()
67n/a
68n/a # Per-command versions of the global flags, so that the user can
69n/a # customize Packaging' behaviour command-by-command and let some
70n/a # commands fall back on the Distribution's behaviour. None means
71n/a # "not defined, check self.distribution's copy", while 0 or 1 mean
72n/a # false and true (duh). Note that this means figuring out the real
73n/a # value of each flag is a touch complicated -- hence "self._dry_run"
74n/a # will be handled by a property, below.
75n/a # XXX This needs to be fixed. [I changed it to a property--does that
76n/a # "fix" it?]
77n/a self._dry_run = None
78n/a
79n/a # Some commands define a 'self.force' option to ignore file
80n/a # timestamps, but methods defined *here* assume that
81n/a # 'self.force' exists for all commands. So define it here
82n/a # just to be safe.
83n/a self.force = None
84n/a
85n/a # The 'help' flag is just used for command line parsing, so
86n/a # none of that complicated bureaucracy is needed.
87n/a self.help = False
88n/a
89n/a # 'finalized' records whether or not 'finalize_options()' has been
90n/a # called. 'finalize_options()' itself should not pay attention to
91n/a # this flag: it is the business of 'ensure_finalized()', which
92n/a # always calls 'finalize_options()', to respect/update it.
93n/a self.finalized = False
94n/a
95n/a # XXX A more explicit way to customize dry_run would be better.
96n/a @property
97n/a def dry_run(self):
98n/a if self._dry_run is None:
99n/a return getattr(self.distribution, 'dry_run')
100n/a else:
101n/a return self._dry_run
102n/a
103n/a def ensure_finalized(self):
104n/a if not self.finalized:
105n/a self.finalize_options()
106n/a self.finalized = True
107n/a
108n/a # Subclasses must define:
109n/a # initialize_options()
110n/a # provide default values for all options; may be customized by
111n/a # setup script, by options from config file(s), or by command-line
112n/a # options
113n/a # finalize_options()
114n/a # decide on the final values for all options; this is called
115n/a # after all possible intervention from the outside world
116n/a # (command line, option file, etc.) has been processed
117n/a # run()
118n/a # run the command: do whatever it is we're here to do,
119n/a # controlled by the command's various option values
120n/a
121n/a def initialize_options(self):
122n/a """Set default values for all the options that this command
123n/a supports. Note that these defaults may be overridden by other
124n/a commands, by the setup script, by config files, or by the
125n/a command line. Thus, this is not the place to code dependencies
126n/a between options; generally, 'initialize_options()' implementations
127n/a are just a bunch of "self.foo = None" assignments.
128n/a
129n/a This method must be implemented by all command classes.
130n/a """
131n/a raise RuntimeError(
132n/a "abstract method -- subclass %s must override" % self.__class__)
133n/a
134n/a def finalize_options(self):
135n/a """Set final values for all the options that this command supports.
136n/a This is always called as late as possible, ie. after any option
137n/a assignments from the command line or from other commands have been
138n/a done. Thus, this is the place to code option dependencies: if
139n/a 'foo' depends on 'bar', then it is safe to set 'foo' from 'bar' as
140n/a long as 'foo' still has the same value it was assigned in
141n/a 'initialize_options()'.
142n/a
143n/a This method must be implemented by all command classes.
144n/a """
145n/a raise RuntimeError(
146n/a "abstract method -- subclass %s must override" % self.__class__)
147n/a
148n/a def dump_options(self, header=None, indent=""):
149n/a if header is None:
150n/a header = "command options for '%s':" % self.get_command_name()
151n/a logger.info(indent + header)
152n/a indent = indent + " "
153n/a negative_opt = getattr(self, 'negative_opt', ())
154n/a for option, _, _ in self.user_options:
155n/a if option in negative_opt:
156n/a continue
157n/a option = option.replace('-', '_')
158n/a if option[-1] == "=":
159n/a option = option[:-1]
160n/a value = getattr(self, option)
161n/a logger.info(indent + "%s = %s", option, value)
162n/a
163n/a def run(self):
164n/a """A command's raison d'etre: carry out the action it exists to
165n/a perform, controlled by the options initialized in
166n/a 'initialize_options()', customized by other commands, the setup
167n/a script, the command line and config files, and finalized in
168n/a 'finalize_options()'. All terminal output and filesystem
169n/a interaction should be done by 'run()'.
170n/a
171n/a This method must be implemented by all command classes.
172n/a """
173n/a raise RuntimeError(
174n/a "abstract method -- subclass %s must override" % self.__class__)
175n/a
176n/a # -- External interface --------------------------------------------
177n/a # (called by outsiders)
178n/a
179n/a def get_source_files(self):
180n/a """Return the list of files that are used as inputs to this command,
181n/a i.e. the files used to generate the output files. The result is used
182n/a by the `sdist` command in determining the set of default files.
183n/a
184n/a Command classes should implement this method if they operate on files
185n/a from the source tree.
186n/a """
187n/a return []
188n/a
189n/a def get_outputs(self):
190n/a """Return the list of files that would be produced if this command
191n/a were actually run. Not affected by the "dry-run" flag or whether
192n/a any other commands have been run.
193n/a
194n/a Command classes should implement this method if they produce any
195n/a output files that get consumed by another command. e.g., `build_ext`
196n/a returns the list of built extension modules, but not any temporary
197n/a files used in the compilation process.
198n/a """
199n/a return []
200n/a
201n/a # -- Option validation methods -------------------------------------
202n/a # (these are very handy in writing the 'finalize_options()' method)
203n/a #
204n/a # NB. the general philosophy here is to ensure that a particular option
205n/a # value meets certain type and value constraints. If not, we try to
206n/a # force it into conformance (eg. if we expect a list but have a string,
207n/a # split the string on comma and/or whitespace). If we can't force the
208n/a # option into conformance, raise PackagingOptionError. Thus, command
209n/a # classes need do nothing more than (eg.)
210n/a # self.ensure_string_list('foo')
211n/a # and they can be guaranteed that thereafter, self.foo will be
212n/a # a list of strings.
213n/a
214n/a def _ensure_stringlike(self, option, what, default=None):
215n/a val = getattr(self, option)
216n/a if val is None:
217n/a setattr(self, option, default)
218n/a return default
219n/a elif not isinstance(val, str):
220n/a raise PackagingOptionError("'%s' must be a %s (got `%s`)" %
221n/a (option, what, val))
222n/a return val
223n/a
224n/a def ensure_string(self, option, default=None):
225n/a """Ensure that 'option' is a string; if not defined, set it to
226n/a 'default'.
227n/a """
228n/a self._ensure_stringlike(option, "string", default)
229n/a
230n/a def ensure_string_list(self, option):
231n/a r"""Ensure that 'option' is a list of strings. If 'option' is
232n/a currently a string, we split it either on /,\s*/ or /\s+/, so
233n/a "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become
234n/a ["foo", "bar", "baz"].
235n/a """
236n/a val = getattr(self, option)
237n/a if val is None:
238n/a return
239n/a elif isinstance(val, str):
240n/a setattr(self, option, re.split(r',\s*|\s+', val))
241n/a else:
242n/a if isinstance(val, list):
243n/a # checks if all elements are str
244n/a ok = True
245n/a for element in val:
246n/a if not isinstance(element, str):
247n/a ok = False
248n/a break
249n/a else:
250n/a ok = False
251n/a
252n/a if not ok:
253n/a raise PackagingOptionError(
254n/a "'%s' must be a list of strings (got %r)" % (option, val))
255n/a
256n/a def _ensure_tested_string(self, option, tester,
257n/a what, error_fmt, default=None):
258n/a val = self._ensure_stringlike(option, what, default)
259n/a if val is not None and not tester(val):
260n/a raise PackagingOptionError(
261n/a ("error in '%s' option: " + error_fmt) % (option, val))
262n/a
263n/a def ensure_filename(self, option):
264n/a """Ensure that 'option' is the name of an existing file."""
265n/a self._ensure_tested_string(option, os.path.isfile,
266n/a "filename",
267n/a "'%s' does not exist or is not a file")
268n/a
269n/a def ensure_dirname(self, option):
270n/a self._ensure_tested_string(option, os.path.isdir,
271n/a "directory name",
272n/a "'%s' does not exist or is not a directory")
273n/a
274n/a # -- Convenience methods for commands ------------------------------
275n/a
276n/a @classmethod
277n/a def get_command_name(cls):
278n/a if hasattr(cls, 'command_name'):
279n/a return cls.command_name
280n/a else:
281n/a return cls.__name__
282n/a
283n/a def set_undefined_options(self, src_cmd, *options):
284n/a """Set values of undefined options from another command.
285n/a
286n/a Undefined options are options set to None, which is the convention
287n/a used to indicate that an option has not been changed between
288n/a 'initialize_options()' and 'finalize_options()'. This method is
289n/a usually called from 'finalize_options()' for options that depend on
290n/a some other command rather than another option of the same command,
291n/a typically subcommands.
292n/a
293n/a The 'src_cmd' argument is the other command from which option values
294n/a will be taken (a command object will be created for it if necessary);
295n/a the remaining positional arguments are strings that give the name of
296n/a the option to set. If the name is different on the source and target
297n/a command, you can pass a tuple with '(name_on_source, name_on_dest)' so
298n/a that 'self.name_on_dest' will be set from 'src_cmd.name_on_source'.
299n/a """
300n/a src_cmd_obj = self.distribution.get_command_obj(src_cmd)
301n/a src_cmd_obj.ensure_finalized()
302n/a for obj in options:
303n/a if isinstance(obj, tuple):
304n/a src_option, dst_option = obj
305n/a else:
306n/a src_option, dst_option = obj, obj
307n/a if getattr(self, dst_option) is None:
308n/a setattr(self, dst_option,
309n/a getattr(src_cmd_obj, src_option))
310n/a
311n/a def get_finalized_command(self, command, create=True):
312n/a """Wrapper around Distribution's 'get_command_obj()' method: find
313n/a (create if necessary and 'create' is true) the command object for
314n/a 'command', call its 'ensure_finalized()' method, and return the
315n/a finalized command object.
316n/a """
317n/a cmd_obj = self.distribution.get_command_obj(command, create)
318n/a cmd_obj.ensure_finalized()
319n/a return cmd_obj
320n/a
321n/a def reinitialize_command(self, command, reinit_subcommands=False):
322n/a return self.distribution.reinitialize_command(
323n/a command, reinit_subcommands)
324n/a
325n/a def run_command(self, command):
326n/a """Run some other command: uses the 'run_command()' method of
327n/a Distribution, which creates and finalizes the command object if
328n/a necessary and then invokes its 'run()' method.
329n/a """
330n/a self.distribution.run_command(command)
331n/a
332n/a def get_sub_commands(self):
333n/a """Determine the sub-commands that are relevant in the current
334n/a distribution (ie., that need to be run). This is based on the
335n/a 'sub_commands' class attribute: each tuple in that list may include
336n/a a method that we call to determine if the subcommand needs to be
337n/a run for the current distribution. Return a list of command names.
338n/a """
339n/a commands = []
340n/a for sub_command in self.sub_commands:
341n/a if len(sub_command) == 2:
342n/a cmd_name, method = sub_command
343n/a if method is None or method(self):
344n/a commands.append(cmd_name)
345n/a else:
346n/a commands.append(sub_command)
347n/a return commands
348n/a
349n/a # -- External world manipulation -----------------------------------
350n/a
351n/a def execute(self, func, args, msg=None, level=1):
352n/a util.execute(func, args, msg, dry_run=self.dry_run)
353n/a
354n/a def mkpath(self, name, mode=0o777, dry_run=None):
355n/a if dry_run is None:
356n/a dry_run = self.dry_run
357n/a name = os.path.normpath(name)
358n/a if os.path.isdir(name) or name == '':
359n/a return
360n/a if dry_run:
361n/a head = ''
362n/a for part in name.split(os.sep):
363n/a logger.info("created directory %s%s", head, part)
364n/a head += part + os.sep
365n/a return
366n/a os.makedirs(name, mode)
367n/a
368n/a def copy_file(self, infile, outfile,
369n/a preserve_mode=True, preserve_times=True, link=None, level=1):
370n/a """Copy a file respecting dry-run and force flags.
371n/a
372n/a (dry-run defaults to whatever is in the Distribution object, and
373n/a force to false for commands that don't define it.)
374n/a """
375n/a if self.dry_run:
376n/a # XXX add a comment
377n/a return
378n/a if os.path.isdir(outfile):
379n/a outfile = os.path.join(outfile, os.path.split(infile)[-1])
380n/a copyfile(infile, outfile)
381n/a return outfile, None # XXX
382n/a
383n/a def copy_tree(self, infile, outfile, preserve_mode=True,
384n/a preserve_times=True, preserve_symlinks=False, level=1):
385n/a """Copy an entire directory tree respecting dry-run
386n/a and force flags.
387n/a """
388n/a if self.dry_run:
389n/a # XXX should not return but let copy_tree log and decide to execute
390n/a # or not based on its dry_run argument
391n/a return
392n/a
393n/a return util.copy_tree(infile, outfile, preserve_mode, preserve_times,
394n/a preserve_symlinks, not self.force, dry_run=self.dry_run)
395n/a
396n/a def move_file(self, src, dst, level=1):
397n/a """Move a file respecting the dry-run flag."""
398n/a if self.dry_run:
399n/a return # XXX same thing
400n/a return move(src, dst)
401n/a
402n/a def spawn(self, cmd, search_path=True, level=1):
403n/a """Spawn an external command respecting dry-run flag."""
404n/a from packaging.util import spawn
405n/a spawn(cmd, search_path, dry_run=self.dry_run)
406n/a
407n/a def make_archive(self, base_name, format, root_dir=None, base_dir=None,
408n/a owner=None, group=None):
409n/a return make_archive(base_name, format, root_dir,
410n/a base_dir, dry_run=self.dry_run,
411n/a owner=owner, group=group)
412n/a
413n/a def make_file(self, infiles, outfile, func, args,
414n/a exec_msg=None, skip_msg=None, level=1):
415n/a """Special case of 'execute()' for operations that process one or
416n/a more input files and generate one output file. Works just like
417n/a 'execute()', except the operation is skipped and a different
418n/a message printed if 'outfile' already exists and is newer than all
419n/a files listed in 'infiles'. If the command defined 'self.force',
420n/a and it is true, then the command is unconditionally run -- does no
421n/a timestamp checks.
422n/a """
423n/a if skip_msg is None:
424n/a skip_msg = "skipping %s (inputs unchanged)" % outfile
425n/a
426n/a # Allow 'infiles' to be a single string
427n/a if isinstance(infiles, str):
428n/a infiles = (infiles,)
429n/a elif not isinstance(infiles, (list, tuple)):
430n/a raise TypeError(
431n/a "'infiles' must be a string, or a list or tuple of strings")
432n/a
433n/a if exec_msg is None:
434n/a exec_msg = "generating %s from %s" % (outfile, ', '.join(infiles))
435n/a
436n/a # If 'outfile' must be regenerated (either because it doesn't
437n/a # exist, is out-of-date, or the 'force' flag is true) then
438n/a # perform the action that presumably regenerates it
439n/a if self.force or util.newer_group(infiles, outfile):
440n/a self.execute(func, args, exec_msg, level)
441n/a
442n/a # Otherwise, print the "skip" message
443n/a else:
444n/a logger.debug(skip_msg)
445n/a
446n/a def byte_compile(self, files, prefix=None):
447n/a """Byte-compile files to pyc and/or pyo files.
448n/a
449n/a This method requires that the calling class define compile and
450n/a optimize options, like build_py and install_lib. It also
451n/a automatically respects the force and dry-run options.
452n/a
453n/a prefix, if given, is a string that will be stripped off the
454n/a filenames encoded in bytecode files.
455n/a """
456n/a if self.compile:
457n/a util.byte_compile(files, optimize=False, prefix=prefix,
458n/a force=self.force, dry_run=self.dry_run)
459n/a if self.optimize:
460n/a util.byte_compile(files, optimize=self.optimize, prefix=prefix,
461n/a force=self.force, dry_run=self.dry_run)