Conversation
| try: | ||
| import gunicorn.http.errors | ||
| GUNICORN_AVAILABLE = True | ||
| except ImportError: | ||
| GUNICORN_AVAILABLE = False | ||
|
|
There was a problem hiding this comment.
Why would Gunicorn be unavailable here?
There was a problem hiding this comment.
Gunicorn might be unavailable in development environments where the application is run using Flask's built-in development server instead of Gunicorn
There was a problem hiding this comment.
Got it. Since our recommendation for running for local development with make serve & Docker Compose, I don't think this will be an issue.
| @app.route( | ||
| "/project/<project_name>/<version>/packages/<first>/<second>/<rest>/<distname>/<path:filepath>/download" | ||
| ) | ||
| def download_file(project_name, version, first, second, rest, distname, filepath): | ||
| """Download individual file from a distribution.""" | ||
| if project_name != canonicalize_name(project_name): | ||
| return redirect( | ||
| url_for( | ||
| "download_file", | ||
| project_name=canonicalize_name(project_name), | ||
| version=version, | ||
| first=first, | ||
| second=second, | ||
| rest=rest, | ||
| distname=distname, | ||
| filepath=filepath, | ||
| ), | ||
| 301, | ||
| ) | ||
|
|
||
| try: | ||
| dist = _get_dist(first, second, rest, distname) | ||
| except InspectorError: | ||
| return abort(400) | ||
|
|
||
| if not dist: | ||
| return abort(404) | ||
|
|
||
| try: | ||
| contents = dist.contents(filepath) | ||
| except FileNotFoundError: | ||
| return abort(404) | ||
| except InspectorError: | ||
| return abort(400) | ||
|
|
||
| # Extract just the filename from the path | ||
| filename = filepath.split("/")[-1] | ||
|
|
||
| # Return the file with proper headers to trigger download | ||
| return Response( | ||
| contents, | ||
| mimetype="application/octet-stream", | ||
| headers={ | ||
| "Content-Disposition": f"attachment; filename={filename}", | ||
| "Content-Length": str(len(contents)), | ||
| }, | ||
| ) |
There was a problem hiding this comment.
This is pretty similar to the file view above, maybe they should share a common function instead?
There was a problem hiding this comment.
You are right, thanks for drawing my attention i'll take care of that
inspector/main.py
Outdated
| @app.route( | ||
| "/project/<project_name>/<version>/packages/<first>/<second>/<rest>/<distname>/download" | ||
| ) | ||
| def download_distribution(project_name, version, first, second, rest, distname): | ||
| """Download entire distribution package.""" | ||
| if project_name != canonicalize_name(project_name): | ||
| return redirect( | ||
| url_for( | ||
| "download_distribution", | ||
| project_name=canonicalize_name(project_name), | ||
| version=version, | ||
| first=first, | ||
| second=second, | ||
| rest=rest, | ||
| distname=distname, | ||
| ), | ||
| 301, | ||
| ) | ||
|
|
||
| try: | ||
| dist = _get_dist(first, second, rest, distname) | ||
| except InspectorError: | ||
| return abort(400) | ||
|
|
||
| if not dist: | ||
| return abort(404) | ||
|
|
||
| # Get the raw distribution file from PyPI | ||
| url = f"https://files.pythonhosted.org/packages/{first}/{second}/{rest}/{distname}" | ||
| try: | ||
| resp = requests_session().get(url, stream=True) | ||
| resp.raise_for_status() | ||
| except Exception: | ||
| return abort(404) | ||
|
|
||
| # Return the file with proper headers to trigger download | ||
| return Response( | ||
| resp.content, | ||
| mimetype="application/octet-stream", | ||
| headers={ | ||
| "Content-Disposition": f"attachment; filename={distname}", | ||
| "Content-Length": str(len(resp.content)), | ||
| }, | ||
| ) |
There was a problem hiding this comment.
I think we can just provide a direct link to the URL where the distribution is hosted on PyPI here, rather than passing it through the application.
There was a problem hiding this comment.
alright i'll take care of that too!!
|
@di can you check the latest changes, thanks |
Fixes #166.