PyXR

c:\python24\lib \ distutils \ command \ register.py



0001 """distutils.command.register
0002 
0003 Implements the Distutils 'register' command (register with the repository).
0004 """
0005 
0006 # created 2002/10/21, Richard Jones
0007 
0008 __revision__ = "$Id: register.py,v 1.7 2004/07/18 06:14:43 tim_one Exp $"
0009 
0010 import sys, os, string, urllib2, getpass, urlparse
0011 import StringIO, ConfigParser
0012 
0013 from distutils.core import Command
0014 from distutils.errors import *
0015 
0016 class register(Command):
0017 
0018     description = ("register the distribution with the Python package index")
0019 
0020     DEFAULT_REPOSITORY = 'http://www.python.org/pypi'
0021 
0022     user_options = [
0023         ('repository=', 'r',
0024          "url of repository [default: %s]"%DEFAULT_REPOSITORY),
0025         ('list-classifiers', None,
0026          'list the valid Trove classifiers'),
0027         ('show-response', None,
0028          'display full response text from server'),
0029         ]
0030     boolean_options = ['verify', 'show-response', 'list-classifiers']
0031 
0032     def initialize_options(self):
0033         self.repository = None
0034         self.show_response = 0
0035         self.list_classifiers = 0
0036 
0037     def finalize_options(self):
0038         if self.repository is None:
0039             self.repository = self.DEFAULT_REPOSITORY
0040 
0041     def run(self):
0042         self.check_metadata()
0043         if self.dry_run:
0044             self.verify_metadata()
0045         elif self.list_classifiers:
0046             self.classifiers()
0047         else:
0048             self.send_metadata()
0049 
0050     def check_metadata(self):
0051         """Ensure that all required elements of meta-data (name, version,
0052            URL, (author and author_email) or (maintainer and
0053            maintainer_email)) are supplied by the Distribution object; warn if
0054            any are missing.
0055         """
0056         metadata = self.distribution.metadata
0057 
0058         missing = []
0059         for attr in ('name', 'version', 'url'):
0060             if not (hasattr(metadata, attr) and getattr(metadata, attr)):
0061                 missing.append(attr)
0062 
0063         if missing:
0064             self.warn("missing required meta-data: " +
0065                       string.join(missing, ", "))
0066 
0067         if metadata.author:
0068             if not metadata.author_email:
0069                 self.warn("missing meta-data: if 'author' supplied, " +
0070                           "'author_email' must be supplied too")
0071         elif metadata.maintainer:
0072             if not metadata.maintainer_email:
0073                 self.warn("missing meta-data: if 'maintainer' supplied, " +
0074                           "'maintainer_email' must be supplied too")
0075         else:
0076             self.warn("missing meta-data: either (author and author_email) " +
0077                       "or (maintainer and maintainer_email) " +
0078                       "must be supplied")
0079 
0080     def classifiers(self):
0081         ''' Fetch the list of classifiers from the server.
0082         '''
0083         response = urllib2.urlopen(self.repository+'?:action=list_classifiers')
0084         print response.read()
0085 
0086     def verify_metadata(self):
0087         ''' Send the metadata to the package index server to be checked.
0088         '''
0089         # send the info to the server and report the result
0090         (code, result) = self.post_to_server(self.build_post_data('verify'))
0091         print 'Server response (%s): %s'%(code, result)
0092 
0093     def send_metadata(self):
0094         ''' Send the metadata to the package index server.
0095 
0096             Well, do the following:
0097             1. figure who the user is, and then
0098             2. send the data as a Basic auth'ed POST.
0099 
0100             First we try to read the username/password from $HOME/.pypirc,
0101             which is a ConfigParser-formatted file with a section
0102             [server-login] containing username and password entries (both
0103             in clear text). Eg:
0104 
0105                 [server-login]
0106                 username: fred
0107                 password: sekrit
0108 
0109             Otherwise, to figure who the user is, we offer the user three
0110             choices:
0111 
0112              1. use existing login,
0113              2. register as a new user, or
0114              3. set the password to a random string and email the user.
0115 
0116         '''
0117         choice = 'x'
0118         username = password = ''
0119 
0120         # see if we can short-cut and get the username/password from the
0121         # config
0122         config = None
0123         if os.environ.has_key('HOME'):
0124             rc = os.path.join(os.environ['HOME'], '.pypirc')
0125             if os.path.exists(rc):
0126                 print 'Using PyPI login from %s'%rc
0127                 config = ConfigParser.ConfigParser()
0128                 config.read(rc)
0129                 username = config.get('server-login', 'username')
0130                 password = config.get('server-login', 'password')
0131                 choice = '1'
0132 
0133         # get the user's login info
0134         choices = '1 2 3 4'.split()
0135         while choice not in choices:
0136             print '''We need to know who you are, so please choose either:
0137  1. use your existing login,
0138  2. register as a new user,
0139  3. have the server generate a new password for you (and email it to you), or
0140  4. quit
0141 Your selection [default 1]: ''',
0142             choice = raw_input()
0143             if not choice:
0144                 choice = '1'
0145             elif choice not in choices:
0146                 print 'Please choose one of the four options!'
0147 
0148         if choice == '1':
0149             # get the username and password
0150             while not username:
0151                 username = raw_input('Username: ')
0152             while not password:
0153                 password = getpass.getpass('Password: ')
0154 
0155             # set up the authentication
0156             auth = urllib2.HTTPPasswordMgr()
0157             host = urlparse.urlparse(self.repository)[1]
0158             auth.add_password('pypi', host, username, password)
0159 
0160             # send the info to the server and report the result
0161             code, result = self.post_to_server(self.build_post_data('submit'),
0162                 auth)
0163             print 'Server response (%s): %s'%(code, result)
0164 
0165             # possibly save the login
0166             if os.environ.has_key('HOME') and config is None and code == 200:
0167                 rc = os.path.join(os.environ['HOME'], '.pypirc')
0168                 print 'I can store your PyPI login so future submissions will be faster.'
0169                 print '(the login will be stored in %s)'%rc
0170                 choice = 'X'
0171                 while choice.lower() not in 'yn':
0172                     choice = raw_input('Save your login (y/N)?')
0173                     if not choice:
0174                         choice = 'n'
0175                 if choice.lower() == 'y':
0176                     f = open(rc, 'w')
0177                     f.write('[server-login]\nusername:%s\npassword:%s\n'%(
0178                         username, password))
0179                     f.close()
0180                     try:
0181                         os.chmod(rc, 0600)
0182                     except:
0183                         pass
0184         elif choice == '2':
0185             data = {':action': 'user'}
0186             data['name'] = data['password'] = data['email'] = ''
0187             data['confirm'] = None
0188             while not data['name']:
0189                 data['name'] = raw_input('Username: ')
0190             while data['password'] != data['confirm']:
0191                 while not data['password']:
0192                     data['password'] = getpass.getpass('Password: ')
0193                 while not data['confirm']:
0194                     data['confirm'] = getpass.getpass(' Confirm: ')
0195                 if data['password'] != data['confirm']:
0196                     data['password'] = ''
0197                     data['confirm'] = None
0198                     print "Password and confirm don't match!"
0199             while not data['email']:
0200                 data['email'] = raw_input('   EMail: ')
0201             code, result = self.post_to_server(data)
0202             if code != 200:
0203                 print 'Server response (%s): %s'%(code, result)
0204             else:
0205                 print 'You will receive an email shortly.'
0206                 print 'Follow the instructions in it to complete registration.'
0207         elif choice == '3':
0208             data = {':action': 'password_reset'}
0209             data['email'] = ''
0210             while not data['email']:
0211                 data['email'] = raw_input('Your email address: ')
0212             code, result = self.post_to_server(data)
0213             print 'Server response (%s): %s'%(code, result)
0214 
0215     def build_post_data(self, action):
0216         # figure the data to send - the metadata plus some additional
0217         # information used by the package server
0218         meta = self.distribution.metadata
0219         data = {
0220             ':action': action,
0221             'metadata_version' : '1.0',
0222             'name': meta.get_name(),
0223             'version': meta.get_version(),
0224             'summary': meta.get_description(),
0225             'home_page': meta.get_url(),
0226             'author': meta.get_contact(),
0227             'author_email': meta.get_contact_email(),
0228             'license': meta.get_licence(),
0229             'description': meta.get_long_description(),
0230             'keywords': meta.get_keywords(),
0231             'platform': meta.get_platforms(),
0232             'classifiers': meta.get_classifiers(),
0233             'download_url': meta.get_download_url(),
0234         }
0235         return data
0236 
0237     def post_to_server(self, data, auth=None):
0238         ''' Post a query to the server, and return a string response.
0239         '''
0240 
0241         # Build up the MIME payload for the urllib2 POST data
0242         boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
0243         sep_boundary = '\n--' + boundary
0244         end_boundary = sep_boundary + '--'
0245         body = StringIO.StringIO()
0246         for key, value in data.items():
0247             # handle multiple entries for the same name
0248             if type(value) != type([]):
0249                 value = [value]
0250             for value in value:
0251                 value = str(value)
0252                 body.write(sep_boundary)
0253                 body.write('\nContent-Disposition: form-data; name="%s"'%key)
0254                 body.write("\n\n")
0255                 body.write(value)
0256                 if value and value[-1] == '\r':
0257                     body.write('\n')  # write an extra newline (lurve Macs)
0258         body.write(end_boundary)
0259         body.write("\n")
0260         body = body.getvalue()
0261 
0262         # build the Request
0263         headers = {
0264             'Content-type': 'multipart/form-data; boundary=%s'%boundary,
0265             'Content-length': str(len(body))
0266         }
0267         req = urllib2.Request(self.repository, body, headers)
0268 
0269         # handle HTTP and include the Basic Auth handler
0270         opener = urllib2.build_opener(
0271             urllib2.HTTPBasicAuthHandler(password_mgr=auth)
0272         )
0273         data = ''
0274         try:
0275             result = opener.open(req)
0276         except urllib2.HTTPError, e:
0277             if self.show_response:
0278                 data = e.fp.read()
0279             result = e.code, e.msg
0280         except urllib2.URLError, e:
0281             result = 500, str(e)
0282         else:
0283             if self.show_response:
0284                 data = result.read()
0285             result = 200, 'OK'
0286         if self.show_response:
0287             print '-'*75, data, '-'*75
0288         return result
0289 

Generated by PyXR 0.9.4
SourceForge.net Logo