diff --git a/twine/commands/upload.py b/twine/commands/upload.py
index 032cc21..2bd4a52 100644
--- a/twine/commands/upload.py
+++ b/twine/commands/upload.py
@@ -67,11 +67,13 @@ def upload(dists, repository, sign, identity, username, password, comment,
     if not sign and identity:
         raise ValueError("sign must be given along with identity")
 
+    dists = find_dists(dists)
+
     # 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")]
+    uploads = [i for i in dists if not i.endswith(".asc")]
 
     config = utils.get_repository_from_config(config_file, repository)
 
@@ -86,24 +88,14 @@ def upload(dists, repository, sign, identity, username, password, comment,
 
     repository = Repository(config["repository"], username, password)
 
-    uploads = find_dists(dists)
-
     for filename in uploads:
         package = PackageFile.from_filename(filename, comment)
-        # Sign the dist if requested
-        # if sign:
-        #     sign_file(sign_with, filename, identity)
 
-        # signed_name = os.path.basename(filename) + ".asc"
-        signed_name = package.signed_filename
+        signed_name = package.signed_basefilename
         if signed_name in signatures:
-            with open(signatures[signed_name], "rb") as gpg:
-                package.gpg_signature = (signed_name, gpg.read())
-                # data["gpg_signature"] = (signed_name, gpg.read())
+            package.add_gpg_signature(signatures[signed_name], signed_name)
         elif sign:
             package.sign(sign_with, identity)
-            # with open(filename + ".asc", "rb") as gpg:
-            #     data["gpg_signature"] = (signed_name, gpg.read())
 
         resp = repository.upload(package)
 
diff --git a/twine/package.py b/twine/package.py
index e80116a..e062c71 100644
--- a/twine/package.py
+++ b/twine/package.py
@@ -49,6 +49,7 @@ class PackageFile(object):
         self.filetype = filetype
         self.safe_name = pkg_resources.safe_name(metadata.name)
         self.signed_filename = self.filename + '.asc'
+        self.signed_basefilename = self.basefilename + '.asc'
         self.gpg_signature = None
 
         md5_hash = hashlib.md5()
@@ -141,6 +142,13 @@ class PackageFile(object):
 
         return data
 
+    def add_gpg_signature(self, signature_filepath, signature_filename):
+        if self.gpg_signature is not None:
+            raise ValueError('GPG Signature can only be added once')
+
+        with open(signature_filepath, "rb") as gpg:
+            self.gpg_signature = (signature_filename, gpg.read())
+
     def sign(self, sign_with, identity):
         print("Signing {0}".format(self.basefilename))
         gpg_args = (sign_with, "--detach-sign")
@@ -149,5 +157,4 @@ class PackageFile(object):
         gpg_args += ("-a", self.filename)
         subprocess.check_call(gpg_args)
 
-        with open(self.signed_filename, "rb") as gpg:
-            self.pg_signature = (self.signed_filename, gpg.read())
+        self.add_gpg_signature(self.signed_filename, self.signed_basefilename)

"twine upload" usually fails to upload .asc files
On the most recent Foolscap release, I signed the sdist tarballs as usual, and tried to use twine to upload everything:

```
% python setup.py sdist --formats=zip,gztar bdist_wheel
% ls dist
foolscap-0.9.1-py2-none-any.whl		foolscap-0.9.1.tar.gz			foolscap-0.9.1.zip
% (gpg sign them all)
% ls dist
foolscap-0.9.1-py2-none-any.whl		foolscap-0.9.1.tar.gz			foolscap-0.9.1.zip
foolscap-0.9.1-py2-none-any.whl.asc	foolscap-0.9.1.tar.gz.asc		foolscap-0.9.1.zip.asc
% python setup.py register
% twine upload dist/*
```

Twine uploaded the tar/zip/whl files, but ignored the .asc signatures, and the resulting [pypi page](https://pypi.python.org/pypi/foolscap/0.9.1) doesn't show them either.

After some digging, I found that `twine/upload.py upload()` will only use pre-signed .asc files if the command was run like `cd dist; twine upload *`. It won't use them if it was run as `cd dist; twine upload ./*` or `twine upload dist/*`. The problem seems to be that the `signatures` dictionary is indexed by the basename of the signature files, while the lookup key is using the full (original) filename of the tarball/etc with ".asc" appended.

I think it might be simpler and safer to have the code just check for a neighboring .asc file inside the upload loop, something like:

```python
for filename in uploads:
    package = PackageFile.from_filename(filename, comment)
    maybe_sig = package.signed_filename + ".asc"
    if os.path.exists(maybe_sig):
        package.gpg_signature = (os.path.basename(maybe_sig), sigdata)
    ...
```

I'll write up a patch for this. I started to look for a way of adding a test, but the code that looks for signatures happens deep enough in `upload()` that it'd need a oversized mock "Repository" class to exercise the .asc check without actually uploading anything. I'm not sure what the best way to approach the test would be.

diff --git a/tests/test_package.py b/tests/test_package.py
index fcc827a..d28eec1 100644
--- a/tests/test_package.py
+++ b/tests/test_package.py
@@ -55,3 +55,18 @@ def test_sign_file_with_identity(monkeypatch):
         pass
     args = ('gpg', '--detach-sign', '--local-user', 'identity', '-a', filename)
     assert replaced_check_call.calls == [pretend.call(args)]
+
+
+def test_package_signed_name_is_correct():
+    filename = 'tests/fixtures/deprecated-pypirc'
+
+    pkg = package.PackageFile(
+        filename=filename,
+        comment=None,
+        metadata=pretend.stub(name="deprecated-pypirc"),
+        python_version=None,
+        filetype=None
+    )
+
+    assert pkg.signed_basefilename == "deprecated-pypirc.asc"
+    assert pkg.signed_filename == (filename + '.asc')
diff --git a/tests/test_upload.py b/tests/test_upload.py
index b40660f..7f99510 100644
--- a/tests/test_upload.py
+++ b/tests/test_upload.py
@@ -66,6 +66,7 @@ def test_find_dists_handles_real_files():
 
 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("""
@@ -75,7 +76,7 @@ def test_get_config_old_format(tmpdir):
         """))
 
     try:
-        upload.upload(dists="foo", repository="pypi", sign=None, identity=None,
+        upload.upload(dists=dists, 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:

pip install -e .
parse_log_pytest
pytest
pytest coverage pretend flake8
apt-get update apt-get install -y gcc
3.9
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
certifi==2025.1.31
charset-normalizer==3.4.1
coverage==7.8.0
exceptiongroup @ file:///croot/exceptiongroup_1706031385326/work
flake8==7.2.0
idna==3.10
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
mccabe==0.7.0
packaging @ file:///croot/packaging_1734472117206/work
pkginfo==1.12.1.2
pluggy @ file:///croot/pluggy_1733169602837/work
pretend==1.0.9
pycodestyle==2.13.0
pyflakes==3.3.1
pytest @ file:///croot/pytest_1738938843180/work
requests==2.32.3
requests-toolbelt==1.0.0
tomli @ file:///opt/conda/conda-bld/tomli_1657175507142/work
-e git+https://github.com/pypa/twine.git@b34f042da78aed22b6e512df61b495638b06ba03#egg=twine
urllib3==2.3.0

name: twine
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - exceptiongroup=1.2.0=py39h06a4308_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.4.4=h6a678d5_1
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=3.0.16=h5eee18b_0
  - packaging=24.2=py39h06a4308_0
  - pip=25.0=py39h06a4308_0
  - pluggy=1.5.0=py39h06a4308_0
  - pytest=8.3.4=py39h06a4308_0
  - python=3.9.21=he870216_1
  - readline=8.2=h5eee18b_0
  - setuptools=75.8.0=py39h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - tomli=2.0.1=py39h06a4308_0
  - tzdata=2025a=h04d1e81_0
  - wheel=0.45.1=py39h06a4308_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - certifi==2025.1.31
      - charset-normalizer==3.4.1
      - coverage==7.8.0
      - flake8==7.2.0
      - idna==3.10
      - mccabe==0.7.0
      - pkginfo==1.12.1.2
      - pretend==1.0.9
      - pycodestyle==2.13.0
      - pyflakes==3.3.1
      - requests==2.32.3
      - requests-toolbelt==1.0.0
      - urllib3==2.3.0
prefix: /opt/conda/envs/twine

tests/test_package.py::test_package_signed_name_is_correct
tests/test_package.py::test_sign_file tests/test_package.py::test_sign_file_with_identity tests/test_upload.py::test_ensure_wheel_files_uploaded_first tests/test_upload.py::test_ensure_if_no_wheel_files tests/test_upload.py::test_find_dists_expands_globs tests/test_upload.py::test_find_dists_errors_on_invalid_globs tests/test_upload.py::test_find_dists_handles_real_files tests/test_upload.py::test_get_config_old_format tests/test_upload.py::test_skip_existing_skips_files_already_on_PyPI tests/test_upload.py::test_skip_upload_respects_skip_existing
twine/package.py twine/commands/upload.py
twine/package.py twine/commands/upload.py