mirror of
https://github.com/python/cpython.git
synced 2025-08-02 16:13:13 +00:00
Merged revisions 72681 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r72681 | tarek.ziade | 2009-05-16 18:37:06 +0200 (Sat, 16 May 2009) | 1 line #6041: sdist and register now use the check command. No more duplicate code for metadata checking ........
This commit is contained in:
parent
afdfbc72fb
commit
5af55c6360
6 changed files with 182 additions and 72 deletions
|
@ -10,6 +10,7 @@ __revision__ = "$Id$"
|
||||||
import os, string, getpass
|
import os, string, getpass
|
||||||
import io
|
import io
|
||||||
import urllib.parse, urllib.request
|
import urllib.parse, urllib.request
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
from distutils.core import PyPIRCCommand
|
from distutils.core import PyPIRCCommand
|
||||||
from distutils.errors import *
|
from distutils.errors import *
|
||||||
|
@ -21,18 +22,34 @@ class register(PyPIRCCommand):
|
||||||
user_options = PyPIRCCommand.user_options + [
|
user_options = PyPIRCCommand.user_options + [
|
||||||
('list-classifiers', None,
|
('list-classifiers', None,
|
||||||
'list the valid Trove classifiers'),
|
'list the valid Trove classifiers'),
|
||||||
|
('strict', None ,
|
||||||
|
'Will stop the registering if the meta-data are not fully compliant')
|
||||||
]
|
]
|
||||||
boolean_options = PyPIRCCommand.boolean_options + [
|
boolean_options = PyPIRCCommand.boolean_options + [
|
||||||
'verify', 'list-classifiers']
|
'verify', 'list-classifiers', 'strict']
|
||||||
|
|
||||||
|
sub_commands = [('check', lambda self: True)]
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
PyPIRCCommand.initialize_options(self)
|
PyPIRCCommand.initialize_options(self)
|
||||||
self.list_classifiers = 0
|
self.list_classifiers = 0
|
||||||
|
self.strict = 0
|
||||||
|
|
||||||
|
def finalize_options(self):
|
||||||
|
PyPIRCCommand.finalize_options(self)
|
||||||
|
# setting options for the `check` subcommand
|
||||||
|
check_options = {'strict': ('register', self.strict),
|
||||||
|
'restructuredtext': ('register', 1)}
|
||||||
|
self.distribution.command_options['check'] = check_options
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.finalize_options()
|
self.finalize_options()
|
||||||
self._set_config()
|
self._set_config()
|
||||||
self.check_metadata()
|
|
||||||
|
# Run sub commands
|
||||||
|
for cmd_name in self.get_sub_commands():
|
||||||
|
self.run_command(cmd_name)
|
||||||
|
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
self.verify_metadata()
|
self.verify_metadata()
|
||||||
elif self.list_classifiers:
|
elif self.list_classifiers:
|
||||||
|
@ -41,34 +58,14 @@ class register(PyPIRCCommand):
|
||||||
self.send_metadata()
|
self.send_metadata()
|
||||||
|
|
||||||
def check_metadata(self):
|
def check_metadata(self):
|
||||||
"""Ensure that all required elements of meta-data (name, version,
|
"""Deprecated API."""
|
||||||
URL, (author and author_email) or (maintainer and
|
warn("distutils.command.register.check_metadata is deprecated, \
|
||||||
maintainer_email)) are supplied by the Distribution object; warn if
|
use the check command instead", PendingDeprecationWarning)
|
||||||
any are missing.
|
check = self.distribution.get_command_obj('check')
|
||||||
"""
|
check.ensure_finalized()
|
||||||
metadata = self.distribution.metadata
|
check.strict = self.strict
|
||||||
|
check.restructuredtext = 1
|
||||||
missing = []
|
check.run()
|
||||||
for attr in ('name', 'version', 'url'):
|
|
||||||
if not (hasattr(metadata, attr) and getattr(metadata, attr)):
|
|
||||||
missing.append(attr)
|
|
||||||
|
|
||||||
if missing:
|
|
||||||
self.warn("missing required meta-data: " +
|
|
||||||
", ".join(missing))
|
|
||||||
|
|
||||||
if metadata.author:
|
|
||||||
if not metadata.author_email:
|
|
||||||
self.warn("missing meta-data: if 'author' supplied, " +
|
|
||||||
"'author_email' must be supplied too")
|
|
||||||
elif metadata.maintainer:
|
|
||||||
if not metadata.maintainer_email:
|
|
||||||
self.warn("missing meta-data: if 'maintainer' supplied, " +
|
|
||||||
"'maintainer_email' must be supplied too")
|
|
||||||
else:
|
|
||||||
self.warn("missing meta-data: either (author and author_email) " +
|
|
||||||
"or (maintainer and maintainer_email) " +
|
|
||||||
"must be supplied")
|
|
||||||
|
|
||||||
def _set_config(self):
|
def _set_config(self):
|
||||||
''' Reads the configuration file and set attributes.
|
''' Reads the configuration file and set attributes.
|
||||||
|
|
|
@ -9,6 +9,8 @@ import string
|
||||||
import sys
|
import sys
|
||||||
from types import *
|
from types import *
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
from warnings import warn
|
||||||
|
|
||||||
from distutils.core import Command
|
from distutils.core import Command
|
||||||
from distutils import dir_util, dep_util, file_util, archive_util
|
from distutils import dir_util, dep_util, file_util, archive_util
|
||||||
from distutils.text_file import TextFile
|
from distutils.text_file import TextFile
|
||||||
|
@ -35,6 +37,12 @@ class sdist(Command):
|
||||||
|
|
||||||
description = "create a source distribution (tarball, zip file, etc.)"
|
description = "create a source distribution (tarball, zip file, etc.)"
|
||||||
|
|
||||||
|
def checking_metadata(self):
|
||||||
|
"""Callable used for the check sub-command.
|
||||||
|
|
||||||
|
Placed here so user_options can view it"""
|
||||||
|
return self.metadata_check
|
||||||
|
|
||||||
user_options = [
|
user_options = [
|
||||||
('template=', 't',
|
('template=', 't',
|
||||||
"name of manifest template file [default: MANIFEST.in]"),
|
"name of manifest template file [default: MANIFEST.in]"),
|
||||||
|
@ -64,11 +72,14 @@ class sdist(Command):
|
||||||
('dist-dir=', 'd',
|
('dist-dir=', 'd',
|
||||||
"directory to put the source distribution archive(s) in "
|
"directory to put the source distribution archive(s) in "
|
||||||
"[default: dist]"),
|
"[default: dist]"),
|
||||||
|
('medata-check', None,
|
||||||
|
"Ensure that all required elements of meta-data "
|
||||||
|
"are supplied. Warn if any missing. [default]"),
|
||||||
]
|
]
|
||||||
|
|
||||||
boolean_options = ['use-defaults', 'prune',
|
boolean_options = ['use-defaults', 'prune',
|
||||||
'manifest-only', 'force-manifest',
|
'manifest-only', 'force-manifest',
|
||||||
'keep-temp']
|
'keep-temp', 'metadata-check']
|
||||||
|
|
||||||
help_options = [
|
help_options = [
|
||||||
('help-formats', None,
|
('help-formats', None,
|
||||||
|
@ -81,6 +92,8 @@ class sdist(Command):
|
||||||
default_format = {'posix': 'gztar',
|
default_format = {'posix': 'gztar',
|
||||||
'nt': 'zip' }
|
'nt': 'zip' }
|
||||||
|
|
||||||
|
sub_commands = [('check', checking_metadata)]
|
||||||
|
|
||||||
def initialize_options(self):
|
def initialize_options(self):
|
||||||
# 'template' and 'manifest' are, respectively, the names of
|
# 'template' and 'manifest' are, respectively, the names of
|
||||||
# the manifest template and manifest file.
|
# the manifest template and manifest file.
|
||||||
|
@ -100,6 +113,7 @@ class sdist(Command):
|
||||||
self.dist_dir = None
|
self.dist_dir = None
|
||||||
|
|
||||||
self.archive_files = None
|
self.archive_files = None
|
||||||
|
self.metadata_check = 1
|
||||||
|
|
||||||
def finalize_options(self):
|
def finalize_options(self):
|
||||||
if self.manifest is None:
|
if self.manifest is None:
|
||||||
|
@ -129,9 +143,9 @@ class sdist(Command):
|
||||||
# manifest
|
# manifest
|
||||||
self.filelist = FileList()
|
self.filelist = FileList()
|
||||||
|
|
||||||
# Ensure that all required meta-data is given; warn if not (but
|
# Run sub commands
|
||||||
# don't die, it's not *that* serious!)
|
for cmd_name in self.get_sub_commands():
|
||||||
self.check_metadata()
|
self.run_command(cmd_name)
|
||||||
|
|
||||||
# Do whatever it takes to get the list of files to process
|
# Do whatever it takes to get the list of files to process
|
||||||
# (process the manifest template, read an existing manifest,
|
# (process the manifest template, read an existing manifest,
|
||||||
|
@ -147,34 +161,12 @@ class sdist(Command):
|
||||||
self.make_distribution()
|
self.make_distribution()
|
||||||
|
|
||||||
def check_metadata(self):
|
def check_metadata(self):
|
||||||
"""Ensure that all required elements of meta-data (name, version,
|
"""Deprecated API."""
|
||||||
URL, (author and author_email) or (maintainer and
|
warn("distutils.command.sdist.check_metadata is deprecated, \
|
||||||
maintainer_email)) are supplied by the Distribution object; warn if
|
use the check command instead", PendingDeprecationWarning)
|
||||||
any are missing.
|
check = self.distribution.get_command_obj('check')
|
||||||
"""
|
check.ensure_finalized()
|
||||||
metadata = self.distribution.metadata
|
check.run()
|
||||||
|
|
||||||
missing = []
|
|
||||||
for attr in ('name', 'version', 'url'):
|
|
||||||
if not (hasattr(metadata, attr) and getattr(metadata, attr)):
|
|
||||||
missing.append(attr)
|
|
||||||
|
|
||||||
if missing:
|
|
||||||
self.warn("missing required meta-data: " +
|
|
||||||
", ".join(missing))
|
|
||||||
|
|
||||||
if metadata.author:
|
|
||||||
if not metadata.author_email:
|
|
||||||
self.warn("missing meta-data: if 'author' supplied, " +
|
|
||||||
"'author_email' must be supplied too")
|
|
||||||
elif metadata.maintainer:
|
|
||||||
if not metadata.maintainer_email:
|
|
||||||
self.warn("missing meta-data: if 'maintainer' supplied, " +
|
|
||||||
"'maintainer_email' must be supplied too")
|
|
||||||
else:
|
|
||||||
self.warn("missing meta-data: either (author and author_email) " +
|
|
||||||
"or (maintainer and maintainer_email) " +
|
|
||||||
"must be supplied")
|
|
||||||
|
|
||||||
def get_file_list(self):
|
def get_file_list(self):
|
||||||
"""Figure out the list of files to include in the source
|
"""Figure out the list of files to include in the source
|
||||||
|
|
|
@ -12,11 +12,31 @@ class LoggingSilencer(object):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.threshold = log.set_threshold(log.FATAL)
|
self.threshold = log.set_threshold(log.FATAL)
|
||||||
|
# catching warnings
|
||||||
|
# when log will be replaced by logging
|
||||||
|
# we won't need such monkey-patch anymore
|
||||||
|
self._old_log = log.Log._log
|
||||||
|
log.Log._log = self._log
|
||||||
|
self.logs = []
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
log.set_threshold(self.threshold)
|
log.set_threshold(self.threshold)
|
||||||
|
log.Log._log = self._old_log
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
||||||
|
def _log(self, level, msg, args):
|
||||||
|
self.logs.append((level, msg, args))
|
||||||
|
|
||||||
|
def get_logs(self, *levels):
|
||||||
|
def _format(msg, args):
|
||||||
|
if len(args) == 0:
|
||||||
|
return msg
|
||||||
|
return msg % args
|
||||||
|
return [_format(msg, args) for level, msg, args
|
||||||
|
in self.logs if level in levels]
|
||||||
|
|
||||||
|
def clear_logs(self):
|
||||||
|
self.logs = []
|
||||||
|
|
||||||
class TempdirManager(object):
|
class TempdirManager(object):
|
||||||
"""Mix-in class that handles temporary directories for test cases.
|
"""Mix-in class that handles temporary directories for test cases.
|
||||||
|
|
|
@ -4,10 +4,14 @@ import os
|
||||||
import unittest
|
import unittest
|
||||||
import getpass
|
import getpass
|
||||||
import urllib
|
import urllib
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from test.support import check_warnings
|
||||||
|
|
||||||
from distutils.command import register as register_module
|
from distutils.command import register as register_module
|
||||||
from distutils.command.register import register
|
from distutils.command.register import register
|
||||||
from distutils.core import Distribution
|
from distutils.core import Distribution
|
||||||
|
from distutils.errors import DistutilsSetupError
|
||||||
|
|
||||||
from distutils.tests import support
|
from distutils.tests import support
|
||||||
from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase
|
from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase
|
||||||
|
@ -59,7 +63,7 @@ class FakeOpener(object):
|
||||||
def read(self):
|
def read(self):
|
||||||
return 'xxx'
|
return 'xxx'
|
||||||
|
|
||||||
class registerTestCase(PyPIRCCommandTestCase):
|
class RegisterTestCase(PyPIRCCommandTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
PyPIRCCommandTestCase.setUp(self)
|
PyPIRCCommandTestCase.setUp(self)
|
||||||
|
@ -76,10 +80,11 @@ class registerTestCase(PyPIRCCommandTestCase):
|
||||||
urllib.request.build_opener = self.old_opener
|
urllib.request.build_opener = self.old_opener
|
||||||
PyPIRCCommandTestCase.tearDown(self)
|
PyPIRCCommandTestCase.tearDown(self)
|
||||||
|
|
||||||
def _get_cmd(self):
|
def _get_cmd(self, metadata=None):
|
||||||
metadata = {'url': 'xxx', 'author': 'xxx',
|
if metadata is None:
|
||||||
'author_email': 'xxx',
|
metadata = {'url': 'xxx', 'author': 'xxx',
|
||||||
'name': 'xxx', 'version': 'xxx'}
|
'author_email': 'xxx',
|
||||||
|
'name': 'xxx', 'version': 'xxx'}
|
||||||
pkg_info, dist = self.create_dist(**metadata)
|
pkg_info, dist = self.create_dist(**metadata)
|
||||||
return register(dist)
|
return register(dist)
|
||||||
|
|
||||||
|
@ -184,8 +189,70 @@ class registerTestCase(PyPIRCCommandTestCase):
|
||||||
self.assertEquals(headers['Content-length'], '290')
|
self.assertEquals(headers['Content-length'], '290')
|
||||||
self.assert_((b'tarek') in req.data)
|
self.assert_((b'tarek') in req.data)
|
||||||
|
|
||||||
|
def test_strict(self):
|
||||||
|
# testing the script option
|
||||||
|
# when on, the register command stops if
|
||||||
|
# the metadata is incomplete or if
|
||||||
|
# long_description is not reSt compliant
|
||||||
|
|
||||||
|
# empty metadata
|
||||||
|
cmd = self._get_cmd({})
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
cmd.strict = 1
|
||||||
|
self.assertRaises(DistutilsSetupError, cmd.run)
|
||||||
|
|
||||||
|
# we don't test the reSt feature if docutils
|
||||||
|
# is not installed
|
||||||
|
try:
|
||||||
|
import docutils
|
||||||
|
except ImportError:
|
||||||
|
return
|
||||||
|
|
||||||
|
# metadata are OK but long_description is broken
|
||||||
|
metadata = {'url': 'xxx', 'author': 'xxx',
|
||||||
|
'author_email': 'xxx',
|
||||||
|
'name': 'xxx', 'version': 'xxx',
|
||||||
|
'long_description': 'title\n==\n\ntext'}
|
||||||
|
|
||||||
|
cmd = self._get_cmd(metadata)
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
cmd.strict = 1
|
||||||
|
self.assertRaises(DistutilsSetupError, cmd.run)
|
||||||
|
|
||||||
|
# now something that works
|
||||||
|
metadata['long_description'] = 'title\n=====\n\ntext'
|
||||||
|
cmd = self._get_cmd(metadata)
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
cmd.strict = 1
|
||||||
|
inputs = RawInputs('1', 'tarek', 'y')
|
||||||
|
register_module.raw_input = inputs.__call__
|
||||||
|
# let's run the command
|
||||||
|
try:
|
||||||
|
cmd.run()
|
||||||
|
finally:
|
||||||
|
del register_module.raw_input
|
||||||
|
|
||||||
|
# strict is not by default
|
||||||
|
cmd = self._get_cmd()
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
inputs = RawInputs('1', 'tarek', 'y')
|
||||||
|
register_module.raw_input = inputs.__call__
|
||||||
|
# let's run the command
|
||||||
|
try:
|
||||||
|
cmd.run()
|
||||||
|
finally:
|
||||||
|
del register_module.raw_input
|
||||||
|
|
||||||
|
def test_check_metadata_deprecated(self):
|
||||||
|
# makes sure make_metadata is deprecated
|
||||||
|
cmd = self._get_cmd()
|
||||||
|
with check_warnings() as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
cmd.check_metadata()
|
||||||
|
self.assertEquals(len(w.warnings), 1)
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.makeSuite(registerTestCase)
|
return unittest.makeSuite(RegisterTestCase)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main(defaultTest="test_suite")
|
unittest.main(defaultTest="test_suite")
|
||||||
|
|
|
@ -6,7 +6,9 @@ import zipfile
|
||||||
from os.path import join
|
from os.path import join
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from test.support import check_warnings
|
||||||
from test.support import captured_stdout
|
from test.support import captured_stdout
|
||||||
|
|
||||||
from distutils.command.sdist import sdist
|
from distutils.command.sdist import sdist
|
||||||
|
@ -16,6 +18,7 @@ from distutils.tests.test_config import PyPIRCCommandTestCase
|
||||||
from distutils.errors import DistutilsExecError, DistutilsOptionError
|
from distutils.errors import DistutilsExecError, DistutilsOptionError
|
||||||
from distutils.spawn import find_executable
|
from distutils.spawn import find_executable
|
||||||
from distutils.tests import support
|
from distutils.tests import support
|
||||||
|
from distutils.log import WARN
|
||||||
from distutils.archive_util import ARCHIVE_FORMATS
|
from distutils.archive_util import ARCHIVE_FORMATS
|
||||||
|
|
||||||
SETUP_PY = """
|
SETUP_PY = """
|
||||||
|
@ -38,12 +41,12 @@ somecode%(sep)sdoc.dat
|
||||||
somecode%(sep)sdoc.txt
|
somecode%(sep)sdoc.txt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
class sdistTestCase(PyPIRCCommandTestCase):
|
class SDistTestCase(PyPIRCCommandTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# PyPIRCCommandTestCase creates a temp dir already
|
# PyPIRCCommandTestCase creates a temp dir already
|
||||||
# and put it in self.tmp_dir
|
# and put it in self.tmp_dir
|
||||||
super(sdistTestCase, self).setUp()
|
super(SDistTestCase, self).setUp()
|
||||||
# setting up an environment
|
# setting up an environment
|
||||||
self.old_path = os.getcwd()
|
self.old_path = os.getcwd()
|
||||||
os.mkdir(join(self.tmp_dir, 'somecode'))
|
os.mkdir(join(self.tmp_dir, 'somecode'))
|
||||||
|
@ -57,7 +60,7 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
# back to normal
|
# back to normal
|
||||||
os.chdir(self.old_path)
|
os.chdir(self.old_path)
|
||||||
super(sdistTestCase, self).tearDown()
|
super(SDistTestCase, self).tearDown()
|
||||||
|
|
||||||
def get_cmd(self, metadata=None):
|
def get_cmd(self, metadata=None):
|
||||||
"""Returns a cmd"""
|
"""Returns a cmd"""
|
||||||
|
@ -214,6 +217,34 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
manifest = open(join(self.tmp_dir, 'MANIFEST')).read()
|
manifest = open(join(self.tmp_dir, 'MANIFEST')).read()
|
||||||
self.assertEquals(manifest, MANIFEST % {'sep': os.sep})
|
self.assertEquals(manifest, MANIFEST % {'sep': os.sep})
|
||||||
|
|
||||||
|
def test_metadata_check_option(self):
|
||||||
|
# testing the `medata-check` option
|
||||||
|
dist, cmd = self.get_cmd(metadata={})
|
||||||
|
|
||||||
|
# this should raise some warnings !
|
||||||
|
# with the `check` subcommand
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
cmd.run()
|
||||||
|
warnings = self.get_logs(WARN)
|
||||||
|
self.assertEquals(len(warnings), 2)
|
||||||
|
|
||||||
|
# trying with a complete set of metadata
|
||||||
|
self.clear_logs()
|
||||||
|
dist, cmd = self.get_cmd()
|
||||||
|
cmd.ensure_finalized()
|
||||||
|
cmd.metadata_check = 0
|
||||||
|
cmd.run()
|
||||||
|
warnings = self.get_logs(WARN)
|
||||||
|
self.assertEquals(len(warnings), 0)
|
||||||
|
|
||||||
|
def test_check_metadata_deprecated(self):
|
||||||
|
# makes sure make_metadata is deprecated
|
||||||
|
dist, cmd = self.get_cmd()
|
||||||
|
with check_warnings() as w:
|
||||||
|
warnings.simplefilter("always")
|
||||||
|
cmd.check_metadata()
|
||||||
|
self.assertEquals(len(w.warnings), 1)
|
||||||
|
|
||||||
def test_show_formats(self):
|
def test_show_formats(self):
|
||||||
with captured_stdout() as stdout:
|
with captured_stdout() as stdout:
|
||||||
show_formats()
|
show_formats()
|
||||||
|
@ -247,7 +278,7 @@ class sdistTestCase(PyPIRCCommandTestCase):
|
||||||
|
|
||||||
|
|
||||||
def test_suite():
|
def test_suite():
|
||||||
return unittest.makeSuite(sdistTestCase)
|
return unittest.makeSuite(SDistTestCase)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main(defaultTest="test_suite")
|
unittest.main(defaultTest="test_suite")
|
||||||
|
|
|
@ -616,6 +616,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #6041: Now distutils `sdist` and `register` commands use `check` as a
|
||||||
|
subcommand.
|
||||||
|
|
||||||
- Issue #6022: a test file was created in the current working directory by
|
- Issue #6022: a test file was created in the current working directory by
|
||||||
test_get_outputs in Distutils.
|
test_get_outputs in Distutils.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue