예제 #1
0
def test_exception_for_redirect(make_settings):
    # Not using fixtures because this setup is significantly different

    upload_settings = make_settings("""
        [pypi]
        repository: https://test.pypi.org/legacy
        username:foo
        password:bar
    """)

    stub_response = pretend.stub(
        is_redirect=True,
        status_code=301,
        headers={"location": "https://test.pypi.org/legacy/"},
    )

    stub_repository = pretend.stub(upload=lambda package: stub_response,
                                   close=lambda: None)

    upload_settings.create_repository = lambda: stub_repository

    with pytest.raises(exceptions.RedirectDetected) as err:
        upload.upload(upload_settings, [helpers.WHEEL_FIXTURE])

    assert "https://test.pypi.org/legacy/" in err.value.args[0]
예제 #2
0
def upload_to_pypi(dists='sdist bdist_wheel',
                   username=None,
                   password=None,
                   skip_existing=False,
                   repository_url=None):
    """
    Creates the wheel and uploads to pypi with twine.

    :param dists: The dists string passed to setup.py. Default: 'bdist_wheel'
    """
    run('python setup.py {}'.format(dists))
    twine_upload.upload(dists=['dist/*'],
                        repository='pypi',
                        sign=False,
                        identity=None,
                        username=username,
                        password=password,
                        comment=None,
                        sign_with='gpg',
                        config_file='~/.pypirc',
                        skip_existing=skip_existing,
                        cert=None,
                        client_cert=None,
                        repository_url=repository_url)
    run('rm -rf build dist')
예제 #3
0
    def handle(self) -> int:
        from twine.settings import Settings
        from twine.commands.upload import upload

        distributions: list[Path] = []

        with tempfile.TemporaryDirectory() as tmpdir:
            for project in self.app.repository.projects():
                if not project.is_python_project: continue

                self.line(f'Build <info>{project.dist_name()}</info>')
                backend = Pep517BuildBackend(
                    project.pyproject_toml.value()['build-system']
                    ['build-backend'], project.directory, Path(tmpdir))

                sdist = backend.build_sdist()
                self.line(f'  <comment>{sdist.name}</comment>')
                wheel = backend.build_wheel()
                self.line(f'  <comment>{wheel.name}</comment>')

                distributions += [sdist, wheel]

            if not self.option("dry"):
                kwargs = {
                    option.name.replace('-', '_'): self.option(option.name)
                    for option in self.options
                }
                kwargs['repository_name'] = kwargs.pop('repository')
                settings = Settings(**kwargs)
                upload(settings, [str(d) for d in distributions])

        return 0
예제 #4
0
 def _upload(self, dist, package):
     upload([
         os.path.join(dist, '{}-{}*'.format(self.poet.name,
                                            self.poet.version))
     ],
            self.option('repository') or 'pypi', False, None, None, None,
            None, None, '~/.pypirc', False, None, None, None)
예제 #5
0
def test_exception_for_http_status(verbose, make_settings, capsys):
    upload_settings = make_settings()
    upload_settings.verbose = verbose

    stub_response = pretend.stub(
        is_redirect=False,
        status_code=403,
        text="Invalid or non-existent authentication information",
        raise_for_status=pretend.raiser(HTTPError))

    stub_repository = pretend.stub(
        upload=lambda package: stub_response,
        close=lambda: None,
    )

    upload_settings.create_repository = lambda: stub_repository

    with pytest.raises(HTTPError):
        upload.upload(upload_settings, [WHEEL_FIXTURE])

    captured = capsys.readouterr()
    assert RELEASE_URL not in captured.out

    if verbose:
        assert stub_response.text in captured.out
        assert '--verbose' not in captured.out
    else:
        assert stub_response.text not in captured.out
        assert '--verbose' in captured.out
예제 #6
0
파일: release.py 프로젝트: iotile/structpp
def upload_component(component):
    """Upload a given component to pypi

    The pypi username and password must either be specified in a ~/.pypirc
    file or in environment variables PYPI_USER and PYPI_PASS
    """

    if 'PYPI_USER' in os.environ and 'PYPI_PASS' in os.environ:
        pypi_user = os.environ['PYPI_USER']
        pypi_pass = os.environ['PYPI_PASS']
    else:
        pypi_user = None
        pypi_pass = None
        print("No PYPI user information in environment")

    _, relative_compath = comp_names[component]
    distpath = os.path.join(relative_compath, 'dist', '*')
    distpath = os.path.realpath(os.path.abspath(distpath))
    dists = glob.glob(distpath)

    if pypi_user is None:
        args = ['twine', 'upload', distpath]
    else:
        args = ['twine', 'upload', '-u', pypi_user, '-p', pypi_pass, distpath]

    #Invoke upload this way since subprocess call of twine cli has cross platform issues
    upload(dists, 'pypi', False, None, pypi_user, pypi_pass, None, None,
           '~/.pypirc', False, None, None, None)
예제 #7
0
def test_get_config_old_format(tmpdir):
    pypirc = os.path.join(str(tmpdir), ".pypirc")
    dists = ["tests/fixtures/twine-1.5.0-py2.py3-none-any.whl"]

    with open(pypirc, "w") as fp:
        fp.write(textwrap.dedent("""
            [server-login]
            username:foo
            password:bar
        """))

    try:
        upload.upload(dists=dists, repository="pypi", sign=None, identity=None,
                      username=None, password=None, comment=None,
                      cert=None, client_cert=None,
                      sign_with=None, config_file=pypirc, skip_existing=False,
                      repository_url=None,
                      )
    except KeyError as err:
        assert err.args[0] == (
            "Missing 'pypi' section from the configuration file\n"
            "or not a complete URL in --repository-url.\n"
            "Maybe you have a out-dated '{0}' format?\n"
            "more info: "
            "https://docs.python.org/distutils/packageindex.html#pypirc\n"
        ).format(pypirc)
예제 #8
0
def test_deprecated_repo(tmpdir):
    with pytest.raises(exceptions.UploadToDeprecatedPyPIDetected) as err:
        pypirc = os.path.join(str(tmpdir), ".pypirc")
        dists = ["tests/fixtures/twine-1.5.0-py2.py3-none-any.whl"]

        with open(pypirc, "w") as fp:
            fp.write(textwrap.dedent("""
                [pypi]
                repository: https://pypi.python.org/pypi/
                username:foo
                password:bar
            """))

        upload_settings = settings.Settings(
            repository_name="pypi", sign=None, identity=None, username=None,
            password=None, comment=None, cert=None, client_cert=None,
            sign_with=None, config_file=pypirc, skip_existing=False,
            repository_url=None, verbose=False,
        )

        upload.upload(upload_settings, dists)

        assert err.args[0] == (
            "You're trying to upload to the legacy PyPI site "
            "'https://pypi.python.org/pypi/'. "
            "Uploading to those sites is deprecated. \n "
            "The new sites are pypi.org and test.pypi.org. Try using "
            "https://upload.pypi.org/legacy/ "
            "(or https://test.pypi.org/legacy/) "
            "to upload your packages instead. "
            "These are the default URLs for Twine now. \n "
            "More at "
            "https://packaging.python.org/guides/migrating-to-pypi-org/ ."
            )
예제 #9
0
def test_check_status_code_for_wrong_repo_url(repo_url, make_settings):
    upload_settings = make_settings()

    # override defaults to use incorrect URL
    upload_settings.repository_config['repository'] = repo_url

    with pytest.raises(twine.exceptions.InvalidPyPIUploadURL):
        upload.upload(upload_settings, [
            WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE
        ])
예제 #10
0
 def publish_to_pypi(self):
     """Uses `twine` to upload to PyPi"""
     if get_tag():
         credentials = ArtifactStore(
             vault_name=self.vault_name,
             vault_client=self.vault_client).store_settings(self.config)
         upload(upload_settings=credentials, dists=["dist/*"])
     else:
         logging.info(
             "Not on a release tag, not publishing artifact on PyPi.")
예제 #11
0
def upload_to_pypi(dists='bdist_wheel'):
    """
    Creates the wheel and uploads to pypi with twine.

    :param dists: The dists string passed to setup.py. Default: 'bdist_wheel'
    """
    run('python setup.py {}'.format(dists))
    twine_upload.upload(dists=['dist/*'], repository='pypi', sign=False, identity=None,
                        username=None, password=None, comment=None, sign_with='gpg')
    run('rm -rf build dist')
예제 #12
0
def publish(ctx, repository):
    files = ctx.invoke(dist)
    from twine.commands.upload import upload
    upload(
        dists=files,
        repository=repository,
        sign=False,
        identity=None,
        username=None,
        password=None,
        comment='',
        sign_with=None,
    )
예제 #13
0
def test_prints_skip_message_for_response(make_settings, capsys):
    upload_settings = make_settings(skip_existing=True)

    stub_response = pretend.stub(
        is_redirect=False,
        status_code=409,
    )

    stub_repository = pretend.stub(
        # Do the upload, triggering the error response
        package_is_uploaded=lambda package: False,
        release_urls=lambda packages: {},
        upload=lambda package: stub_response,
        close=lambda: None)

    upload_settings.create_repository = lambda: stub_repository

    result = upload.upload(upload_settings, [WHEEL_FIXTURE])

    # A truthy result means the upload failed
    assert result is None

    captured = capsys.readouterr()
    assert "Skipping twine-1.5.0-py2.py3-none-any.whl" in captured.out
    assert RELEASE_URL not in captured.out
예제 #14
0
def test_successful_upload(tmpdir):
    pypirc = os.path.join(str(tmpdir), ".pypirc")
    dists = ["tests/fixtures/twine-1.5.0-py2.py3-none-any.whl"]

    with open(pypirc, "w") as fp:
        fp.write(textwrap.dedent("""
            [pypi]
            username:foo
            password:bar
        """))

    upload_settings = settings.Settings(
        repository_name="pypi", sign=None, identity=None, username=None,
        password=None, comment=None, cert=None, client_cert=None,
        sign_with=None, config_file=pypirc, skip_existing=False,
        repository_url=None, verbose=False,
    )

    stub_response = pretend.stub(
        is_redirect=False, status_code=201, raise_for_status=lambda: None
    )
    stub_repository = pretend.stub(
        upload=lambda package: stub_response, close=lambda: None
    )

    upload_settings.create_repository = lambda: stub_repository

    result = upload.upload(upload_settings, dists)

    # Raising an exception or returning anything truthy would mean that the
    # upload has failed
    assert result is None
예제 #15
0
def test_successful_upload(make_settings, capsys):
    upload_settings = make_settings()

    stub_response = pretend.stub(is_redirect=False,
                                 status_code=201,
                                 raise_for_status=lambda: None)

    stub_repository = pretend.stub(
        upload=lambda package: stub_response,
        close=lambda: None,
        release_urls=lambda packages: {RELEASE_URL, NEW_RELEASE_URL},
    )

    upload_settings.create_repository = lambda: stub_repository

    result = upload.upload(
        upload_settings,
        [WHEEL_FIXTURE, SDIST_FIXTURE, NEW_SDIST_FIXTURE, NEW_WHEEL_FIXTURE],
    )

    # A truthy result means the upload failed
    assert result is None

    captured = capsys.readouterr()
    assert captured.out.count(RELEASE_URL) == 1
    assert captured.out.count(NEW_RELEASE_URL) == 1
예제 #16
0
def test_success_when_gpg_is_run(upload_settings, stub_repository,
                                 monkeypatch):
    """Adds GPG signature generated by gpg command to uploaded package."""
    # Indicate that upload() should run_gpg() to generate the signature, which
    # we'll stub out to use WHEEL_FIXTURE + ".asc"
    upload_settings.sign = True
    upload_settings.sign_with = "gpg"
    monkeypatch.setattr(
        package_file.PackageFile,
        "run_gpg",
        pretend.call_recorder(lambda cls, gpg_args: None),
    )

    # Upload an unsigned distribution
    result = upload.upload(upload_settings, [helpers.WHEEL_FIXTURE])
    assert result is None

    # The signature shoud be added via package.sign()
    package = stub_repository.upload.calls[0].args[0]
    assert len(package.run_gpg.calls) == 1
    assert helpers.WHEEL_FIXTURE in package.run_gpg.calls[0].args[1]
    assert package.gpg_signature == (
        "twine-1.5.0-py2.py3-none-any.whl.asc",
        b"signature",
    )
예제 #17
0
def test_check_status_code_for_wrong_repo_url(repo_url, upload_settings,
                                              stub_response):
    upload_settings.repository_config["repository"] = repo_url

    stub_response.url = repo_url
    stub_response.status_code = 405

    with pytest.raises(exceptions.InvalidPyPIUploadURL):
        upload.upload(
            upload_settings,
            [
                helpers.WHEEL_FIXTURE,
                helpers.SDIST_FIXTURE,
                helpers.NEW_SDIST_FIXTURE,
                helpers.NEW_WHEEL_FIXTURE,
            ],
        )
예제 #18
0
def upload_component(component_path,
                     repo="pypi",
                     username=None,
                     password=None):
    """Upload a given component to pypi

    The pypi username and password must either be specified in a ~/.pypirc
    file or in environment variables PYPI_USER and PYPI_PASS
    """

    if username is None:
        username = input("Enter your username [%s]: " % repo)

    if password is None:
        password = getpass(
            ("Enter your password [%s]: " % repo).encode('utf-8'))

    distpath = os.path.join(component_path, 'dist', '*')
    distpath = os.path.realpath(os.path.abspath(distpath))
    dists = glob.glob(distpath)

    repo_name = repo
    repo_url = None
    if "://" in repo_name:
        repo_url = repo
        repo_name = None

    try:
        #Invoke upload this way since subprocess call of twine cli has cross platform issues
        settings = Settings(username=username,
                            password=password,
                            repository_name=repo_name,
                            repository_url=repo_url)
        upload(settings, dists)
    except requests.exceptions.HTTPError as exc:
        code = exc.response.status_code

        if repo_name is None:
            repo_name = repo_url

        msg = "Unknown response from server"
        if code == 409 or code == 400:
            msg = "Package already exists"

        raise ExternalError("PyPI repository '%s'" % repo_name,
                            "HTTP status %d: %s" % (code, msg))
예제 #19
0
def test_deprecated_repo(make_settings):
    with pytest.raises(exceptions.UploadToDeprecatedPyPIDetected) as err:
        upload_settings = make_settings("""
            [pypi]
            repository: https://pypi.python.org/pypi/
            username:foo
            password:bar
        """)

        upload.upload(upload_settings, [WHEEL_FIXTURE])

    assert all(text in err.value.args[0] for text in [
        "https://pypi.python.org/pypi/",
        "https://upload.pypi.org/legacy/",
        "https://test.pypi.org/legacy/",
        "https://packaging.python.org/",
    ])
예제 #20
0
def upload_package(
        package,
        repository,
        pypirc='~/.pypirc',
        sign=False,
        identity=None,
        username=None,
        password=None,
        comment=None,
        sign_with=None,
        skip_existing=False,
        certfile=None,
        client_certfile=None
        ):
    """
    :param package: path to sdist package
    :param repository: repo name to upload to
    :param pypirc: path to pypirc file

    """
    cirrus_conf = load_configuration()
    if cirrus_conf.has_section('twine'):
        username = username or cirrus_conf.get_param('twine', 'username', None)
        password = password or cirrus_conf.get_param('twine', 'password', None)
        certfile = certfile or cirrus_conf.get_param('twine', 'certfile', None)
        identity = identity or cirrus_conf.get_param('twine', 'identity', None)
        sign_with = sign_with or cirrus_conf.get_param('twine', 'sign_with', None)
        client_certfile = client_certfile or cirrus_conf.get_param('twine', 'client_certfile', None)

    upload(
        [package],
        repository,
        sign,
        identity,
        username,
        password,
        comment,
        sign_with,
        pypirc,
        skip_existing,
        certfile,
        client_certfile,
        None
    )
예제 #21
0
    def _upload_dists(self, repo, dists):
        """Upload a given component to pypi

        The pypi username and password must either be specified in a ~/.pypirc
        file or in environment variables PYPI_USER and PYPI_PASS
        """

        from twine.commands.upload import upload

        if 'PYPI_USER' in os.environ and 'PYPI_PASS' in os.environ:
            pypi_user = os.environ['PYPI_USER']
            pypi_pass = os.environ['PYPI_PASS']
        else:
            pypi_user = None
            pypi_pass = None

        # Invoke upload this way since subprocess call of twine cli has cross platform issues
        upload(dists, repo, False, None, pypi_user, pypi_pass, None, None,
               '~/.pypirc', False, None, None, None)
예제 #22
0
def pypi(package, dry_run):
    """Deploys build artifacts (python packages to PyPI)

    Deployment is only allowed for packages in which the visibility is
    "public".  This check prevents publishing of private resources to
    the (public) PyPI webserver.
    """

    if dry_run:
        logger.warn("!!!! DRY RUN MODE !!!!")
        logger.warn("Nothing is being deployed to server")

    # determine project visibility
    public = os.environ["CI_PROJECT_VISIBILITY"] == "public"

    if not public:
        raise RuntimeError(
            "The repository %s is not public - a package "
            "deriving from it therefore, CANNOT be published to PyPI. "
            "You must follow the relevant software disclosure procedures "
            'and set this repository to "public" before trying again.' %
            os.environ["CI_PROJECT_PATH"])

    from twine.settings import Settings

    from ..constants import CACERT

    settings = Settings(
        username=os.environ["PYPIUSER"],
        password=os.environ["PYPIPASS"],
        skip_existing=True,
        cacert=CACERT,
    )

    if not dry_run:
        from twine.commands.upload import upload

        for k in package:

            logger.info("Deploying python package %s to PyPI", k)
            upload(settings, [k])
            logger.info("%s: Deployed to PyPI - OK", k)
예제 #23
0
파일: test_upload.py 프로젝트: warner/twine
def test_get_config_old_format(tmpdir):
    pypirc = os.path.join(str(tmpdir), ".pypirc")

    with open(pypirc, "w") as fp:
        fp.write(textwrap.dedent("""
            [server-login]
            username:foo
            password:bar
        """))

    try:
        upload.upload(dists="foo", repository="pypi", sign=None, identity=None,
                      username=None, password=None, comment=None,
                      sign_with=None, config_file=pypirc, skip_existing=False)
    except KeyError as err:
        assert err.args[0] == (
            "Missing 'pypi' section from the configuration file.\n"
            "Maybe you have a out-dated '{0}' format?\n"
            "more info: "
            "https://docs.python.org/distutils/packageindex.html#pypirc\n"
        ).format(pypirc)
예제 #24
0
def test_exception_for_http_status(verbose, upload_settings, stub_response,
                                   capsys):
    upload_settings.verbose = verbose

    stub_response.is_redirect = False
    stub_response.status_code = 403
    stub_response.text = "Invalid or non-existent authentication information"
    stub_response.raise_for_status = pretend.raiser(requests.HTTPError)

    with pytest.raises(requests.HTTPError):
        upload.upload(upload_settings, [helpers.WHEEL_FIXTURE])

    captured = capsys.readouterr()
    assert RELEASE_URL not in captured.out

    if verbose:
        assert stub_response.text in captured.out
        assert "--verbose" not in captured.out
    else:
        assert stub_response.text not in captured.out
        assert "--verbose" in captured.out
예제 #25
0
def test_prints_skip_message_for_uploaded_package(upload_settings,
                                                  stub_repository, capsys):
    upload_settings.skip_existing = True

    # Short-circuit the upload
    stub_repository.package_is_uploaded = lambda package: True

    result = upload.upload(upload_settings, [helpers.WHEEL_FIXTURE])
    assert result is None

    captured = capsys.readouterr()
    assert "Skipping twine-1.5.0-py2.py3-none-any.whl" in captured.out
    assert RELEASE_URL not in captured.out
예제 #26
0
def test_exception_for_redirect(make_settings):
    upload_settings = make_settings("""
        [pypi]
        repository: https://test.pypi.org/legacy
        username:foo
        password:bar
    """)

    stub_response = pretend.stub(
        is_redirect=True,
        status_code=301,
        headers={'location': 'https://test.pypi.org/legacy/'})

    stub_repository = pretend.stub(upload=lambda package: stub_response,
                                   close=lambda: None)

    upload_settings.create_repository = lambda: stub_repository

    with pytest.raises(exceptions.RedirectDetected) as err:
        upload.upload(upload_settings, [WHEEL_FIXTURE])

    assert "https://test.pypi.org/legacy/" in err.value.args[0]
예제 #27
0
def test_prints_skip_message_for_response(upload_settings, stub_response,
                                          stub_repository, capsys):
    upload_settings.skip_existing = True

    stub_response.status_code = 409

    # Do the upload, triggering the error response
    stub_repository.package_is_uploaded = lambda package: False

    result = upload.upload(upload_settings, [helpers.WHEEL_FIXTURE])
    assert result is None

    captured = capsys.readouterr()
    assert "Skipping twine-1.5.0-py2.py3-none-any.whl" in captured.out
    assert RELEASE_URL not in captured.out
예제 #28
0
def test_success_with_pre_signed_distribution(upload_settings,
                                              stub_repository):
    """Adds GPG signature provided by user to uploaded package."""
    # Upload a pre-signed distribution
    result = upload.upload(
        upload_settings,
        [helpers.WHEEL_FIXTURE, helpers.WHEEL_FIXTURE + ".asc"])
    assert result is None

    # The signature shoud be added via package.add_gpg_signature()
    package = stub_repository.upload.calls[0].args[0]
    assert package.gpg_signature == (
        "twine-1.5.0-py2.py3-none-any.whl.asc",
        b"signature",
    )
예제 #29
0
def test_print_packages_if_verbose(upload_settings, capsys):
    """Print the path and file size of each distribution attempting to be uploaded."""
    dists_to_upload = {
        helpers.WHEEL_FIXTURE: "15.4 KB",
        helpers.SDIST_FIXTURE: "20.8 KB",
        helpers.NEW_SDIST_FIXTURE: "26.1 KB",
        helpers.NEW_WHEEL_FIXTURE: "21.9 KB",
    }

    upload_settings.verbose = True

    result = upload.upload(upload_settings, dists_to_upload.keys())
    assert result is None

    captured = capsys.readouterr()

    for filename, size in dists_to_upload.items():
        assert captured.out.count(f"{filename} ({size})") == 1
예제 #30
0
def test_prints_skip_message_for_uploaded_package(make_settings, capsys):
    upload_settings = make_settings(skip_existing=True)

    stub_repository = pretend.stub(
        # Short-circuit the upload, so no need for a stub response
        package_is_uploaded=lambda package: True,
        release_urls=lambda packages: {},
        close=lambda: None)

    upload_settings.create_repository = lambda: stub_repository

    result = upload.upload(upload_settings, [WHEEL_FIXTURE])

    # A truthy result means the upload failed
    assert result is None

    captured = capsys.readouterr()
    assert "Skipping twine-1.5.0-py2.py3-none-any.whl" in captured.out
    assert RELEASE_URL not in captured.out
예제 #31
0
def test_successs_prints_release_urls(upload_settings, stub_repository,
                                      capsys):
    """Prints PyPI release URLS for each uploaded package."""
    stub_repository.release_urls = lambda packages: {
        RELEASE_URL, NEW_RELEASE_URL
    }

    result = upload.upload(
        upload_settings,
        [
            helpers.WHEEL_FIXTURE,
            helpers.SDIST_FIXTURE,
            helpers.NEW_SDIST_FIXTURE,
            helpers.NEW_WHEEL_FIXTURE,
        ],
    )
    assert result is None

    captured = capsys.readouterr()
    assert captured.out.count(RELEASE_URL) == 1
    assert captured.out.count(NEW_RELEASE_URL) == 1