d8cf42c7d40d640f902aa7e4b49b31ba3a94ac23
"""distutils.command.register
Implements the Distutils 'register' command (register with the repository).
# created 2002/10/21, Richard Jones
__revision__
= "$Id: register.py,v 1.7.4.1 2005/03/31 14:16:30 doerwalter Exp $"
import sys
, os
, string
, urllib2
, getpass
, urlparse
import StringIO
, ConfigParser
from distutils
.core
import Command
from distutils
.errors
import *
description
= ("register the distribution with the Python package index")
DEFAULT_REPOSITORY
= 'http://www.python.org/pypi'
"url of repository [default: %s]"%DEFAULT_REPOSITORY
),
('list-classifiers', None,
'list the valid Trove classifiers'),
'display full response text from server'),
boolean_options
= ['verify', 'show-response', 'list-classifiers']
def initialize_options(self
):
self
.list_classifiers
= 0
def finalize_options(self
):
if self
.repository
is None:
self
.repository
= self
.DEFAULT_REPOSITORY
elif self
.list_classifiers
:
def check_metadata(self
):
"""Ensure that all required elements of meta-data (name, version,
URL, (author and author_email) or (maintainer and
maintainer_email)) are supplied by the Distribution object; warn if
metadata
= self
.distribution
.metadata
for attr
in ('name', 'version', 'url'):
if not (hasattr(metadata
, attr
) and getattr(metadata
, attr
)):
self
.warn("missing required meta-data: " +
string
.join(missing
, ", "))
if not metadata
.author_email
:
self
.warn("missing meta-data: if 'author' supplied, " +
"'author_email' must be supplied too")
elif metadata
.maintainer
:
if not metadata
.maintainer_email
:
self
.warn("missing meta-data: if 'maintainer' supplied, " +
"'maintainer_email' must be supplied too")
self
.warn("missing meta-data: either (author and author_email) " +
"or (maintainer and maintainer_email) " +
''' Fetch the list of classifiers from the server.
response
= urllib2
.urlopen(self
.repository
+'?:action=list_classifiers')
def verify_metadata(self
):
''' Send the metadata to the package index server to be checked.
# send the info to the server and report the result
(code
, result
) = self
.post_to_server(self
.build_post_data('verify'))
print 'Server response (%s): %s'%(code
, result
)
''' Send the metadata to the package index server.
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
Otherwise, to figure who the user is, we offer the user three
2. register as a new user, or
3. set the password to a random string and email the user.
# see if we can short-cut and get the username/password from the
if os
.environ
.has_key('HOME'):
rc
= os
.path
.join(os
.environ
['HOME'], '.pypirc')
print 'Using PyPI login from %s'%rc
config
= ConfigParser
.ConfigParser()
username
= config
.get('server-login', 'username')
password
= config
.get('server-login', 'password')
# get the user's login info
choices
= '1 2 3 4'.split()
while choice
not in choices
:
print '''We need to know who you are, so please choose either:
1. use your existing login,
2. register as a new user,
3. have the server generate a new password for you (and email it to you), or
Your selection [default 1]: ''',
elif choice
not in choices
:
print 'Please choose one of the four options!'
# get the username and password
username
= raw_input('Username: ')
password
= getpass
.getpass('Password: ')
# set up the authentication
auth
= urllib2
.HTTPPasswordMgr()
host
= urlparse
.urlparse(self
.repository
)[1]
auth
.add_password('pypi', host
, username
, password
)
# send the info to the server and report the result
code
, result
= self
.post_to_server(self
.build_post_data('submit'),
print 'Server response (%s): %s'%(code
, result
)
# possibly save the login
if os
.environ
.has_key('HOME') and config
is None 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 '(the login will be stored in %s)'%rc
while choice
.lower() not in 'yn':
choice
= raw_input('Save your login (y/N)?')
if choice
.lower() == 'y':
f
.write('[server-login]\nusername:%s\npassword:%s\n'%(
data
= {':action': 'user'}
data
['name'] = data
['password'] = data
['email'] = ''
data
['name'] = raw_input('Username: ')
while data
['password'] != data
['confirm']:
while not data
['password']:
data
['password'] = getpass
.getpass('Password: ')
while not data
['confirm']:
data
['confirm'] = getpass
.getpass(' Confirm: ')
if data
['password'] != data
['confirm']:
print "Password and confirm don't match!"
data
['email'] = raw_input(' EMail: ')
code
, result
= self
.post_to_server(data
)
print 'Server response (%s): %s'%(code
, result
)
print 'You will receive an email shortly.'
print 'Follow the instructions in it to complete registration.'
data
= {':action': 'password_reset'}
data
['email'] = raw_input('Your email address: ')
code
, result
= self
.post_to_server(data
)
print 'Server response (%s): %s'%(code
, result
)
def build_post_data(self
, action
):
# figure the data to send - the metadata plus some additional
# information used by the package server
meta
= self
.distribution
.metadata
'metadata_version' : '1.0',
'version': meta
.get_version(),
'summary': meta
.get_description(),
'home_page': meta
.get_url(),
'author': meta
.get_contact(),
'author_email': meta
.get_contact_email(),
'license': meta
.get_licence(),
'description': meta
.get_long_description(),
'keywords': meta
.get_keywords(),
'platform': meta
.get_platforms(),
'classifiers': meta
.get_classifiers(),
'download_url': meta
.get_download_url(),
def post_to_server(self
, data
, auth
=None):
''' Post a query to the server, and return a string response.
# Build up the MIME payload for the urllib2 POST data
boundary
= '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
sep_boundary
= '\n--' + boundary
end_boundary
= sep_boundary
+ '--'
body
= StringIO
.StringIO()
for key
, value
in data
.items():
# handle multiple entries for the same name
if type(value
) != type([]):
value
= unicode(value
).encode("utf-8")
body
.write('\nContent-Disposition: form-data; name="%s"'%key
)
if value
and value
[-1] == '\r':
body
.write('\n') # write an extra newline (lurve Macs)
'Content-type': 'multipart/form-data; boundary=%s; charset=utf-8'%boundary
,
'Content-length': str(len(body
))
req
= urllib2
.Request(self
.repository
, body
, headers
)
# handle HTTP and include the Basic Auth handler
opener
= urllib2
.build_opener(
urllib2
.HTTPBasicAuthHandler(password_mgr
=auth
)
result
= opener
.open(req
)
except urllib2
.HTTPError
, e
:
except urllib2
.URLError
, e
:
print '-'*75, data
, '-'*75