Commit f71e81f1 authored by Alexandre Vassalotti's avatar Alexandre Vassalotti

Merged revisions...

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.
........
parent 67495c27
...@@ -8,42 +8,34 @@ Implements the Distutils 'register' command (register with the repository). ...@@ -8,42 +8,34 @@ Implements the Distutils 'register' command (register with the repository).
__revision__ = "$Id$" __revision__ = "$Id$"
import os, string, urllib2, getpass, urlparse 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.errors import *
from distutils import log
def raw_input(prompt): def raw_input(prompt):
sys.stdout.write(prompt) sys.stdout.write(prompt)
sys.stdout.flush() sys.stdout.flush()
return sys.stdin.readline() return sys.stdin.readline()
class register(Command): class register(PyPIRCCommand):
description = ("register the distribution with the Python package index") description = ("register the distribution with the Python package index")
user_options = PyPIRCCommand.user_options + [
DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi'
user_options = [
('repository=', 'r',
"url of repository [default: %s]"%DEFAULT_REPOSITORY),
('list-classifiers', None, ('list-classifiers', None,
'list the valid Trove classifiers'), '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): def initialize_options(self):
self.repository = None PyPIRCCommand.initialize_options(self)
self.show_response = 0
self.list_classifiers = 0 self.list_classifiers = 0
def finalize_options(self):
if self.repository is None:
self.repository = self.DEFAULT_REPOSITORY
def run(self): def run(self):
self.finalize_options()
self._set_config()
self.check_metadata() self.check_metadata()
if self.dry_run: if self.dry_run:
self.verify_metadata() self.verify_metadata()
...@@ -82,6 +74,23 @@ class register(Command): ...@@ -82,6 +74,23 @@ class register(Command):
"or (maintainer and maintainer_email) " + "or (maintainer and maintainer_email) " +
"must be supplied") "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): def classifiers(self):
''' Fetch the list of classifiers from the server. ''' Fetch the list of classifiers from the server.
''' '''
...@@ -95,6 +104,7 @@ class register(Command): ...@@ -95,6 +104,7 @@ class register(Command):
(code, result) = self.post_to_server(self.build_post_data('verify')) (code, result) = self.post_to_server(self.build_post_data('verify'))
print('Server response (%s): %s'%(code, result)) print('Server response (%s): %s'%(code, result))
def send_metadata(self): def send_metadata(self):
''' Send the metadata to the package index server. ''' Send the metadata to the package index server.
...@@ -104,10 +114,14 @@ class register(Command): ...@@ -104,10 +114,14 @@ class register(Command):
First we try to read the username/password from $HOME/.pypirc, First we try to read the username/password from $HOME/.pypirc,
which is a ConfigParser-formatted file with a section 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: in clear text). Eg:
[server-login] [distutils]
index-servers =
pypi
[pypi]
username: fred username: fred
password: sekrit password: sekrit
...@@ -119,21 +133,15 @@ class register(Command): ...@@ -119,21 +133,15 @@ class register(Command):
3. set the password to a random string and email the user. 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 # see if we can short-cut and get the username/password from the
# config # config
config = None if self.has_config:
if 'HOME' in os.environ: choice = '1'
rc = os.path.join(os.environ['HOME'], '.pypirc') username = self.username
if os.path.exists(rc): password = self.password
print('Using PyPI login from %s'%rc) else:
config = ConfigParser.ConfigParser() choice = 'x'
config.read(rc) username = password = ''
username = config.get('server-login', 'username')
password = config.get('server-login', 'password')
choice = '1'
# get the user's login info # get the user's login info
choices = '1 2 3 4'.split() choices = '1 2 3 4'.split()
...@@ -160,32 +168,24 @@ Your selection [default 1]: ''', end=' ') ...@@ -160,32 +168,24 @@ Your selection [default 1]: ''', end=' ')
# set up the authentication # set up the authentication
auth = urllib2.HTTPPasswordMgr() auth = urllib2.HTTPPasswordMgr()
host = urlparse.urlparse(self.repository)[1] 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 # send the info to the server and report the result
code, result = self.post_to_server(self.build_post_data('submit'), code, result = self.post_to_server(self.build_post_data('submit'),
auth) auth)
print('Server response (%s): %s'%(code, result)) print('Server response (%s): %s'%(code, result))
# possibly save the login # possibly save the login
if 'HOME' in os.environ and config is None and code == 200: if not self.has_config and code == 200:
rc = os.path.join(os.environ['HOME'], '.pypirc')
print('I can store your PyPI login so future submissions will be faster.') 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' choice = 'X'
while choice.lower() not in 'yn': while choice.lower() not in 'yn':
choice = raw_input('Save your login (y/N)?') choice = raw_input('Save your login (y/N)?')
if not choice: if not choice:
choice = 'n' choice = 'n'
if choice.lower() == 'y': if choice.lower() == 'y':
f = open(rc, 'w') self._store_pypirc(username, password)
f.write('[server-login]\nusername:%s\npassword:%s\n'%(
username, password))
f.close()
try:
os.chmod(rc, 0o600)
except:
pass
elif choice == '2': elif choice == '2':
data = {':action': 'user'} data = {':action': 'user'}
data['name'] = data['password'] = data['email'] = '' data['name'] = data['password'] = data['email'] = ''
...@@ -248,7 +248,8 @@ Your selection [default 1]: ''', end=' ') ...@@ -248,7 +248,8 @@ Your selection [default 1]: ''', end=' ')
def post_to_server(self, data, auth=None): def post_to_server(self, data, auth=None):
''' Post a query to the server, and return a string response. ''' 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 # Build up the MIME payload for the urllib2 POST data
boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary = '\n--' + boundary sep_boundary = '\n--' + boundary
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
Implements the Distutils 'upload' subcommand (upload package to PyPI).""" Implements the Distutils 'upload' subcommand (upload package to PyPI)."""
from distutils.errors import * from distutils.errors import *
from distutils.core import Command from distutils.core import PyPIRCCommand
from distutils.spawn import spawn from distutils.spawn import spawn
from distutils import log from distutils import log
from hashlib import md5 from hashlib import md5
...@@ -15,53 +15,38 @@ import httplib ...@@ -15,53 +15,38 @@ import httplib
import base64 import base64
import urlparse import urlparse
class upload(Command): class upload(PyPIRCCommand):
description = "upload binary package to PyPI" description = "upload binary package to PyPI"
DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' user_options = PyPIRCCommand.user_options + [
user_options = [
('repository=', 'r',
"url of repository [default: %s]" % DEFAULT_REPOSITORY),
('show-response', None,
'display full response text from server'),
('sign', 's', ('sign', 's',
'sign files to upload using gpg'), 'sign files to upload using gpg'),
('identity=', 'i', 'GPG identity used to sign files'), ('identity=', 'i', 'GPG identity used to sign files'),
] ]
boolean_options = ['show-response', 'sign']
boolean_options = PyPIRCCommand.boolean_options + ['sign']
def initialize_options(self): def initialize_options(self):
PyPIRCCommand.initialize_options(self)
self.username = '' self.username = ''
self.password = '' self.password = ''
self.repository = ''
self.show_response = 0 self.show_response = 0
self.sign = False self.sign = False
self.identity = None self.identity = None
def finalize_options(self): def finalize_options(self):
PyPIRCCommand.finalize_options(self)
if self.identity and not self.sign: if self.identity and not self.sign:
raise DistutilsOptionError( raise DistutilsOptionError(
"Must use --sign for --identity to have meaning" "Must use --sign for --identity to have meaning"
) )
if 'HOME' in os.environ: config = self._read_pypirc()
rc = os.path.join(os.environ['HOME'], '.pypirc') if config != {}:
if os.path.exists(rc): self.username = config['username']
self.announce('Using PyPI login from %s' % rc) self.password = config['password']
config = ConfigParser.ConfigParser({ self.repository = config['repository']
'username':'', self.realm = config['realm']
'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
def run(self): def run(self):
if not self.distribution.dist_files: if not self.distribution.dist_files:
......
...@@ -49,7 +49,7 @@ class PyPIRCCommand(Command): ...@@ -49,7 +49,7 @@ class PyPIRCCommand(Command):
finally: finally:
f.close() f.close()
try: try:
os.chmod(rc, 0600) os.chmod(rc, 0o600)
except OSError: except OSError:
# should do something better here # should do something better here
pass pass
...@@ -58,7 +58,7 @@ class PyPIRCCommand(Command): ...@@ -58,7 +58,7 @@ class PyPIRCCommand(Command):
"""Reads the .pypirc file.""" """Reads the .pypirc file."""
rc = self._get_rc_file() rc = self._get_rc_file()
if os.path.exists(rc): 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 repository = self.repository or self.DEFAULT_REPOSITORY
realm = self.realm or self.DEFAULT_REALM realm = self.realm or self.DEFAULT_REALM
......
...@@ -17,6 +17,7 @@ from distutils.util import grok_environment_error ...@@ -17,6 +17,7 @@ from distutils.util import grok_environment_error
# Mainly import these so setup scripts can "from distutils.core import" them. # Mainly import these so setup scripts can "from distutils.core import" them.
from distutils.dist import Distribution from distutils.dist import Distribution
from distutils.cmd import Command from distutils.cmd import Command
from distutils.config import PyPIRCCommand
from distutils.extension import Extension from distutils.extension import Extension
# This is a barebones help message generated displayed when the user # This is a barebones help message generated displayed when the user
......
...@@ -334,10 +334,9 @@ Common commands: (see '--help-commands' for more) ...@@ -334,10 +334,9 @@ Common commands: (see '--help-commands' for more)
user_filename = "pydistutils.cfg" user_filename = "pydistutils.cfg"
# And look for the user config file # And look for the user config file
if 'HOME' in os.environ: user_file = os.path.join(os.path.expanduser('~'), user_filename)
user_file = os.path.join(os.environ.get('HOME'), user_filename) if os.path.isfile(user_file):
if os.path.isfile(user_file): files.append(user_file)
files.append(user_file)
# All platforms support local setup.cfg # All platforms support local setup.cfg
local_file = "setup.cfg" local_file = "setup.cfg"
......
"""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")
...@@ -55,6 +55,7 @@ class DistributionTestCase(unittest.TestCase): ...@@ -55,6 +55,7 @@ class DistributionTestCase(unittest.TestCase):
self.assertEqual(d.get_command_packages(), ["distutils.command"]) self.assertEqual(d.get_command_packages(), ["distutils.command"])
def test_command_packages_cmdline(self): def test_command_packages_cmdline(self):
from distutils.tests.test_dist import test_dist
sys.argv.extend(["--command-packages", sys.argv.extend(["--command-packages",
"foo.bar,distutils.tests", "foo.bar,distutils.tests",
"test_dist", "test_dist",
...@@ -179,9 +180,54 @@ class MetadataTestCase(unittest.TestCase): ...@@ -179,9 +180,54 @@ class MetadataTestCase(unittest.TestCase):
dist.metadata.write_pkg_file(sio) dist.metadata.write_pkg_file(sio)
return sio.getvalue() 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(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(DistributionTestCase)) suite.addTest(unittest.makeSuite(DistributionTestCase))
suite.addTest(unittest.makeSuite(MetadataTestCase)) suite.addTest(unittest.makeSuite(MetadataTestCase))
return suite return suite
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")
"""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")
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment