edi-core 1.1.0__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.
- edi_core/__init__.py +0 -0
- edi_core/cloud/README.md +1 -0
- edi_core/cloud/__init__.py +0 -0
- edi_core/cloud/oss.py +64 -0
- edi_core/db/__init__.py +0 -0
- edi_core/db/simple_kv.py +50 -0
- edi_core/db/tinydb.py +23 -0
- edi_core/scm/__init__.py +0 -0
- edi_core/scm/git.py +6 -0
- edi_core/utils/__init__.py +0 -0
- edi_core/utils/assertions.py +22 -0
- edi_core/utils/audio.py +37 -0
- edi_core/utils/cli.py +51 -0
- edi_core/utils/datetime.py +6 -0
- edi_core/utils/encoding.py +25 -0
- edi_core/utils/env.py +41 -0
- edi_core/utils/file.py +98 -0
- edi_core/utils/filetype.py +5 -0
- edi_core/utils/hash.py +9 -0
- edi_core/win/__init__.py +0 -0
- edi_core/win/control.py +5 -0
- edi_core/win/reg.py +24 -0
- edi_core-1.1.0.dist-info/METADATA +28 -0
- edi_core-1.1.0.dist-info/RECORD +25 -0
- edi_core-1.1.0.dist-info/WHEEL +4 -0
edi_core/__init__.py
ADDED
|
File without changes
|
edi_core/cloud/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
https://help.aliyun.com/zh/oss/developer-reference/get-started-with-oss-sdk-for-python-v2?spm=a2c4g.11186623.help-menu-31815.d_5_2_2_0_0.31152f8dIqy5FD
|
|
File without changes
|
edi_core/cloud/oss.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from abc import ABC
|
|
2
|
+
|
|
3
|
+
import alibabacloud_oss_v2 as oss
|
|
4
|
+
from alibabacloud_oss_v2 import GetObjectMetaRequest, GetObjectMetaResult, GetObjectRequest
|
|
5
|
+
from loguru import logger as log
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class OssClient(ABC):
|
|
9
|
+
def get_object_metadata(self, key: str):
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
def get_object(self, key: str, target_path: str):
|
|
13
|
+
pass
|
|
14
|
+
|
|
15
|
+
def put_object(self, source_path: str, key: str):
|
|
16
|
+
pass
|
|
17
|
+
|
|
18
|
+
def delete_object(self, key: str):
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class AliCloudOssClient(OssClient):
|
|
23
|
+
_config: oss.Config
|
|
24
|
+
_client: oss.Client
|
|
25
|
+
_bucket: str
|
|
26
|
+
|
|
27
|
+
def __init__(self, region: str, access_key: str, secret_key: str, endpoint: str, bucket: str):
|
|
28
|
+
config = oss.config.load_default()
|
|
29
|
+
config.region = region
|
|
30
|
+
config.credentials_provider = oss.credentials.StaticCredentialsProvider(access_key_id=access_key,
|
|
31
|
+
access_key_secret=secret_key)
|
|
32
|
+
config.endpoint = endpoint
|
|
33
|
+
self._config = config
|
|
34
|
+
self.print_config()
|
|
35
|
+
self._client = oss.Client(self._config)
|
|
36
|
+
self._bucket = bucket
|
|
37
|
+
|
|
38
|
+
def get_config(self) -> oss.Config:
|
|
39
|
+
return self._config
|
|
40
|
+
|
|
41
|
+
def get_object_metadata(self, key: str) -> GetObjectMetaResult:
|
|
42
|
+
request = GetObjectMetaRequest(bucket=self._bucket, key=key)
|
|
43
|
+
return self._client.get_object_meta(request)
|
|
44
|
+
|
|
45
|
+
def get_object(self, key: str, target_path: str):
|
|
46
|
+
log.debug(f"downloading {key} to {target_path}")
|
|
47
|
+
request = GetObjectRequest(bucket=self._bucket, key=key)
|
|
48
|
+
result = self._client.get_object(request)
|
|
49
|
+
with result.body as body_stream:
|
|
50
|
+
data = body_stream.read()
|
|
51
|
+
with open(target_path, 'wb') as f:
|
|
52
|
+
f.write(data)
|
|
53
|
+
log.debug(f"finished downloading {key} to {target_path}")
|
|
54
|
+
|
|
55
|
+
def put_object(self, source_path: str, key: str):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def delete_object(self, key: str):
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
def print_config(self):
|
|
62
|
+
config_attrs = vars(self._config)
|
|
63
|
+
config_str = "\n".join(f"{key}={value}" for key, value in config_attrs.items())
|
|
64
|
+
log.debug(f"OSS Config: {config_str}")
|
edi_core/db/__init__.py
ADDED
|
File without changes
|
edi_core/db/simple_kv.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from tinydb import TinyDB, Query
|
|
5
|
+
|
|
6
|
+
from edi_core.utils.file import get_path_from_app_dir, ensure_parent_dir_exists
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class CreateStrategy(Enum):
|
|
10
|
+
RECREATE = 1
|
|
11
|
+
REUSE_IF_PRESENT = 2
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SimpleKV(ABC):
|
|
15
|
+
@abstractmethod
|
|
16
|
+
def get_str(self, key: str):
|
|
17
|
+
raise NotImplementedError("get_str is not implemented")
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def set_str(self, key: str, value: str):
|
|
21
|
+
raise NotImplementedError("set_str is not implemented")
|
|
22
|
+
|
|
23
|
+
@abstractmethod
|
|
24
|
+
def print_all(self):
|
|
25
|
+
raise NotImplementedError("print_all is not implemented")
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class TinyDbSimpleKV(SimpleKV):
|
|
29
|
+
db_path: str
|
|
30
|
+
db: TinyDB
|
|
31
|
+
|
|
32
|
+
def __init__(self, db_name: str, create_strategy: CreateStrategy = CreateStrategy.RECREATE):
|
|
33
|
+
self.db_path = get_path_from_app_dir(db_name)
|
|
34
|
+
ensure_parent_dir_exists(self.db_path)
|
|
35
|
+
self.db = TinyDB(f'{self.db_path}.json')
|
|
36
|
+
if create_strategy == CreateStrategy.RECREATE:
|
|
37
|
+
self.db.truncate()
|
|
38
|
+
|
|
39
|
+
def get_str(self, key: str):
|
|
40
|
+
results = self.db.search(Query().key == key)
|
|
41
|
+
if len(results) == 0:
|
|
42
|
+
raise KeyError("Key not found")
|
|
43
|
+
return results[0]["value"]
|
|
44
|
+
|
|
45
|
+
def set_str(self, key: str, value: str):
|
|
46
|
+
self.db.remove(Query().key == key)
|
|
47
|
+
self.db.insert({"key": key, "value": value})
|
|
48
|
+
|
|
49
|
+
def print_all(self):
|
|
50
|
+
return self.db.all()
|
edi_core/db/tinydb.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
|
|
3
|
+
from tinydb import TinyDB
|
|
4
|
+
from tinydb.table import Document
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Tiny:
|
|
8
|
+
_db = None
|
|
9
|
+
|
|
10
|
+
def __init__(self, db_file):
|
|
11
|
+
self._db = TinyDB(db_file)
|
|
12
|
+
|
|
13
|
+
def insert(self, data: dict) -> int:
|
|
14
|
+
return self._db.insert(data)
|
|
15
|
+
|
|
16
|
+
def all(self) -> List[Document]:
|
|
17
|
+
return self._db.all()
|
|
18
|
+
|
|
19
|
+
def search(self, query) -> List[Document]:
|
|
20
|
+
return self._db.search(query)
|
|
21
|
+
|
|
22
|
+
def close(self):
|
|
23
|
+
self._db.close()
|
edi_core/scm/__init__.py
ADDED
|
File without changes
|
edi_core/scm/git.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
from typing import Callable
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def assert_file_exists(
|
|
6
|
+
path: str,
|
|
7
|
+
exception_supplier: Callable[[], Exception] | None = None,
|
|
8
|
+
):
|
|
9
|
+
if not os.path.isfile(path):
|
|
10
|
+
if exception_supplier is None:
|
|
11
|
+
raise ValueError(f"File does not exist: {path}")
|
|
12
|
+
raise exception_supplier()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def assert_dir_exists(
|
|
16
|
+
path: str,
|
|
17
|
+
exception_supplier: Callable[[], Exception] | None = None,
|
|
18
|
+
):
|
|
19
|
+
if not os.path.isdir(path):
|
|
20
|
+
if exception_supplier is None:
|
|
21
|
+
raise ValueError(f"Directory does not exist: {path}")
|
|
22
|
+
raise exception_supplier()
|
edi_core/utils/audio.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import subprocess
|
|
3
|
+
|
|
4
|
+
from edi_core.utils.assertions import assert_file_exists
|
|
5
|
+
from edi_core.utils.file import dir_exists, get_file_name_without_extension
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def extract_audio(file_path: str, output_path: str):
|
|
9
|
+
assert_file_exists(file_path)
|
|
10
|
+
result = subprocess.run(
|
|
11
|
+
['ffmpeg', '-i', file_path, '-q:a', '0', '-map', 'a', output_path],
|
|
12
|
+
stdout=subprocess.PIPE,
|
|
13
|
+
stderr=subprocess.PIPE
|
|
14
|
+
)
|
|
15
|
+
if result.returncode != 0:
|
|
16
|
+
raise RuntimeError(f"Failed to extract audio: {result.stderr.decode()}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def split_audio(source_file: str, dest_dir: str, seconds: int):
|
|
20
|
+
assert_file_exists(source_file)
|
|
21
|
+
if not dir_exists(dest_dir):
|
|
22
|
+
os.makedirs(dest_dir, exist_ok=True)
|
|
23
|
+
|
|
24
|
+
base_name = get_file_name_without_extension(source_file)
|
|
25
|
+
segment_pattern = os.path.join(dest_dir, f"{base_name}_%03d.mp3")
|
|
26
|
+
|
|
27
|
+
result = subprocess.run(
|
|
28
|
+
['ffmpeg', '-i', source_file, '-f', 'segment', '-segment_time', str(seconds), '-c', 'copy', segment_pattern],
|
|
29
|
+
stdout=subprocess.PIPE,
|
|
30
|
+
stderr=subprocess.PIPE
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if result.returncode != 0:
|
|
34
|
+
raise RuntimeError(f"Failed to split audio: {result.stderr.decode()}")
|
|
35
|
+
|
|
36
|
+
return sorted([os.path.join(dest_dir, f) for f in os.listdir(dest_dir) if f.startswith(base_name)],
|
|
37
|
+
key=lambda x: x.lower())
|
edi_core/utils/cli.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from typing import TypeVar, Callable
|
|
2
|
+
|
|
3
|
+
T = TypeVar('T')
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def select_option(
|
|
7
|
+
options: list[T],
|
|
8
|
+
prompt: str,
|
|
9
|
+
display_names: list[str] | None = None,
|
|
10
|
+
to_display_name: Callable[[T], str] | None = None,
|
|
11
|
+
) -> T:
|
|
12
|
+
"""
|
|
13
|
+
Interactive CLI option selector.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
options: List of options to choose from
|
|
17
|
+
prompt: Message to display to the user
|
|
18
|
+
display_names: Optional list of display names for options
|
|
19
|
+
to_display_name: Optional function to convert option to display name
|
|
20
|
+
(used if display_names is not provided)
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
The selected option
|
|
24
|
+
|
|
25
|
+
Raises:
|
|
26
|
+
ValueError: If options is empty or display_names length doesn't match
|
|
27
|
+
"""
|
|
28
|
+
if not options:
|
|
29
|
+
raise ValueError("Options list cannot be empty")
|
|
30
|
+
|
|
31
|
+
if display_names is not None:
|
|
32
|
+
if len(display_names) != len(options):
|
|
33
|
+
raise ValueError("display_names must have same length as options")
|
|
34
|
+
names = display_names
|
|
35
|
+
elif to_display_name is not None:
|
|
36
|
+
names = [to_display_name(opt) for opt in options]
|
|
37
|
+
else:
|
|
38
|
+
names = [str(opt) for opt in options]
|
|
39
|
+
|
|
40
|
+
print(prompt)
|
|
41
|
+
for i, name in enumerate(names, start=1):
|
|
42
|
+
print(f"{i}. {name}")
|
|
43
|
+
|
|
44
|
+
while True:
|
|
45
|
+
try:
|
|
46
|
+
choice = int(input())
|
|
47
|
+
if 1 <= choice <= len(options):
|
|
48
|
+
return options[choice - 1]
|
|
49
|
+
print(f"Please enter a number between 1 and {len(options)}")
|
|
50
|
+
except ValueError:
|
|
51
|
+
print("Please enter a valid number")
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def encode_base64_str(data: str, encoding: str = 'utf-8'):
|
|
5
|
+
data_bytes = data.encode(encoding)
|
|
6
|
+
base64_bytes = base64.b64encode(data_bytes)
|
|
7
|
+
return base64_bytes.decode(encoding)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def decode_base64_str(data: str, encoding: str = 'utf-8'):
|
|
11
|
+
data_bytes = data.encode(encoding)
|
|
12
|
+
base64_bytes = base64.b64decode(data_bytes)
|
|
13
|
+
return base64_bytes.decode(encoding)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def encode_base64_bytes(data: bytes):
|
|
17
|
+
return base64.b64encode(data)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def decode_base64_bytes(data: bytes):
|
|
21
|
+
return base64.b64decode(data)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def to_bytes(data: str, encoding: str = 'utf-8'):
|
|
25
|
+
return data.encode(encoding)
|
edi_core/utils/env.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import platform
|
|
3
|
+
|
|
4
|
+
from dotenv import load_dotenv
|
|
5
|
+
|
|
6
|
+
dotenv_loaded = False
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def load_env():
|
|
10
|
+
global dotenv_loaded
|
|
11
|
+
if not dotenv_loaded:
|
|
12
|
+
load_dotenv()
|
|
13
|
+
dotenv_loaded = True
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_env(key: str, default: str = None):
|
|
17
|
+
load_env()
|
|
18
|
+
value = os.environ.get(key)
|
|
19
|
+
if value:
|
|
20
|
+
return value
|
|
21
|
+
|
|
22
|
+
if default is None:
|
|
23
|
+
raise ValueError(f'Env {key} not found')
|
|
24
|
+
else:
|
|
25
|
+
return default
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_platform():
|
|
29
|
+
return platform.platform()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_system():
|
|
33
|
+
return platform.system()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def is_windows():
|
|
37
|
+
return get_system() == 'Windows'
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_app_name():
|
|
41
|
+
return get_env('APP_NAME')
|
edi_core/utils/file.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import os.path
|
|
2
|
+
import shutil
|
|
3
|
+
from io import TextIOWrapper
|
|
4
|
+
|
|
5
|
+
from edi_core.utils.assertions import assert_file_exists
|
|
6
|
+
from edi_core.utils.env import get_env
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def dir_exists(path: str) -> bool:
|
|
10
|
+
return os.path.isdir(path)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def file_exists(path: str) -> bool:
|
|
14
|
+
return os.path.isfile(path)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def path_exists(path: str) -> bool:
|
|
18
|
+
return os.path.exists(path)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def move(src, dest):
|
|
22
|
+
shutil.move(src, dest)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def delete_file(path: str):
|
|
26
|
+
if file_exists(path):
|
|
27
|
+
os.remove(path)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def get_file_name_without_extension(path: str) -> str:
|
|
31
|
+
base_name = os.path.basename(path)
|
|
32
|
+
name_without_extension, _ = os.path.splitext(base_name)
|
|
33
|
+
return name_without_extension
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_file_name_with_extension(path: str) -> str:
|
|
37
|
+
return os.path.basename(path)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_output_dir():
|
|
41
|
+
return os.path.expanduser(get_env("OUTPUT_DIR"))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_input_dir():
|
|
45
|
+
return os.path.expanduser(get_env("INPUT_DIR"))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def to_output_path(relative_path: str):
|
|
49
|
+
return os.path.join(get_output_dir(), relative_path)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def to_input_path(relative_path: str):
|
|
53
|
+
return os.path.join(get_input_dir(), relative_path)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def ensure_parent_dir_exists(path: str):
|
|
57
|
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def save_str_to_output_dir(relative_path: str, content: str) -> str:
|
|
61
|
+
output_path = to_output_path(relative_path)
|
|
62
|
+
ensure_parent_dir_exists(output_path)
|
|
63
|
+
with open(output_path, 'w', encoding='utf-8') as file:
|
|
64
|
+
file.write(content)
|
|
65
|
+
return output_path
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def save_bytes_to_output_dir(relative_path: str, content: bytes) -> str:
|
|
69
|
+
output_path = to_output_path(relative_path)
|
|
70
|
+
ensure_parent_dir_exists(output_path)
|
|
71
|
+
with open(output_path, 'wb') as file:
|
|
72
|
+
file.write(content)
|
|
73
|
+
return output_path
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def open_file_in_output_for_write(relative_path: str) -> TextIOWrapper:
|
|
77
|
+
output_path = to_output_path(relative_path)
|
|
78
|
+
ensure_parent_dir_exists(output_path)
|
|
79
|
+
return open(output_path, 'w', encoding='utf-8')
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def open_file_in_input_for_read(relative_path: str) -> TextIOWrapper:
|
|
83
|
+
input_path = to_input_path(relative_path)
|
|
84
|
+
return open(input_path, 'r', encoding='utf-8')
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def read_file(path: str) -> str:
|
|
88
|
+
assert_file_exists(path)
|
|
89
|
+
with open(path, 'r', encoding='utf-8') as file:
|
|
90
|
+
return file.read()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_app_dir():
|
|
94
|
+
return os.path.expanduser(get_env("APP_DIR"))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def get_path_from_app_dir(relative_path: str) -> str:
|
|
98
|
+
return os.path.join(get_app_dir(), relative_path)
|
edi_core/utils/hash.py
ADDED
edi_core/win/__init__.py
ADDED
|
File without changes
|
edi_core/win/control.py
ADDED
edi_core/win/reg.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import winreg
|
|
2
|
+
|
|
3
|
+
SUB_KEY_KEYBOARD_LAYOUT = "SYSTEM\CurrentControlSet\Control\Keyboard Layout"
|
|
4
|
+
|
|
5
|
+
type_dict = {
|
|
6
|
+
winreg.REG_BINARY: "Binary",
|
|
7
|
+
winreg.REG_SZ: "String",
|
|
8
|
+
winreg.REG_EXPAND_SZ: "Expandable String",
|
|
9
|
+
winreg.REG_DWORD: "DWORD (32-bit number)",
|
|
10
|
+
winreg.REG_MULTI_SZ: "Multi-String",
|
|
11
|
+
winreg.REG_QWORD: "QWORD (64-bit number)",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def read_key_for_current_user(sub_key: str, name: str):
|
|
16
|
+
hkey = winreg.OpenKey(winreg.HKEY_CURRENT_USER, sub_key, 0, winreg.KEY_READ)
|
|
17
|
+
return winreg.QueryValueEx(hkey, name)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def get_keyboard_scancode_map():
|
|
21
|
+
hkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, SUB_KEY_KEYBOARD_LAYOUT, 0, winreg.KEY_READ)
|
|
22
|
+
value, type_id = winreg.QueryValueEx(hkey, "Scancode Map")
|
|
23
|
+
print(type_id)
|
|
24
|
+
print(value[0])
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: edi-core
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary:
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: LtttAZ
|
|
7
|
+
Author-email: louis_zhang_1303@126.com
|
|
8
|
+
Requires-Python: ==3.13.2
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Requires-Dist: alibabacloud-oss-v2 (>=1.2.1,<2.0.0)
|
|
12
|
+
Requires-Dist: filetype (>=1.2.0,<2.0.0)
|
|
13
|
+
Requires-Dist: gitpython (>=3.1.45,<4.0.0)
|
|
14
|
+
Requires-Dist: loguru (>=0.7.3,<0.8.0)
|
|
15
|
+
Requires-Dist: matplotlib (>=3.10.7,<4.0.0)
|
|
16
|
+
Requires-Dist: packaging (>=25.0,<26.0)
|
|
17
|
+
Requires-Dist: pendulum (>=3.1.0,<4.0.0)
|
|
18
|
+
Requires-Dist: poetry-core (>=2.2.1,<3.0.0)
|
|
19
|
+
Requires-Dist: pyautogui (>=0.9.54,<0.10.0)
|
|
20
|
+
Requires-Dist: pydantic (>=2.12.4,<3.0.0)
|
|
21
|
+
Requires-Dist: python-dotenv (>=1.2.1,<2.0.0)
|
|
22
|
+
Requires-Dist: requests (>=2.32.5,<3.0.0)
|
|
23
|
+
Requires-Dist: tinydb (>=4.8.2,<5.0.0)
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# EDI
|
|
27
|
+
|
|
28
|
+
[PYPI](https://pypi.org/project/edi-core/)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
edi_core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
edi_core/cloud/README.md,sha256=eORYs2CT7hkm2i2A7xmREaW4I_Scl1uTbYNwu8TzhhI,151
|
|
3
|
+
edi_core/cloud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
edi_core/cloud/oss.py,sha256=8w5CB1INo1e69VJSjPhbvnqKOUig3JjF3fDMcags1uE,2151
|
|
5
|
+
edi_core/db/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
edi_core/db/simple_kv.py,sha256=8PzWUzwuOOWUXhVr9CzsNf1ljeqaLJvzgw5eLlfaLcg,1420
|
|
7
|
+
edi_core/db/tinydb.py,sha256=DB8trZcsxsLPSwlQjJemlOs68F4AcEMJJmyK0x7BXg0,463
|
|
8
|
+
edi_core/scm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
+
edi_core/scm/git.py,sha256=-TVM0_IDd34zAuJPZweksTItzqhUV75DtG4YXe9qQvM,150
|
|
10
|
+
edi_core/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
edi_core/utils/assertions.py,sha256=HFgfxOkNUp0RkI2NpAthy7wnlfBEJSYL3zps6JNrG7Y,596
|
|
12
|
+
edi_core/utils/audio.py,sha256=gBLIntKW7ScLiN93jl_SJtM1LHMYtTUftxc-EGxVGO8,1325
|
|
13
|
+
edi_core/utils/cli.py,sha256=40_YXu8NCcC4_7Z650Clb49nk-xgG9zd5suvWO459XE,1524
|
|
14
|
+
edi_core/utils/datetime.py,sha256=sctJzZw_Uruq-qp6IW_JuqZvcJq_fXDbTMpfEwkAPlg,117
|
|
15
|
+
edi_core/utils/encoding.py,sha256=6QgiPsuKPE8rhTkNqC7KqEzV_41YilykMW2LqbkDLf0,625
|
|
16
|
+
edi_core/utils/env.py,sha256=r4ffjexjq8tUh-8xlailykoKO7OiM23rx6DDuYc_3l0,648
|
|
17
|
+
edi_core/utils/file.py,sha256=ohlwL2bMTyhwA239vv4VgVH6sud-CK5rIKGJWrG4JKY,2454
|
|
18
|
+
edi_core/utils/filetype.py,sha256=yfGavZWzMkbmRUeYPFySZ7xVd1olbeCBc7oQVOMvtCE,77
|
|
19
|
+
edi_core/utils/hash.py,sha256=9YRLLDbPdTlZok6zGKfCLmDL9wXUpYVyHcTgz1Gt0Yc,200
|
|
20
|
+
edi_core/win/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
+
edi_core/win/control.py,sha256=W8JROSAAc900qUWNlCIQV9BikqeAtEycOXxA_7Eimqc,100
|
|
22
|
+
edi_core/win/reg.py,sha256=-l5aCGvyHtRY9pclxrov9-FtbkCroZInX9RFh6a0rpM,770
|
|
23
|
+
edi_core-1.1.0.dist-info/METADATA,sha256=sgZfP515CvmEJM8737bTvvdBdPPRsQnanTx7BpTeF7Q,902
|
|
24
|
+
edi_core-1.1.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
25
|
+
edi_core-1.1.0.dist-info/RECORD,,
|