flashboot-core 0.1.2__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.
- flashboot_core-0.1.2/PKG-INFO +9 -0
- flashboot_core-0.1.2/flashboot_core/__init__.py +0 -0
- flashboot_core-0.1.2/flashboot_core/env/__init__.py +7 -0
- flashboot_core-0.1.2/flashboot_core/env/environment.py +40 -0
- flashboot_core-0.1.2/flashboot_core/env/properties_property_source_loader.py +0 -0
- flashboot_core-0.1.2/flashboot_core/env/property_source.py +20 -0
- flashboot_core-0.1.2/flashboot_core/env/property_source_loader.py +45 -0
- flashboot_core-0.1.2/flashboot_core/env/yaml_property_source_loader.py +15 -0
- flashboot_core-0.1.2/flashboot_core/event_bus/__init__.py +9 -0
- flashboot_core-0.1.2/flashboot_core/event_bus/async_event_bus.py +21 -0
- flashboot_core-0.1.2/flashboot_core/event_bus/base.py +29 -0
- flashboot_core-0.1.2/flashboot_core/event_bus/sync_event_bus.py +46 -0
- flashboot_core-0.1.2/flashboot_core/exceptions/__init__.py +5 -0
- flashboot_core-0.1.2/flashboot_core/exceptions/base.py +3 -0
- flashboot_core-0.1.2/flashboot_core/exceptions/event_bus.py +9 -0
- flashboot_core-0.1.2/flashboot_core/io/__init__.py +5 -0
- flashboot_core-0.1.2/flashboot_core/io/file.py +13 -0
- flashboot_core-0.1.2/flashboot_core/io/file_system_resource.py +16 -0
- flashboot_core-0.1.2/flashboot_core/io/resource.py +14 -0
- flashboot_core-0.1.2/flashboot_core/utils/__init__.py +0 -0
- flashboot_core-0.1.2/flashboot_core.egg-info/PKG-INFO +9 -0
- flashboot_core-0.1.2/flashboot_core.egg-info/SOURCES.txt +25 -0
- flashboot_core-0.1.2/flashboot_core.egg-info/dependency_links.txt +1 -0
- flashboot_core-0.1.2/flashboot_core.egg-info/requires.txt +4 -0
- flashboot_core-0.1.2/flashboot_core.egg-info/top_level.txt +1 -0
- flashboot_core-0.1.2/pyproject.toml +11 -0
- flashboot_core-0.1.2/setup.cfg +4 -0
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import os
|
|
3
|
+
from typing import Literal, Optional, get_args
|
|
4
|
+
|
|
5
|
+
from commons_lang.text import string_utils
|
|
6
|
+
|
|
7
|
+
ACTIVE_PROFILES_PROPERTY_NAME = "profiles.active"
|
|
8
|
+
|
|
9
|
+
Profile = Literal["dev", "test", "prod"]
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Environment(object):
|
|
13
|
+
|
|
14
|
+
@staticmethod
|
|
15
|
+
def get_active_profiles(default_profile: Optional[Profile] = "prod") -> list[str]:
|
|
16
|
+
"""
|
|
17
|
+
Get the active profiles from the environment.
|
|
18
|
+
The value may be comma-delimited.
|
|
19
|
+
:return: The active profiles.
|
|
20
|
+
"""
|
|
21
|
+
profiles = []
|
|
22
|
+
active_profiles = os.getenv(ACTIVE_PROFILES_PROPERTY_NAME)
|
|
23
|
+
if string_utils.is_blank(active_profiles):
|
|
24
|
+
parser = argparse.ArgumentParser()
|
|
25
|
+
parser.add_argument(
|
|
26
|
+
f"--{ACTIVE_PROFILES_PROPERTY_NAME}",
|
|
27
|
+
dest="active_profiles",
|
|
28
|
+
help="The active profiles",
|
|
29
|
+
default=default_profile,
|
|
30
|
+
choices=list(map(lambda x: str(x), get_args(Profile))),
|
|
31
|
+
required=True
|
|
32
|
+
)
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
active_profiles = args.active_profiles
|
|
35
|
+
|
|
36
|
+
if string_utils.is_not_blank(active_profiles):
|
|
37
|
+
profiles.extend(active_profiles.split(","))
|
|
38
|
+
if len(profiles) == 0:
|
|
39
|
+
raise RuntimeError("No active profiles found")
|
|
40
|
+
return profiles
|
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
T = typing.TypeVar("T")
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PropertySource(object):
|
|
7
|
+
def __init__(self, name: str, source: typing.Optional[T] = object):
|
|
8
|
+
self.name = name
|
|
9
|
+
self.source = source
|
|
10
|
+
assert self.name is not None
|
|
11
|
+
assert self.source is not None
|
|
12
|
+
|
|
13
|
+
def get_name(self) -> str:
|
|
14
|
+
return self.name
|
|
15
|
+
|
|
16
|
+
def get_source(self) -> T:
|
|
17
|
+
return self.source
|
|
18
|
+
|
|
19
|
+
def get_contains_property(self, name: str):
|
|
20
|
+
pass
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from flashboot_core.env.environment import Environment
|
|
6
|
+
from flashboot_core.env.property_source import PropertySource
|
|
7
|
+
from flashboot_core.io.resource import Resource
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class PropertySourceLoader(ABC):
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
def get_file_extensions(self) -> typing.List[str]:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def load(self, name: str, source: Resource) -> PropertySource:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SimpleYamlLoader:
|
|
22
|
+
configs = {}
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
self.env = Environment()
|
|
26
|
+
|
|
27
|
+
def load(self, source: Optional[Resource]) -> None:
|
|
28
|
+
profiles = self.env.get_active_profiles()
|
|
29
|
+
for profile in profiles:
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# yaml_loader = SimpleYamlLoader()
|
|
34
|
+
# yaml_loader.load("")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def property_bind(property_path: str):
|
|
38
|
+
def decorator(cls):
|
|
39
|
+
if property_path is None:
|
|
40
|
+
return
|
|
41
|
+
|
|
42
|
+
setattr(cls, "property_path", property_path)
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
return decorator
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import typing
|
|
2
|
+
|
|
3
|
+
from flashboot_core.env.property_source import PropertySource
|
|
4
|
+
from flashboot_core.env.property_source_loader import PropertySourceLoader
|
|
5
|
+
from flashboot_core.io.resource import Resource
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# TODO 使用YamlPropertySourceLoader而不是SimpleYamlLoader
|
|
9
|
+
class YamlPropertySourceLoader(PropertySourceLoader):
|
|
10
|
+
|
|
11
|
+
def get_file_extensions(self) -> typing.List[str]:
|
|
12
|
+
return ["yml", "yaml"]
|
|
13
|
+
|
|
14
|
+
def load(self, name: str, source: Resource) -> PropertySource:
|
|
15
|
+
pass
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from flashboot_core.event_bus.base import BaseEventBus
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class AsyncEventBus(BaseEventBus):
|
|
7
|
+
|
|
8
|
+
def on(self, event: str, /, *, priority: int = 1) -> Callable | int:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
def subscribe(self, event: str, callback: Callable, /, *, priority: int = 1) -> int:
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
def unsubscribe(self, event: str, callback: Callable, /) -> int | None:
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def emit(self, event: str, /, **kwargs) -> int:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async_event_bus = AsyncEventBus()
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
from typing import Dict, List, Callable, Any
|
|
3
|
+
|
|
4
|
+
from flashboot_core.exceptions.event_bus import InvalidEventException
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseEventBus:
|
|
8
|
+
subscribers: Dict[str, List[Dict]] = {}
|
|
9
|
+
|
|
10
|
+
@abstractmethod
|
|
11
|
+
def on(self, event: str, /, *, priority: int = 1) -> Callable | int:
|
|
12
|
+
...
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
def subscribe(self, event: str, callback: Callable, /, *, priority: int = 1) -> int:
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
@abstractmethod
|
|
19
|
+
def unsubscribe(self, event: str, callback: Callable, /) -> int | None:
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def emit(self, event: str, /, **kwargs) -> int:
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
@staticmethod
|
|
27
|
+
def validate_event(event: Any):
|
|
28
|
+
if not isinstance(event, str):
|
|
29
|
+
raise InvalidEventException(event)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Callable
|
|
2
|
+
|
|
3
|
+
from flashboot_core.event_bus.base import BaseEventBus
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SyncEventBus(BaseEventBus):
|
|
7
|
+
|
|
8
|
+
def on(self, event: str, /, *, priority: int = 1) -> Callable:
|
|
9
|
+
"""
|
|
10
|
+
Decorator for event subscribe, do not use for instance method.
|
|
11
|
+
:param event:
|
|
12
|
+
:param priority:
|
|
13
|
+
:return:
|
|
14
|
+
"""
|
|
15
|
+
self.validate_event(event)
|
|
16
|
+
|
|
17
|
+
def wrapper(callback: Callable):
|
|
18
|
+
self.subscribe(event, callback, priority=priority)
|
|
19
|
+
return callback
|
|
20
|
+
|
|
21
|
+
return wrapper
|
|
22
|
+
|
|
23
|
+
def subscribe(self, event: str, callback: Callable, /, *, priority: int = 1) -> None:
|
|
24
|
+
if event not in self.subscribers:
|
|
25
|
+
self.subscribers[event] = []
|
|
26
|
+
self.subscribers[event].append({"callback": callback, "priority": priority})
|
|
27
|
+
self.subscribers[event].sort(key=lambda x: x["priority"], reverse=True)
|
|
28
|
+
|
|
29
|
+
def unsubscribe(self, event: str, callback: Callable, /) -> None:
|
|
30
|
+
if event not in self.subscribers:
|
|
31
|
+
return
|
|
32
|
+
self.subscribers[event] = [x for x in self.subscribers[event] if x["callback"] != callback]
|
|
33
|
+
|
|
34
|
+
def emit(self, event: str, *args, **kwargs) -> int:
|
|
35
|
+
self.validate_event(event)
|
|
36
|
+
|
|
37
|
+
emit_count: int = 0
|
|
38
|
+
for subscriber in self.subscribers.get(event, []):
|
|
39
|
+
callback = subscriber["callback"]
|
|
40
|
+
callback(*args, **kwargs)
|
|
41
|
+
emit_count += 1
|
|
42
|
+
|
|
43
|
+
return emit_count
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
sync_event_bus = SyncEventBus()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from flashboot_core.exceptions.base import FlashBootException
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class InvalidEventException(FlashBootException):
|
|
7
|
+
|
|
8
|
+
def __init__(self, event: Any) -> None:
|
|
9
|
+
super().__init__(f"Expected type \"str\" but got type \"{type(event).__name__}\" instead")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class File:
|
|
5
|
+
|
|
6
|
+
def __init__(self, pathname: str | Path):
|
|
7
|
+
self.pathname = Path(pathname)
|
|
8
|
+
|
|
9
|
+
def get_name(self) -> str:
|
|
10
|
+
return str(self.pathname)
|
|
11
|
+
|
|
12
|
+
def get_absolute_path(self) -> str:
|
|
13
|
+
return str(self.pathname.absolute())
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
from flashboot_core.io import File
|
|
4
|
+
from flashboot_core.io.resource import Resource
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FileSystemResource(Resource):
|
|
8
|
+
|
|
9
|
+
def __init__(self, pathname: str | Path):
|
|
10
|
+
self.pathname = Path(pathname)
|
|
11
|
+
|
|
12
|
+
def get_file(self) -> File:
|
|
13
|
+
return File(self.pathname)
|
|
14
|
+
|
|
15
|
+
def get_file_name(self) -> str:
|
|
16
|
+
return self.pathname.name
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
flashboot_core/__init__.py
|
|
3
|
+
flashboot_core.egg-info/PKG-INFO
|
|
4
|
+
flashboot_core.egg-info/SOURCES.txt
|
|
5
|
+
flashboot_core.egg-info/dependency_links.txt
|
|
6
|
+
flashboot_core.egg-info/requires.txt
|
|
7
|
+
flashboot_core.egg-info/top_level.txt
|
|
8
|
+
flashboot_core/env/__init__.py
|
|
9
|
+
flashboot_core/env/environment.py
|
|
10
|
+
flashboot_core/env/properties_property_source_loader.py
|
|
11
|
+
flashboot_core/env/property_source.py
|
|
12
|
+
flashboot_core/env/property_source_loader.py
|
|
13
|
+
flashboot_core/env/yaml_property_source_loader.py
|
|
14
|
+
flashboot_core/event_bus/__init__.py
|
|
15
|
+
flashboot_core/event_bus/async_event_bus.py
|
|
16
|
+
flashboot_core/event_bus/base.py
|
|
17
|
+
flashboot_core/event_bus/sync_event_bus.py
|
|
18
|
+
flashboot_core/exceptions/__init__.py
|
|
19
|
+
flashboot_core/exceptions/base.py
|
|
20
|
+
flashboot_core/exceptions/event_bus.py
|
|
21
|
+
flashboot_core/io/__init__.py
|
|
22
|
+
flashboot_core/io/file.py
|
|
23
|
+
flashboot_core/io/file_system_resource.py
|
|
24
|
+
flashboot_core/io/resource.py
|
|
25
|
+
flashboot_core/utils/__init__.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flashboot_core
|