Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 61353) +++ Misc/NEWS (working copy) @@ -21,6 +21,11 @@ Library ------- +- Issues #2166, #1741 and #1531505: now distutils deals with HOME + correctly under win32 + +- distutils: added multiple server support in .pypirc + - Issue #1106316: pdb.post_mortem()'s parameter, "traceback", is now optional: it defaults to the traceback of the exception that is currently being handled (is mandatory to be in the middle of an exception, otherwise Index: Misc/ACKS =================================================================== --- Misc/ACKS (revision 61353) +++ Misc/ACKS (working copy) @@ -741,5 +741,6 @@ Milan Zamazal Artur Zaprzala Mike Zarnstorff +Tarek Ziadé Siebren van der Zee Uwe Zessin Index: Doc/distutils/uploading.rst =================================================================== --- Doc/distutils/uploading.rst (revision 61353) +++ Doc/distutils/uploading.rst (working copy) @@ -24,14 +24,20 @@ from the :file:`$HOME/.pypirc` file (see section :ref:`pypirc` for more on this file). +You can specify another PyPI server with the :option:`--repository=*url*` option:: + + python setup.py sdist bdist_wininst upload -r http://example.com/pypi + +See section :ref:`pypirc` for more on defining several servers. + You can use the :option:`--sign` option to tell :command:`upload` to sign each uploaded file using GPG (GNU Privacy Guard). The :program:`gpg` program must be available for execution on the system :envvar:`PATH`. You can also specify which key to use for signing using the :option:`--identity=*name*` option. -Other :command:`upload` options include :option:`--repository=*url*` (which -lets you override the repository setting from :file:`$HOME/.pypirc`), and +Other :command:`upload` options include :option:`--repository=*url*` +or :option:`--repository=*section*` where `url` is the url of the server +and `section` the name of the section in :file:`$HOME/.pypirc`, and :option:`--show-response` (which displays the full response text from the PyPI server for help in debugging upload problems). - Index: Doc/distutils/packageindex.rst =================================================================== --- Doc/distutils/packageindex.rst (revision 61353) +++ Doc/distutils/packageindex.rst (working copy) @@ -55,11 +55,40 @@ The format of the :file:`.pypirc` file is as follows:: - [server-login] + [distutils] + index-servers = + pypi + + [pypi] repository: username: password: *repository* can be omitted and defaults to ``http://www.python.org/pypi``. +If you want to define another server a new section can be created:: + [distutils] + index-servers = + pypi + other + + [pypi] + repository: + username: + password: + + [other] + repository: http://example.com/pypi + username: + password: + +The command can then be called with the -r option:: + + python setup.py register -r http://example.com/pypi + +Or even with the section name:: + + python setup.py register -r other + + Index: Lib/distutils/core.py =================================================================== --- Lib/distutils/core.py (revision 61353) +++ Lib/distutils/core.py (working copy) @@ -20,6 +20,7 @@ # 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 Index: Lib/distutils/config.py =================================================================== --- Lib/distutils/config.py (revision 0) +++ Lib/distutils/config.py (revision 0) @@ -0,0 +1,142 @@ +"""distutils.pypirc + +Provides the PyPIRCCommand class, the base class for the command classes +that uses .pypirc in the distutils.command package. +""" +import os +import sys +from ConfigParser import ConfigParser + +from distutils.core import Command + +DEFAULT_PYPIRC = """\ +[pypirc] +servers = + pypi + +[pypi] +username:%s +password:%s +""" + +class PyPIRCCommand(Command): + """Base command that knows how to handle the .pypirc file + """ + DEFAULT_REPOSITORY = 'http://pypi.python.org/pypi' + DEFAULT_REALM = 'pypi' + repository = None + realm = None + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % \ + DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server')] + + boolean_options = ['show-response'] + + def _get_rc_file(self): + """Returns rc file path.""" + return os.path.join(os.path.expanduser('~'), '.pypirc') + + def _store_pypirc(self, username, password): + """Creates a default .pypirc file.""" + rc = self._get_rc_file() + f = open(rc, 'w') + try: + f.write(DEFAULT_PYPIRC % (username, password)) + finally: + f.close() + try: + os.chmod(rc, 0600) + except OSError: + # should do something better here + pass + + def _read_pypirc(self): + """Reads the .pypirc file.""" + rc = self._get_rc_file() + if os.path.exists(rc): + print 'Using PyPI login from %s' % rc + repository = self.repository or self.DEFAULT_REPOSITORY + realm = self.realm or self.DEFAULT_REALM + + config = ConfigParser() + config.read(rc) + sections = config.sections() + if 'distutils' in sections: + # let's get the list of servers + index_servers = config.get('distutils', 'index-servers') + _servers = [server.strip() for server in + index_servers.split('\n') + if server.strip() != ''] + if _servers == []: + # nothing set, let's try to get the defaut pypi + if 'pypi' in sections: + _servers = ['pypi'] + else: + # the file is not properly defined, returning + # an empty dict + return {} + for server in _servers: + current = {'server': server} + current['username'] = config.get(server, 'username') + current['password'] = config.get(server, 'password') + + # optional params + for key, default in (('repository', + self.DEFAULT_REPOSITORY), + ('realm', self.DEFAULT_REALM)): + if config.has_option(server, key): + current[key] = config.get(server, key) + else: + current[key] = default + if (current['server'] == repository or + current['repository'] == repository): + return current + elif 'server-login' in sections: + # old format + server = 'server-login' + if config.has_option(server, 'repository'): + repository = config.get(server, 'repository') + else: + repository = self.DEFAULT_REPOSITORY + return {'username': config.get(server, 'username'), + 'password': config.get(server, 'password'), + 'repository': repository, + 'server': server, + 'realm': self.DEFAULT_REALM} + + return {} + + def initialize_options(self): + """Initialize options.""" + self.repository = None + self.realm = None + self.show_response = 0 + + def finalize_options(self): + """Finalizes options.""" + # let's get --repository and --show_response + # they can be anywhere in the arg list + # XXX this is a bit hacky and was made + # to avoid having the -r option twice + # in the command line when register and upload + # are used. We should consider adding a global_options + # at command level to allow this. + if '-r' in sys.argv or '--repository' in sys.argv: + if '-r' in sys.argv: + pos = sys.argv.index('-r') + 1 + else: + pos = sys.argv.index('--repository') + 1 + if len(sys.argv) > pos: + self.repository = sys.argv[pos] + + self.show_response = '--show-response' in sys.argv + + if self.repository is None: + self.repository = self.DEFAULT_REPOSITORY + if self.realm is None: + self.realm = self.DEFAULT_REALM + Property changes on: Lib/distutils/config.py ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: Lib/distutils/tests/test_dist.py =================================================================== --- Lib/distutils/tests/test_dist.py (revision 61353) +++ Lib/distutils/tests/test_dist.py (working copy) @@ -179,7 +179,49 @@ 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)) Index: Lib/distutils/tests/test_register.py =================================================================== --- Lib/distutils/tests/test_register.py (revision 0) +++ Lib/distutils/tests/test_register.py (revision 0) @@ -0,0 +1,188 @@ +"""Tests for distutils.command.register.""" +import sys +import os +import unittest +from cStringIO import StringIO + +from distutils.command.register import register +from distutils.core import Distribution + +from distutils.tests import support +from distutils.tests.test_config import PYPIRC, PyPIRCCommandTestCase + +import urllib2 + +data_sent = {} + +class Opener(object): + def open(self, req, data=None, timeout=None): + if isinstance(req, str): + return StringIO('OK') + else: + data_sent[req.get_host()] = (req.headers, req.data) + +def build_opener(*auth): + return Opener() + +urllib2.build_opener = build_opener + +class registerTestCase(PyPIRCCommandTestCase): + + def setUp(self): + PyPIRCCommandTestCase.setUp(self) + f = open(self.rc, 'w') + f.write(PYPIRC) + f.close() + self.dist = Distribution() + self.cmd = register(self.dist) + + def _run_send_metadata(self): + self.cmd.list_classifiers = 0 + self.cmd.dry_run = 0 + self.cmd.run() + + def test_mregister(self): + self._run_send_metadata() + length = data_sent['pypi.python.org'][0]['Content-length'] + self.assertEquals(length, '1392') + + def test_get_non_default(self): + # tests if we send data to the non default + self.cmd.repository = 'server2' + self._run_send_metadata() + self.assert_('another.pypi' in data_sent) + + # tests if we send data to the non default + import urllib2 + old = urllib2.HTTPPasswordMgr + class _HTTPPasswordMgr: + def add_password(self, realm, *args): + urllib2._realm = realm + urllib2.HTTPPasswordMgr = _HTTPPasswordMgr + + self.cmd.repository = 'server2' + self._run_send_metadata() + self.assert_('another.pypi' in data_sent) + self.assertEquals(urllib2._realm, 'acme') + urllib2.HTTPPasswordMgr = old + delattr(urllib2, '_realm') + + def test_not_existing(self): + # making sure we get an explicit message when the server + # does not exists in the .pypirc file + self.cmd.repository = 'server128' + self.assertRaises(ValueError, self._run_send_metadata) + + def test_creating_pypirc(self): + # making sure we create a pypirc + os.remove(self.cmd._get_rc_file()) + + self.cmd.repository = 'pypi' + + # patching things to avoid interaction + def _raw_input(msg=''): + if msg == 'Save your login (y/N)?': + return 'y' + return '1' + import getpass + getpass.getpass = _raw_input + func_globs = self.cmd.send_metadata.im_func.func_globals + func_globs['raw_input'] = _raw_input + + # calling the register + self._run_send_metadata() + + # now checking the created file + content = open(self.cmd._get_rc_file()).read() + content = content.replace(' ', '') + wanted = """\ + [pypirc] + servers = + pypi + + [pypi] + username:1 + password:1""".strip() + + self.assertEquals(content.strip(), wanted.replace(' ', '')) + + def test_register_option(self): + # make sure the command gets the --show-response + # option and the --repository option + # no matter where they are located in the command + # line otherwise some sequence will not work + # and the --list-classifiers interacts with it nicely + old_args = sys.argv + try: + # 1. --repository + sys.argv = ['testing', 'register', 'sdist', 'upload', '-r', + 'server2'] + self.cmd.finalize_options() + self.assertEquals(self.cmd.repository, 'server2') + self.assertEquals(self.cmd.show_response, 0) + + # 2. --repository + --show-response + sys.argv = ['testing', 'register', 'sdist', 'upload', '-r', + 'server2', '--show-response'] + self.dist.command_options = {} + self.dist.parse_command_line() + self.assertEquals(self.dist.commands, + ['register', 'sdist', 'upload'] ) + items = sorted(self.dist.command_options['upload'].items()) + self.assertEquals(list(items), [('repository', + ('command line', 'server2')), + ('show_response', + ('command line', 1))]) + + self.cmd.finalize_options() + self.assertEquals(self.cmd.repository, 'server2') + self.assertEquals(self.cmd.show_response, 1) + self.assertEquals(self.cmd.list_classifiers, 0) + + # 3. --repository + --list-classifiers + sys.argv = ['testing', 'register', '--list-classifiers'] + self.dist.command_options = {} + self.dist.parse_command_line() + self.assertEquals(self.dist.commands, ['register']) + self.assertEquals(self.dist.command_options['register'], + {'list_classifiers': ('command line', 1)}) + self.cmd.finalize_options() + self.assertEquals(self.cmd.repository, 'server2') + + # 4. --repository + --list-classifiers + sys.argv = ['testing', 'register', '--list-classifiers', + 'sdist', 'upload', '-r', 'server2'] + self.dist.command_options = {} + self.dist.parse_command_line() + + self.assertEquals(self.dist.commands, + ['register', 'sdist', 'upload']) + self.assertEquals(self.dist.command_options['register'], + {'list_classifiers': ('command line', 1)}) + + self.assertEquals(self.dist.command_options['upload'], + {'repository': ('command line', 'server2')}) + + self.cmd.finalize_options() + self.assertEquals(self.cmd.repository, 'server2') + + finally: + sys.argv = old_args + + def test_contracted_repository(self): + # make sure the repository url is extracted from the .pypirc file + # when it is given in the command line + self.cmd.list_classifiers = 1 + self.cmd.repository = 'server2' + self.cmd.run() + self.cmd.list_classifiers = 0 + self.cmd.dry_run = 1 + self.cmd.run() + + +def test_suite(): + return unittest.makeSuite(registerTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") + Property changes on: Lib/distutils/tests/test_register.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/distutils/tests/test_upload.py =================================================================== --- Lib/distutils/tests/test_upload.py (revision 0) +++ Lib/distutils/tests/test_upload.py (revision 0) @@ -0,0 +1,35 @@ +"""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") + Property changes on: Lib/distutils/tests/test_upload.py ___________________________________________________________________ Name: svn:eol-style + native Index: Lib/distutils/tests/test_config.py =================================================================== --- Lib/distutils/tests/test_config.py (revision 0) +++ Lib/distutils/tests/test_config.py (revision 0) @@ -0,0 +1,116 @@ +"""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 os.environ.has_key('HOME'): + 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 = config.items() + config.sort() + 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 = config.items() + config.sort() + waited = [('password', 'secret'), ('realm', 'pypi'), + ('repository', 'http://pypi.python.org/pypi'), + ('server', 'server-login'), ('username', 'tarek')] + self.assertEquals(config, waited) + + def test_repository_in_args(self): + # make sure the -r option is always caught + + sys.argv.extend(['-r', 'toto']) + try: + cmd = PyPIRCCommand(self.dist) + cmd.finalize_options() + self.assertEquals(cmd.repository, 'toto') + finally: + sys.argv = sys.argv[:-2] + +def test_suite(): + return unittest.makeSuite(PyPIRCCommandTestCase) + +if __name__ == "__main__": + unittest.main(defaultTest="test_suite") Property changes on: Lib/distutils/tests/test_config.py ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: Lib/distutils/command/register.py =================================================================== --- Lib/distutils/command/register.py (revision 61353) +++ Lib/distutils/command/register.py (working copy) @@ -8,37 +8,29 @@ __revision__ = "$Id$" import os, string, urllib2, getpass, urlparse -import StringIO, ConfigParser +import StringIO -from distutils.core import Command +from distutils.core import PyPIRCCommand from distutils.errors import * +from distutils import log -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() @@ -77,6 +69,23 @@ "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. ''' @@ -90,45 +99,44 @@ (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. Well, do the following: 1. figure who the user is, and then 2. send the data as a Basic auth'ed POST. - + 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 Otherwise, to figure who the user is, we offer the user three choices: - + 1. use existing login, 2. register as a new user, or 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() @@ -155,32 +163,24 @@ # 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) + 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, 0600) - except: - pass + self._store_pypirc(username, password) + elif choice == '2': data = {':action': 'user'} data['name'] = data['password'] = data['email'] = '' @@ -243,7 +243,8 @@ 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 Index: Lib/distutils/command/upload.py =================================================================== --- Lib/distutils/command/upload.py (revision 61353) +++ Lib/distutils/command/upload.py (working copy) @@ -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 @@ -16,53 +16,38 @@ import urlparse import cStringIO as StringIO -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: Index: Lib/distutils/dist.py =================================================================== --- Lib/distutils/dist.py (revision 61353) +++ Lib/distutils/dist.py (working copy) @@ -343,11 +343,10 @@ 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" if os.path.isfile(local_file):