Skip to content

Commit

Permalink
Drop toml dependency
Browse files Browse the repository at this point in the history
https://toml.io/en/
uiri/toml#267
uiri/toml#279 (comment)

While the TOML spec is alive and well, the `toml` package that was used
in this project is dead (uiri/toml#267). There are several alternatives.
`rtoml` is the fastest, but does not provide "round trip" guarantees
(meaning that it can't load, then dump, and get an identical result).
However, for simple loading and parsing it's fine. `tomli` is another
alternative, but it is read-only (writing requires a separate `tomli-w`
package), and requires files to be opened in binary mode to parse TOML.
`tomlkit` is used by Poetry (from the Poetry author), but is currently
70x slower than `rtoml`.

It's also important to note that the TOML parsing and settings loading
is somewhat tangential to the focus of the inboard project. A separate
project, https://github.com/br3ndonland/fastenv, is more focused on
settings management, and may feature TOML support in the future.

This commit will remove `toml` from the `fastapi` Poetry extras group.
Note that `toml` is still a sub-dependency of some `dev-dependencies`,
including pre-commit and pytest.
  • Loading branch information
br3ndonland committed Sep 15, 2021
1 parent ddffe97 commit 619f63c
Show file tree
Hide file tree
Showing 6 changed files with 10 additions and 107 deletions.
12 changes: 2 additions & 10 deletions inboard/app/main_fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,7 @@
from fastapi import Depends, FastAPI, status
from fastapi.middleware.cors import CORSMiddleware

from inboard.app.utilities_fastapi import (
GetRoot,
GetStatus,
GetUser,
Settings,
basic_auth,
)
from inboard.app.utilities_fastapi import GetRoot, GetStatus, GetUser, basic_auth

origin_regex = r"^(https?:\/\/)(localhost|([\w\.]+\.)?br3ndon.land)(:[0-9]+)?$"
server = (
Expand All @@ -20,9 +14,7 @@
)
version = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"

settings = Settings()

app = FastAPI(title=settings.name, version=settings.version)
app = FastAPI(title="inboard")
app.add_middleware(
CORSMiddleware,
allow_credentials=True,
Expand Down
46 changes: 2 additions & 44 deletions inboard/app/utilities_fastapi.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import os
import secrets
from pathlib import Path
from typing import List, Optional
from typing import Optional

import toml
from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from pydantic import BaseModel, BaseSettings
from pydantic import BaseModel


async def basic_auth(credentials: HTTPBasicCredentials = Depends(HTTPBasic())) -> str:
Expand All @@ -30,46 +28,6 @@ async def basic_auth(credentials: HTTPBasicCredentials = Depends(HTTPBasic())) -
return credentials.username


def set_fields_from_pyproject(
fields: dict,
pyproject_path: Path = Path(__file__).parents[2].joinpath("pyproject.toml"),
name: str = "inboard",
version: str = "0.1.0",
) -> dict:
"""Create a dictionary of keys and values corresponding to pydantic model fields.
When instantiating the pydantic model, the dictionary can be unpacked and used to
set fields in the model.
"""
try:
pyproject = dict(toml.load(pyproject_path))["tool"]["poetry"]
return {key: pyproject.get(key) for key in fields if pyproject.get(key)}
except Exception:
return {"name": name, "version": version}


class Settings(BaseSettings):
"""[_pydantic_ settings model](https://pydantic-docs.helpmanual.io/usage/settings/)
---
Settings are from [`pyproject.toml`](https://python-poetry.org/docs/pyproject/),
and are tested by `test_metadata.py`. The `__fields__` attribute provides a
dictionary of pydantic model fields, without having to instantiate the model.
"""

name: str
version: str
description: Optional[str]
authors: Optional[List[str]]
license: Optional[str]
homepage: Optional[str]
readme: Optional[str]
include: Optional[List[str]]
keywords: Optional[List[str]]
classifiers: Optional[List[str]]

def __init__(self, **fields: dict) -> None:
super().__init__(**set_fields_from_pyproject(self.__fields__), **fields)


class GetRoot(BaseModel):
Hello: str = "World"

Expand Down
8 changes: 4 additions & 4 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ gunicorn = "^20"
uvicorn = {version = "^0.15", extras = ["standard"]}
fastapi = {version = "^0.68", optional = true}
starlette = {version = "^0.14", optional = true}
toml = {version = ">=0.10", optional = true}

[tool.poetry.dev-dependencies]
black = {version = "21.7b0", allow-prereleases = true}
Expand All @@ -50,8 +49,8 @@ pytest-timeout = "^1.4"
requests = "^2.24"

[tool.poetry.extras]
all = ["fastapi", "toml"]
fastapi = ["fastapi", "toml"]
all = ["fastapi"]
fastapi = ["fastapi"]
starlette = ["starlette"]

[tool.poetry.urls]
Expand Down
7 changes: 0 additions & 7 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from inboard.app.main_base import app as base_app
from inboard.app.main_fastapi import app as fastapi_app
from inboard.app.main_starlette import app as starlette_app
from inboard.app.utilities_fastapi import Settings


@pytest.fixture(scope="session")
Expand Down Expand Up @@ -161,12 +160,6 @@ def pre_start_script_tmp_sh(tmp_path: Path) -> Path:
return Path(tmp_file)


@pytest.fixture(scope="session")
def settings() -> Settings:
"""Instantiate a _pydantic_ Settings model for testing."""
return Settings()


@pytest.fixture(scope="session")
def uvicorn_options_default() -> dict:
"""Return default options used by `uvicorn.run()` for use in test assertions."""
Expand Down
39 changes: 0 additions & 39 deletions tests/test_metadata.py

This file was deleted.

0 comments on commit 619f63c

Please sign in to comment.