Skip to content

Commit bc4c2cd

Browse files
authored
chore(devcontainer): Update devcontainer configuration and enhance Python environment (#126)
- Renamed the devcontainer to "EcoIndex Python" and updated the base image version. - Removed unnecessary extensions and added essential Python extensions for linting and formatting. - Configured VSCode settings for Python formatting and linting. - Added a new function in tasks.py to convert URLs with emoji domains to Punycode for compatibility with requests. - Updated the add_ecoindex_analysis_task function to use the new URL conversion function.
1 parent 44ec88f commit bc4c2cd

File tree

2 files changed

+74
-34
lines changed

2 files changed

+74
-34
lines changed

.devcontainer/devcontainer.json

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,33 @@
11
{
2-
"name": "Ecoindex python full stack dev container",
3-
"image": "mcr.microsoft.com/devcontainers/python:3.12",
4-
"postCreateCommand": "pipx install poetry==1.8.5 && poetry self add poetry-multiproject-plugin && poetry self add poetry-polylith-plugin",
2+
"name": "EcoIndex Python",
3+
"image": "mcr.microsoft.com/devcontainers/python:1-3.12",
54
"features": {
65
"ghcr.io/audacioustux/devcontainers/taskfile": {},
7-
"ghcr.io/devcontainers/features/docker-in-docker:2": {
8-
"installDockerBuildx": true,
9-
"version": "latest",
10-
"dockerDashComposeVersion": "v2"
11-
}
6+
"ghcr.io/devcontainers/features/docker-in-docker:2": {}
127
},
13-
"forwardPorts": [
14-
8000
15-
],
168
"customizations": {
179
"vscode": {
1810
"extensions": [
19-
"-ms-python.autopep8",
20-
"adrianwilczynski.alpine-js-intellisense",
21-
"adrianwilczynski.alpine-js-intellisense",
22-
"bierner.markdown-emoji",
23-
"charliermarsh.ruff",
24-
"Codeium.codeium",
25-
"github.vscode-github-actions",
26-
"Gruntfuggly.todo-tree",
27-
"mhutchie.git-graph",
28-
"ms-azuretools.vscode-docker",
29-
"ms-python.mypy-type-checker",
3011
"ms-python.python",
31-
"Perkovec.emoji",
32-
"samuelcolvin.jinjahtml",
12+
"ms-python.vscode-pylance",
13+
"ms-python.black-formatter",
14+
"charliermarsh.ruff",
3315
"tamasfe.even-better-toml",
34-
"ue.alphabetical-sorter",
35-
"yzhang.markdown-all-in-one",
36-
"esbenp.prettier-vscode",
37-
"ms-pyright.pyright",
38-
"-ms-python.vscode-pylance"
39-
]
16+
"ms-python.mypy-type-checker",
17+
"mhutchie.git-graph"
18+
],
19+
"settings": {
20+
"python.defaultInterpreterPath": "/usr/local/bin/python",
21+
"python.formatting.provider": "black",
22+
"python.linting.enabled": true,
23+
"python.linting.ruffEnabled": true,
24+
"editor.formatOnSave": true,
25+
"editor.codeActionsOnSave": {
26+
"source.organizeImports": "explicit"
27+
}
28+
}
4029
}
41-
}
30+
},
31+
"postCreateCommand": "pipx install poetry==1.8.5 && poetry self add poetry-multiproject-plugin && poetry self add poetry-polylith-plugin",
32+
"remoteUser": "vscode"
4233
}

bases/ecoindex/backend/routers/tasks.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from json import loads
22
from typing import Annotated
3+
from urllib.parse import urlparse, urlunparse
34

5+
import idna
46
import requests
57
from celery.result import AsyncResult
68
from ecoindex.backend.dependencies.validation import validate_api_key_batch
@@ -26,6 +28,48 @@
2628
router = APIRouter(prefix="/v1/tasks/ecoindexes", tags=["Tasks"])
2729

2830

31+
def convert_url_to_punycode(url: str) -> str:
32+
"""
33+
Convert an URL with emoji domain (or any Unicode domain) to Punycode.
34+
This makes the URL compatible with requests library.
35+
36+
Args:
37+
url: The URL string that may contain Unicode characters in the domain
38+
39+
Returns:
40+
The URL with the domain converted to Punycode
41+
"""
42+
parsed = urlparse(url)
43+
44+
# Extract the hostname (netloc may contain port, so we need to handle that)
45+
hostname = parsed.hostname
46+
if not hostname:
47+
return url
48+
49+
try:
50+
# Convert the hostname to Punycode
51+
hostname_punycode = idna.encode(hostname).decode("ascii")
52+
53+
# Reconstruct the netloc with the converted hostname
54+
if parsed.port:
55+
netloc = f"{hostname_punycode}:{parsed.port}"
56+
else:
57+
netloc = hostname_punycode
58+
59+
# Reconstruct the URL with the converted hostname
60+
return urlunparse((
61+
parsed.scheme,
62+
netloc,
63+
parsed.path,
64+
parsed.params,
65+
parsed.query,
66+
parsed.fragment,
67+
))
68+
except (idna.IDNAError, UnicodeError):
69+
# If conversion fails, return the original URL
70+
return url
71+
72+
2973
@router.post(
3074
name="Add new ecoindex analysis task to the waiting queue",
3175
path="/",
@@ -46,7 +90,8 @@ async def add_ecoindex_analysis_task(
4690
Body(
4791
default=...,
4892
title="Web page to analyze defined by its url and its screen resolution",
49-
example=WebPage(url="https://www.ecoindex.fr", width=1920, height=1080),
93+
example=WebPage(url="https://www.ecoindex.fr",
94+
width=1920, height=1080),
5095
),
5196
],
5297
custom_headers: Annotated[
@@ -64,7 +109,8 @@ async def add_ecoindex_analysis_task(
64109
)
65110

66111
if remaining_quota:
67-
response.headers["X-Remaining-Daily-Requests"] = str(remaining_quota - 1)
112+
response.headers["X-Remaining-Daily-Requests"] = str(
113+
remaining_quota - 1)
68114

69115
if (
70116
Settings().EXCLUDED_HOSTS
@@ -78,9 +124,12 @@ async def add_ecoindex_analysis_task(
78124
ua = EcoindexScraper.get_user_agent()
79125
headers = {**custom_headers, **ua.headers.get()}
80126

127+
# Convert URL to Punycode to handle emoji domains and other Unicode domains
128+
url_for_request = convert_url_to_punycode(str(web_page.url))
129+
81130
try:
82131
r = requests.head(
83-
url=web_page.url,
132+
url=url_for_request,
84133
timeout=5,
85134
headers=headers,
86135
)

0 commit comments

Comments
 (0)