diff options
author | Alexandre Vassalotti <alexandre@peadrop.com> | 2008-05-16 00:03:33 (GMT) |
---|---|---|
committer | Alexandre Vassalotti <alexandre@peadrop.com> | 2008-05-16 00:03:33 (GMT) |
commit | 5f8ced2b959f306b3a1747a1f3daa4274b8c78b8 (patch) | |
tree | 75172061d8b246659f822876d22a10f7bcebeb0b /Lib/distutils | |
parent | a79e33e039530e5ca62f5dc19981cf76f4dcf824 (diff) | |
download | cpython-5f8ced2b959f306b3a1747a1f3daa4274b8c78b8.zip cpython-5f8ced2b959f306b3a1747a1f3daa4274b8c78b8.tar.gz cpython-5f8ced2b959f306b3a1747a1f3daa4274b8c78b8.tar.bz2 |
Merged revisions 62998-63003,63005-63006,63009-63012,63014-63017,63019-63020,63022-63024,63026-63029,63031-63041,63043-63045,63047-63054,63056-63062 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r62998 | andrew.kuchling | 2008-05-10 15:51:55 -0400 (Sat, 10 May 2008) | 7 lines
#1858 from Tarek Ziade:
Allow multiple repositories in .pypirc; see http://wiki.python.org/moin/EnhancedPyPI
for discussion.
The patch is slightly revised from Tarek's last patch: I've simplified
the PyPIRCCommand.finalize_options() method to not look at sys.argv.
Tests still pass.
........
r63000 | alexandre.vassalotti | 2008-05-10 15:59:16 -0400 (Sat, 10 May 2008) | 5 lines
Cleaned up io._BytesIO.write().
I am amazed that the old code, for inserting null-bytes, actually
worked. Who wrote that thing? Oh, it is me... doh.
........
r63002 | brett.cannon | 2008-05-10 16:52:01 -0400 (Sat, 10 May 2008) | 2 lines
Revert r62998 as it broke the build (seems distutils.config is missing).
........
r63014 | andrew.kuchling | 2008-05-10 18:12:38 -0400 (Sat, 10 May 2008) | 1 line
#1858: add distutils.config module
........
r63027 | brett.cannon | 2008-05-10 21:09:32 -0400 (Sat, 10 May 2008) | 2 lines
Flesh out the 3.0 deprecation to suggest using the ctypes module.
........
r63028 | skip.montanaro | 2008-05-10 22:59:30 -0400 (Sat, 10 May 2008) | 4 lines
Copied two versions of the example from the interactive session. Delete
one.
........
r63037 | georg.brandl | 2008-05-11 03:02:17 -0400 (Sun, 11 May 2008) | 2 lines
reload() takes the module itself.
........
r63038 | alexandre.vassalotti | 2008-05-11 03:06:04 -0400 (Sun, 11 May 2008) | 4 lines
Added test framework for handling module renames.
Factored the import guard in test_py3kwarn.TestStdlibRemovals into
a context manager, namely test_support.CleanImport.
........
r63039 | georg.brandl | 2008-05-11 03:06:05 -0400 (Sun, 11 May 2008) | 2 lines
#2742: ``''`` is not converted to NULL in getaddrinfo.
........
r63040 | alexandre.vassalotti | 2008-05-11 03:08:12 -0400 (Sun, 11 May 2008) | 2 lines
Fixed typo in a comment of test_support.CleanImport.
........
r63041 | alexandre.vassalotti | 2008-05-11 03:10:25 -0400 (Sun, 11 May 2008) | 2 lines
Removed a dead line of code.
........
r63043 | georg.brandl | 2008-05-11 04:47:53 -0400 (Sun, 11 May 2008) | 2 lines
#2812: document property.getter/setter/deleter.
........
r63049 | georg.brandl | 2008-05-11 05:06:30 -0400 (Sun, 11 May 2008) | 2 lines
#1153769: document PEP 237 changes to string formatting.
........
r63050 | georg.brandl | 2008-05-11 05:11:40 -0400 (Sun, 11 May 2008) | 2 lines
#2809: elaborate str.split docstring a bit.
........
r63051 | georg.brandl | 2008-05-11 06:13:59 -0400 (Sun, 11 May 2008) | 2 lines
Fix typo.
........
r63052 | georg.brandl | 2008-05-11 06:33:27 -0400 (Sun, 11 May 2008) | 2 lines
#2709: clarification.
........
r63053 | georg.brandl | 2008-05-11 06:42:28 -0400 (Sun, 11 May 2008) | 2 lines
#2659: add ``break_on_hyphens`` to TextWrapper.
........
r63057 | georg.brandl | 2008-05-11 06:59:39 -0400 (Sun, 11 May 2008) | 2 lines
#2741: clarification of value range for address_family.
........
r63058 | georg.brandl | 2008-05-11 07:09:35 -0400 (Sun, 11 May 2008) | 2 lines
#2452: timeout is used for all blocking operations.
........
r63059 | andrew.kuchling | 2008-05-11 09:33:56 -0400 (Sun, 11 May 2008) | 2 lines
#1792: Improve performance of marshal.dumps() on large objects by increasing
the size of the buffer more quickly.
........
r63060 | andrew.kuchling | 2008-05-11 10:00:00 -0400 (Sun, 11 May 2008) | 1 line
#1858: re-apply patch for this, adding the missing files
........
r63061 | benjamin.peterson | 2008-05-11 10:13:25 -0400 (Sun, 11 May 2008) | 2 lines
Add the "until" command to pdb
........
r63062 | georg.brandl | 2008-05-11 10:17:13 -0400 (Sun, 11 May 2008) | 2 lines
Add some sentence endings.
........
Diffstat (limited to 'Lib/distutils')
-rw-r--r-- | Lib/distutils/command/register.py | 95 | ||||
-rw-r--r-- | Lib/distutils/command/upload.py | 41 | ||||
-rw-r--r-- | Lib/distutils/config.py | 4 | ||||
-rw-r--r-- | Lib/distutils/core.py | 1 | ||||
-rw-r--r-- | Lib/distutils/dist.py | 7 | ||||
-rw-r--r-- | Lib/distutils/tests/test_config.py | 103 | ||||
-rw-r--r-- | Lib/distutils/tests/test_dist.py | 46 | ||||
-rw-r--r-- | Lib/distutils/tests/test_upload.py | 34 |
8 files changed, 250 insertions, 81 deletions
diff --git a/Lib/distutils/command/register.py b/Lib/distutils/command/register.py index b6a36f5..89cb2d4 100644 --- a/Lib/distutils/command/register.py +++ b/Lib/distutils/command/register.py @@ -8,42 +8,34 @@ Implements the Distutils 'register' command (register with the repository). __revision__ = "$Id$" import os, string, urllib2, getpass, urlparse -import io, configparser +import io -from distutils.core import Command +from distutils.core import PyPIRCCommand from distutils.errors import * +from distutils import log def raw_input(prompt): sys.stdout.write(prompt) sys.stdout.flush() return sys.stdin.readline() -class register(Command): +class register(PyPIRCCommand): description = ("register the distribution with the Python package index") - - DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' - - user_options = [ - ('repository=', 'r', - "url of repository [default: %s]"%DEFAULT_REPOSITORY), + user_options = PyPIRCCommand.user_options + [ ('list-classifiers', None, 'list the valid Trove classifiers'), - ('show-response', None, - 'display full response text from server'), ] - boolean_options = ['verify', 'show-response', 'list-classifiers'] + boolean_options = PyPIRCCommand.boolean_options + [ + 'verify', 'list-classifiers'] def initialize_options(self): - self.repository = None - self.show_response = 0 + PyPIRCCommand.initialize_options(self) self.list_classifiers = 0 - def finalize_options(self): - if self.repository is None: - self.repository = self.DEFAULT_REPOSITORY - def run(self): + self.finalize_options() + self._set_config() self.check_metadata() if self.dry_run: self.verify_metadata() @@ -82,6 +74,23 @@ class register(Command): "or (maintainer and maintainer_email) " + "must be supplied") + def _set_config(self): + ''' Reads the configuration file and set attributes. + ''' + config = self._read_pypirc() + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] + self.has_config = True + else: + if self.repository not in ('pypi', self.DEFAULT_REPOSITORY): + raise ValueError('%s not found in .pypirc' % self.repository) + if self.repository == 'pypi': + self.repository = self.DEFAULT_REPOSITORY + self.has_config = False + def classifiers(self): ''' Fetch the list of classifiers from the server. ''' @@ -95,6 +104,7 @@ class register(Command): (code, result) = self.post_to_server(self.build_post_data('verify')) print('Server response (%s): %s'%(code, result)) + def send_metadata(self): ''' Send the metadata to the package index server. @@ -104,10 +114,14 @@ class register(Command): First we try to read the username/password from $HOME/.pypirc, which is a ConfigParser-formatted file with a section - [server-login] containing username and password entries (both + [distutils] containing username and password entries (both in clear text). Eg: - [server-login] + [distutils] + index-servers = + pypi + + [pypi] username: fred password: sekrit @@ -119,21 +133,15 @@ class register(Command): 3. set the password to a random string and email the user. ''' - choice = 'x' - username = password = '' - # see if we can short-cut and get the username/password from the # config - config = None - if 'HOME' in os.environ: - rc = os.path.join(os.environ['HOME'], '.pypirc') - if os.path.exists(rc): - print('Using PyPI login from %s'%rc) - config = ConfigParser.ConfigParser() - config.read(rc) - username = config.get('server-login', 'username') - password = config.get('server-login', 'password') - choice = '1' + if self.has_config: + choice = '1' + username = self.username + password = self.password + else: + choice = 'x' + username = password = '' # get the user's login info choices = '1 2 3 4'.split() @@ -160,32 +168,24 @@ Your selection [default 1]: ''', end=' ') # set up the authentication auth = urllib2.HTTPPasswordMgr() host = urlparse.urlparse(self.repository)[1] - auth.add_password('pypi', host, username, password) - + auth.add_password(self.realm, host, username, password) # send the info to the server and report the result code, result = self.post_to_server(self.build_post_data('submit'), auth) print('Server response (%s): %s'%(code, result)) # possibly save the login - if 'HOME' in os.environ and config is None and code == 200: - rc = os.path.join(os.environ['HOME'], '.pypirc') + if not self.has_config and code == 200: print('I can store your PyPI login so future submissions will be faster.') - print('(the login will be stored in %s)'%rc) + print('(the login will be stored in %s)' % self._get_rc_file()) choice = 'X' while choice.lower() not in 'yn': choice = raw_input('Save your login (y/N)?') if not choice: choice = 'n' if choice.lower() == 'y': - f = open(rc, 'w') - f.write('[server-login]\nusername:%s\npassword:%s\n'%( - username, password)) - f.close() - try: - os.chmod(rc, 0o600) - except: - pass + self._store_pypirc(username, password) + elif choice == '2': data = {':action': 'user'} data['name'] = data['password'] = data['email'] = '' @@ -248,7 +248,8 @@ Your selection [default 1]: ''', end=' ') def post_to_server(self, data, auth=None): ''' Post a query to the server, and return a string response. ''' - + self.announce('Registering %s to %s' % (data['name'], + self.repository), log.INFO) # Build up the MIME payload for the urllib2 POST data boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' sep_boundary = '\n--' + boundary diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py index 23999ae..603336c 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py @@ -3,7 +3,7 @@ Implements the Distutils 'upload' subcommand (upload package to PyPI).""" from distutils.errors import * -from distutils.core import Command +from distutils.core import PyPIRCCommand from distutils.spawn import spawn from distutils import log from hashlib import md5 @@ -15,53 +15,38 @@ import httplib import base64 import urlparse -class upload(Command): +class upload(PyPIRCCommand): description = "upload binary package to PyPI" - DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' - - user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server'), + user_options = PyPIRCCommand.user_options + [ ('sign', 's', 'sign files to upload using gpg'), ('identity=', 'i', 'GPG identity used to sign files'), ] - boolean_options = ['show-response', 'sign'] + + boolean_options = PyPIRCCommand.boolean_options + ['sign'] def initialize_options(self): + PyPIRCCommand.initialize_options(self) self.username = '' self.password = '' - self.repository = '' self.show_response = 0 self.sign = False self.identity = None def finalize_options(self): + PyPIRCCommand.finalize_options(self) if self.identity and not self.sign: raise DistutilsOptionError( "Must use --sign for --identity to have meaning" ) - if 'HOME' in os.environ: - rc = os.path.join(os.environ['HOME'], '.pypirc') - if os.path.exists(rc): - self.announce('Using PyPI login from %s' % rc) - config = ConfigParser.ConfigParser({ - 'username':'', - 'password':'', - 'repository':''}) - config.read(rc) - if not self.repository: - self.repository = config.get('server-login', 'repository') - if not self.username: - self.username = config.get('server-login', 'username') - if not self.password: - self.password = config.get('server-login', 'password') - if not self.repository: - self.repository = self.DEFAULT_REPOSITORY + config = self._read_pypirc() + if config != {}: + self.username = config['username'] + self.password = config['password'] + self.repository = config['repository'] + self.realm = config['realm'] def run(self): if not self.distribution.dist_files: diff --git a/Lib/distutils/config.py b/Lib/distutils/config.py index e9ba402..a625aec 100644 --- a/Lib/distutils/config.py +++ b/Lib/distutils/config.py @@ -49,7 +49,7 @@ class PyPIRCCommand(Command): finally: f.close() try: - os.chmod(rc, 0600) + os.chmod(rc, 0o600) except OSError: # should do something better here pass @@ -58,7 +58,7 @@ class PyPIRCCommand(Command): """Reads the .pypirc file.""" rc = self._get_rc_file() if os.path.exists(rc): - print 'Using PyPI login from %s' % rc + print('Using PyPI login from %s' % rc) repository = self.repository or self.DEFAULT_REPOSITORY realm = self.realm or self.DEFAULT_REALM diff --git a/Lib/distutils/core.py b/Lib/distutils/core.py index a4c5e18..6e48920 100644 --- a/Lib/distutils/core.py +++ b/Lib/distutils/core.py @@ -17,6 +17,7 @@ from distutils.util import grok_environment_error # Mainly import these so setup scripts can "from distutils.core import" them. from distutils.dist import Distribution from distutils.cmd import Command +from distutils.config import PyPIRCCommand from distutils.extension import Extension # This is a barebones help message generated displayed when the user diff --git a/Lib/distutils/dist.py b/Lib/distutils/dist.py index 847eb90..ddde909 100644 --- a/Lib/distutils/dist.py +++ b/Lib/distutils/dist.py @@ -334,10 +334,9 @@ Common commands: (see '--help-commands' for more) user_filename = "pydistutils.cfg" # And look for the user config file - if 'HOME' in os.environ: - user_file = os.path.join(os.environ.get('HOME'), user_filename) - if os.path.isfile(user_file): - files.append(user_file) + user_file = os.path.join(os.path.expanduser('~'), user_filename) + if os.path.isfile(user_file): + files.append(user_file) # All platforms support local setup.cfg local_file = "setup.cfg" diff --git a/Lib/distutils/tests/test_config.py b/Lib/distutils/tests/test_config.py new file mode 100644 index 0000000..016ba4c --- /dev/null +++ b/Lib/distutils/tests/test_config.py @@ -0,0 +1,103 @@ +"""Tests for distutils.pypirc.pypirc.""" +import sys +import os +import unittest + +from distutils.core import PyPIRCCommand +from distutils.core import Distribution + +from distutils.tests import support + +PYPIRC = """\ +[distutils] + +index-servers = + server1 + server2 + +[server1] +username:me +password:secret + +[server2] +username:meagain +password: secret +realm:acme +repository:http://another.pypi/ +""" + +PYPIRC_OLD = """\ +[server-login] +username:tarek +password:secret +""" + +class PyPIRCCommandTestCase(support.TempdirManager, unittest.TestCase): + + def setUp(self): + """Patches the environment.""" + if 'HOME' in os.environ: + self._old_home = os.environ['HOME'] + else: + self._old_home = None + curdir = os.path.dirname(__file__) + os.environ['HOME'] = curdir + self.rc = os.path.join(curdir, '.pypirc') + self.dist = Distribution() + + class command(PyPIRCCommand): + def __init__(self, dist): + PyPIRCCommand.__init__(self, dist) + def initialize_options(self): + pass + finalize_options = initialize_options + + self._cmd = command + + def tearDown(self): + """Removes the patch.""" + if self._old_home is None: + del os.environ['HOME'] + else: + os.environ['HOME'] = self._old_home + if os.path.exists(self.rc): + os.remove(self.rc) + + def test_server_registration(self): + # This test makes sure PyPIRCCommand knows how to: + # 1. handle several sections in .pypirc + # 2. handle the old format + + # new format + f = open(self.rc, 'w') + try: + f.write(PYPIRC) + finally: + f.close() + + cmd = self._cmd(self.dist) + config = cmd._read_pypirc() + + config = list(sorted(config.items())) + waited = [('password', 'secret'), ('realm', 'pypi'), + ('repository', 'http://pypi.python.org/pypi'), + ('server', 'server1'), ('username', 'me')] + self.assertEquals(config, waited) + + # old format + f = open(self.rc, 'w') + f.write(PYPIRC_OLD) + f.close() + + config = cmd._read_pypirc() + config = list(sorted(config.items())) + waited = [('password', 'secret'), ('realm', 'pypi'), + ('repository', 'http://pypi.python.org/pypi'), + ('server', 'server-login'), ('username', 'tarek')] + self.assertEquals(config, waited) + +def test_suite(): + return unittest.makeSuite(PyPIRCCommandTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/distutils/tests/test_dist.py b/Lib/distutils/tests/test_dist.py index 91acf45..81459ac 100644 --- a/Lib/distutils/tests/test_dist.py +++ b/Lib/distutils/tests/test_dist.py @@ -55,6 +55,7 @@ class DistributionTestCase(unittest.TestCase): self.assertEqual(d.get_command_packages(), ["distutils.command"]) def test_command_packages_cmdline(self): + from distutils.tests.test_dist import test_dist sys.argv.extend(["--command-packages", "foo.bar,distutils.tests", "test_dist", @@ -179,9 +180,54 @@ class MetadataTestCase(unittest.TestCase): dist.metadata.write_pkg_file(sio) return sio.getvalue() + def test_custom_pydistutils(self): + # fixes #2166 + # make sure pydistutils.cfg is found + old = {} + for env in ('HOME', 'HOMEPATH', 'HOMEDRIVE'): + value = os.environ.get(env) + old[env] = value + if value is not None: + del os.environ[env] + + if os.name == 'posix': + user_filename = ".pydistutils.cfg" + else: + user_filename = "pydistutils.cfg" + + curdir = os.path.dirname(__file__) + user_filename = os.path.join(curdir, user_filename) + f = open(user_filename, 'w') + f.write('.') + f.close() + + try: + dist = distutils.dist.Distribution() + + # linux-style + if sys.platform in ('linux', 'darwin'): + os.environ['HOME'] = curdir + files = dist.find_config_files() + self.assert_(user_filename in files) + + # win32-style + if sys.platform == 'win32': + # home drive should be found + os.environ['HOMEPATH'] = curdir + files = dist.find_config_files() + self.assert_(user_filename in files) + finally: + for key, value in old.items(): + if value is None: + continue + os.environ[key] = value + os.remove(user_filename) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DistributionTestCase)) suite.addTest(unittest.makeSuite(MetadataTestCase)) return suite + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py new file mode 100644 index 0000000..b05ab1f --- /dev/null +++ b/Lib/distutils/tests/test_upload.py @@ -0,0 +1,34 @@ +"""Tests for distutils.command.upload.""" +import sys +import os +import unittest + +from distutils.command.upload import upload +from distutils.core import Distribution + +from distutils.tests import support +from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase + +class uploadTestCase(PyPIRCCommandTestCase): + + def test_finalize_options(self): + + # new format + f = open(self.rc, 'w') + f.write(PYPIRC) + f.close() + + dist = Distribution() + cmd = upload(dist) + cmd.finalize_options() + for attr, waited in (('username', 'me'), ('password', 'secret'), + ('realm', 'pypi'), + ('repository', 'http://pypi.python.org/pypi')): + self.assertEquals(getattr(cmd, attr), waited) + + +def test_suite(): + return unittest.makeSuite(uploadTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") |