Skip to content

Commit 2864ad2

Browse files
Merge pull request #12 from WoosterTech/app/mood
App/mood
2 parents 69f8942 + 10aaedd commit 2864ad2

File tree

20 files changed

+489
-303
lines changed

20 files changed

+489
-303
lines changed

.pre-commit-config.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,16 @@ default_stages:
88

99
exclude: ^docs/|/migrations/|devcontainer.json|/users/
1010
repos:
11+
- repo: local
12+
hooks:
13+
- id: update-build-info
14+
name: Update build_info.py
15+
entry: python devtools/bump_build.py
16+
language: system
17+
pass_filenames: false
18+
stages: [commit]
1119
- repo: https://github.com/pre-commit/pre-commit-hooks
12-
rev: v5.0.0
20+
rev: v6.0.0
1321
hooks:
1422
- id: trailing-whitespace
1523
- id: end-of-file-fixer
@@ -31,11 +39,11 @@ repos:
3139
hooks:
3240
- id: check-json5
3341
- repo: https://github.com/fpgmaas/deptry.git
34-
rev: 0.23.0
42+
rev: 0.23.1
3543
hooks:
3644
- id: deptry
3745
- repo: https://github.com/astral-sh/ruff-pre-commit
38-
rev: v0.11.13
46+
rev: v0.12.8
3947
hooks:
4048
- id: ruff-check
4149
args: [--fix]

.vscode/settings.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@
1111
"source.organizeImports": "explicit"
1212
},
1313
"editor.formatOnSave": true,
14+
"editor.rulers": [100]
1415
},
1516
}

config/settings/base.py

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,18 @@
33
"""Base settings to build other settings files upon."""
44

55
from pathlib import Path
6+
from typing import cast
67

78
import environ
89
from django.contrib.messages import constants as message_constants
910
from loguru import logger
1011

1112
from config.settings.drf_models import Spectacular
1213
from config.settings.settings_models import Databases, Logging
14+
from devtools.bump_build import BUILD_INFO_FILE, GitInfo
15+
from incredible_data import (
16+
__version__, # pyright: ignore[reportAttributeAccessIssue, reportUnknownVariableType]
17+
)
1318

1419
BASE_DIR = Path(__file__).resolve(strict=True).parent.parent.parent
1520
# incredible_data/
@@ -18,6 +23,22 @@
1823
SOCIALACCOUNT_PROVIDERS=(dict, {}),
1924
)
2025

26+
27+
def get_git_info() -> GitInfo:
28+
"""Attempts to use git to collect versioning info, falling back to the build info file."""
29+
try:
30+
return GitInfo.get_info()
31+
except RuntimeError:
32+
return GitInfo.from_file(BUILD_INFO_FILE)
33+
34+
35+
git_info = get_git_info()
36+
37+
VERSION = cast("str", __version__)
38+
BUILD_NUMBER = git_info.commit_hash
39+
40+
logger.debug(f"Current version: {VERSION}+{BUILD_NUMBER}")
41+
2142
READ_DOT_ENV_FILE = env.bool("DJANGO_READ_DOT_ENV_FILE", default=False)
2243

2344
if READ_DOT_ENV_FILE:
@@ -56,13 +77,14 @@
5677
# DATABASES
5778
# ------------------------------------------------------------------------------
5879
# https://docs.djangoproject.com/en/dev/ref/settings/#databases
59-
# databases_obj = Databases.model_validate(
60-
# {"default": env.db("DATABASE_URL", default="sqlite:///db.sqlite3")}
61-
# )
62-
# databases_obj["default"].atomic_requests = True
63-
DATABASES = {"default": env.db("DATABASE_URL", default="sqlite:///db.sqlite3")}
64-
DATABASES["default"]["ATOMIC_REQUESTS"] = True
65-
logger.debug(f"Databases settings: {DATABASES}")
80+
databases_obj = Databases.model_validate(
81+
{"default": env.db("DATABASE_URL", default="sqlite:///db.sqlite3")}
82+
)
83+
databases_obj.default.atomic_requests = True
84+
DATABASES = databases_obj.render()
85+
# DATABASES = {"default": env.db("DATABASE_URL", default="sqlite:///db.sqlite3")}
86+
# DATABASES["default"]["ATOMIC_REQUESTS"] = True
87+
logger.debug(f"Default database engine: {databases_obj.default.engine_name}")
6688
# https://docs.djangoproject.com/en/stable/ref/settings/#std:setting-DEFAULT_AUTO_FIELD
6789
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
6890

@@ -83,7 +105,7 @@
83105
"django.contrib.messages",
84106
"django.contrib.staticfiles",
85107
# "django.contrib.humanize", # Handy template tags
86-
# "constance",
108+
"constance",
87109
"django.contrib.admin",
88110
"django.forms",
89111
]
@@ -238,6 +260,7 @@
238260
"django.template.context_processors.static",
239261
"django.template.context_processors.tz",
240262
"django.contrib.messages.context_processors.messages",
263+
"incredible_data.helpers.context_processors.version",
241264
"incredible_data.users.context_processors.allauth_settings",
242265
],
243266
},
@@ -402,15 +425,24 @@
402425
CURRENCIES = ("USD",)
403426
DEFAULT_CURRENCY = "USD"
404427

428+
## Constance
429+
405430
# CONSTANCE_REDIS_CONNECTION = env.cache_url("REDIS_URL")
431+
CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend"
432+
433+
CONSTANCE_CONFIG = {
434+
# "Morning Start": (dt.time(6, 0), "hello"),
435+
# "Morning End": (dt.time(12, 0), "hello"),
436+
# "Afternoon Start": (dt.time(12, 0), "hello"),
437+
# "Afternoon End": (dt.time(18, 0), "hello"),
438+
# "Evening Start": (dt.time(18, 0), "hello"),
439+
# "Evening End": (dt.time(21, 0), "hello"),
440+
}
406441

407-
# CONSTANCE_CONFIG = {
408-
# "AZURE_ENDPOINT": (
409-
# "Set Azure Endpoint",
410-
# "Azure Endpoint assigned to project for receipt ML.",
411-
# str,
412-
# ),
413-
# "AZURE_KEY": ("must set azure key", "Unique Key for receipt ML", str),
442+
# CONSTANCE_CONFIG_FIELDSETS = {
443+
# "Morning": ("Morning Start", "Morning End"),
444+
# "Afternoon": ("Afternoon Start", "Afternoon End"),
445+
# "Evening": ("Evening Start", "Evening End"),
414446
# }
415447

416448
AZURE_ENDPOINT = env.str("DJANGO_AZURE_ENDPOINT", "")

config/settings/settings_models.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44

55
from attrmagic import ClassBase, SimpleDict
66
from attrmagic.sentinels import MISSING, Missing
7-
from pydantic import ConfigDict, Field, SecretStr, model_serializer
7+
from loguru import logger
8+
from pydantic import ConfigDict, Field, SecretStr, field_validator, model_serializer
89

910

1011
def serialize_missing(self: ClassBase) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
@@ -108,12 +109,29 @@ class Database(ClassBase):
108109
conn_health_checks: bool | Missing = MISSING
109110
options: DatabaseOptions | Missing = MISSING
110111
password: SecretStr | Missing = MISSING
111-
port: Annotated[int | Missing, Field(ge=0, le=65535)] = MISSING
112+
port: Annotated[int, Field(ge=0, le=65535)] | Missing = MISSING
112113
time_zone: str | Missing = MISSING
113114
disable_server_side_cursors: bool | Missing = MISSING
114115
user: str | Missing = MISSING
115116
test: TestDatabase | Missing = MISSING
116117

118+
@field_validator("engine", mode="before")
119+
@classmethod
120+
def validate_builtin_engine(cls, v: Any) -> Any: # pyright: ignore[reportAny, reportExplicitAny]
121+
try:
122+
return BuiltInEngine(v)
123+
except KeyError:
124+
logger.warning(f"Unknown database engine: {v}")
125+
126+
return v # pyright: ignore[reportAny]
127+
128+
@field_validator("port", mode="before")
129+
@classmethod
130+
def validate_empty_port(cls, v: Any) -> Any: # pyright: ignore[reportAny, reportExplicitAny]
131+
if v in ("",):
132+
return MISSING
133+
return v # pyright: ignore[reportAny]
134+
117135
@model_serializer
118136
def serialize_missing(self) -> dict[str, Any]: # pyright: ignore[reportExplicitAny]
119137
output: dict[str, Any] = {} # pyright: ignore[reportExplicitAny]
@@ -128,6 +146,16 @@ def serialize_missing(self) -> dict[str, Any]: # pyright: ignore[reportExplicit
128146

129147
return output
130148

149+
@property
150+
def engine_name(self) -> str | None:
151+
try:
152+
return self.engine.name # pyright: ignore[reportUnknownVariableType, reportUnknownMemberType, reportAttributeAccessIssue]
153+
154+
except AttributeError:
155+
if self.engine is MISSING:
156+
return None
157+
return self.engine
158+
131159

132160
class Databases(SimpleDict[str, Database]):
133161
def render(self) -> dict[str, dict[str, Any]]: # pyright: ignore[reportExplicitAny]
@@ -136,6 +164,11 @@ def render(self) -> dict[str, dict[str, Any]]: # pyright: ignore[reportExplicit
136164
"""
137165
return {db_name: db.model_dump(by_alias=True) for db_name, db in self.items()}
138166

167+
@property
168+
def default(self) -> Database:
169+
assert "default" in self.root
170+
return self["default"]
171+
139172

140173
if __name__ == "__main__":
141174
# This block is for testing purposes only

devtools/__init__.py

Whitespace-only changes.

devtools/bump_build.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import re
2+
import subprocess
3+
from enum import StrEnum
4+
from pathlib import Path
5+
from typing import ClassVar, Self
6+
7+
from attrmagic import ClassBase
8+
9+
PROJECT_BASE_PATH = Path(__file__).parent.parent / "incredible_data"
10+
11+
VERSION_FILE = PROJECT_BASE_PATH / "__init__.py"
12+
BUILD_INFO_FILE = PROJECT_BASE_PATH / "build_info.py"
13+
14+
assert VERSION_FILE.exists(), "Version file does not exist, check the path"
15+
16+
17+
def bump_build():
18+
text = VERSION_FILE.read_text()
19+
value_pattern = r"__build__\s*=\s*(\d+)"
20+
match = re.search(value_pattern, text)
21+
22+
if not match:
23+
msg = "Could not find __build__ in version file"
24+
raise ValueError(msg)
25+
26+
build_number = int(match.group(1)) + 1
27+
28+
replace_pattern = r"(__build__\s*=\s*)(\d+)"
29+
new_text = re.sub(replace_pattern, rf"\1{build_number}", text)
30+
31+
_ = VERSION_FILE.write_text(new_text)
32+
33+
34+
class GitCommand(StrEnum):
35+
REV_LIST = "rev-list"
36+
REV_PARSE = "rev-parse"
37+
38+
39+
def git_output(command: GitCommand, *options: str, commit: str = "HEAD") -> str:
40+
result = subprocess.check_output( # noqa: S603
41+
["git", command, *options, commit], # noqa: S607
42+
stderr=subprocess.DEVNULL,
43+
)
44+
return result.decode("utf-8").strip()
45+
46+
47+
class GitInfo(ClassBase):
48+
commit_count: int
49+
commit_hash: str
50+
51+
build_number_variable_name: ClassVar[str] = "BUILD_NUMBER"
52+
commit_hash_variable_name: ClassVar[str] = "COMMIT_HASH"
53+
54+
@classmethod
55+
def get_info(cls) -> Self:
56+
try:
57+
commit_count = git_output(GitCommand.REV_LIST, "--count")
58+
commit_hash = git_output(GitCommand.REV_PARSE, "--short")
59+
return cls(commit_count=commit_count, commit_hash=commit_hash) # pyright: ignore[reportArgumentType]
60+
except subprocess.CalledProcessError:
61+
msg = "Failed to get git info, is git installed?"
62+
raise RuntimeError(msg) from None
63+
64+
def write_file(self, file_path: Path) -> None:
65+
content = (
66+
f'BUILD_NUMBER = {self.commit_count}\nCOMMIT_HASH = "{self.commit_hash}"\n'
67+
)
68+
_ = file_path.write_text(content)
69+
70+
@classmethod
71+
def _build_build_number_pattern(cls) -> "re.Pattern[str]":
72+
return re.compile(rf"^{cls.build_number_variable_name}\s*=\s*(\d+)")
73+
74+
@classmethod
75+
def _build_commit_hash_pattern(cls) -> "re.Pattern[str]":
76+
return re.compile(rf"^{cls.commit_hash_variable_name}\s*=\s*\"([0-9a-f]+)\"")
77+
78+
@classmethod
79+
def from_file(cls, file_path: Path) -> Self:
80+
content = file_path.read_text()
81+
build_number_matches = cls._build_build_number_pattern().search(content)
82+
commit_hash_matches = cls._build_commit_hash_pattern().search(content)
83+
84+
if not build_number_matches or not commit_hash_matches:
85+
msg = "Failed to parse build info file"
86+
raise ValueError(msg)
87+
88+
build_number = int(build_number_matches.group(1))
89+
commit_hash = commit_hash_matches.group(1)
90+
91+
return cls(commit_count=build_number, commit_hash=commit_hash)
92+
93+
94+
def _stage_file(file_path: Path) -> None:
95+
file_path_str = str(file_path)
96+
_ = subprocess.run(["git", "add", file_path_str], check=False) # noqa: S603, S607
97+
98+
99+
def update_build_info():
100+
git_info = GitInfo.get_info()
101+
git_info.write_file(BUILD_INFO_FILE)
102+
_stage_file(BUILD_INFO_FILE)
103+
104+
105+
if __name__ == "__main__":
106+
update_build_info()

incredible_data/build_info.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
BUILD_NUMBER = 175
2+
COMMIT_HASH = "0543f4e"

0 commit comments

Comments
 (0)