Skip to content

Commit

Permalink
Merge pull request #4 from a-luna:changes-20231126
Browse files Browse the repository at this point in the history
Fix enum behavior and update dependencies
  • Loading branch information
a-luna authored Jan 3, 2024
2 parents 9caa378 + 5352fff commit f7d80aa
Show file tree
Hide file tree
Showing 26 changed files with 500 additions and 335 deletions.
25 changes: 11 additions & 14 deletions app/api/api_v1/dependencies/db_session.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,15 @@ def get_character_properties(
return get_character_properties(self.engine, codepoint, show_props, verbose)

def filter_all_characters(self, filter_params: FilterParameters) -> list[int]:
queries = [
query for table in CHAR_TABLES if (query := construct_filter_query(filter_params, table)) is not None
]
return apply_filter(self.session, queries)
matching_codepoints = []
for query in get_filter_queries(filter_params):
results = self.session.execute(query).scalars().all()
matching_codepoints.extend(results)
return sorted(set(matching_codepoints))


def get_filter_queries(filter_params: FilterParameters) -> list[Select | None]:
return [query for table in CHAR_TABLES if (query := construct_filter_query(filter_params, table)) is not None]


def construct_filter_query( # noqa: C901
Expand All @@ -44,9 +49,9 @@ def construct_filter_query( # noqa: C901
return None
query = select(column("codepoint_dec")).select_from(table)
if filter_params.name:
query = query.where(column("name").contains(filter_params.name.upper()))
query = query.where(column("name").regexp_match(f"\\b{filter_params.name.upper()}\\b"))
if filter_params.cjk_definition:
query = query.where(column("description").contains(filter_params.cjk_definition))
query = query.where(column("description").regexp_match(f"\\b{filter_params.cjk_definition.lower()}\\b"))
if filter_params.blocks:
query = query.where(column("block_id").in_(filter_params.blocks))
if filter_params.categories:
Expand Down Expand Up @@ -74,11 +79,3 @@ def construct_filter_query( # noqa: C901
query = query.where(or_(*flag_conditions))

return query


def apply_filter(session: Session, queries: list[Select]) -> list[int]:
matching_codepoints = []
for query in queries:
results = session.execute(query).scalars().all()
matching_codepoints.extend(results)
return sorted(set(matching_codepoints))
2 changes: 1 addition & 1 deletion app/api/api_v1/dependencies/filter_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,4 +240,4 @@ def parse_all_enum_values( # noqa: C901
if errors:
all_errors = f"Invalid values were provided for the following {len(errors)} parameters:\n\n"
all_errors += "\n\n".join(errors)
raise HTTPException(status_code=int(HTTPStatus.BAD_REQUEST), detail=all_errors) # type: ignore # noqa: PGH003, E501
raise HTTPException(status_code=int(HTTPStatus.BAD_REQUEST), detail=all_errors) # type: ignore # noqa: PGH003
7 changes: 3 additions & 4 deletions app/core/config/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import os

from app.core.config.config import UnicodeApiSettings
from app.core.config.test_config import UnicodeApiSettingsTest
from app.core.config.config import UnicodeApiSettings, get_api_settings, get_test_settings


def get_settings():
return UnicodeApiSettings() if os.environ["ENV"] != "TEST" else UnicodeApiSettingsTest()
def get_settings() -> UnicodeApiSettings:
return get_api_settings() if "TEST" not in os.environ.get("ENV", "DEV") else get_test_settings()
207 changes: 158 additions & 49 deletions app/core/config/config.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import json
import os
from dataclasses import dataclass
from datetime import timedelta
from pathlib import Path
from typing import Any

from pydantic import BaseSettings

from app.core.dotenv_file import DotEnvFile
from app.data.constants import UNICODE_PLANES_DEFAULT

Expand All @@ -18,6 +17,7 @@
XML_ZIP_FILE_NAME = "ucd.all.flat.zip"
DB_FILE_NAME = "unicode-api.db"
DB_ZIP_FILE_NAME = "unicode-api.db.zip"
JSON_ZIP_FILE_NAME = "unicode_json.zip"

APP_FOLDER = Path(__file__).parent.parent.parent
ROOT_FOLDER = APP_FOLDER.parent
Expand Down Expand Up @@ -50,52 +50,49 @@
}


class UnicodeApiSettings(BaseSettings):
ENV: str = os.environ.get("ENV", "DEV")
UNICODE_VERSION: str = os.environ.get("UNICODE_VERSION", "")
PROJECT_NAME: str = "Unicode API"
API_VERSION: str = "/v1"
REDIS_PW: str = os.environ.get("REDIS_PW", "")
REDIS_HOST: str = os.environ.get("REDIS_HOST", "")
REDIS_PORT: int = int(os.environ.get("REDIS_PORT", ""))
REDIS_DB: int = int(os.environ.get("REDIS_DB", "0"))
RATE_LIMIT_PER_PERIOD: int = int(os.environ.get("RATE_LIMIT_PER_PERIOD", "1"))
RATE_LIMIT_PERIOD_SECONDS: timedelta = timedelta(seconds=int(os.environ.get("RATE_LIMIT_PERIOD_SECONDS", "100")))
RATE_LIMIT_BURST: int = int(os.environ.get("RATE_LIMIT_BURST", "10"))
SERVER_NAME: str = "unicode-api.aaronluna.dev"
SERVER_HOST: str = PROD_API_ROOT
CACHE_HEADER: str = "X-UnicodeAPI-Cache"
API_ROOT = DEV_API_ROOT if os.environ.get("ENV", "") != "PROD" else PROD_API_ROOT
LOGGING_CONFIG: dict[str, Any] = LOGGING_CONFIG

ROOT_FOLDER: Path = ROOT_FOLDER
APP_FOLDER: Path = ROOT_FOLDER.joinpath("app")
DATA_FOLDER: Path = APP_FOLDER.joinpath("data")
TESTS_FOLDER: Path = APP_FOLDER.joinpath("tests")
VERSION_FOLDER: Path = DATA_FOLDER.joinpath("unicode_versions").joinpath(UNICODE_VERSION)
XML_FOLDER: Path = VERSION_FOLDER.joinpath("xml")
XML_FILE: Path = XML_FOLDER.joinpath(XML_FILE_NAME)
XML_ZIP_FILE: Path = XML_FOLDER.joinpath(XML_ZIP_FILE_NAME)
DB_FOLDER: Path = VERSION_FOLDER.joinpath("db")
DB_FILE: Path = DB_FOLDER.joinpath(DB_FILE_NAME)
DB_ZIP_FILE: Path = DB_FOLDER.joinpath(DB_ZIP_FILE_NAME)
DB_ZIP_URL: str = f"{HTTP_BUCKET_URL}/{UNICODE_VERSION}/{DB_ZIP_FILE.name}"
DB_URL: str = f"sqlite:///{DB_FILE}"
S3_BUCKET_URL: str = S3_BUCKET_URL
JSON_FOLDER: Path = VERSION_FOLDER.joinpath("json")
PLANES_JSON: Path = JSON_FOLDER.joinpath("planes.json")
BLOCKS_JSON: Path = JSON_FOLDER.joinpath("blocks.json")
CHAR_NAME_MAP: Path = JSON_FOLDER.joinpath("char_name_map.json")
JSON_ZIP_FILE: Path = JSON_FOLDER.joinpath("unicode_json.zip")
JSON_ZIP_URL: str = f"{HTTP_BUCKET_URL}/{UNICODE_VERSION}/{JSON_ZIP_FILE.name}"
CSV_FOLDER: Path = VERSION_FOLDER.joinpath("csv")
PLANES_CSV: Path = CSV_FOLDER.joinpath("planes.csv")
BLOCKS_CSV: Path = CSV_FOLDER.joinpath("blocks.csv")
NAMED_CHARS_CSV: Path = CSV_FOLDER.joinpath("named_chars.csv")
UNIHAN_CHARS_CSV: Path = CSV_FOLDER.joinpath("unihan_chars.csv")

class Config:
case_sensitive = True
@dataclass
class UnicodeApiSettings:
ENV: str
UNICODE_VERSION: str
PROJECT_NAME: str
API_VERSION: str
REDIS_PW: str
REDIS_HOST: str
REDIS_PORT: int
REDIS_DB: int
RATE_LIMIT_PER_PERIOD: int
RATE_LIMIT_PERIOD_SECONDS: timedelta
RATE_LIMIT_BURST: int
SERVER_NAME: str
SERVER_HOST: str
CACHE_HEADER: str
API_ROOT: str
LOGGING_CONFIG: dict[str, Any]
ROOT_FOLDER: Path
APP_FOLDER: Path
DATA_FOLDER: Path
TESTS_FOLDER: Path
VERSION_FOLDER: Path
XML_FOLDER: Path
XML_FILE: Path
XML_ZIP_FILE: Path
DB_FOLDER: Path
DB_FILE: Path
DB_ZIP_FILE: Path
DB_ZIP_URL: str
DB_URL: str
S3_BUCKET_URL: str
JSON_FOLDER: Path
PLANES_JSON: Path
BLOCKS_JSON: Path
CHAR_NAME_MAP: Path
JSON_ZIP_FILE: Path
JSON_ZIP_URL: str
CSV_FOLDER: Path
PLANES_CSV: Path
BLOCKS_CSV: Path
NAMED_CHARS_CSV: Path
UNIHAN_CHARS_CSV: Path

def init_data_folders(self) -> None:
self.DB_FOLDER.mkdir(parents=True, exist_ok=True)
Expand All @@ -110,7 +107,7 @@ def init_data_folders(self) -> None:
if self.CHAR_NAME_MAP.exists():
self.CHAR_NAME_MAP.unlink()

if os.environ.get("ENV") == "PROD":
if "PROD" in self.ENV:
return

self.CSV_FOLDER.mkdir(parents=True, exist_ok=True)
Expand All @@ -127,3 +124,115 @@ def init_data_folders(self) -> None:

def create_planes_json(self) -> None:
self.PLANES_JSON.write_text(json.dumps(UNICODE_PLANES_DEFAULT, indent=4))


def get_api_settings() -> UnicodeApiSettings:
env = os.environ.get("ENV", "DEV")
unicode_version = os.environ.get("UNICODE_VERSION", "15.0.0")
data_folder = APP_FOLDER.joinpath("data")
version_folder = data_folder.joinpath("unicode_versions").joinpath(unicode_version)
xml_folder = version_folder.joinpath("xml")
db_folder = version_folder.joinpath("db")
json_folder = version_folder.joinpath("json")
csv_folder = version_folder.joinpath("csv")

settings = UnicodeApiSettings(
ENV=env,
UNICODE_VERSION=unicode_version,
PROJECT_NAME="Unicode API",
API_VERSION="/v1",
REDIS_PW=os.environ.get("REDIS_PW", ""),
REDIS_HOST=os.environ.get("REDIS_HOST", ""),
REDIS_PORT=int(os.environ.get("REDIS_PORT", "")),
REDIS_DB=int(os.environ.get("REDIS_DB", "0")),
RATE_LIMIT_PER_PERIOD=int(os.environ.get("RATE_LIMIT_PER_PERIOD", "1")),
RATE_LIMIT_PERIOD_SECONDS=timedelta(seconds=int(os.environ.get("RATE_LIMIT_PERIOD_SECONDS", "100"))),
RATE_LIMIT_BURST=int(os.environ.get("RATE_LIMIT_BURST", "10")),
SERVER_NAME="unicode-api.aaronluna.dev",
SERVER_HOST=PROD_API_ROOT,
CACHE_HEADER="X-UnicodeAPI-Cache",
API_ROOT=DEV_API_ROOT if "PROD" not in env else PROD_API_ROOT,
LOGGING_CONFIG=LOGGING_CONFIG,
ROOT_FOLDER=ROOT_FOLDER,
APP_FOLDER=ROOT_FOLDER.joinpath("app"),
DATA_FOLDER=data_folder,
TESTS_FOLDER=APP_FOLDER.joinpath("tests"),
VERSION_FOLDER=version_folder,
XML_FOLDER=xml_folder,
XML_FILE=xml_folder.joinpath(XML_FILE_NAME),
XML_ZIP_FILE=xml_folder.joinpath(XML_ZIP_FILE_NAME),
DB_FOLDER=db_folder,
DB_FILE=db_folder.joinpath(DB_FILE_NAME),
DB_ZIP_FILE=db_folder.joinpath(DB_ZIP_FILE_NAME),
DB_ZIP_URL=f"{HTTP_BUCKET_URL}/{unicode_version}/{DB_ZIP_FILE_NAME}",
DB_URL=f"sqlite:///{db_folder.joinpath(DB_FILE_NAME)}",
S3_BUCKET_URL=S3_BUCKET_URL,
JSON_FOLDER=json_folder,
PLANES_JSON=json_folder.joinpath("planes.json"),
BLOCKS_JSON=json_folder.joinpath("blocks.json"),
CHAR_NAME_MAP=json_folder.joinpath("char_name_map.json"),
JSON_ZIP_FILE=json_folder.joinpath(JSON_ZIP_FILE_NAME),
JSON_ZIP_URL=f"{HTTP_BUCKET_URL}/{unicode_version}/{JSON_ZIP_FILE_NAME}",
CSV_FOLDER=csv_folder,
PLANES_CSV=csv_folder.joinpath("planes.csv"),
BLOCKS_CSV=csv_folder.joinpath("blocks.csv"),
NAMED_CHARS_CSV=csv_folder.joinpath("named_chars.csv"),
UNIHAN_CHARS_CSV=csv_folder.joinpath("unihan_chars.csv"),
)
return settings


def get_test_settings() -> UnicodeApiSettings:
env = "TEST"
unicode_version = "15.0.0"
data_folder = APP_FOLDER.joinpath("data")
version_folder = data_folder.joinpath("unicode_versions").joinpath(unicode_version)
xml_folder = version_folder.joinpath("xml")
db_folder = version_folder.joinpath("db")
json_folder = version_folder.joinpath("json")
csv_folder = version_folder.joinpath("csv")

settings = UnicodeApiSettings(
ENV=env,
UNICODE_VERSION=unicode_version,
PROJECT_NAME="Test Unicode API",
API_VERSION="/v1",
REDIS_PW="",
REDIS_HOST="",
REDIS_PORT=0,
REDIS_DB=0,
RATE_LIMIT_PER_PERIOD=1,
RATE_LIMIT_PERIOD_SECONDS=timedelta(seconds=100),
RATE_LIMIT_BURST=10,
SERVER_NAME="",
SERVER_HOST="",
CACHE_HEADER="",
API_ROOT=DEV_API_ROOT,
LOGGING_CONFIG=LOGGING_CONFIG,
ROOT_FOLDER=ROOT_FOLDER,
APP_FOLDER=ROOT_FOLDER.joinpath("app"),
DATA_FOLDER=data_folder,
TESTS_FOLDER=APP_FOLDER.joinpath("tests"),
VERSION_FOLDER=version_folder,
XML_FOLDER=xml_folder,
XML_FILE=xml_folder.joinpath(XML_FILE_NAME),
XML_ZIP_FILE=xml_folder.joinpath(XML_ZIP_FILE_NAME),
DB_FOLDER=db_folder,
DB_FILE=db_folder.joinpath(DB_FILE_NAME),
DB_ZIP_FILE=db_folder.joinpath(DB_ZIP_FILE_NAME),
DB_ZIP_URL=f"{HTTP_BUCKET_URL}/{unicode_version}/{DB_ZIP_FILE_NAME}",
DB_URL=f"sqlite:///{db_folder.joinpath(DB_FILE_NAME)}",
S3_BUCKET_URL=S3_BUCKET_URL,
JSON_FOLDER=json_folder,
PLANES_JSON=json_folder.joinpath("planes.json"),
BLOCKS_JSON=json_folder.joinpath("blocks.json"),
CHAR_NAME_MAP=json_folder.joinpath("char_name_map.json"),
JSON_ZIP_FILE=json_folder.joinpath(JSON_ZIP_FILE_NAME),
JSON_ZIP_URL=f"{HTTP_BUCKET_URL}/{unicode_version}/{JSON_ZIP_FILE_NAME}",
CSV_FOLDER=csv_folder,
PLANES_CSV=csv_folder.joinpath("planes.csv"),
BLOCKS_CSV=csv_folder.joinpath("blocks.csv"),
NAMED_CHARS_CSV=csv_folder.joinpath("named_chars.csv"),
UNIHAN_CHARS_CSV=csv_folder.joinpath("unihan_chars.csv"),
)
return settings
88 changes: 0 additions & 88 deletions app/core/config/test_config.py

This file was deleted.

Loading

0 comments on commit f7d80aa

Please sign in to comment.