Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adopt Python 3.7+ syntax #882

Merged
merged 2 commits into from Mar 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions tests/test_auth.py
Expand Up @@ -17,7 +17,7 @@ def test_get_password_keyring_overrides_prompt(monkeypatch, config):
class MockKeyring:
@staticmethod
def get_password(system, user):
return "{user}@{system} sekure pa55word".format(**locals())
return f"{user}@{system} sekure pa55word"

monkeypatch.setattr(auth, "keyring", MockKeyring)

Expand Down Expand Up @@ -68,7 +68,7 @@ class MockKeyring:
@staticmethod
def get_credential(system, user):
return auth.CredentialInput(
"real_user", "real_user@{system} sekure pa55word".format(**locals())
"real_user", f"real_user@{system} sekure pa55word"
)

@staticmethod
Expand Down
92 changes: 45 additions & 47 deletions tests/test_package.py
Expand Up @@ -36,7 +36,7 @@ def test_sign_file(monkeypatch):
)
try:
package.sign("gpg2", None)
except IOError:
except OSError:
pass
args = ("gpg2", "--detach-sign", "-a", filename)
assert replaced_check_call.calls == [pretend.call(args)]
Expand All @@ -56,7 +56,7 @@ def test_sign_file_with_identity(monkeypatch):
)
try:
package.sign("gpg", "identity")
except IOError:
except OSError:
pass
args = ("gpg", "--detach-sign", "--local-user", "identity", "-a", filename)
assert replaced_check_call.calls == [pretend.call(args)]
Expand Down Expand Up @@ -139,51 +139,49 @@ def test_package_safe_name_is_correct(pkg_name, expected_name):
def test_metadata_dictionary_keys():
"""Merge multiple sources of metadata into a single dictionary."""
package = package_file.PackageFile.from_filename(helpers.SDIST_FIXTURE, None)
assert set(package.metadata_dictionary()) == set(
[
# identify release
"name",
"version",
# file content
"filetype",
"pyversion",
# additional meta-data
"metadata_version",
"summary",
"home_page",
"author",
"author_email",
"maintainer",
"maintainer_email",
"license",
"description",
"keywords",
"platform",
"classifiers",
"download_url",
"supported_platform",
"comment",
"md5_digest",
"sha256_digest",
"blake2_256_digest",
# PEP 314
"provides",
"requires",
"obsoletes",
# Metadata 1.2
"project_urls",
"provides_dist",
"obsoletes_dist",
"requires_dist",
"requires_external",
"requires_python",
# Metadata 2.1
"provides_extras",
"description_content_type",
# Metadata 2.2
"dynamic",
]
)
assert set(package.metadata_dictionary()) == {
# identify release
"name",
"version",
# file content
"filetype",
"pyversion",
# additional meta-data
"metadata_version",
"summary",
"home_page",
"author",
"author_email",
"maintainer",
"maintainer_email",
"license",
"description",
"keywords",
"platform",
"classifiers",
"download_url",
"supported_platform",
"comment",
"md5_digest",
"sha256_digest",
"blake2_256_digest",
# PEP 314
"provides",
"requires",
"obsoletes",
# Metadata 1.2
"project_urls",
"provides_dist",
"obsoletes_dist",
"requires_dist",
"requires_external",
"requires_python",
# Metadata 2.1
"provides_extras",
"description_content_type",
# Metadata 2.2
"dynamic",
}


@pytest.mark.parametrize("gpg_signature", [(None), (pretend.stub())])
Expand Down
2 changes: 0 additions & 2 deletions tests/test_register.py
@@ -1,5 +1,3 @@
from __future__ import unicode_literals

import pretend
import pytest

Expand Down
2 changes: 1 addition & 1 deletion twine/cli.py
Expand Up @@ -97,7 +97,7 @@ def dispatch(argv: List[str]) -> Any:
parser.add_argument(
"--version",
action="version",
version="%(prog)s version {} ({})".format(twine.__version__, dep_versions()),
version=f"%(prog)s version {twine.__version__} ({dep_versions()})",
)
parser.add_argument(
"--no-color",
Expand Down
4 changes: 2 additions & 2 deletions twine/repository.py
Expand Up @@ -214,7 +214,7 @@ def package_is_uploaded(
releases = self._releases_json_data.get(safe_name)

if releases is None:
url = "{url}pypi/{package}/json".format(package=safe_name, url=LEGACY_PYPI)
url = f"{LEGACY_PYPI}pypi/{safe_name}/json"
headers = {"Accept": "application/json"}
response = self.session.get(url, headers=headers)
if response.status_code == 200:
Expand All @@ -240,7 +240,7 @@ def release_urls(self, packages: List[package_file.PackageFile]) -> Set[str]:
return set()

return {
"{}project/{}/{}/".format(url, package.safe_name, package.metadata.version)
f"{url}project/{package.safe_name}/{package.metadata.version}/"
for package in packages
}

Expand Down
4 changes: 1 addition & 3 deletions twine/settings.py
Expand Up @@ -11,8 +11,6 @@
# 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
from __future__ import annotations

# limitations under the License.
import argparse
import contextlib
Expand Down Expand Up @@ -138,7 +136,7 @@ def password(self) -> Optional[str]:
# Workaround for https://github.com/python/mypy/issues/5858
return cast(Optional[str], self.auth.password)

def _allow_noninteractive(self) -> contextlib.AbstractContextManager[None]:
def _allow_noninteractive(self) -> "contextlib.AbstractContextManager[None]":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did this become quoted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I was referring to here:

I found a workaround for the one instance where __future__ annotations was used.

The quotes avoid a syntax error in Python < 3.9 (which introduces typed generics), similar to forward references:

twine/twine/settings.py

Lines 276 to 281 in a0ba32d

def from_argparse(cls, args: argparse.Namespace) -> "Settings":
"""Generate the Settings from parsed arguments."""
settings = vars(args)
settings["repository_name"] = settings.pop("repository")
settings["cacert"] = settings.pop("cert")
return cls(**settings)

My understanding is that __future__ annotations treats type annotations as strings, so this mirrors that behavior. It feels more consistent with the rest of the project, and avoids pyupgrade making other typing rewrites when that import is present.

"""Bypass NonInteractive error when client cert is present."""
suppressed = (exceptions.NonInteractive,) if self.client_cert else ()
return contextlib.suppress(*suppressed)
Expand Down
2 changes: 1 addition & 1 deletion twine/wheel.py
Expand Up @@ -53,7 +53,7 @@ def py_version(self) -> str:
def find_candidate_metadata_files(names: List[str]) -> List[List[str]]:
"""Filter files that may be METADATA files."""
tuples = [x.split("/") for x in names if "METADATA" in x]
return [x[1] for x in sorted([(len(x), x) for x in tuples])]
return [x[1] for x in sorted((len(x), x) for x in tuples)]

def read(self) -> bytes:
fqn = os.path.abspath(os.path.normpath(self.filename))
Expand Down
2 changes: 1 addition & 1 deletion twine/wininst.py
Expand Up @@ -47,7 +47,7 @@ def read_file(name: str) -> bytes:
for x in names
if x.endswith(".egg-info") or x.endswith("PKG-INFO")
]
schwarz = sorted([(len(x), x) for x in tuples])
schwarz = sorted((len(x), x) for x in tuples)
for path in [x[1] for x in schwarz]:
candidate = "/".join(path)
data = read_file(candidate)
Expand Down