summaryrefslogtreecommitdiff
path: root/setuptools/package_index.py
diff options
context:
space:
mode:
Diffstat (limited to 'setuptools/package_index.py')
-rwxr-xr-xsetuptools/package_index.py73
1 files changed, 70 insertions, 3 deletions
diff --git a/setuptools/package_index.py b/setuptools/package_index.py
index 94873620..4a3f49c7 100755
--- a/setuptools/package_index.py
+++ b/setuptools/package_index.py
@@ -17,7 +17,8 @@ from distutils.errors import DistutilsError
from setuptools.compat import (urllib2, httplib, StringIO, HTTPError,
urlparse, urlunparse, unquote, splituser,
url2pathname, name2codepoint,
- unichr, urljoin, urlsplit, urlunsplit)
+ unichr, urljoin, urlsplit, urlunsplit,
+ ConfigParser)
from setuptools.compat import filterfalse
from fnmatch import translate
from setuptools.py24compat import hashlib
@@ -907,8 +908,13 @@ def _encode_auth(auth):
"""
A function compatible with Python 2.3-3.3 that will encode
auth from a URL suitable for an HTTP header.
- >>> _encode_auth('username%3Apassword')
- u'dXNlcm5hbWU6cGFzc3dvcmQ='
+ >>> str(_encode_auth('username%3Apassword'))
+ 'dXNlcm5hbWU6cGFzc3dvcmQ='
+
+ Long auth strings should not cause a newline to be inserted.
+ >>> long_auth = 'username:' + 'password'*10
+ >>> chr(10) in str(_encode_auth(long_auth))
+ False
"""
auth_s = unquote(auth)
# convert to bytes
@@ -920,6 +926,60 @@ def _encode_auth(auth):
# strip the trailing carriage return
return encoded.replace('\n','')
+class Credential(object):
+ """
+ A username/password pair. Use like a namedtuple.
+ """
+ def __init__(self, username, password):
+ self.username = username
+ self.password = password
+
+ def __iter__(self):
+ yield self.username
+ yield self.password
+
+ def __str__(self):
+ return '%(username)s:%(password)s' % vars(self)
+
+class PyPIConfig(ConfigParser.ConfigParser):
+
+ def __init__(self):
+ """
+ Load from ~/.pypirc
+ """
+ defaults = dict.fromkeys(['username', 'password', 'repository'], '')
+ ConfigParser.ConfigParser.__init__(self, defaults)
+
+ rc = os.path.join(os.path.expanduser('~'), '.pypirc')
+ if os.path.exists(rc):
+ self.read(rc)
+
+ @property
+ def creds_by_repository(self):
+ sections_with_repositories = [
+ section for section in self.sections()
+ if self.get(section, 'repository').strip()
+ ]
+
+ return dict(map(self._get_repo_cred, sections_with_repositories))
+
+ def _get_repo_cred(self, section):
+ repo = self.get(section, 'repository').strip()
+ return repo, Credential(
+ self.get(section, 'username').strip(),
+ self.get(section, 'password').strip(),
+ )
+
+ def find_credential(self, url):
+ """
+ If the URL indicated appears to be a repository defined in this
+ config, return the credential for that repository.
+ """
+ for repository, cred in self.creds_by_repository.items():
+ if url.startswith(repository):
+ return cred
+
+
def open_with_auth(url, opener=urllib2.urlopen):
"""Open a urllib2 request, handling HTTP authentication"""
@@ -935,6 +995,13 @@ def open_with_auth(url, opener=urllib2.urlopen):
else:
auth = None
+ if not auth:
+ cred = PyPIConfig().find_credential(url)
+ if cred:
+ auth = str(cred)
+ info = cred.username, url
+ log.info('Authenticating as %s for %s (from .pypirc)' % info)
+
if auth:
auth = "Basic " + _encode_auth(auth)
new_url = urlunparse((scheme,host,path,params,query,frag))