ft3 0.0.1__py3-none-any.whl
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.
- ft3/__init__.py +56 -0
- ft3/cli/__init__.py +31 -0
- ft3/cli/cfg.py +11 -0
- ft3/cli/lib.py +7 -0
- ft3/cli/obj.py +34 -0
- ft3/cli/utl.py +25 -0
- ft3/core/__init__.py +37 -0
- ft3/core/cfg.py +67 -0
- ft3/core/codecs/__init__.py +15 -0
- ft3/core/codecs/cfg.py +46 -0
- ft3/core/codecs/enm.py +65 -0
- ft3/core/codecs/lib.py +20 -0
- ft3/core/codecs/typ.py +14 -0
- ft3/core/codecs/utl.py +352 -0
- ft3/core/enm.py +23 -0
- ft3/core/exc.py +39 -0
- ft3/core/lib.py +57 -0
- ft3/core/strings/__init__.py +19 -0
- ft3/core/strings/cfg.py +55 -0
- ft3/core/strings/enm.py +20 -0
- ft3/core/strings/exc.py +29 -0
- ft3/core/strings/lib.py +7 -0
- ft3/core/strings/obj.py +448 -0
- ft3/core/strings/typ.py +7 -0
- ft3/core/strings/utl.py +410 -0
- ft3/core/typ/__init__.py +52 -0
- ft3/core/typ/cfg.py +11 -0
- ft3/core/typ/lib.py +16 -0
- ft3/core/typ/obj.py +560 -0
- ft3/core/typ/typ.py +123 -0
- ft3/core/typ/utl/__init__.py +9 -0
- ft3/core/typ/utl/check.py +550 -0
- ft3/core/typ/utl/hint.py +189 -0
- ft3/docs/__init__.py +33 -0
- ft3/docs/cfg.py +25 -0
- ft3/docs/enm.py +45 -0
- ft3/docs/lib.py +16 -0
- ft3/docs/obj.py +173 -0
- ft3/docs/static/__init__.py +12 -0
- ft3/docs/static/conf.tpl +106 -0
- ft3/docs/static/favicon.ico +0 -0
- ft3/docs/static/logo.png +0 -0
- ft3/docs/utl.py +437 -0
- ft3/loggers/__init__.py +55 -0
- ft3/loggers/cfg.py +26 -0
- ft3/loggers/exc.py +37 -0
- ft3/loggers/lib.py +18 -0
- ft3/loggers/obj.py +291 -0
- ft3/loggers/typ.py +59 -0
- ft3/loggers/utl.py +108 -0
- ft3/objects/__init__.py +48 -0
- ft3/objects/cfg.py +79 -0
- ft3/objects/enm.py +26 -0
- ft3/objects/exc.py +299 -0
- ft3/objects/fields/__init__.py +10 -0
- ft3/objects/fields/obj.py +781 -0
- ft3/objects/lib.py +20 -0
- ft3/objects/metas/__init__.py +12 -0
- ft3/objects/metas/obj.py +309 -0
- ft3/objects/metas/utl.py +181 -0
- ft3/objects/objs/__init__.py +10 -0
- ft3/objects/objs/obj.py +922 -0
- ft3/objects/queries/__init__.py +11 -0
- ft3/objects/queries/obj.py +213 -0
- ft3/objects/typ.py +54 -0
- ft3/objects/utl.py +130 -0
- ft3-0.0.1.dist-info/LICENSE +165 -0
- ft3-0.0.1.dist-info/METADATA +443 -0
- ft3-0.0.1.dist-info/RECORD +111 -0
- ft3-0.0.1.dist-info/WHEEL +5 -0
- ft3-0.0.1.dist-info/entry_points.txt +2 -0
- ft3-0.0.1.dist-info/top_level.txt +2 -0
- tests/__init__.py +7 -0
- tests/ci/__init__.py +7 -0
- tests/ci/cfg.py +9 -0
- tests/ci/commit_msg_test.py +105 -0
- tests/core/__init__.py +7 -0
- tests/core/cfg.py +11 -0
- tests/core/codecs/__init__.py +7 -0
- tests/core/codecs/cfg.py +11 -0
- tests/core/codecs/utl_test.py +463 -0
- tests/core/strings/__init__.py +7 -0
- tests/core/strings/cfg.py +15 -0
- tests/core/strings/exc_test.py +29 -0
- tests/core/strings/utl_test.py +190 -0
- tests/core/typings/__init__.py +7 -0
- tests/core/typings/cfg.py +13 -0
- tests/core/typings/utl_test.py +148 -0
- tests/loggers/__init__.py +7 -0
- tests/loggers/backup.py +397 -0
- tests/loggers/cfg.py +11 -0
- tests/loggers/exc_test.py +19 -0
- tests/loggers/obj_test.py +510 -0
- tests/mocking/__init__.py +103 -0
- tests/mocking/examples.py +13 -0
- tests/objects/__init__.py +7 -0
- tests/objects/cfg.py +11 -0
- tests/objects/exc_test.py +78 -0
- tests/objects/fields/__init__.py +7 -0
- tests/objects/fields/cfg.py +11 -0
- tests/objects/fields/fields_test.py +299 -0
- tests/objects/metas/__init__.py +7 -0
- tests/objects/metas/cfg.py +11 -0
- tests/objects/metas/metas_test.py +333 -0
- tests/objects/objs/__init__.py +7 -0
- tests/objects/objs/cfg.py +11 -0
- tests/objects/objs/objs_test.py +382 -0
- tests/objects/queries/__init__.py +7 -0
- tests/objects/queries/cfg.py +11 -0
- tests/objects/queries/queries_test.py +175 -0
- tests/readme_test.py +134 -0
ft3/__init__.py
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Overview
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
**Author:** dan@1howardcapital.com
|
|
6
|
+
|
|
7
|
+
**Summary:** Zero-dependency python framework for object oriented development.
|
|
8
|
+
Implement _once_, document _once_, in _one_ place.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
With ft3, you will quickly learn established best practice... \
|
|
13
|
+
or face the consequences of runtime errors that will break your code \
|
|
14
|
+
if you deviate from it.
|
|
15
|
+
|
|
16
|
+
Experienced python engineers will find a framework \
|
|
17
|
+
that expects and rewards intuitive magic method implementations, \
|
|
18
|
+
consistent type annotations, and robust docstrings.
|
|
19
|
+
|
|
20
|
+
Implement _pythonically_ with ft3 and you will only ever need to: \
|
|
21
|
+
implement _once_, document _once_, in _one_ place.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Getting Started
|
|
26
|
+
---------------
|
|
27
|
+
|
|
28
|
+
### Installation
|
|
29
|
+
|
|
30
|
+
Install from command line, with pip:
|
|
31
|
+
|
|
32
|
+
`$ pip install ft3`
|
|
33
|
+
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
__all__ = (
|
|
37
|
+
'cli',
|
|
38
|
+
'core',
|
|
39
|
+
'docs',
|
|
40
|
+
'log',
|
|
41
|
+
'loggers',
|
|
42
|
+
'objects',
|
|
43
|
+
'Field',
|
|
44
|
+
'Object'
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
__version__ = '0.0.1'
|
|
48
|
+
|
|
49
|
+
from . import cli
|
|
50
|
+
from . import core
|
|
51
|
+
from . import docs
|
|
52
|
+
from . import loggers
|
|
53
|
+
from . import objects
|
|
54
|
+
|
|
55
|
+
from . loggers import log
|
|
56
|
+
from . objects import Field, Object
|
ft3/cli/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Overview
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
**Summary:** Primary command-line interface (CLI) to ft3.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Usage
|
|
10
|
+
-----
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
$ ft3 --help
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
__all__ = (
|
|
19
|
+
'cfg',
|
|
20
|
+
'lib',
|
|
21
|
+
'obj',
|
|
22
|
+
'main',
|
|
23
|
+
'utl',
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from . import cfg
|
|
27
|
+
from . import lib
|
|
28
|
+
from . import obj
|
|
29
|
+
from . import utl
|
|
30
|
+
|
|
31
|
+
from . utl import main
|
ft3/cli/cfg.py
ADDED
ft3/cli/lib.py
ADDED
ft3/cli/obj.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""CLI objects."""
|
|
2
|
+
|
|
3
|
+
__all__ = (
|
|
4
|
+
'parsers',
|
|
5
|
+
'root_parser',
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
from .. import __version__
|
|
9
|
+
|
|
10
|
+
from . import cfg
|
|
11
|
+
from . import lib
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Constants(cfg.Constants):
|
|
15
|
+
"""Constant values specific to CLI objs."""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
root_parser = lib.argparse.ArgumentParser(
|
|
19
|
+
description='root_parser',
|
|
20
|
+
formatter_class=lib.argparse.ArgumentDefaultsHelpFormatter,
|
|
21
|
+
prog='ft3',
|
|
22
|
+
)
|
|
23
|
+
root_parser.add_argument(
|
|
24
|
+
'--version',
|
|
25
|
+
'-v',
|
|
26
|
+
action='version',
|
|
27
|
+
version=__version__,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
parsers = root_parser.add_subparsers(
|
|
31
|
+
title='module',
|
|
32
|
+
required=True,
|
|
33
|
+
help='specify a module to access its commands'
|
|
34
|
+
)
|
ft3/cli/utl.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""CLI utility functions."""
|
|
2
|
+
|
|
3
|
+
__all__ = (
|
|
4
|
+
'main',
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
from . import obj
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None: # pragma: no cover
|
|
11
|
+
"""
|
|
12
|
+
Main CLI entrypoint.
|
|
13
|
+
|
|
14
|
+
Commands follow the structure:
|
|
15
|
+
|
|
16
|
+
`$ ft3 {fgr_module_name} ...`
|
|
17
|
+
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
args = obj.root_parser.parse_args()
|
|
21
|
+
kwargs = args._get_kwargs()
|
|
22
|
+
as_args = [v for k, v in kwargs if k != 'func']
|
|
23
|
+
args.func(*as_args) # type: ignore[attr-defined]
|
|
24
|
+
|
|
25
|
+
return None
|
ft3/core/__init__.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Overview
|
|
3
|
+
========
|
|
4
|
+
|
|
5
|
+
**Author:** dan@1howardcapital.com
|
|
6
|
+
|
|
7
|
+
**Summary:** Zero-dependency python framework for object oriented development.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
Usage
|
|
12
|
+
-----
|
|
13
|
+
|
|
14
|
+
```py
|
|
15
|
+
import ft3
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
__all__ = (
|
|
22
|
+
'cfg',
|
|
23
|
+
'codecs',
|
|
24
|
+
'enm',
|
|
25
|
+
'exc',
|
|
26
|
+
'lib',
|
|
27
|
+
'strings',
|
|
28
|
+
'typ',
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
from . import cfg
|
|
32
|
+
from . import codecs
|
|
33
|
+
from . import enm
|
|
34
|
+
from . import exc
|
|
35
|
+
from . import lib
|
|
36
|
+
from . import strings
|
|
37
|
+
from . import typ
|
ft3/core/cfg.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Core constants."""
|
|
2
|
+
|
|
3
|
+
__all__ = (
|
|
4
|
+
'Constants',
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
from . import lib
|
|
8
|
+
|
|
9
|
+
if lib.t.TYPE_CHECKING: # pragma: no cover
|
|
10
|
+
from . import typ
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Constants:
|
|
14
|
+
"""Constant values shared across all of ft3."""
|
|
15
|
+
|
|
16
|
+
PACAKGE = 'ft3'
|
|
17
|
+
"""Reference to package name."""
|
|
18
|
+
|
|
19
|
+
CLASS_AS_DICT: 'typ.string[typ.snake_case]' = 'class_as_dict'
|
|
20
|
+
"""Common string reference."""
|
|
21
|
+
|
|
22
|
+
DELIM = '-'
|
|
23
|
+
"""Common delimiter used throughout package."""
|
|
24
|
+
|
|
25
|
+
INDENT = int(lib.os.getenv('INDENT', 2))
|
|
26
|
+
"""
|
|
27
|
+
Default, package-wide indentation.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
Used for `__repr__`, log messages, etc.
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
UNDEFINED = f'[[{PACAKGE.upper()}_DEFAULT_PLACEHOLDER]]'
|
|
36
|
+
"""Placeholder for undefined values that should not be `None`."""
|
|
37
|
+
|
|
38
|
+
ENV = lib.os.getenv('ENV', 'local').lower()
|
|
39
|
+
"""The lowered name of our runtime environment."""
|
|
40
|
+
|
|
41
|
+
DEPLOY_ENVS = (
|
|
42
|
+
'dev',
|
|
43
|
+
'develop',
|
|
44
|
+
'qa',
|
|
45
|
+
'test',
|
|
46
|
+
'testing',
|
|
47
|
+
'stg',
|
|
48
|
+
'stage',
|
|
49
|
+
'staging',
|
|
50
|
+
'uat',
|
|
51
|
+
'prod',
|
|
52
|
+
'production',
|
|
53
|
+
)
|
|
54
|
+
"""Valid, non-local runtime environment names."""
|
|
55
|
+
|
|
56
|
+
DELIM_REBASE = '_X_'
|
|
57
|
+
|
|
58
|
+
__ANNOTATIONS__: 'typ.string[typ.snake_case]' = '__annotations__'
|
|
59
|
+
__DATACLASS_FIELDS__: 'typ.string[typ.snake_case]' = '__dataclass_fields__'
|
|
60
|
+
__DICT__: 'typ.string[typ.snake_case]' = '__dict__'
|
|
61
|
+
__HERITAGE__: 'typ.string[typ.snake_case]' = '__heritage__'
|
|
62
|
+
__SLOTS__: 'typ.string[typ.snake_case]' = '__slots__'
|
|
63
|
+
__MODULE__: 'typ.string[typ.snake_case]' = '__module__'
|
|
64
|
+
|
|
65
|
+
FIELDS: 'typ.string[typ.snake_case]' = 'fields'
|
|
66
|
+
ENUMERATIONS: 'typ.string[typ.snake_case]' = 'enumerations'
|
|
67
|
+
HASH_FIELDS: 'typ.string[typ.snake_case]' = 'hash_fields'
|
ft3/core/codecs/cfg.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Codec constants."""
|
|
2
|
+
|
|
3
|
+
__all__ = (
|
|
4
|
+
'Constants',
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
from .. import cfg
|
|
8
|
+
|
|
9
|
+
from . import lib
|
|
10
|
+
from . import typ
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def _isoformat_encoder(
|
|
14
|
+
o: lib.datetime.datetime | lib.datetime.date | lib.datetime.time
|
|
15
|
+
) -> str:
|
|
16
|
+
return o.isoformat()
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class Constants(cfg.Constants):
|
|
20
|
+
"""Constant values shared across core codecs modules."""
|
|
21
|
+
|
|
22
|
+
ENCODERS: dict[
|
|
23
|
+
type[lib.t.Any],
|
|
24
|
+
lib.t.Callable[[lib.t.Any], typ.Serial]
|
|
25
|
+
] = {
|
|
26
|
+
bytes: lambda o: getattr(o, 'decode')(),
|
|
27
|
+
lib.datetime.date: _isoformat_encoder,
|
|
28
|
+
lib.datetime.datetime: _isoformat_encoder,
|
|
29
|
+
lib.datetime.time: _isoformat_encoder,
|
|
30
|
+
lib.datetime.timedelta: lambda td: getattr(td, 'total_seconds')(),
|
|
31
|
+
lib.decimal.Decimal: float,
|
|
32
|
+
lib.enum.Enum: lambda o: getattr(o, 'value'),
|
|
33
|
+
frozenset: list,
|
|
34
|
+
lib.collections.deque: list,
|
|
35
|
+
lib.types.GeneratorType: list,
|
|
36
|
+
lib.ipaddress.IPv4Address: str,
|
|
37
|
+
lib.ipaddress.IPv4Interface: str,
|
|
38
|
+
lib.ipaddress.IPv4Network: str,
|
|
39
|
+
lib.ipaddress.IPv6Address: str,
|
|
40
|
+
lib.ipaddress.IPv6Interface: str,
|
|
41
|
+
lib.ipaddress.IPv6Network: str,
|
|
42
|
+
lib.pathlib.Path: str,
|
|
43
|
+
lib.re.Pattern: lambda o: getattr(o, 'pattern'),
|
|
44
|
+
set: list,
|
|
45
|
+
lib.uuid.UUID: str,
|
|
46
|
+
}
|
ft3/core/codecs/enm.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Codecs enumerations."""
|
|
2
|
+
|
|
3
|
+
from .. import enm
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'ParseErrorRef',
|
|
7
|
+
*enm.__all__
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from .. enm import *
|
|
11
|
+
|
|
12
|
+
from . import lib
|
|
13
|
+
from . import typ
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ParseErrorRef(lib.enum.Enum):
|
|
17
|
+
"""
|
|
18
|
+
Valid ErrorRef Enumeration.
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
bool_decode = typ.ErrorRef(
|
|
23
|
+
'Could not decode valid JSON string to python `bool`.'
|
|
24
|
+
)
|
|
25
|
+
invalid_arr_decode = typ.ErrorRef(
|
|
26
|
+
'Could not decode valid JSON array to python: `invalid item type(s)`.'
|
|
27
|
+
)
|
|
28
|
+
invalid_arr_len = typ.ErrorRef(
|
|
29
|
+
'Could not decode valid JSON array to python: `invalid array length`.'
|
|
30
|
+
)
|
|
31
|
+
invalid_json = typ.ErrorRef(
|
|
32
|
+
'Could not deserialize string as valid JSON.'
|
|
33
|
+
)
|
|
34
|
+
invalid_keys_decode = typ.ErrorRef(
|
|
35
|
+
'Could not decode valid JSON object to python: `invalid keys`.'
|
|
36
|
+
)
|
|
37
|
+
invalid_map_decode = typ.ErrorRef(
|
|
38
|
+
' '.join(
|
|
39
|
+
(
|
|
40
|
+
'Could not decode valid JSON object to python:',
|
|
41
|
+
'`invalid item type(s)`.'
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
)
|
|
45
|
+
invalid_values_decode = typ.ErrorRef(
|
|
46
|
+
'Could not decode valid JSON object to python: `invalid values`.'
|
|
47
|
+
)
|
|
48
|
+
number_decode = typ.ErrorRef(
|
|
49
|
+
' '.join(
|
|
50
|
+
(
|
|
51
|
+
'Could not decode valid JSON string to python',
|
|
52
|
+
'`numbers.Number`.'
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
null_decode = typ.ErrorRef(
|
|
57
|
+
'Could not decode valid JSON string to python `None`.'
|
|
58
|
+
)
|
|
59
|
+
datetime_decode = typ.ErrorRef(
|
|
60
|
+
'Could not decode value to valid `datetime`.'
|
|
61
|
+
)
|
|
62
|
+
literal_decode = typ.ErrorRef(
|
|
63
|
+
'Could not decode value to valid `Literal`.'
|
|
64
|
+
)
|
|
65
|
+
value_decode = typ.ErrorRef('Could not decode invalid value.')
|
ft3/core/codecs/lib.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Codecs imports."""
|
|
2
|
+
|
|
3
|
+
from .. import lib
|
|
4
|
+
|
|
5
|
+
__all__ = (
|
|
6
|
+
'collections',
|
|
7
|
+
'ipaddress',
|
|
8
|
+
'numbers',
|
|
9
|
+
'pathlib',
|
|
10
|
+
'uuid',
|
|
11
|
+
*lib.__all__
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
import collections.abc
|
|
15
|
+
import ipaddress
|
|
16
|
+
import numbers
|
|
17
|
+
import pathlib
|
|
18
|
+
import uuid
|
|
19
|
+
|
|
20
|
+
from .. lib import *
|