def test_get_config_no_distutils(tmpdir): """ Even if the user hasn't set PyPI has an index server in 'index-servers', default to uploading to PyPI. """ pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write( textwrap.dedent(""" [pypi] username = testuser password = testpassword """)) assert utils.get_config(pypirc) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": "******", "password": "******", }, "testpypi": { "repository": utils.TEST_REPOSITORY, "username": None, "password": None, }, }
def test_get_config_no_distutils(tmpdir): """ Even if the user hasn't set PyPI has an index server in 'index-servers', default to uploading to PyPI. """ pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write(textwrap.dedent(""" [pypi] username = testuser password = testpassword """)) assert utils.get_config(pypirc) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": "******", "password": "******", }, "testpypi": { "repository": utils.TEST_REPOSITORY, "username": None, "password": None, }, }
def test_get_config_no_distutils(tmpdir): """Upload by default to PyPI if an index server is not set in .pypirc.""" pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write( textwrap.dedent( """ [pypi] username = testuser password = testpassword """ ) ) assert utils.get_config(pypirc) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": "******", "password": "******", }, "testpypi": { "repository": utils.TEST_REPOSITORY, "username": None, "password": None, }, }
def _pypirc_section_for_repo(repo): from twine import utils config = utils.get_config() for section in config: if config[section].get("repository") == repo: return section return None
def test_get_config_override_pypi_url(write_config_file): config_file = write_config_file( """ [pypi] repository = http://pypiproxy """ ) assert utils.get_config(config_file)["pypi"]["repository"] == "http://pypiproxy"
def test_get_config_missing(tmpdir): pypirc = os.path.join(str(tmpdir), ".pypirc") assert get_config(pypirc) == { "pypi": { "repository": DEFAULT_REPOSITORY, "username": None, "password": None, }, }
def test_get_config_override_pypi_url(tmpdir): pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write(textwrap.dedent(""" [pypi] repository = http://pypiproxy """)) assert utils.get_config(pypirc)['pypi']['repository'] == 'http://pypiproxy'
def test_get_config_deprecated_pypirc(): tests_dir = os.path.dirname(os.path.abspath(__file__)) deprecated_pypirc_path = os.path.join(tests_dir, 'fixtures', 'deprecated-pypirc') assert utils.get_config(deprecated_pypirc_path) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": '******', "password": '******', }, }
def test_get_config_deprecated_pypirc(): tests_dir = os.path.dirname(os.path.abspath(__file__)) deprecated_pypirc_path = os.path.join(tests_dir, 'fixtures', 'deprecated-pypirc') assert get_config(deprecated_pypirc_path) == { "pypi": { "repository": DEFAULT_REPOSITORY, "username": '******', "password": '******', }, }
def test_get_config_missing(config_file): assert utils.get_config(config_file) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": None, "password": None, }, "testpypi": { "repository": utils.TEST_REPOSITORY, "username": None, "password": None, }, }
def check_pypirc(): try: config = get_config() except Error as e: raise ScriptError('Failed to parse .pypirc file: {}'.format(e)) if config is None: raise ScriptError('Failed to parse .pypirc file') if 'pypi' not in config: raise ScriptError('Missing [pypi] section in .pypirc file') if not (config['pypi'].get('username') and config['pypi'].get('password')): raise ScriptError('Missing login/password pair for pypi repo')
def test_empty_userpass(write_config_file): """Suppress prompts if empty username and password are provided in .pypirc.""" config_file = write_config_file( """ [pypi] username= password= """ ) config = utils.get_config(config_file) pypi = config["pypi"] assert pypi["username"] == pypi["password"] == ""
def test_empty_userpass(tmpdir): """Suppress prompts if empty username and password are provided in .pypirc.""" pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write( textwrap.dedent(""" [pypi] username= password= """)) config = utils.get_config(pypirc) pypi = config["pypi"] assert pypi["username"] == pypi["password"] == ""
def test_get_config_no_distutils(tmpdir): pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write(textwrap.dedent(""" [pypi] username = testuser password = testpassword """)) assert utils.get_config(pypirc) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": "******", "password": "******", }, }
def test_get_config_no_distutils(tmpdir): pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write(textwrap.dedent(""" [pypi] username = testuser password = testpassword """)) assert get_config(pypirc) == { "pypi": { "repository": DEFAULT_REPOSITORY, "username": "******", "password": "******", }, }
def test_empty_userpass(tmpdir): """ Empty username and password may be supplied to suppress prompts. See #426. """ pypirc = os.path.join(str(tmpdir), ".pypirc") with open(pypirc, "w") as fp: fp.write(textwrap.dedent(""" [pypi] username= password= """)) config = utils.get_config(pypirc) pypi = config['pypi'] assert pypi['username'] == pypi['password'] == ''
def test_get_config_no_section(write_config_file): config_file = write_config_file( """ [distutils] index-servers = pypi foo [pypi] username = testuser password = testpassword """ ) assert utils.get_config(config_file) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": "******", "password": "******", }, }
def test_get_config_no_distutils(write_config_file): """Upload by default to PyPI if an index server is not set in .pypirc.""" config_file = write_config_file( """ [pypi] username = testuser password = testpassword """ ) assert utils.get_config(config_file) == { "pypi": { "repository": utils.DEFAULT_REPOSITORY, "username": "******", "password": "******", }, "testpypi": { "repository": utils.TEST_REPOSITORY, "username": None, "password": None, }, }
def upload(dists, repository, sign, identity, username, password, comment, sign_with, config_file): # Check that a nonsensical option wasn't given if not sign and identity: raise ValueError("sign must be given along with identity") # Determine if the user has passed in pre-signed distributions signatures = dict( (os.path.basename(d), d) for d in dists if d.endswith(".asc")) dists = [i for i in dists if not i.endswith(".asc")] # Get our config from the .pypirc file try: config = get_config(config_file)[repository] except KeyError: raise KeyError( "Missing '{0}' section from the configuration file".format( repository, ), ) parsed = urlparse(config["repository"]) if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]: config["repository"] = urlunparse(("https", ) + parsed[1:]) print("Uploading distributions to {0}".format(config["repository"])) username = get_username(username, config) password = get_password(password, config) session = requests.session() uploads = find_dists(dists) for filename in uploads: # Sign the dist if requested if sign: sign_file(sign_with, filename, identity) # Extract the metadata from the package for ext, dtype in DIST_EXTENSIONS.items(): if filename.endswith(ext): meta = DIST_TYPES[dtype](filename) break else: raise ValueError("Unknown distribution format: '%s'" % os.path.basename(filename)) if dtype == "bdist_egg": pkgd = pkg_resources.Distribution.from_filename(filename) py_version = pkgd.py_version elif dtype == "bdist_wheel": py_version = meta.py_version elif dtype == "bdist_wininst": py_version = meta.py_version else: py_version = None # Fill in the data - send all the meta-data in case we need to # register a new release data = { # action ":action": "file_upload", "protcol_version": "1", # identify release "name": pkg_resources.safe_name(meta.name), "version": meta.version, # file content "filetype": dtype, "pyversion": py_version, # additional meta-data "metadata_version": meta.metadata_version, "summary": meta.summary, "home_page": meta.home_page, "author": meta.author, "author_email": meta.author_email, "maintainer": meta.maintainer, "maintainer_email": meta.maintainer_email, "license": meta.license, "description": meta.description, "keywords": meta.keywords, "platform": meta.platforms, "classifiers": meta.classifiers, "download_url": meta.download_url, "supported_platform": meta.supported_platforms, "comment": comment, # PEP 314 "provides": meta.provides, "requires": meta.requires, "obsoletes": meta.obsoletes, # Metadata 1.2 "project_urls": meta.project_urls, "provides_dist": meta.provides_dist, "obsoletes_dist": meta.obsoletes_dist, "requires_dist": meta.requires_dist, "requires_external": meta.requires_external, "requires_python": meta.requires_python, } md5_hash = hashlib.md5() with open(filename, "rb") as fp: content = fp.read(4096) while content: md5_hash.update(content) content = fp.read(4096) data["md5_digest"] = md5_hash.hexdigest() signed_name = os.path.basename(filename) + ".asc" if signed_name in signatures: with open(signatures[signed_name], "rb") as gpg: data["gpg_signature"] = (signed_name, gpg.read()) elif sign: with open(filename + ".asc", "rb") as gpg: data["gpg_signature"] = (signed_name, gpg.read()) print("Uploading {0}".format(os.path.basename(filename))) data_to_send = [] for key, value in data.items(): if isinstance(value, (list, tuple)): for item in value: data_to_send.append((key, item)) else: data_to_send.append((key, value)) with open(filename, "rb") as fp: data_to_send.append(( "content", (os.path.basename(filename), fp, "application/octet-stream"), )) encoder = MultipartEncoder(data_to_send) resp = session.post( config["repository"], data=encoder, auth=(username, password), allow_redirects=False, headers={'Content-Type': encoder.content_type}, ) # Bug 28. Try to silence a ResourceWarning by releasing the socket and # clearing the connection pool. resp.close() session.close() # Bug 92. If we get a redirect we should abort because something seems # funky. The behaviour is not well defined and redirects being issued # by PyPI should never happen in reality. This should catch malicious # redirects as well. if resp.is_redirect: raise exc.RedirectDetected( ('"{0}" attempted to redirect to "{1}" during upload.' ' Aborting...').format(config["respository"], resp.headers["location"])) # Otherwise, raise an HTTPError based on the status code. resp.raise_for_status()
def upload(dists, repository, sign, identity, username, password, comment, sign_with, config_file): # Check that a nonsensical option wasn't given if not sign and identity: raise ValueError("sign must be given along with identity") # Determine if the user has passed in pre-signed distributions signatures = dict( (os.path.basename(d), d) for d in dists if d.endswith(".asc") ) dists = [i for i in dists if not i.endswith(".asc")] # Get our config from the .pypirc file try: config = get_config(config_file)[repository] except KeyError: msg = ( "Missing '{repo}' section from the configuration file.\n" "Maybe you have a out-dated '{cfg}' format?\n" "more info: " "https://docs.python.org/distutils/packageindex.html#pypirc\n" ).format( repo=repository, cfg=config_file ) raise KeyError(msg) parsed = urlparse(config["repository"]) if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]: config["repository"] = urlunparse( ("https",) + parsed[1:] ) print("Uploading distributions to {0}".format(config["repository"])) username = get_username(username, config) password = get_password(password, config) session = requests.session() uploads = find_dists(dists) for filename in uploads: # Sign the dist if requested if sign: sign_file(sign_with, filename, identity) # Extract the metadata from the package for ext, dtype in DIST_EXTENSIONS.items(): if filename.endswith(ext): meta = DIST_TYPES[dtype](filename) break else: raise ValueError( "Unknown distribution format: '%s'" % os.path.basename(filename) ) if dtype == "bdist_egg": pkgd = pkg_resources.Distribution.from_filename(filename) py_version = pkgd.py_version elif dtype == "bdist_wheel": py_version = meta.py_version elif dtype == "bdist_wininst": py_version = meta.py_version else: py_version = None # Fill in the data - send all the meta-data in case we need to # register a new release data = { # action ":action": "file_upload", "protcol_version": "1", # identify release "name": pkg_resources.safe_name(meta.name), "version": meta.version, # file content "filetype": dtype, "pyversion": py_version, # additional meta-data "metadata_version": meta.metadata_version, "summary": meta.summary, "home_page": meta.home_page, "author": meta.author, "author_email": meta.author_email, "maintainer": meta.maintainer, "maintainer_email": meta.maintainer_email, "license": meta.license, "description": meta.description, "keywords": meta.keywords, "platform": meta.platforms, "classifiers": meta.classifiers, "download_url": meta.download_url, "supported_platform": meta.supported_platforms, "comment": comment, # PEP 314 "provides": meta.provides, "requires": meta.requires, "obsoletes": meta.obsoletes, # Metadata 1.2 "project_urls": meta.project_urls, "provides_dist": meta.provides_dist, "obsoletes_dist": meta.obsoletes_dist, "requires_dist": meta.requires_dist, "requires_external": meta.requires_external, "requires_python": meta.requires_python, } md5_hash = hashlib.md5() with open(filename, "rb") as fp: content = fp.read(4096) while content: md5_hash.update(content) content = fp.read(4096) data["md5_digest"] = md5_hash.hexdigest() signed_name = os.path.basename(filename) + ".asc" if signed_name in signatures: with open(signatures[signed_name], "rb") as gpg: data["gpg_signature"] = (signed_name, gpg.read()) elif sign: with open(filename + ".asc", "rb") as gpg: data["gpg_signature"] = (signed_name, gpg.read()) print("Uploading {0}".format(os.path.basename(filename))) data_to_send = [] for key, value in data.items(): if isinstance(value, (list, tuple)): for item in value: data_to_send.append((key, item)) else: data_to_send.append((key, value)) with open(filename, "rb") as fp: data_to_send.append(( "content", (os.path.basename(filename), fp, "application/octet-stream"), )) encoder = MultipartEncoder(data_to_send) resp = session.post( config["repository"], data=encoder, auth=(username, password), allow_redirects=False, headers={'Content-Type': encoder.content_type}, ) # Bug 28. Try to silence a ResourceWarning by releasing the socket and # clearing the connection pool. resp.close() session.close() # Bug 92. If we get a redirect we should abort because something seems # funky. The behaviour is not well defined and redirects being issued # by PyPI should never happen in reality. This should catch malicious # redirects as well. if resp.is_redirect: raise exc.RedirectDetected( ('"{0}" attempted to redirect to "{1}" during upload.' ' Aborting...').format(config["respository"], resp.headers["location"])) # Otherwise, raise an HTTPError based on the status code. resp.raise_for_status()
def upload(dists, repository, sign, identity, username, password, comment): # Check that a nonsensical option wasn't given if not sign and identity: raise ValueError("sign must be given along with identity") # Determine if the user has passed in pre-signed distributions signatures = dict( (os.path.basename(d), d) for d in dists if d.endswith(".asc") ) dists = [i for i in dists if not i.endswith(".asc")] # Get our config from ~/.pypirc try: config = get_config()[repository] except KeyError: raise KeyError( "Missing '{0}' section from the configuration file".format( repository, ), ) parsed = urlparse(config["repository"]) if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]: config["repository"] = urlunparse( ("https",) + parsed[1:] ) print("Uploading distributions to {0}".format(config["repository"])) session = requests.session() for filename in dists: # Sign the dist if requested if sign: print("Signing {0}".format(os.path.basename(filename))) gpg_args = ["gpg", "--detach-sign", "-a", filename] if identity: gpg_args[2:2] = ["--local-user", identity] subprocess.check_call(gpg_args) # Extract the metadata from the package for ext, dtype in DIST_EXTENSIONS.items(): if filename.endswith(ext): meta = DIST_TYPES[dtype](filename) break else: raise ValueError( "Unknown distribution format: '%s'" % os.path.basename(filename) ) if dtype == "bdist_egg": pkgd = pkg_resources.Distribution.from_filename(filename) py_version = pkgd.py_version elif dtype == "bdist_wheel": py_version = meta.py_version else: py_version = None # Fill in the data - send all the meta-data in case we need to # register a new release data = { # action ":action": "file_upload", "protcol_version": "1", # identify release "name": meta.name, "version": meta.version, # file content "filetype": dtype, "pyversion": py_version, # additional meta-data "metadata_version": meta.metadata_version, "summary": meta.summary, "home_page": meta.home_page, "author": meta.author, "author_email": meta.author_email, "maintainer": meta.maintainer, "maintainer_email": meta.maintainer_email, "license": meta.license, "description": meta.description, "keywords": meta.keywords, "platform": meta.platforms, "classifiers": meta.classifiers, "download_url": meta.download_url, "supported_platform": meta.supported_platforms, "comment": comment, # PEP 314 "provides": meta.provides, "requires": meta.requires, "obsoletes": meta.obsoletes, # Metadata 1.2 "project_urls": meta.project_urls, "provides_dist": meta.provides_dist, "obsoletes_dist": meta.obsoletes_dist, "requires_dist": meta.requires_dist, "requires_external": meta.requires_external, "requires_python": meta.requires_python, } with open(filename, "rb") as fp: content = fp.read() filedata = { "content": (os.path.basename(filename), content), } data["md5_digest"] = hashlib.md5(content).hexdigest() signed_name = os.path.basename(filename) + ".asc" if signed_name in signatures: with open(signatures[signed_name], "rb") as gpg: filedata["gpg_signature"] = (signed_name, gpg.read()) elif sign: with open(filename + ".asc", "rb") as gpg: filedata["gpg_signature"] = (signed_name, gpg.read()) print("Uploading {0}".format(os.path.basename(filename))) resp = session.post( config["repository"], data=dict((k, v) for k, v in data.items() if v), files=filedata, auth=( username or config.get("username"), password or config.get("password"), ), ) resp.raise_for_status()
def upload(dists, repository, sign, identity, username, password, comment): # Check that a nonsensical option wasn't given if not sign and identity: raise ValueError("sign must be given along with identity") # Determine if the user has passed in pre-signed distributions signatures = dict( (os.path.basename(d), d) for d in dists if d.endswith(".asc")) dists = [i for i in dists if not i.endswith(".asc")] # Get our config from ~/.pypirc try: config = get_config()[repository] except KeyError: raise KeyError( "Missing '{0}' section from the configuration file".format( repository, ), ) parsed = urlparse(config["repository"]) if parsed.netloc in ["pypi.python.org", "testpypi.python.org"]: config["repository"] = urlunparse(("https", ) + parsed[1:]) print("Uploading distributions to {0}".format(config["repository"])) session = requests.session() for filename in dists: # Sign the dist if requested if sign: print("Signing {0}".format(os.path.basename(filename))) gpg_args = ["gpg", "--detach-sign", "-a", filename] if identity: gpg_args[2:2] = ["--local-user", identity] subprocess.check_call(gpg_args) # Extract the metadata from the package for ext, dtype in DIST_EXTENSIONS.items(): if filename.endswith(ext): meta = DIST_TYPES[dtype](filename) break else: raise ValueError("Unknown distribution format: '%s'" % os.path.basename(filename)) if dtype == "bdist_egg": pkgd = pkg_resources.Distribution.from_filename(filename) py_version = pkgd.py_version elif dtype == "bdist_wheel": py_version = meta.py_version else: py_version = None # Fill in the data - send all the meta-data in case we need to # register a new release data = { # action ":action": "file_upload", "protcol_version": "1", # identify release "name": meta.name, "version": meta.version, # file content "filetype": dtype, "pyversion": py_version, # additional meta-data "metadata_version": meta.metadata_version, "summary": meta.summary, "home_page": meta.home_page, "author": meta.author, "author_email": meta.author_email, "maintainer": meta.maintainer, "maintainer_email": meta.maintainer_email, "license": meta.license, "description": meta.description, "keywords": meta.keywords, "platform": meta.platforms, "classifiers": meta.classifiers, "download_url": meta.download_url, "supported_platform": meta.supported_platforms, "comment": comment, # PEP 314 "provides": meta.provides, "requires": meta.requires, "obsoletes": meta.obsoletes, # Metadata 1.2 "project_urls": meta.project_urls, "provides_dist": meta.provides_dist, "obsoletes_dist": meta.obsoletes_dist, "requires_dist": meta.requires_dist, "requires_external": meta.requires_external, "requires_python": meta.requires_python, } with open(filename, "rb") as fp: content = fp.read() filedata = { "content": (os.path.basename(filename), content), } data["md5_digest"] = hashlib.md5(content).hexdigest() signed_name = os.path.basename(filename) + ".asc" if signed_name in signatures: with open(signatures[signed_name], "rb") as gpg: filedata["gpg_signature"] = (signed_name, gpg.read()) elif sign: with open(filename + ".asc", "rb") as gpg: filedata["gpg_signature"] = (signed_name, gpg.read()) print("Uploading {0}".format(os.path.basename(filename))) resp = session.post( config["repository"], data=dict((k, v) for k, v in data.items() if v), files=filedata, auth=( username or config.get("username"), password or config.get("password"), ), ) resp.raise_for_status()