mirror of
https://github.com/EvolutionAPI/evolution-client-python.git
synced 2025-12-21 12:52:18 -06:00
initial commit
This commit is contained in:
54
env/lib/python3.10/site-packages/twine/commands/__init__.py
vendored
Normal file
54
env/lib/python3.10/site-packages/twine/commands/__init__.py
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
"""Module containing the logic for the ``twine`` sub-commands.
|
||||
|
||||
The contents of this package are not a public API. For more details, see
|
||||
https://github.com/pypa/twine/issues/194 and https://github.com/pypa/twine/issues/665.
|
||||
"""
|
||||
|
||||
# Copyright 2013 Donald Stufft
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import glob
|
||||
import os.path
|
||||
from typing import List
|
||||
|
||||
from twine import exceptions
|
||||
|
||||
__all__: List[str] = []
|
||||
|
||||
|
||||
def _group_wheel_files_first(files: List[str]) -> List[str]:
|
||||
if not any(fname for fname in files if fname.endswith(".whl")):
|
||||
# Return early if there's no wheel files
|
||||
return files
|
||||
|
||||
files.sort(key=lambda x: -1 if x.endswith(".whl") else 0)
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def _find_dists(dists: List[str]) -> List[str]:
|
||||
uploads = []
|
||||
for filename in dists:
|
||||
if os.path.exists(filename):
|
||||
uploads.append(filename)
|
||||
continue
|
||||
# The filename didn't exist so it may be a glob
|
||||
files = glob.glob(filename)
|
||||
# If nothing matches, files is []
|
||||
if not files:
|
||||
raise exceptions.InvalidDistribution(
|
||||
"Cannot find file (or expand pattern): '%s'" % filename
|
||||
)
|
||||
# Otherwise, files will be filenames that exist
|
||||
uploads.extend(files)
|
||||
return _group_wheel_files_first(uploads)
|
||||
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/__init__.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/__init__.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/check.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/check.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/register.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/register.cpython-310.pyc
vendored
Normal file
Binary file not shown.
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/upload.cpython-310.pyc
vendored
Normal file
BIN
env/lib/python3.10/site-packages/twine/commands/__pycache__/upload.cpython-310.pyc
vendored
Normal file
Binary file not shown.
194
env/lib/python3.10/site-packages/twine/commands/check.py
vendored
Normal file
194
env/lib/python3.10/site-packages/twine/commands/check.py
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
"""Module containing the logic for ``twine check``."""
|
||||
|
||||
# Copyright 2018 Dustin Ingram
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
import email.message
|
||||
import io
|
||||
import logging
|
||||
import re
|
||||
from typing import Dict, List, Optional, Tuple, cast
|
||||
|
||||
import readme_renderer.rst
|
||||
from rich import print
|
||||
|
||||
from twine import commands
|
||||
from twine import package as package_file
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
_RENDERERS = {
|
||||
None: readme_renderer.rst, # Default if description_content_type is None
|
||||
"text/plain": None, # Rendering cannot fail
|
||||
"text/x-rst": readme_renderer.rst,
|
||||
"text/markdown": None, # Rendering cannot fail
|
||||
}
|
||||
|
||||
|
||||
# Regular expression used to capture and reformat docutils warnings into
|
||||
# something that a human can understand. This is loosely borrowed from
|
||||
# Sphinx: https://github.com/sphinx-doc/sphinx/blob
|
||||
# /c35eb6fade7a3b4a6de4183d1dd4196f04a5edaf/sphinx/util/docutils.py#L199
|
||||
_REPORT_RE = re.compile(
|
||||
r"^<string>:(?P<line>(?:\d+)?): "
|
||||
r"\((?P<level>DEBUG|INFO|WARNING|ERROR|SEVERE)/(\d+)?\) "
|
||||
r"(?P<message>.*)",
|
||||
re.DOTALL | re.MULTILINE,
|
||||
)
|
||||
|
||||
|
||||
class _WarningStream(io.StringIO):
|
||||
def write(self, text: str) -> int:
|
||||
matched = _REPORT_RE.search(text)
|
||||
if matched:
|
||||
line = matched.group("line")
|
||||
level_text = matched.group("level").capitalize()
|
||||
message = matched.group("message").rstrip("\r\n")
|
||||
text = f"line {line}: {level_text}: {message}\n"
|
||||
|
||||
return super().write(text)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.getvalue().strip()
|
||||
|
||||
|
||||
def _parse_content_type(value: str) -> Tuple[str, Dict[str, str]]:
|
||||
"""Implement logic of deprecated cgi.parse_header().
|
||||
|
||||
From https://docs.python.org/3.11/library/cgi.html#cgi.parse_header.
|
||||
"""
|
||||
msg = email.message.EmailMessage()
|
||||
msg["content-type"] = value
|
||||
return msg.get_content_type(), msg["content-type"].params
|
||||
|
||||
|
||||
def _check_file(
|
||||
filename: str, render_warning_stream: _WarningStream
|
||||
) -> Tuple[List[str], bool]:
|
||||
"""Check given distribution."""
|
||||
warnings = []
|
||||
is_ok = True
|
||||
|
||||
package = package_file.PackageFile.from_filename(filename, comment=None)
|
||||
|
||||
metadata = package.metadata_dictionary()
|
||||
description = cast(Optional[str], metadata["description"])
|
||||
description_content_type = cast(Optional[str], metadata["description_content_type"])
|
||||
|
||||
if description_content_type is None:
|
||||
warnings.append(
|
||||
"`long_description_content_type` missing. defaulting to `text/x-rst`."
|
||||
)
|
||||
description_content_type = "text/x-rst"
|
||||
|
||||
content_type, params = _parse_content_type(description_content_type)
|
||||
renderer = _RENDERERS.get(content_type, _RENDERERS[None])
|
||||
|
||||
if description is None or description.rstrip() == "UNKNOWN":
|
||||
warnings.append("`long_description` missing.")
|
||||
elif renderer:
|
||||
rendering_result = renderer.render(
|
||||
description, stream=render_warning_stream, **params
|
||||
)
|
||||
if rendering_result is None:
|
||||
is_ok = False
|
||||
|
||||
return warnings, is_ok
|
||||
|
||||
|
||||
def check(
|
||||
dists: List[str],
|
||||
strict: bool = False,
|
||||
) -> bool:
|
||||
"""Check that a distribution will render correctly on PyPI and display the results.
|
||||
|
||||
This is currently only validates ``long_description``, but more checks could be
|
||||
added; see https://github.com/pypa/twine/projects/2.
|
||||
|
||||
:param dists:
|
||||
The distribution files to check.
|
||||
:param output_stream:
|
||||
The destination of the resulting output.
|
||||
:param strict:
|
||||
If ``True``, treat warnings as errors.
|
||||
|
||||
:return:
|
||||
``True`` if there are rendering errors, otherwise ``False``.
|
||||
"""
|
||||
uploads = [i for i in commands._find_dists(dists) if not i.endswith(".asc")]
|
||||
if not uploads: # Return early, if there are no files to check.
|
||||
logger.error("No files to check.")
|
||||
return False
|
||||
|
||||
failure = False
|
||||
|
||||
for filename in uploads:
|
||||
print(f"Checking {filename}: ", end="")
|
||||
render_warning_stream = _WarningStream()
|
||||
warnings, is_ok = _check_file(filename, render_warning_stream)
|
||||
|
||||
# Print the status and/or error
|
||||
if not is_ok:
|
||||
failure = True
|
||||
print("[red]FAILED[/red]")
|
||||
logger.error(
|
||||
"`long_description` has syntax errors in markup"
|
||||
" and would not be rendered on PyPI."
|
||||
f"\n{render_warning_stream}"
|
||||
)
|
||||
elif warnings:
|
||||
if strict:
|
||||
failure = True
|
||||
print("[red]FAILED due to warnings[/red]")
|
||||
else:
|
||||
print("[yellow]PASSED with warnings[/yellow]")
|
||||
else:
|
||||
print("[green]PASSED[/green]")
|
||||
|
||||
# Print warnings after the status and/or error
|
||||
for message in warnings:
|
||||
logger.warning(message)
|
||||
|
||||
return failure
|
||||
|
||||
|
||||
def main(args: List[str]) -> bool:
|
||||
"""Execute the ``check`` command.
|
||||
|
||||
:param args:
|
||||
The command-line arguments.
|
||||
|
||||
:return:
|
||||
The exit status of the ``check`` command.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog="twine check")
|
||||
parser.add_argument(
|
||||
"dists",
|
||||
nargs="+",
|
||||
metavar="dist",
|
||||
help="The distribution files to check, usually dist/*",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--strict",
|
||||
action="store_true",
|
||||
default=False,
|
||||
required=False,
|
||||
help="Fail on warnings",
|
||||
)
|
||||
|
||||
parsed_args = parser.parse_args(args)
|
||||
|
||||
# Call the check function with the arguments from the command line
|
||||
return check(parsed_args.dists, strict=parsed_args.strict)
|
||||
87
env/lib/python3.10/site-packages/twine/commands/register.py
vendored
Normal file
87
env/lib/python3.10/site-packages/twine/commands/register.py
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
"""Module containing the logic for ``twine register``."""
|
||||
|
||||
# Copyright 2015 Ian Cordasco
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
import os.path
|
||||
from typing import List, cast
|
||||
|
||||
from rich import print
|
||||
|
||||
from twine import exceptions
|
||||
from twine import package as package_file
|
||||
from twine import settings
|
||||
|
||||
|
||||
def register(register_settings: settings.Settings, package: str) -> None:
|
||||
"""Pre-register a package name with a repository before uploading a distribution.
|
||||
|
||||
Pre-registration is not supported on PyPI, so the ``register`` command is only
|
||||
necessary if you are using a different repository that requires it.
|
||||
|
||||
:param register_settings:
|
||||
The configured options relating to repository registration.
|
||||
:param package:
|
||||
The path of the distribution to use for package metadata.
|
||||
|
||||
:raises twine.exceptions.TwineException:
|
||||
The registration failed due to a configuration error.
|
||||
:raises requests.HTTPError:
|
||||
The repository responded with an error.
|
||||
"""
|
||||
repository_url = cast(str, register_settings.repository_config["repository"])
|
||||
print(f"Registering package to {repository_url}")
|
||||
repository = register_settings.create_repository()
|
||||
|
||||
if not os.path.exists(package):
|
||||
raise exceptions.PackageNotFound(
|
||||
f'"{package}" does not exist on the file system.'
|
||||
)
|
||||
|
||||
resp = repository.register(
|
||||
package_file.PackageFile.from_filename(package, register_settings.comment)
|
||||
)
|
||||
repository.close()
|
||||
|
||||
if resp.is_redirect:
|
||||
raise exceptions.RedirectDetected.from_args(
|
||||
repository_url,
|
||||
resp.headers["location"],
|
||||
)
|
||||
|
||||
resp.raise_for_status()
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
"""Execute the ``register`` command.
|
||||
|
||||
:param args:
|
||||
The command-line arguments.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="twine register",
|
||||
description="register operation is not required with PyPI.org",
|
||||
)
|
||||
settings.Settings.register_argparse_arguments(parser)
|
||||
parser.add_argument(
|
||||
"package",
|
||||
metavar="package",
|
||||
help="File from which we read the package metadata.",
|
||||
)
|
||||
|
||||
parsed_args = parser.parse_args(args)
|
||||
register_settings = settings.Settings.from_argparse(parsed_args)
|
||||
|
||||
# Call the register function with the args from the command line
|
||||
register(register_settings, parsed_args.package)
|
||||
298
env/lib/python3.10/site-packages/twine/commands/upload.py
vendored
Normal file
298
env/lib/python3.10/site-packages/twine/commands/upload.py
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
"""Module containing the logic for ``twine upload``."""
|
||||
|
||||
# Copyright 2013 Donald Stufft
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import argparse
|
||||
import fnmatch
|
||||
import logging
|
||||
import os.path
|
||||
from typing import Dict, List, NamedTuple, cast
|
||||
|
||||
import requests
|
||||
from rich import print
|
||||
|
||||
from twine import commands
|
||||
from twine import exceptions
|
||||
from twine import package as package_file
|
||||
from twine import settings
|
||||
from twine import utils
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def skip_upload(
|
||||
response: requests.Response, skip_existing: bool, package: package_file.PackageFile
|
||||
) -> bool:
|
||||
"""Determine if a failed upload is an error or can be safely ignored.
|
||||
|
||||
:param response:
|
||||
The response from attempting to upload ``package`` to a repository.
|
||||
:param skip_existing:
|
||||
If ``True``, use the status and content of ``response`` to determine if the
|
||||
package already exists on the repository. If so, then a failed upload is safe
|
||||
to ignore.
|
||||
:param package:
|
||||
The package that was being uploaded.
|
||||
|
||||
:return:
|
||||
``True`` if a failed upload can be safely ignored, otherwise ``False``.
|
||||
"""
|
||||
if not skip_existing:
|
||||
return False
|
||||
|
||||
status = response.status_code
|
||||
reason = getattr(response, "reason", "").lower()
|
||||
text = getattr(response, "text", "").lower()
|
||||
|
||||
# NOTE(sigmavirus24): PyPI presently returns a 400 status code with the
|
||||
# error message in the reason attribute. Other implementations return a
|
||||
# 403 or 409 status code.
|
||||
return (
|
||||
# pypiserver (https://pypi.org/project/pypiserver)
|
||||
status == 409
|
||||
# PyPI / TestPyPI / GCP Artifact Registry
|
||||
or (status == 400 and any("already exist" in x for x in [reason, text]))
|
||||
# Nexus Repository OSS (https://www.sonatype.com/nexus-repository-oss)
|
||||
or (status == 400 and any("updating asset" in x for x in [reason, text]))
|
||||
# Artifactory (https://jfrog.com/artifactory/)
|
||||
or (status == 403 and "overwrite artifact" in text)
|
||||
# Gitlab Enterprise Edition (https://about.gitlab.com)
|
||||
or (status == 400 and "already been taken" in text)
|
||||
)
|
||||
|
||||
|
||||
def _make_package(
|
||||
filename: str,
|
||||
signatures: Dict[str, str],
|
||||
attestations: List[str],
|
||||
upload_settings: settings.Settings,
|
||||
) -> package_file.PackageFile:
|
||||
"""Create and sign a package, based off of filename, signatures, and settings.
|
||||
|
||||
Additionally, any supplied attestations are attached to the package when
|
||||
the settings indicate to do so.
|
||||
"""
|
||||
package = package_file.PackageFile.from_filename(filename, upload_settings.comment)
|
||||
|
||||
signed_name = package.signed_basefilename
|
||||
if signed_name in signatures:
|
||||
package.add_gpg_signature(signatures[signed_name], signed_name)
|
||||
elif upload_settings.sign:
|
||||
package.sign(upload_settings.sign_with, upload_settings.identity)
|
||||
|
||||
# Attestations are only attached if explicitly requested with `--attestations`.
|
||||
if upload_settings.attestations:
|
||||
# Passing `--attestations` without any actual attestations present
|
||||
# indicates user confusion, so we fail rather than silently allowing it.
|
||||
if not attestations:
|
||||
raise exceptions.InvalidDistribution(
|
||||
"Upload with attestations requested, but "
|
||||
f"{filename} has no associated attestations"
|
||||
)
|
||||
package.add_attestations(attestations)
|
||||
|
||||
file_size = utils.get_file_size(package.filename)
|
||||
logger.info(f"{package.filename} ({file_size})")
|
||||
if package.gpg_signature:
|
||||
logger.info(f"Signed with {package.signed_filename}")
|
||||
|
||||
return package
|
||||
|
||||
|
||||
class Inputs(NamedTuple):
|
||||
"""Represents structured user inputs."""
|
||||
|
||||
dists: List[str]
|
||||
signatures: Dict[str, str]
|
||||
attestations_by_dist: Dict[str, List[str]]
|
||||
|
||||
|
||||
def _split_inputs(
|
||||
inputs: List[str],
|
||||
) -> Inputs:
|
||||
"""
|
||||
Split the unstructured list of input files provided by the user into groups.
|
||||
|
||||
Three groups are returned: upload files (i.e. dists), signatures, and attestations.
|
||||
|
||||
Upload files are returned as a linear list, signatures are returned as a
|
||||
dict of ``basename -> path``, and attestations are returned as a dict of
|
||||
``dist-path -> [attestation-path]``.
|
||||
"""
|
||||
signatures = {os.path.basename(i): i for i in fnmatch.filter(inputs, "*.asc")}
|
||||
attestations = fnmatch.filter(inputs, "*.*.attestation")
|
||||
dists = [
|
||||
dist
|
||||
for dist in inputs
|
||||
if dist not in (set(signatures.values()) | set(attestations))
|
||||
]
|
||||
|
||||
attestations_by_dist = {}
|
||||
for dist in dists:
|
||||
dist_basename = os.path.basename(dist)
|
||||
attestations_by_dist[dist] = [
|
||||
a for a in attestations if os.path.basename(a).startswith(dist_basename)
|
||||
]
|
||||
|
||||
return Inputs(dists, signatures, attestations_by_dist)
|
||||
|
||||
|
||||
def upload(upload_settings: settings.Settings, dists: List[str]) -> None:
|
||||
"""Upload one or more distributions to a repository, and display the progress.
|
||||
|
||||
If a package already exists on the repository, most repositories will return an
|
||||
error response. However, if ``upload_settings.skip_existing`` is ``True``, a message
|
||||
will be displayed and any remaining distributions will be uploaded.
|
||||
|
||||
For known repositories (like PyPI), the web URLs of successfully uploaded packages
|
||||
will be displayed.
|
||||
|
||||
:param upload_settings:
|
||||
The configured options related to uploading to a repository.
|
||||
:param dists:
|
||||
The distribution files to upload to the repository. This can also include
|
||||
``.asc`` and ``.attestation`` files, which will be added to their respective
|
||||
file uploads.
|
||||
|
||||
:raises twine.exceptions.TwineException:
|
||||
The upload failed due to a configuration error.
|
||||
:raises requests.HTTPError:
|
||||
The repository responded with an error.
|
||||
"""
|
||||
upload_settings.check_repository_url()
|
||||
repository_url = cast(str, upload_settings.repository_config["repository"])
|
||||
|
||||
# Attestations are only supported on PyPI and TestPyPI at the moment.
|
||||
# We warn instead of failing to allow twine to be used in local testing
|
||||
# setups (where the PyPI deployment doesn't have a well-known domain).
|
||||
if upload_settings.attestations and not repository_url.startswith(
|
||||
(utils.DEFAULT_REPOSITORY, utils.TEST_REPOSITORY)
|
||||
):
|
||||
logger.warning(
|
||||
"Only PyPI and TestPyPI support attestations; "
|
||||
"if you experience failures, remove the --attestations flag and "
|
||||
"re-try this command"
|
||||
)
|
||||
|
||||
dists = commands._find_dists(dists)
|
||||
# Determine if the user has passed in pre-signed distributions or any attestations.
|
||||
uploads, signatures, attestations_by_dist = _split_inputs(dists)
|
||||
|
||||
print(f"Uploading distributions to {utils.sanitize_url(repository_url)}")
|
||||
|
||||
packages_to_upload = [
|
||||
_make_package(
|
||||
filename, signatures, attestations_by_dist[filename], upload_settings
|
||||
)
|
||||
for filename in uploads
|
||||
]
|
||||
|
||||
if any(p.gpg_signature for p in packages_to_upload):
|
||||
if repository_url.startswith((utils.DEFAULT_REPOSITORY, utils.TEST_REPOSITORY)):
|
||||
# Warn the user if they're trying to upload a PGP signature to PyPI
|
||||
# or TestPyPI, which will (as of May 2023) ignore it.
|
||||
# This warning is currently limited to just those indices, since other
|
||||
# indices may still support PGP signatures.
|
||||
logger.warning(
|
||||
"One or more packages has an associated PGP signature; "
|
||||
"these will be silently ignored by the index"
|
||||
)
|
||||
else:
|
||||
# On other indices, warn the user that twine is considering
|
||||
# removing PGP support outright.
|
||||
logger.warning(
|
||||
"One or more packages has an associated PGP signature; "
|
||||
"a future version of twine may silently ignore these. "
|
||||
"See https://github.com/pypa/twine/issues/1009 for more "
|
||||
"information"
|
||||
)
|
||||
|
||||
repository = upload_settings.create_repository()
|
||||
uploaded_packages = []
|
||||
|
||||
if signatures and not packages_to_upload:
|
||||
raise exceptions.InvalidDistribution(
|
||||
"Cannot upload signed files by themselves, must upload with a "
|
||||
"corresponding distribution file."
|
||||
)
|
||||
|
||||
for package in packages_to_upload:
|
||||
skip_message = (
|
||||
f"Skipping {package.basefilename} because it appears to already exist"
|
||||
)
|
||||
|
||||
# Note: The skip_existing check *needs* to be first, because otherwise
|
||||
# we're going to generate extra HTTP requests against a hardcoded
|
||||
# URL for no reason.
|
||||
if upload_settings.skip_existing and repository.package_is_uploaded(package):
|
||||
logger.warning(skip_message)
|
||||
continue
|
||||
|
||||
resp = repository.upload(package)
|
||||
logger.info(f"Response from {resp.url}:\n{resp.status_code} {resp.reason}")
|
||||
if resp.text:
|
||||
logger.info(resp.text)
|
||||
|
||||
# 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 exceptions.RedirectDetected.from_args(
|
||||
utils.sanitize_url(repository_url),
|
||||
utils.sanitize_url(resp.headers["location"]),
|
||||
)
|
||||
|
||||
if skip_upload(resp, upload_settings.skip_existing, package):
|
||||
logger.warning(skip_message)
|
||||
continue
|
||||
|
||||
utils.check_status_code(resp, upload_settings.verbose)
|
||||
|
||||
uploaded_packages.append(package)
|
||||
|
||||
release_urls = repository.release_urls(uploaded_packages)
|
||||
if release_urls:
|
||||
print("\n[green]View at:")
|
||||
for url in release_urls:
|
||||
print(url)
|
||||
|
||||
# Bug 28. Try to silence a ResourceWarning by clearing the connection
|
||||
# pool.
|
||||
repository.close()
|
||||
|
||||
|
||||
def main(args: List[str]) -> None:
|
||||
"""Execute the ``upload`` command.
|
||||
|
||||
:param args:
|
||||
The command-line arguments.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(prog="twine upload")
|
||||
settings.Settings.register_argparse_arguments(parser)
|
||||
parser.add_argument(
|
||||
"dists",
|
||||
nargs="+",
|
||||
metavar="dist",
|
||||
help="The distribution files to upload to the repository "
|
||||
"(package index). Usually dist/* . May additionally contain "
|
||||
"a .asc file to include an existing signature with the "
|
||||
"file upload.",
|
||||
)
|
||||
|
||||
parsed_args = parser.parse_args(args)
|
||||
upload_settings = settings.Settings.from_argparse(parsed_args)
|
||||
|
||||
# Call the upload function with the arguments from the command line
|
||||
return upload(upload_settings, parsed_args.dists)
|
||||
Reference in New Issue
Block a user