sotkalib 0.0.6.post1__tar.gz → 0.1.0b1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/PKG-INFO +1 -1
  2. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/pyproject.toml +1 -1
  3. sotkalib-0.1.0b1/src/sotkalib/__init__.py +3 -0
  4. sotkalib-0.1.0b1/src/sotkalib/dict/__init__.py +13 -0
  5. sotkalib-0.1.0b1/src/sotkalib/enum/__init__.py +3 -0
  6. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/enum/mixins.py +17 -3
  7. sotkalib-0.1.0b1/src/sotkalib/exceptions/__init__.py +4 -0
  8. sotkalib-0.1.0b1/src/sotkalib/exceptions/traceback.py +5 -0
  9. sotkalib-0.1.0b1/src/sotkalib/func/__init__.py +6 -0
  10. sotkalib-0.1.0b1/src/sotkalib/func/concur.py +12 -0
  11. sotkalib-0.1.0b1/src/sotkalib/func/cond.py +40 -0
  12. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/http/client_session.py +3 -3
  13. sotkalib-0.1.0b1/src/sotkalib/sqla/__init__.py +4 -0
  14. sotkalib-0.1.0b1/src/sotkalib/sqla/dbm.py +20 -0
  15. sotkalib-0.1.0b1/src/sotkalib/time/__init__.py +10 -0
  16. sotkalib-0.1.0b1/src/sotkalib/type/__init__.py +18 -0
  17. sotkalib-0.0.6.post1/src/sotkalib/__init__.py +0 -3
  18. sotkalib-0.0.6.post1/src/sotkalib/enum/__init__.py +0 -3
  19. sotkalib-0.0.6.post1/src/sotkalib/exceptions/__init__.py +0 -3
  20. sotkalib-0.0.6.post1/src/sotkalib/exceptions/api/__init__.py +0 -1
  21. sotkalib-0.0.6.post1/src/sotkalib/sqla/__init__.py +0 -3
  22. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/README.md +0 -0
  23. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/config/__init__.py +0 -0
  24. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/config/field.py +0 -0
  25. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/config/struct.py +0 -0
  26. /sotkalib-0.0.6.post1/src/sotkalib/exceptions/api/exc.py → /sotkalib-0.1.0b1/src/sotkalib/exceptions/api.py +0 -0
  27. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/exceptions/handlers/__init__.py +0 -0
  28. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/exceptions/handlers/args_incl_error.py +0 -0
  29. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/exceptions/handlers/core.py +0 -0
  30. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/http/__init__.py +0 -0
  31. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/log/__init__.py +0 -0
  32. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/log/factory.py +0 -0
  33. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/py.typed +0 -0
  34. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/redis/__init__.py +0 -0
  35. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/redis/client.py +0 -0
  36. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/redis/lock.py +0 -0
  37. {sotkalib-0.0.6.post1 → sotkalib-0.1.0b1}/src/sotkalib/sqla/db.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sotkalib
3
- Version: 0.0.6.post1
3
+ Version: 0.1.0b1
4
4
  Summary:
5
5
  Author: alexey
6
6
  Author-email: alexey <me@pyrorhythm.dev>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sotkalib"
3
- version = "0.0.6.post1"
3
+ version = "0.1.0b1"
4
4
  description = ""
5
5
  authors = [
6
6
  { email = "me@pyrorhythm.dev", name = "alexey" }
@@ -0,0 +1,3 @@
1
+ from . import config, enum, exceptions, http, log, redis, sqla, time, type
2
+
3
+ __all__ = ["config", "enum", "exceptions", "http", "log", "redis", "sqla", "time", "type"]
@@ -0,0 +1,13 @@
1
+ from typing import Any
2
+
3
+ from sotkalib.type import Unset
4
+
5
+
6
+ def without_unset(d: dict[str, Any]) -> dict[str, Any]:
7
+ newd = {}
8
+ for k, v in d.items():
9
+ if v == Unset:
10
+ continue
11
+ newd[k] = v
12
+ return newd
13
+
@@ -0,0 +1,3 @@
1
+ from .mixins import UppercaseMixin, ValidatorMixin, ValuesMixin
2
+
3
+ __all__ = ["ValidatorMixin", "UppercaseMixin", "ValuesMixin"]
@@ -1,15 +1,15 @@
1
1
  from collections.abc import Sequence
2
- from enum import Enum
2
+ from enum import StrEnum
3
3
  from typing import Any, Literal, Self, overload
4
4
 
5
5
 
6
- class UppercaseStrEnumMixin(str, Enum):
6
+ class UppercaseMixin(StrEnum):
7
7
  @staticmethod
8
8
  def _generate_next_value_(name: str, start: int, count: int, last_values: Sequence) -> str: # noqa
9
9
  return name.upper()
10
10
 
11
11
 
12
- class ValidatorStrEnumMixin(str, Enum):
12
+ class ValidatorMixin(StrEnum):
13
13
  @classmethod
14
14
  def _normalize_value(cls, val: Any) -> str:
15
15
  if isinstance(val, (str, bytes, bytearray)):
@@ -57,3 +57,17 @@ class ValidatorStrEnumMixin(str, Enum):
57
57
  @classmethod
58
58
  def values(cls) -> Sequence[Self]:
59
59
  return list(cls)
60
+
61
+
62
+ class ValuesMixin:
63
+ @classmethod
64
+ def values_list(cls) -> list[str]:
65
+ return [v for k, v in vars(cls).items() if not k.startswith("_") and isinstance(v, str)]
66
+
67
+ @classmethod
68
+ def values_set(cls) -> set[str]:
69
+ return set(cls.values_list())
70
+
71
+ @classmethod
72
+ def names_list(cls) -> list[str]:
73
+ return [k for k, v in vars(cls).items() if not k.startswith("_") and isinstance(v, str)]
@@ -0,0 +1,4 @@
1
+ from . import api, handlers
2
+ from .traceback import traceback_from
3
+
4
+ __all__ = ["api", "handlers", "traceback_from"]
@@ -0,0 +1,5 @@
1
+ import traceback
2
+
3
+
4
+ def traceback_from(exc: BaseException) -> str:
5
+ return "".join(traceback.format_exception(exc))
@@ -0,0 +1,6 @@
1
+ from .concur import asyncfn, asyncfn_or_raise
2
+ from .cond import or_raise, suppress, type_or_raise
3
+
4
+ __all__ = [
5
+ "asyncfn", "asyncfn_or_raise", "or_raise", "type_or_raise", "suppress"
6
+ ]
@@ -0,0 +1,12 @@
1
+ import inspect
2
+ from collections.abc import Callable
3
+ from typing import Any
4
+
5
+
6
+ def asyncfn(fn: Callable[..., Any]) -> bool:
7
+ return inspect.iscoroutinefunction(fn)
8
+
9
+
10
+ def asyncfn_or_raise(fn: Callable[..., Any]) -> None:
11
+ if not inspect.iscoroutinefunction(fn):
12
+ raise TypeError(f"{fn} is not an async function")
@@ -0,0 +1,40 @@
1
+ from collections.abc import Generator, Sequence
2
+ from contextlib import contextmanager
3
+ from typing import Literal
4
+ from warnings import warn
5
+
6
+
7
+ @contextmanager
8
+ def suppress(
9
+ mode: Literal["all", "exact"] = "all", excts: Sequence[type[BaseException]] | None = None
10
+ ) -> Generator[None]:
11
+ if excts is None:
12
+ if mode == "exact":
13
+ warn("mode = 'exact' and excts = None is passed to suppress, bubbling exception up")
14
+ exc_ts = ()
15
+ else:
16
+ exc_ts = excts
17
+
18
+ try:
19
+ yield None
20
+ except Exception as exc:
21
+ if mode == "all":
22
+ return
23
+
24
+ if mode == "exact" and type(exc) in exc_ts:
25
+ return
26
+
27
+ raise exc
28
+
29
+
30
+ def or_raise[T](v: T | None, msg: str = "v is None") -> T:
31
+ if v is None:
32
+ raise ValueError(msg)
33
+
34
+ return v
35
+
36
+
37
+ def type_or_raise[T](v: object, exp: type[T], msg: str | None = None) -> T:
38
+ if not isinstance(v, exp):
39
+ raise TypeError(msg or f"want {exp}, got {type(v)}")
40
+ return v
@@ -189,9 +189,9 @@ class ClientSettings(BaseModel):
189
189
  for k, v in kws.items():
190
190
  if "." in k:
191
191
  pk, ck = k.split(".")
192
- setattr(self, pk, setattr(getattr(self, pk), ck, v))
193
-
194
- setattr(self, k, v)
192
+ setattr(getattr(self, pk), ck, v)
193
+ else:
194
+ setattr(self, k, v)
195
195
 
196
196
  return self
197
197
 
@@ -0,0 +1,4 @@
1
+ from .db import Database, DatabaseSettings
2
+ from .dbm import BasicDBM
3
+
4
+ __all__ = ("Database", "DatabaseSettings", "BasicDBM")
@@ -0,0 +1,20 @@
1
+ from typing import Any
2
+
3
+ from sqlalchemy import inspect
4
+ from sqlalchemy.orm import DeclarativeBase
5
+
6
+
7
+ class BasicDBM(DeclarativeBase):
8
+ __abstract__ = True
9
+ __table_args__ = {"extend_existing": True}
10
+
11
+ def dict(self, **kw) -> dict[str, Any]:
12
+ result = {field.name: getattr(self, field.name) for field in self.__table__.c}
13
+ if kw is not None:
14
+ result.update(kw)
15
+ return result
16
+
17
+ def attribute_loaded(self, key: str):
18
+ if key not in (k := {c.key for c in inspect(self).mapper.all_orm_descriptors}): # type:ignore
19
+ raise KeyError(k)
20
+ return key not in inspect(self).unloaded
@@ -0,0 +1,10 @@
1
+ from datetime import UTC, datetime, timezone
2
+
3
+ __all__ = ["utcnow", "now"]
4
+
5
+ def utcnow() -> datetime:
6
+ return datetime.now(UTC)
7
+
8
+
9
+ def now(tz: timezone | None = None) -> datetime:
10
+ return datetime.now(tz)
@@ -0,0 +1,18 @@
1
+ __all__ = ["Unset", "unset"]
2
+
3
+
4
+ class _UnsetType:
5
+ __slots__ = ()
6
+
7
+ def __repr__(self) -> str:
8
+ return "Unset"
9
+
10
+ def __bool__(self) -> bool:
11
+ return False
12
+
13
+
14
+ Unset = _UnsetType()
15
+
16
+
17
+ def unset(val: object) -> bool:
18
+ return val is Unset
@@ -1,3 +0,0 @@
1
- from . import config, enum, exceptions, http, log, redis, sqla
2
-
3
- __all__ = ["config", "enum", "exceptions", "http", "log", "redis", "sqla"]
@@ -1,3 +0,0 @@
1
- from .mixins import UppercaseStrEnumMixin, ValidatorStrEnumMixin
2
-
3
- __all__ = ["ValidatorStrEnumMixin", "UppercaseStrEnumMixin"]
@@ -1,3 +0,0 @@
1
- from . import api, handlers
2
-
3
- __all__ = ["api", "handlers"]
@@ -1 +0,0 @@
1
- from .exc import APIError, ErrorSchema
@@ -1,3 +0,0 @@
1
- from .db import Database, DatabaseSettings
2
-
3
- __all__ = ("Database", "DatabaseSettings")
File without changes