[Python-checkins] r63060 - in python/trunk: Doc/distutils/packageindex.rst Doc/distutils/uploading.rst Lib/distutils/command/register.py Lib/distutils/command/upload.py Lib/distutils/core.py Lib/distutils/dist.py Lib/distutils/tests/test_config.py Lib/distutils/tests/test_dist.py Lib/distutils/tests/test_upload.py Misc/ACKS Misc/NEWS

andrew.kuchling python-checkins at python.org
Sun May 11 16:00:01 CEST 2008


Author: andrew.kuchling
Date: Sun May 11 16:00:00 2008
New Revision: 63060

Log:
#1858: re-apply patch for this, adding the missing files

Added:
   python/trunk/Lib/distutils/tests/test_config.py
   python/trunk/Lib/distutils/tests/test_upload.py
Modified:
   python/trunk/Doc/distutils/packageindex.rst
   python/trunk/Doc/distutils/uploading.rst
   python/trunk/Lib/distutils/command/register.py
   python/trunk/Lib/distutils/command/upload.py
   python/trunk/Lib/distutils/core.py
   python/trunk/Lib/distutils/dist.py
   python/trunk/Lib/distutils/tests/test_dist.py
   python/trunk/Misc/ACKS
   python/trunk/Misc/NEWS

Modified: python/trunk/Doc/distutils/packageindex.rst
==============================================================================
--- python/trunk/Doc/distutils/packageindex.rst	(original)
+++ python/trunk/Doc/distutils/packageindex.rst	Sun May 11 16:00:00 2008
@@ -55,11 +55,40 @@
 
 The format of the :file:`.pypirc` file is as follows::
 
-   [server-login]
+   [distutils]
+   index-servers =
+     pypi
+
+   [pypi]
    repository: <repository-url>
    username: <username>
    password: <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: <repository-url>
+   username: <username>
+   password: <password>
+
+   [other]
+   repository: http://example.com/pypi
+   username: <username>
+   password: <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
 
+ 

Modified: python/trunk/Doc/distutils/uploading.rst
==============================================================================
--- python/trunk/Doc/distutils/uploading.rst	(original)
+++ python/trunk/Doc/distutils/uploading.rst	Sun May 11 16:00:00 2008
@@ -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).
 
-

Modified: python/trunk/Lib/distutils/command/register.py
==============================================================================
--- python/trunk/Lib/distutils/command/register.py	(original)
+++ python/trunk/Lib/distutils/command/register.py	Sun May 11 16:00:00 2008
@@ -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,6 +99,7 @@
         (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.
 
@@ -99,10 +109,14 @@
 
             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
 
@@ -114,21 +128,15 @@
              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

Modified: python/trunk/Lib/distutils/command/upload.py
==============================================================================
--- python/trunk/Lib/distutils/command/upload.py	(original)
+++ python/trunk/Lib/distutils/command/upload.py	Sun May 11 16:00:00 2008
@@ -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:

Modified: python/trunk/Lib/distutils/core.py
==============================================================================
--- python/trunk/Lib/distutils/core.py	(original)
+++ python/trunk/Lib/distutils/core.py	Sun May 11 16:00:00 2008
@@ -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

Modified: python/trunk/Lib/distutils/dist.py
==============================================================================
--- python/trunk/Lib/distutils/dist.py	(original)
+++ python/trunk/Lib/distutils/dist.py	Sun May 11 16:00:00 2008
@@ -343,10 +343,9 @@
             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"

Added: python/trunk/Lib/distutils/tests/test_config.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/distutils/tests/test_config.py	Sun May 11 16:00:00 2008
@@ -0,0 +1,105 @@
+"""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_suite():
+    return unittest.makeSuite(PyPIRCCommandTestCase)
+
+if __name__ == "__main__":
+    unittest.main(defaultTest="test_suite")

Modified: python/trunk/Lib/distutils/tests/test_dist.py
==============================================================================
--- python/trunk/Lib/distutils/tests/test_dist.py	(original)
+++ python/trunk/Lib/distutils/tests/test_dist.py	Sun May 11 16:00:00 2008
@@ -55,6 +55,7 @@
         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 @@
         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")

Added: python/trunk/Lib/distutils/tests/test_upload.py
==============================================================================
--- (empty file)
+++ python/trunk/Lib/distutils/tests/test_upload.py	Sun May 11 16:00:00 2008
@@ -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")

Modified: python/trunk/Misc/ACKS
==============================================================================
--- python/trunk/Misc/ACKS	(original)
+++ python/trunk/Misc/ACKS	Sun May 11 16:00:00 2008
@@ -758,3 +758,4 @@
 Uwe Zessin
 Amaury Forgeot d'Arc
 Peter Åstrand
+Tarek ZiadŽ

Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS	(original)
+++ python/trunk/Misc/NEWS	Sun May 11 16:00:00 2008
@@ -381,6 +381,11 @@
   platforms when x is too large to fit into an IEEE 754 float; previously
   it only raised OverflowError on non IEEE 754 platforms.
 
+- Issues #2166, #1741 and #1531505: now distutils deals with HOME
+  correctly under win32
+
+- #1858: 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


More information about the Python-checkins mailing list