Skip to content

Commit ce38691

Browse files
authored
Merge pull request #2 from chriskuehl/fix-type-checking
Fix types
2 parents 7357462 + 96eaafd commit ce38691

File tree

5 files changed

+88
-28
lines changed

5 files changed

+88
-28
lines changed

poetry.lock

Lines changed: 41 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pypi_browser/app.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import mimetypes
66
import os.path
77
import re
8+
import typing
89

910
import fluffy_code.code
1011
import fluffy_code.prebuilt_styles
@@ -60,7 +61,11 @@
6061

6162
class CacheControlHeaderMiddleware(BaseHTTPMiddleware):
6263

63-
async def dispatch(self, request, call_next):
64+
async def dispatch(
65+
self,
66+
request: Request,
67+
call_next: typing.Callable[[Request], typing.Awaitable[Response]],
68+
) -> Response:
6469
response = await call_next(request)
6570
# TODO: There should be a better way to do this...
6671
response.headers['Cache-Control'] = 'no-cache'
@@ -267,9 +272,9 @@ async def package_file_archive_path(request: Request) -> Response:
267272
('Mode', Markup(f'<tt>{entry.mode}</tt>')),
268273
)
269274

270-
def _transfer_raw():
275+
def _transfer_raw() -> Response:
271276
"""Return the file verbatim."""
272-
async def transfer_file():
277+
async def transfer_file() -> typing.AsyncIterator[bytes]:
273278
async with package.open_from_archive(archive_path) as f:
274279
data = None
275280
while data is None or len(data) > 0:
@@ -306,10 +311,15 @@ async def transfer_file():
306311
style_config = fluffy_code.prebuilt_styles.default_style()
307312

308313
try:
309-
lexer = pygments.lexers.guess_lexer_for_filename(
310-
archive_path,
311-
text,
312-
stripnl=False,
314+
# TODO: Remove this cast once
315+
# https://github.com/python/typeshed/pull/8777 is merged.
316+
lexer = typing.cast(
317+
pygments.lexer.Lexer,
318+
pygments.lexers.guess_lexer_for_filename(
319+
archive_path,
320+
text,
321+
stripnl=False,
322+
),
313323
)
314324
except pygments.lexers.ClassNotFound:
315325
lexer = pygments.lexers.special.TextLexer(stripnl=False)

pypi_browser/packaging.py

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import typing
1010
import zipfile
1111
from dataclasses import dataclass
12+
from types import TracebackType
1213

1314

1415
def pep426_normalize(package_name: str) -> str:
@@ -63,23 +64,25 @@ def _package_entries_from_tarball(path: str) -> typing.Set[PackageEntry]:
6364
}
6465

6566

66-
ArchiveFile = typing.Union[zipfile.ZipExtFile]
67-
68-
6967
class AsyncArchiveFile:
7068

71-
file_: ArchiveFile
69+
file_: typing.IO[bytes]
7270

73-
def __init__(self, file_: ArchiveFile) -> None:
71+
def __init__(self, file_: typing.IO[bytes]) -> None:
7472
self.file_ = file_
7573

7674
async def __aenter__(self) -> 'AsyncArchiveFile':
7775
return self
7876

79-
async def __aexit__(self, exc_t, exc_v, exc_tb) -> None:
77+
async def __aexit__(
78+
self,
79+
exc_t: typing.Optional[typing.Type[BaseException]],
80+
exc_v: typing.Optional[BaseException],
81+
exc_tb: typing.Optional[TracebackType],
82+
) -> None:
8083
await asyncio.to_thread(self.file_.close)
8184

82-
async def read(self, n_bytes: typing.Optional[int] = None) -> bytes:
85+
async def read(self, n_bytes: int = -1) -> bytes:
8386
return await asyncio.to_thread(self.file_.read, n_bytes)
8487

8588

@@ -123,21 +126,22 @@ async def entries(self) -> typing.Set[PackageEntry]:
123126
raise AssertionError(self.package_format)
124127

125128
@contextlib.asynccontextmanager
126-
async def open_from_archive(self, path: str) -> str:
129+
async def open_from_archive(self, path: str) -> typing.AsyncIterator[AsyncArchiveFile]:
127130
if self.package_format is PackageFormat.ZIPFILE:
128131
zf = await asyncio.to_thread(zipfile.ZipFile, self.path)
129-
archive_file = await asyncio.to_thread(zf.open, path)
130132
try:
131-
async with AsyncArchiveFile(archive_file) as zip_archive_file:
132-
yield zip_archive_file
133+
zip_archive_file = await asyncio.to_thread(zf.open, path)
134+
async with AsyncArchiveFile(zip_archive_file) as wrapped:
135+
yield wrapped
133136
finally:
134137
await asyncio.to_thread(zf.close)
135138
elif self.package_format is PackageFormat.TARBALL:
136139
tf = await asyncio.to_thread(tarfile.open, self.path)
137-
archive_file = await asyncio.to_thread(tf.extractfile, path)
138140
try:
139-
async with AsyncArchiveFile(archive_file) as zip_archive_file:
140-
yield zip_archive_file
141+
tar_archive_file = await asyncio.to_thread(tf.extractfile, path)
142+
assert tar_archive_file is not None, path
143+
async with AsyncArchiveFile(tar_archive_file) as wrapped:
144+
yield wrapped
141145
finally:
142146
await asyncio.to_thread(tf.close)
143147
else:

pypi_browser/pypi.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ class PackageDoesNotExist(Exception):
2020
pass
2121

2222

23-
async def package_metadata(config: PyPIConfig, client: httpx.AsyncClient, package: str) -> typing.Dict:
23+
async def package_metadata(
24+
config: PyPIConfig,
25+
client: httpx.AsyncClient,
26+
package: str,
27+
) -> typing.Dict[typing.Any, typing.Any]:
2428
resp = await client.get(f'{config.pypi_url}/pypi/{package}/json')
2529
if resp.status_code == 404:
2630
raise PackageDoesNotExist(package)
@@ -54,16 +58,17 @@ def _storage_path(config: PyPIConfig, package: str, filename: str) -> str:
5458

5559

5660
@contextlib.asynccontextmanager
57-
async def _atomic_file(path: str, mode: str = 'w') -> typing.Any:
58-
async with aiofiles.tempfile.NamedTemporaryFile(mode, dir=os.path.dirname(path), delete=False) as f:
61+
async def _atomic_file(path: str) -> typing.AsyncIterator[aiofiles.threadpool.binary.AsyncBufferedIOBase]:
62+
async with aiofiles.tempfile.NamedTemporaryFile('wb', dir=os.path.dirname(path), delete=False) as f:
63+
tmp_path = typing.cast(str, f.name)
5964
try:
6065
yield f
6166
except BaseException:
62-
await aiofiles.os.remove(f.name)
67+
await aiofiles.os.remove(tmp_path)
6368
raise
6469
else:
6570
# This is atomic since the temporary file was created in the same directory.
66-
await aiofiles.os.rename(f.name, path)
71+
await aiofiles.os.rename(tmp_path, path)
6772

6873

6974
async def downloaded_file_path(config: PyPIConfig, package: str, filename: str) -> str:
@@ -91,7 +96,7 @@ async def downloaded_file_path(config: PyPIConfig, package: str, filename: str)
9196

9297
await aiofiles.os.makedirs(os.path.dirname(stored_path), exist_ok=True)
9398

94-
async with _atomic_file(stored_path, 'wb') as f:
99+
async with _atomic_file(stored_path) as f:
95100
async with client.stream('GET', url) as resp:
96101
resp.raise_for_status()
97102
async for chunk in resp.aiter_bytes():

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pytest = "^7.1.3"
2727
mypy = "^0.971"
2828
coverage = "^6.4.4"
2929
types-aiofiles = "^22.1.0"
30+
types-Pygments = "^2.13.0"
3031

3132
[build-system]
3233
requires = ["poetry-core"]

0 commit comments

Comments
 (0)