Skip to content

Commit 432810c

Browse files
authored
Dev (#300)
* Merge changes from main (#298) * Dev (#294) * Start work on HTTPX utils improvements (#290) * Update demo(). Add vscode workspace. Update httpx validators. Move file_utils -> path_utils * Merge changes from main (#293) * Dev (#291) * Start work on HTTPX utils improvements (#290) * Update demo(). Add vscode workspace. Update httpx validators. Move file_utils -> path_utils * release(v0.2.9): (#292) Rename file_utils -> path_utils. Improve validators. Add core.constants, with directory consts like DATA_DIR and CACHE_DIR. TODO: replace any data/cache/serialize dir references with the new constants * remove old references to hardcoded data/cache/serialize dirs. Replace references with new core.constant values * Fix LOG_DIR import * release(v0.2.10): Small update (#295) Update references to default values in core.constants throughout app * release(v0.2.11): Bugfix (#297) Fix issues with imports, where the script was still trying to import variables from constants.py files that no longer exist. * Feat/sqlite utils (#299) * Dev (#294) * Start work on HTTPX utils improvements (#290) * Update demo(). Add vscode workspace. Update httpx validators. Move file_utils -> path_utils * Merge changes from main (#293) * Dev (#291) * Start work on HTTPX utils improvements (#290) * Update demo(). Add vscode workspace. Update httpx validators. Move file_utils -> path_utils * release(v0.2.9): (#292) Rename file_utils -> path_utils. Improve validators. Add core.constants, with directory consts like DATA_DIR and CACHE_DIR. TODO: replace any data/cache/serialize dir references with the new constants * remove old references to hardcoded data/cache/serialize dirs. Replace references with new core.constant values * Fix LOG_DIR import * release(v0.2.10): Small update (#295) Update references to default values in core.constants throughout app * release(v0.2.11): Bugfix (#297) Fix issues with imports, where the script was still trying to import variables from constants.py files that no longer exist. * Add util for initializing SQLite databases. * Add DB_DIR const. Update SQLite schema with DB_DIR * Run linters, formatters
1 parent bc0de85 commit 432810c

File tree

18 files changed

+190
-24
lines changed

18 files changed

+190
-24
lines changed

demo.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
23
import sys
34

45
sys.path.append(".")
@@ -12,8 +13,8 @@
1213
from red_utils.std import (
1314
context_managers,
1415
dict_utils,
15-
path_utils,
1616
hash_utils,
17+
path_utils,
1718
time_utils,
1819
uuid_utils,
1920
)
@@ -44,7 +45,6 @@
4445
from red_utils import CustomException
4546
from red_utils.ext.context_managers import cli_spinners
4647

47-
4848
def test_file_utils_list() -> list[Path]:
4949
cwd = Path.cwd()
5050
search_dir = f"{cwd}/red_utils"

red_utils/core/__init__.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
from __future__ import annotations
22

3-
from . import dataclass_utils, constants
4-
3+
from . import constants, dataclass_utils
54
from .constants import (
6-
DATA_DIR,
75
CACHE_DIR,
8-
SERIALIZE_DIR,
9-
JSON_DIR,
6+
DATA_DIR,
7+
DB_DIR,
108
ENSURE_EXIST_DIRS,
9+
JSON_DIR,
1110
LOG_DIR,
11+
SERIALIZE_DIR,
1212
)

red_utils/core/constants.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
from __future__ import annotations
2+
13
from pathlib import Path
24

35
DATA_DIR: Path = Path(".data")
46
CACHE_DIR: Path = Path(".cache")
57
SERIALIZE_DIR: Path = Path(".serialize")
68
JSON_DIR: Path = Path(f"{DATA_DIR}/json")
79
LOG_DIR: Path = Path("logs")
10+
DB_DIR: Path = Path(".db")
811

912
ENSURE_EXIST_DIRS: list[Path] = [DATA_DIR, CACHE_DIR, SERIALIZE_DIR, LOG_DIR]

red_utils/ext/diskcache_utils/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
from typing import Any
44

5+
from red_utils.core.constants import CACHE_DIR
6+
57
from .classes import CacheInstance
68
from .constants import (
79
default_timeout_dict,
810
valid_key_types,
911
valid_tag_types,
1012
valid_val_types,
1113
)
12-
from red_utils.core.constants import CACHE_DIR
13-
1414
from .operations import (
1515
check_cache,
1616
check_cache_key_exists,

red_utils/ext/diskcache_utils/classes.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from pathlib import Path
55
from typing import Any, Union
66

7-
from red_utils.std.dataclass_mixins import DictMixin
87
from red_utils.core.constants import CACHE_DIR
8+
from red_utils.std.dataclass_mixins import DictMixin
99

1010
from .operations import (
1111
check_cache,
@@ -34,7 +34,6 @@
3434
from diskcache import Cache
3535
from diskcache.core import warnings
3636

37-
3837
def default_timeout() -> int:
3938
timeout = convert_to_seconds(amount=24, unit="hours")
4039
return timeout

red_utils/ext/diskcache_utils/operations.py

-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
from diskcache import Cache
3333

34-
3534
def convert_to_seconds(amount: int = None, unit: str = None) -> int:
3635
"""Convert an amount of time to seconds.
3736

red_utils/ext/httpx_utils/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
from .constants import default_headers
99
from .operations import get_req_client, make_request, merge_headers, update_headers
1010
from .validators import (
11-
validate_headers,
1211
valid_methods,
1312
validate_client,
13+
validate_headers,
1414
validate_method,
1515
)

red_utils/ext/httpx_utils/classes.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1+
from __future__ import annotations
2+
3+
from dataclasses import dataclass, field
14
from typing import Union
25

36
from red_utils.core.dataclass_utils import DictMixin
4-
57
from red_utils.validators.ext.httpx_validators import (
68
valid_methods,
79
validate_client,
810
validate_headers,
911
validate_method,
1012
)
11-
from .constants import default_headers
1213

13-
from dataclasses import dataclass, field
14+
from .constants import default_headers
1415

1516
import httpx
1617

17-
1818
@dataclass
1919
class SimpleHTTPXClientBase:
2020
method: str | None = field(default="GET")

red_utils/ext/httpx_utils/operations.py

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
from httpx import Client
1515

16-
1716
def merge_headers(
1817
original_headers: dict[str, str] = default_headers,
1918
update_vals: dict[str, str] = None,

red_utils/ext/httpx_utils/validators.py

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from __future__ import annotations
2+
13
from typing import Union
4+
25
from httpx import AsyncClient, Client
36

47
valid_methods: list[str] = ["GET", "POST", "PUT", "UPDATE", "DELETE"]

red_utils/ext/loguru_utils/sinks.py

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from typing import Generic, TextIO, TypeVar, Union
77

8+
from red_utils.core.constants import LOG_DIR
89
from red_utils.core.dataclass_utils import DictMixin
910
from red_utils.core.constants import LOG_DIR
1011

red_utils/ext/msgpack_utils/operations.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
from typing import Union
55
from uuid import uuid4
66

7-
from .classes import SerialFunctionResponse
87
from red_utils.core.constants import SERIALIZE_DIR
98

10-
import msgpack
9+
from .classes import SerialFunctionResponse
1110

11+
import msgpack
1212

1313
def ensure_path(dir: Union[str, Path] = None) -> bool:
1414
"""Ensure a directory path exists.

red_utils/std/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
context_managers,
55
dataclass_mixins,
66
dict_utils,
7-
path_utils,
87
hash_utils,
8+
path_utils,
9+
sqlite_utils,
910
time_utils,
1011
uuid_utils,
1112
)

red_utils/std/path_utils/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
from . import constants, operations
44
from .operations import (
55
crawl_dir,
6+
delete_path,
7+
ensure_dirs_exist,
68
export_json,
79
list_files,
8-
ensure_dirs_exist,
9-
delete_path,
1010
)

red_utils/std/path_utils/operations.py

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
from red_utils.core.constants import JSON_DIR
1111

12-
1312
def file_ts(fmt: str = "%Y-%m-%d_%H:%M:%S") -> str:
1413
"""Return a formatted timestamp, useful for prepending to dir/file names."""
1514
now: str = datetime.now().strftime(fmt)
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from __future__ import annotations
2+
3+
import sys
4+
5+
sys.path.append(".")
6+
7+
from .operations import get_demo_db, get_sqlite_db, init_sqlite_db
8+
from .schemas import SQLiteDB
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""Create an empty sqlite database.
2+
"""
3+
from __future__ import annotations
4+
5+
from pathlib import Path
6+
from typing import Union
7+
8+
from .schemas import SQLiteDB
9+
10+
def init_sqlite_db(db_definition: SQLiteDB = None):
11+
"""Initialize an empty SQLite database.
12+
13+
Params:
14+
-------
15+
- db_definition (SQLiteDB): An initialized SQLiteDB object defining the SQLite database to create.
16+
"""
17+
if db_definition is None:
18+
raise ValueError("Missing SQLiteDB object.")
19+
20+
if db_definition.exists:
21+
print(f"Database already exists at {db_definition.db_path}")
22+
return False
23+
24+
try:
25+
db_definition.create_empty_db()
26+
27+
return True
28+
29+
except Exception as exc:
30+
msg = Exception(
31+
f"Unhandled exception initializing empty SQLite database. Details: {exc}"
32+
)
33+
print(msg)
34+
35+
return False
36+
37+
38+
def get_demo_db() -> SQLiteDB:
39+
"""Return an initialized SQLiteDB object with default settings.
40+
41+
A new database called "demo.db" will be created at the default '.db' path.
42+
"""
43+
try:
44+
_db: SQLiteDB = SQLiteDB()
45+
return _db
46+
except Exception as exc:
47+
raise Exception(
48+
f"Unhandled exception initializing default database. Details: {exc}"
49+
)
50+
51+
52+
def get_sqlite_db(name: str = None, location: Union[str, Path] = None) -> SQLiteDB:
53+
"""Initialize a SQLiteDB object.
54+
55+
This is the same as simply instantiating a SQLiteDB object, like:
56+
example_db: SQLiteDB = SQLiteDB(name=..., location=...)
57+
58+
Params:
59+
-------
60+
- name (str): The name of the SQLite database. This will be used for the filename.
61+
- location (str|Path): The directory location to save the database. Note that Path values will be converted to string, then
62+
back to Path, so it is best to just pass the location as a string.
63+
"""
64+
if name is None:
65+
raise ValueError("Missing database name")
66+
if location is None:
67+
raise ValueError("Missing output path location for database")
68+
if isinstance(location, Path):
69+
location: str = str(location)
70+
71+
try:
72+
_db: SQLiteDB = SQLiteDB(name=name, location=location)
73+
return _db
74+
except Exception as exc:
75+
raise Exception(f"Unhandled exception creating SQLite database. Details: {exc}")
76+
77+
78+
if __name__ == "__main__":
79+
demo_db: SQLiteDB = SQLiteDB()
80+
print(demo_db.stat_str)
81+
82+
init_sqlite_db(demo_db)

red_utils/std/sqlite_utils/schemas.py

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from __future__ import annotations
2+
3+
from dataclasses import dataclass, field
4+
from pathlib import Path
5+
import sqlite3
6+
7+
from core import DB_DIR
8+
9+
@dataclass
10+
class SQLiteDB:
11+
"""Define a simple SQLite database path.
12+
13+
Use this object's .create_empty_db() function to
14+
attempt to create a database at the object's db_path
15+
property.
16+
"""
17+
18+
name: str = field(default="demo")
19+
ext: str = field(default=".sqlite")
20+
location: str = field(default=DB_DIR)
21+
22+
@property
23+
def filename(self) -> str:
24+
_filename: str = f"{self.name}{self.ext}"
25+
26+
return _filename
27+
28+
@property
29+
def db_path(self) -> str:
30+
_path: str = f"{self.location}/{self.filename}"
31+
32+
return _path
33+
34+
@property
35+
def exists(self) -> bool:
36+
if Path(self.db_path).exists():
37+
return True
38+
else:
39+
return False
40+
41+
@property
42+
def stat_str(self) -> str:
43+
_str: str = f"[{self.filename}] | {'Exists' if self.exists else 'Does not exist'} @ {self.db_path}/"
44+
45+
return _str
46+
47+
def create_empty_db(self) -> bool:
48+
if not self.exists:
49+
try:
50+
connection = sqlite3.Connection = sqlite3.connect(self.db_path)
51+
print(f"Initializing empty database file at: {self.db_path}")
52+
53+
connection.close()
54+
55+
return True
56+
except Exception as exc:
57+
print(
58+
Exception(
59+
f"Unhandled exception initializing an empty SQLite database at {self.db_path}. Details: {exc}"
60+
)
61+
)
62+
63+
return False
64+
else:
65+
return True
66+
67+
def __post_init__(self):
68+
if not self.ext.startswith("."):
69+
self.ext = f".{self.ext}"
70+
71+
if not Path(self.db_path).exists():
72+
Path(self.db_path).parent.mkdir(parents=True, exist_ok=True)

0 commit comments

Comments
 (0)