Browse Source

feat: add type checking with BasedPyright

Zubarev Grigoriy 7 months ago
parent
commit
5f7d8a4a91
3 changed files with 27 additions and 7 deletions
  1. 18 1
      pyproject.toml
  2. 3 0
      requirements-dev.lock
  3. 6 6
      src/rural_dict/__main__.py

+ 18 - 1
pyproject.toml

@@ -30,7 +30,9 @@ build-backend = "hatchling.build"
 [tool.rye]
 managed = true
 universal = true
-dev-dependencies = []
+dev-dependencies = [
+    "basedpyright>=1.16.0",
+]
 
 [tool.rye.scripts]
 dev = "uvicorn src.rural_dict.__main__:app --port 8080 --reload --reload-dir src/rural_dict"
@@ -82,3 +84,18 @@ select = [
     "PTH", # flake8-use-pathlib
     "ASYNC", # flake8-async
 ]
+
+[tool.basedpyright]
+exclude = [
+    ".git",
+    ".venv",
+    ".idea",
+    ".tests",
+    "build",
+    "dist",
+]
+typeCheckingMode = "standard"
+pythonPlatform = "All"
+pythonVersion = "3.12"
+reportMissingImports = true
+reportMissingTypeStubs = false

+ 3 - 0
requirements-dev.lock

@@ -23,6 +23,7 @@ anyio==4.4.0
     # via watchfiles
 attrs==24.2.0
     # via aiohttp
+basedpyright==1.16.0
 click==8.1.7
     # via uvicorn
 colorama==0.4.6 ; platform_system == 'Windows' or sys_platform == 'win32'
@@ -47,6 +48,8 @@ markupsafe==2.1.5
 multidict==6.0.5
     # via aiohttp
     # via yarl
+nodejs-wheel-binaries==20.16.0
+    # via basedpyright
 pydantic==2.8.2
     # via fastapi
 pydantic-core==2.20.1

+ 6 - 6
src/rural_dict/__main__.py

@@ -23,13 +23,13 @@ ROOT_PATH = Path(__file__).parent
 app = FastAPI(lifespan=lifespan, docs_url=None, redoc_url=None)
 app.mount("/static", StaticFiles(directory=ROOT_PATH / "static"), name="static")
 templates = Jinja2Templates(directory=ROOT_PATH / "templates")
-session: aiohttp.ClientSession | None = None
+session: aiohttp.ClientSession = None  # pyright: ignore[reportAssignmentType]
 
 
 def remove_classes(node: Node) -> Node:
     """Recursively remove all classes from all nodes."""
     if "class" in node.attributes:
-        del node.attrs["class"]
+        del node.attrs["class"]  # pyright: ignore [reportIndexIssue]
     for child in node.iter():
         remove_classes(child)
     return node
@@ -45,7 +45,7 @@ async def catch_all(response: Request):
 
     async with session.get(url) as dict_response:
         if dict_response.history:
-            return RedirectResponse(dict_response.url.relative(), status_code=301)
+            return RedirectResponse(str(dict_response.url.relative()), status_code=301)
         html = await dict_response.text()
 
     results = []
@@ -54,7 +54,7 @@ async def catch_all(response: Request):
     try:
         thumbs_api_url = (
             f'https://api.urbandictionary.com/v0/uncacheable?ids='
-            f'{",".join(d.attributes["data-defid"] for d in definitions)}'
+            f'{",".join(d.attributes["data-defid"] or "-1" for d in definitions)}'
         )
         async with session.get(thumbs_api_url) as thumbs_response:
             thumbs_json = await thumbs_response.json()
@@ -67,7 +67,7 @@ async def catch_all(response: Request):
         meaning = remove_classes(definition.css_first("div.meaning")).html
         example = remove_classes(definition.css_first("div.example")).html
         contributor = remove_classes(definition.css_first("div.contributor")).html
-        definition_id = int(definition.attributes["data-defid"])
+        definition_id = int(definition.attributes["data-defid"] or "-1")
         definition_thumbs = thumbs_data.get(definition_id, {})
         thumbs_up = definition_thumbs.get("up")
         thumbs_down = definition_thumbs.get("down")
@@ -76,7 +76,7 @@ async def catch_all(response: Request):
         )
     if (pagination := parser.css_first("div.pagination")) is not None:
         pagination = remove_classes(pagination)
-        pagination.attrs["class"] = "pagination"
+        pagination.attrs["class"] = "pagination"  # pyright: ignore [reportIndexIssue]
         pagination = pagination.html
 
     return templates.TemplateResponse(