Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Feature Flags module to Ligare.web and Ligare.platform #107

Merged
merged 42 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7a66456
Add methods to get all feature flags.
aholmes Aug 12, 2024
9b6d788
Add tests and update const names.
aholmes Aug 12, 2024
d9ae007
Add tests for feature flag filtering from getter.
aholmes Aug 13, 2024
f0d5a6e
Fix error with database feature flags not returning descriptions
aholmes Aug 13, 2024
a38123d
Ensure `get_feature_flags` in DB updates cache.
aholmes Aug 13, 2024
6201212
Return old/new state when feature value changes.
aholmes Aug 13, 2024
2b1bbc8
Initial FeatureFlag modules for API and DI.
aholmes Aug 20, 2024
0cc2bc7
Fix a type issue, add some TODOs
aholmes Aug 21, 2024
83af0ae
Make ApplicationBuilder work.
aholmes Sep 6, 2024
f10e796
Move old application bootstrapping into builders.
aholmes Sep 9, 2024
e8a2d43
Add a nested dictionary type with generic keys.
aholmes Sep 10, 2024
3cde543
Further updates to builders. Update associated tests.
aholmes Sep 10, 2024
3ce5233
Fix automatic configuration of module config types.
aholmes Sep 10, 2024
abefe0a
Use first application config for root by default.
aholmes Sep 11, 2024
5e28cee
Fix crash caused by dataclass decorator on dataclass subclass.
aholmes Sep 11, 2024
30aa6ef
Replace OpenAPI spec with dict in test fixtures.
aholmes Sep 11, 2024
a811c0e
Make feature flags work with user sessions.
aholmes Sep 12, 2024
960eaa8
Fix some type errors.
aholmes Sep 12, 2024
91b94a5
Make "get" work for feature flags and add test.
aholmes Sep 13, 2024
f5a7068
Make feature flag PATCH request work and add test.
aholmes Sep 17, 2024
f57ca2f
Support querying for one or more specific feature flags.
aholmes Sep 17, 2024
40cdf08
Remove commented code.
aholmes Sep 19, 2024
a903db9
Remove useless `pass`
aholmes Sep 19, 2024
fd35330
Add Alembic migration files for feature flags.
aholmes Sep 20, 2024
abdf491
Fix issues with Alembic migrations not running successfully.
aholmes Sep 20, 2024
a28c866
Ignore some pyright type errors.
aholmes Sep 20, 2024
e96d700
Fix crash when web openapi app tries to log username but login_manage…
aholmes Sep 20, 2024
75045fb
Change feature flag root API URL to /platform.
aholmes Sep 20, 2024
1607b57
Add the ability for Feature Flags to work without user sessions.
aholmes Sep 23, 2024
b4a4674
Final rename changes necessary after rebase with main.
aholmes Sep 27, 2024
26078da
Fix Makefile issues:
aholmes Sep 27, 2024
d56215e
Prevent tests from writing alembic.ini at project root.
aholmes Sep 27, 2024
6329907
Revert unintentional changes to pyproject.toml files.
aholmes Sep 27, 2024
de10375
Alter test OpenAPI/Flask client to pass partially initialized
aholmes Sep 30, 2024
ff18f90
Get feature flag middleware to permit access to GET when flask-login is
aholmes Oct 1, 2024
d44b79f
Fix type errors.
aholmes Oct 1, 2024
aa15c3d
Improve docs for `login_required`
aholmes Oct 2, 2024
38736c9
Merge branch 'main' into aholmes-update-feature-flags
aholmes Oct 3, 2024
186b929
Treat use of deprecated types as an error.
aholmes Oct 3, 2024
4be9a49
Deprecated old methods for creating an application.
aholmes Oct 3, 2024
371c953
Update tests to comply with deprecation.
aholmes Oct 3, 2024
62e47bd
Update some docs for Feature Flag middleware.
aholmes Oct 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,6 @@ TOX_DIR := .tox
DEFAULT_TARGET ?= dev
.DEFAULT_GOAL := $(DEFAULT_TARGET)


ifeq ($(DEFAULT_TARGET),dev)
BUILD_TARGET := $(SETUP_DEV_SENTINEL)
else ifeq ($(DEFAULT_TARGET),cicd)
BUILD_TARGET := $(SETUP_CICD_SENTINEL)
else
$(error DEFAULT_TARGET must be one of "dev" or "cicd")
endif


ACTIVATE_VENV := . $(VENV)/bin/activate
REPORT_VENV_USAGE := echo '\nActivate your venv with `. $(VENV)/bin/activate`'

Expand All @@ -73,6 +63,15 @@ SETUP_DEV_SENTINEL = $(MAKE_ARTIFACT_DIRECTORY)/setup_dev_sentinel
SETUP_CICD_SENTINEL = $(MAKE_ARTIFACT_DIRECTORY)/setup_cicd_sentinel
PYPROJECT_FILES_SENTINEL = $(MAKE_ARTIFACT_DIRECTORY)/pyproject_sentinel

ifeq ($(DEFAULT_TARGET),dev)
BUILD_TARGET := $(SETUP_DEV_SENTINEL)
else ifeq ($(DEFAULT_TARGET),cicd)
BUILD_TARGET := $(SETUP_CICD_SENTINEL)
else
$(error DEFAULT_TARGET must be one of "dev" or "cicd")
endif


$(PYPROJECT_FILES_SENTINEL): $(VENV)
$(MAKE) $(PYPROJECT_FILES)
touch $@
Expand Down Expand Up @@ -196,10 +195,10 @@ test-bandit : $(VENV) $(BUILD_TARGET)
-r .

test-pytest : $(VENV) $(BUILD_TARGET)
-$(ACTIVATE_VENV) && \
$(ACTIVATE_VENV) && \
PYTEST_TARGET=$(PYTEST_TARGET) tox && PYTEST_EXIT_CODE=0 || PYTEST_EXIT_CODE=$$?; \
coverage html --data-file=$(REPORTS_DIR)/$(PYTEST_REPORT)/.coverage; \
junit2html $(REPORTS_DIR)/$(PYTEST_REPORT)/pytest.xml $(REPORTS_DIR)/$(PYTEST_REPORT)/pytest.html; \
junit2html $(REPORTS_DIR)/$(PYTEST_REPORT)/pytest.xml $(REPORTS_DIR)/$(PYTEST_REPORT)/pytest.html && \
exit $$PYTEST_EXIT_CODE

.PHONY: test test-pytest test-bandit test-pyright test-ruff test-isort
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ reportUnnecessaryTypeIgnoreComment = "information"
reportUnusedCallResult = "information"
reportMissingTypeStubs = "information"
reportWildcardImportFromLibrary = "warning"
reportDeprecated = "error"

[tool.pytest.ini_options]
pythonpath = [
Expand Down
9 changes: 9 additions & 0 deletions src/database/Ligare/database/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from Ligare.programming.config import AbstractConfig
from pydantic import BaseModel
from pydantic.config import ConfigDict
from typing_extensions import override


class DatabaseConnectArgsConfig(BaseModel):
Expand Down Expand Up @@ -36,6 +37,10 @@ def __init__(self, **data: Any):
elif self.connection_string.startswith("postgresql://"):
self.connect_args = PostgreSQLDatabaseConnectArgsConfig(**model_data)

@override
def post_load(self) -> None:
return super().post_load()

connection_string: str = "sqlite:///:memory:"
sqlalchemy_echo: bool = False
# the static field allows Pydantic to store
Expand All @@ -44,4 +49,8 @@ def __init__(self, **data: Any):


class Config(BaseModel, AbstractConfig):
@override
def post_load(self) -> None:
return super().post_load()

database: DatabaseConfig
11 changes: 9 additions & 2 deletions src/database/Ligare/database/dependency_injection.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
from injector import Binder, CallableProvider, Injector, Module, inject, singleton
from injector import Binder, CallableProvider, Injector, inject, singleton
from Ligare.database.config import Config, DatabaseConfig
from Ligare.database.engine import DatabaseEngine
from Ligare.database.types import MetaBase
from Ligare.programming.config import AbstractConfig
from Ligare.programming.dependency_injection import ConfigModule
from Ligare.programming.patterns.dependency_injection import ConfigurableModule
from sqlalchemy.orm.scoping import ScopedSession
from sqlalchemy.orm.session import Session
from typing_extensions import override

from .config import DatabaseConfig


class ScopedSessionModule(Module):
class ScopedSessionModule(ConfigurableModule):
"""
Configure SQLAlchemy Session depedencies for Injector.
"""

@override
@staticmethod
def get_config_type() -> type[AbstractConfig]:
return DatabaseConfig

_bases: list[MetaBase | type[MetaBase]] | None = None

@override
Expand Down
209 changes: 0 additions & 209 deletions src/database/Ligare/database/migrations/alembic.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ def _run_migrations(
try:
if connection.engine.name == "postgresql":
_ = connection.execute(
f"SET search_path TO {','.join(schemas)},public;"
f"SET search_path TO {','.join(schemas + ['public'])};"
)
context.run_migrations()
except ProgrammingError as error:
Expand Down
4 changes: 2 additions & 2 deletions src/database/Ligare/database/schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
_dialect_type_map = {"sqlite": SQLiteDialect, "postgresql": PostgreSQLDialect}


def get_type_from_dialect(dialect: Dialect):
def get_type_from_dialect(dialect: Dialect) -> PostgreSQLDialect | SQLiteDialect:
if not _dialect_type_map.get(dialect.name):
raise ValueError(
f"Unexpected dialect with name `{dialect.name}`. Expected one of {list(_dialect_type_map.keys())}."
Expand All @@ -16,6 +16,6 @@ def get_type_from_dialect(dialect: Dialect):
return _dialect_type_map[dialect.name](dialect)


def get_type_from_op(op: Operations):
def get_type_from_op(op: Operations) -> PostgreSQLDialect | SQLiteDialect:
dialect: Dialect = op.get_bind().dialect
return get_type_from_dialect(dialect)
8 changes: 4 additions & 4 deletions src/database/Ligare/database/schema/dialect.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class DialectBase(ABC):
supports_schemas: bool = False

@staticmethod
def get_schema(meta: MetaBase):
def get_schema(meta: MetaBase) -> str | None:
table_args = hasattr(meta, "__table_args__") and meta.__table_args__ or None

if isinstance(table_args, dict):
Expand All @@ -21,7 +21,7 @@ def iterate_table_names(
dialect: "DialectBase",
schema_tables: dict[MetaBase, list[str]],
table_name_callback: TableNameCallback,
):
) -> None:
"""
Call `table_name_callback` once for every table in every Base.

Expand All @@ -40,13 +40,13 @@ def iterate_table_names(
dialect_schema, full_table_name, base_table, meta_base
)

def get_dialect_schema(self, meta: MetaBase):
def get_dialect_schema(self, meta: MetaBase) -> str | None:
if self.supports_schemas:
return DialectBase.get_schema(meta)

return None

def get_full_table_name(self, table_name: str, meta: MetaBase):
def get_full_table_name(self, table_name: str, meta: MetaBase) -> str:
"""
If the dialect supports schemas, then the table name does not have the schema prepended.
In dialects that don't support schemas, e.g., SQLite, the table name has the schema prepended.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def test__LigareAlembic__passes_through_to_alembic_with_default_config_when_not_
)

ligare_alembic = LigareAlembic(None, MagicMock())
ligare_alembic._write_ligare_alembic_config = MagicMock() # pyright: ignore[reportPrivateUsage]
ligare_alembic.run()

assert alembic_main.called
Expand Down
Loading
Loading