Coverage for app/views/routes/search.py: 0%

34 statements  

« prev     ^ index     » next       coverage.py v7.6.10, created at 2026-06-04 22:29 +0000

1from typing import Annotated 

2 

3from fastapi import APIRouter, Header, Request 

4from fastapi.responses import HTMLResponse 

5from sqlalchemy import text 

6 

7from app.core.db import read_engine 

8from app.core.logger import logger 

9from app.core.templates import templates 

10from app.normalization import NormalizedPackageName 

11from app.utils import parse_query_params, validate_package 

12 

13router: APIRouter = APIRouter() 

14 

15 

16@router.get("/package-search-input", response_class=HTMLResponse) 

17def get_search_input( 

18 request: Request, 

19 package_name: NormalizedPackageName, 

20 url: Annotated[str, Header(alias="HX-Current-URL")], 

21) -> HTMLResponse: 

22 query_params = parse_query_params(url) 

23 

24 if query_params.error: 

25 logger.warning(query_params.error) 

26 return HTMLResponse(status_code=422, content=query_params.error) 

27 

28 error_message = "" 

29 is_valid_submission = True 

30 

31 if package_name != "": 

32 if package_name in query_params.packages: 

33 is_valid_submission = False 

34 error_message = f"'{package_name}' already selected" 

35 elif not validate_package(package_name): 

36 is_valid_submission = False 

37 error_message = f"'{package_name}' not found on PyPI" 

38 

39 return templates.TemplateResponse( 

40 request=request, 

41 name="fragments/package_search_input.html", 

42 context={ 

43 "package_name": package_name, 

44 "is_valid_submission": is_valid_submission, 

45 "error_message": error_message, 

46 }, 

47 ) 

48 

49 

50@router.get("/package-search-results", response_class=HTMLResponse) 

51def get_search_results( 

52 request: Request, 

53 package_name: NormalizedPackageName, 

54) -> HTMLResponse: 

55 logger.info(f"Searching for packages matching: '{package_name}'") 

56 with read_engine.connect() as conn: 

57 result = conn.execute( 

58 text(""" 

59 select 

60 package_name, 

61 package_summary 

62 from 

63 pypi_packages 

64 where 

65 package_name like :package_name 

66 order by 

67 package_name limit 10 

68 """), 

69 {"package_name": package_name + "%"}, 

70 ) 

71 packages = result.fetchall() 

72 

73 logger.info(f"Found {len(packages)} results for search term '{package_name}'") 

74 

75 return templates.TemplateResponse( 

76 "pages/package_search_results.html", 

77 {"request": request, "packages": packages, "package_name": package_name}, 

78 )