4
4
import os .path
5
5
import re
6
6
7
- import pygments .lexers
8
- import pygments .lexers .special
9
7
import fluffy_code .code
10
8
import fluffy_code .prebuilt_styles
9
+ import pygments .lexers .special
11
10
from identify import identify
12
- from starlette .middleware .base import BaseHTTPMiddleware
13
- from starlette .middleware import Middleware
14
11
from starlette .applications import Starlette
15
- from starlette .staticfiles import StaticFiles
12
+ from starlette .middleware import Middleware
13
+ from starlette .middleware .base import BaseHTTPMiddleware
16
14
from starlette .requests import Request
17
- from starlette .responses import Response
18
15
from starlette .responses import PlainTextResponse
19
16
from starlette .responses import RedirectResponse
17
+ from starlette .responses import Response
20
18
from starlette .responses import StreamingResponse
21
- from starlette .routing import Route
19
+ from starlette .staticfiles import StaticFiles
22
20
from starlette .templating import Jinja2Templates
23
21
24
22
from pypi_view import packaging
25
23
from pypi_view import pypi
26
24
27
25
PACKAGE_TYPE_NOT_SUPPORTED_ERROR = (
28
- " Sorry, this package type is not yet supported (only .zip and .whl supported currently)."
26
+ ' Sorry, this package type is not yet supported (only .zip and .whl supported currently).'
29
27
)
30
28
TEXT_RENDER_FILESIZE_LIMIT = 20 * 1024 # 20 KiB
31
29
@@ -66,63 +64,63 @@ class CacheControlHeaderMiddleware(BaseHTTPMiddleware):
66
64
async def dispatch (self , request , call_next ):
67
65
response = await call_next (request )
68
66
# TODO: There should be a better way to do this...
69
- response .headers [" Cache-Control" ] = " no-cache"
67
+ response .headers [' Cache-Control' ] = ' no-cache'
70
68
return response
71
69
72
70
73
71
app = Starlette (
74
- debug = os .environ .get (" PYPI_VIEW_DEBUG" ) == "1" ,
72
+ debug = os .environ .get (' PYPI_VIEW_DEBUG' ) == '1' ,
75
73
middleware = [
76
74
Middleware (CacheControlHeaderMiddleware ),
77
75
],
78
76
)
79
77
app .mount ('/static' , StaticFiles (directory = os .path .join (install_root , 'static' )), name = 'static' )
80
78
81
79
templates = Jinja2Templates (
82
- directory = os .path .join (install_root , " templates" ),
80
+ directory = os .path .join (install_root , ' templates' ),
83
81
)
84
82
85
83
86
84
@app .route ('/' )
87
85
async def home (request : Request ) -> Response :
88
- return templates .TemplateResponse (" home.html" , {" request" : request })
86
+ return templates .TemplateResponse (' home.html' , {' request' : request })
89
87
90
88
91
89
@app .route ('/package/{package}' )
92
90
async def package (request : Request ) -> Response :
93
- package_name = request .path_params [" package" ]
91
+ package_name = request .path_params [' package' ]
94
92
try :
95
93
version_to_files = await pypi .files_for_package (package_name )
96
94
except pypi .PackageDoesNotExist :
97
95
return PlainTextResponse (
98
- f" Package { package_name !r} does not exist on PyPI." ,
96
+ f' Package { package_name !r} does not exist on PyPI.' ,
99
97
status_code = 404 ,
100
98
)
101
99
else :
102
100
return templates .TemplateResponse (
103
- " package.html" ,
101
+ ' package.html' ,
104
102
{
105
- " request" : request ,
106
- " package" : package_name ,
107
- " version_to_files" : version_to_files ,
103
+ ' request' : request ,
104
+ ' package' : package_name ,
105
+ ' version_to_files' : version_to_files ,
108
106
},
109
107
)
110
108
111
109
112
110
@app .route ('/package/{package}/{filename}' )
113
111
async def package_file (request : Request ) -> Response :
114
- package_name = request .path_params [" package" ]
115
- file_name = request .path_params [" filename" ]
112
+ package_name = request .path_params [' package' ]
113
+ file_name = request .path_params [' filename' ]
116
114
try :
117
115
archive = await pypi .downloaded_file_path (package_name , file_name )
118
116
except pypi .PackageDoesNotExist :
119
117
return PlainTextResponse (
120
- f" Package { package_name !r} does not exist on PyPI." ,
118
+ f' Package { package_name !r} does not exist on PyPI.' ,
121
119
status_code = 404 ,
122
120
)
123
121
except pypi .CannotFindFileError :
124
122
return PlainTextResponse (
125
- f" File { file_name !r} does not exist for package { package_name !r} ." ,
123
+ f' File { file_name !r} does not exist for package { package_name !r} .' ,
126
124
status_code = 404 ,
127
125
)
128
126
@@ -138,14 +136,15 @@ async def package_file(request: Request) -> Response:
138
136
metadata_entries = [
139
137
entry
140
138
for entry in entries
141
- if re .match (r'(?:[^/]+\.dist-info/METADATA|^[^/]+/PKG-INFO)$' , entry .path ) and entry .size <= TEXT_RENDER_FILESIZE_LIMIT
139
+ if re .match (r'(?:[^/]+\.dist-info/METADATA|^[^/]+/PKG-INFO)$' , entry .path )
140
+ and entry .size <= TEXT_RENDER_FILESIZE_LIMIT
142
141
]
143
142
if len (metadata_entries ) > 0 :
144
143
metadata_path = metadata_entries [0 ].path
145
144
metadata = {}
146
145
147
146
async with package .open_from_archive (metadata_path ) as f :
148
- metadata_file = io .StringIO ((await f .read ()).decode (" utf8" , errors = " ignore" ))
147
+ metadata_file = io .StringIO ((await f .read ()).decode (' utf8' , errors = ' ignore' ))
149
148
150
149
message = email .message_from_file (metadata_file )
151
150
metadata = {
@@ -156,35 +155,34 @@ async def package_file(request: Request) -> Response:
156
155
metadata_path = None
157
156
metadata = {}
158
157
159
-
160
158
return templates .TemplateResponse (
161
- " package_file.html" ,
159
+ ' package_file.html' ,
162
160
{
163
- " request" : request ,
164
- " package" : package_name ,
165
- " filename" : file_name ,
166
- " entries" : entries ,
167
- " metadata_path" : metadata_path ,
168
- " metadata" : metadata ,
161
+ ' request' : request ,
162
+ ' package' : package_name ,
163
+ ' filename' : file_name ,
164
+ ' entries' : entries ,
165
+ ' metadata_path' : metadata_path ,
166
+ ' metadata' : metadata ,
169
167
},
170
168
)
171
169
172
170
173
171
@app .route ('/package/{package}/{filename}/{archive_path:path}' )
174
172
async def package_file_archive_path (request : Request ) -> Response :
175
- package_name = request .path_params [" package" ]
176
- file_name = request .path_params [" filename" ]
177
- archive_path = request .path_params [" archive_path" ]
173
+ package_name = request .path_params [' package' ]
174
+ file_name = request .path_params [' filename' ]
175
+ archive_path = request .path_params [' archive_path' ]
178
176
try :
179
177
archive = await pypi .downloaded_file_path (package_name , file_name )
180
178
except pypi .PackageDoesNotExist :
181
179
return PlainTextResponse (
182
- f" Package { package_name !r} does not exist on PyPI." ,
180
+ f' Package { package_name !r} does not exist on PyPI.' ,
183
181
status_code = 404 ,
184
182
)
185
183
except pypi .CannotFindFileError :
186
184
return PlainTextResponse (
187
- f" File { file_name !r} does not exist for package { package_name !r} ." ,
185
+ f' File { file_name !r} does not exist for package { package_name !r} .' ,
188
186
status_code = 404 ,
189
187
)
190
188
try :
@@ -199,7 +197,7 @@ async def package_file_archive_path(request: Request) -> Response:
199
197
matching_entries = [entry for entry in entries if entry .path == archive_path ]
200
198
if len (matching_entries ) == 0 :
201
199
return PlainTextResponse (
202
- f" Path { archive_path !r} does not exist in archive." ,
200
+ f' Path { archive_path !r} does not exist in archive.' ,
203
201
status_code = 404 ,
204
202
)
205
203
entry = matching_entries [0 ]
@@ -216,11 +214,11 @@ async def transfer_file():
216
214
217
215
return StreamingResponse (
218
216
transfer_file (),
219
- media_type = mimetype if (mimetype or "" ).startswith (MIME_WHITELIST ) else None ,
220
- headers = {" Content-Length" : str (entry .size )},
217
+ media_type = mimetype if (mimetype or '' ).startswith (MIME_WHITELIST ) else None ,
218
+ headers = {' Content-Length' : str (entry .size )},
221
219
)
222
220
223
- if " raw" in request .query_params :
221
+ if ' raw' in request .query_params :
224
222
return _transfer_raw ()
225
223
226
224
# There are a few cases to handle here:
@@ -258,46 +256,46 @@ async def transfer_file():
258
256
lexer = pygments .lexers .special .TextLexer ()
259
257
260
258
return templates .TemplateResponse (
261
- " package_file_archive_path.html" ,
259
+ ' package_file_archive_path.html' ,
262
260
{
263
- " request" : request ,
264
- " package" : package_name ,
265
- " filename" : file_name ,
266
- " archive_path" : archive_path ,
267
- " rendered_text" : fluffy_code .code .render (
261
+ ' request' : request ,
262
+ ' package' : package_name ,
263
+ ' filename' : file_name ,
264
+ ' archive_path' : archive_path ,
265
+ ' rendered_text' : fluffy_code .code .render (
268
266
first_chunk ,
269
267
style_config = style_config ,
270
268
highlight_config = fluffy_code .code .HighlightConfig (
271
269
lexer = lexer ,
272
270
highlight_diff = False ,
273
271
),
274
272
),
275
- " extra_css" : fluffy_code .code .get_global_css () + " \n " + style_config .css ,
276
- " extra_js" : fluffy_code .code .get_global_javascript (),
273
+ ' extra_css' : fluffy_code .code .get_global_css () + ' \n ' + style_config .css ,
274
+ ' extra_js' : fluffy_code .code .get_global_javascript (),
277
275
},
278
276
)
279
277
else :
280
278
# Case 2: too long to syntax highlight.
281
279
return templates .TemplateResponse (
282
- " package_file_archive_path_cannot_render.html" ,
280
+ ' package_file_archive_path_cannot_render.html' ,
283
281
{
284
- " request" : request ,
285
- " package" : package_name ,
286
- " filename" : file_name ,
287
- " archive_path" : archive_path ,
288
- " error" : " This file is too long to syntax highlight." ,
282
+ ' request' : request ,
283
+ ' package' : package_name ,
284
+ ' filename' : file_name ,
285
+ ' archive_path' : archive_path ,
286
+ ' error' : ' This file is too long to syntax highlight.' ,
289
287
},
290
288
)
291
289
292
290
# Case 4: link to binary
293
291
return templates .TemplateResponse (
294
- " package_file_archive_path_cannot_render.html" ,
292
+ ' package_file_archive_path_cannot_render.html' ,
295
293
{
296
- " request" : request ,
297
- " package" : package_name ,
298
- " filename" : file_name ,
299
- " archive_path" : archive_path ,
300
- " error" : " This file appears to be a binary." ,
294
+ ' request' : request ,
295
+ ' package' : package_name ,
296
+ ' filename' : file_name ,
297
+ ' archive_path' : archive_path ,
298
+ ' error' : ' This file appears to be a binary.' ,
301
299
},
302
300
)
303
301
0 commit comments