libdev 0.95__tar.gz → 0.97__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 (48) hide show
  1. libdev-0.97/PKG-INFO +94 -0
  2. {libdev-0.95 → libdev-0.97}/README.md +7 -0
  3. libdev-0.97/env/bin/jp.py +54 -0
  4. {libdev-0.95 → libdev-0.97}/libdev/__init__.py +1 -1
  5. {libdev-0.95 → libdev-0.97}/libdev/cfg.py +23 -4
  6. {libdev-0.95 → libdev-0.97}/libdev/check.py +1 -0
  7. libdev-0.97/libdev/dev.py +29 -0
  8. libdev-0.97/libdev/doc.py +29 -0
  9. {libdev-0.95 → libdev-0.97}/libdev/num.py +31 -10
  10. {libdev-0.95 → libdev-0.97}/libdev/req.py +14 -19
  11. {libdev-0.95 → libdev-0.97}/libdev/time.py +51 -12
  12. libdev-0.97/libdev.egg-info/PKG-INFO +94 -0
  13. {libdev-0.95 → libdev-0.97}/libdev.egg-info/SOURCES.txt +2 -0
  14. libdev-0.97/libdev.egg-info/requires.txt +13 -0
  15. libdev-0.97/libdev.egg-info/top_level.txt +4 -0
  16. libdev-0.97/pyproject.toml +75 -0
  17. {libdev-0.95 → libdev-0.97}/setup.py +21 -17
  18. {libdev-0.95 → libdev-0.97}/tests/test_num.py +1 -0
  19. {libdev-0.95 → libdev-0.97}/tests/test_time.py +7 -0
  20. libdev-0.95/PKG-INFO +0 -50
  21. libdev-0.95/libdev/dev.py +0 -21
  22. libdev-0.95/libdev/doc.py +0 -17
  23. libdev-0.95/libdev.egg-info/PKG-INFO +0 -50
  24. libdev-0.95/libdev.egg-info/requires.txt +0 -5
  25. libdev-0.95/libdev.egg-info/top_level.txt +0 -1
  26. {libdev-0.95 → libdev-0.97}/LICENSE +0 -0
  27. {libdev-0.95 → libdev-0.97}/libdev/codes.py +0 -0
  28. {libdev-0.95 → libdev-0.97}/libdev/crypt.py +0 -0
  29. {libdev-0.95 → libdev-0.97}/libdev/fin.py +0 -0
  30. {libdev-0.95 → libdev-0.97}/libdev/gen.py +0 -0
  31. {libdev-0.95 → libdev-0.97}/libdev/img.py +0 -0
  32. {libdev-0.95 → libdev-0.97}/libdev/lang.py +0 -0
  33. {libdev-0.95 → libdev-0.97}/libdev/log.py +0 -0
  34. {libdev-0.95 → libdev-0.97}/libdev/s3.py +0 -0
  35. {libdev-0.95 → libdev-0.97}/libdev.egg-info/dependency_links.txt +0 -0
  36. {libdev-0.95 → libdev-0.97}/setup.cfg +0 -0
  37. {libdev-0.95 → libdev-0.97}/tests/test_cfg.py +0 -0
  38. {libdev-0.95 → libdev-0.97}/tests/test_check.py +0 -0
  39. {libdev-0.95 → libdev-0.97}/tests/test_codes.py +0 -0
  40. {libdev-0.95 → libdev-0.97}/tests/test_crypt.py +0 -0
  41. {libdev-0.95 → libdev-0.97}/tests/test_dev.py +0 -0
  42. {libdev-0.95 → libdev-0.97}/tests/test_doc.py +0 -0
  43. {libdev-0.95 → libdev-0.97}/tests/test_gen.py +0 -0
  44. {libdev-0.95 → libdev-0.97}/tests/test_img.py +0 -0
  45. {libdev-0.95 → libdev-0.97}/tests/test_lang.py +0 -0
  46. {libdev-0.95 → libdev-0.97}/tests/test_log.py +0 -0
  47. {libdev-0.95 → libdev-0.97}/tests/test_req.py +0 -0
  48. {libdev-0.95 → libdev-0.97}/tests/test_s3.py +0 -0
libdev-0.97/PKG-INFO ADDED
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: libdev
3
+ Version: 0.97
4
+ Summary: Set of standard functions for development
5
+ Home-page: https://github.com/chilleco/lib
6
+ Author: Alex Poloz
7
+ Author-email: Alex Poloz <alexypoloz@gmail.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2021 Alexey Poloz
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+
30
+ Project-URL: Source, https://github.com/chilleco/lib
31
+ Keywords: standard,lib,dev,development,cfg,config,generate,codes,tokens,ids,passwords,generator,ciphers,time,formatter,nlp,natural language,aws,s3,upload file,file server
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3 :: Only
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Operating System :: OS Independent
44
+ Requires-Python: >=3.10, <4
45
+ Description-Content-Type: text/markdown
46
+ License-File: LICENSE
47
+ Requires-Dist: aiohttp>=3.13.2
48
+ Requires-Dist: python-dotenv>=1.2.1
49
+ Requires-Dist: boto3>=1.42.0
50
+ Requires-Dist: Pillow>=12.0.0
51
+ Requires-Dist: loguru>=0.7.3
52
+ Provides-Extra: dev
53
+ Requires-Dist: build>=1.3.0; extra == "dev"
54
+ Requires-Dist: setuptools>=80.9.0; extra == "dev"
55
+ Requires-Dist: twine>=6.2.0; extra == "dev"
56
+ Requires-Dist: pylint>=4.0.4; extra == "dev"
57
+ Requires-Dist: pytest>=9.0.1; extra == "dev"
58
+ Requires-Dist: pytest-asyncio>=1.3.0; extra == "dev"
59
+ Dynamic: author
60
+ Dynamic: home-page
61
+ Dynamic: license-file
62
+ Dynamic: requires-python
63
+
64
+ # LibDev
65
+ Development library — Set of standard functions for development
66
+
67
+ [GitHub](https://github.com/chilleco/lib)
68
+ | [PyPI](https://pypi.org/project/libdev/)
69
+
70
+ ## Requirements
71
+ - Python 3.10+ (dependencies are 3.14-ready)
72
+
73
+ ## Installation
74
+ - Runtime: `pip install .`
75
+ - Dev / tests: `pip install .[dev]` or `make setup-dev`
76
+
77
+ ## Submodules
78
+ Stream | Submodule | Description
79
+ ---|---|---
80
+ System | ` libdev.cfg ` | Configuration getting
81
+ &nbsp; | ` libdev.req ` | AsyncIO requests (AIOHTTP wrapper)
82
+ &nbsp; | ` libdev.log ` | Logger (Loguru wrapper)
83
+ Data Format | ` libdev.num ` | Numeric conversions & handlers
84
+ &nbsp; | ` libdev.time ` | Time processing
85
+ Transforms | ` libdev.gen ` | Code & token generators
86
+ &nbsp; | ` libdev.codes ` | Ciphers: langs & flags / networks / user statuses
87
+ &nbsp; | ` libdev.check ` | Validation functions
88
+ &nbsp; | ` libdev.crypt ` | Encryption and decryption functions
89
+ Fields | ` libdev.dev ` | Development tools
90
+ &nbsp; | ` libdev.fin ` | Financial codes and tools
91
+ &nbsp; | ` libdev.lang ` | Natural language formatters
92
+ Files | ` libdev.doc ` | Base64 / JSON handlers
93
+ &nbsp; | ` libdev.s3 ` | S3 file server functions
94
+ &nbsp; | ` libdev.img ` | Image processing
@@ -4,6 +4,13 @@ Development library — Set of standard functions for development
4
4
  [GitHub](https://github.com/chilleco/lib)
5
5
  | [PyPI](https://pypi.org/project/libdev/)
6
6
 
7
+ ## Requirements
8
+ - Python 3.10+ (dependencies are 3.14-ready)
9
+
10
+ ## Installation
11
+ - Runtime: `pip install .`
12
+ - Dev / tests: `pip install .[dev]` or `make setup-dev`
13
+
7
14
  ## Submodules
8
15
  Stream | Submodule | Description
9
16
  ---|---|---
@@ -0,0 +1,54 @@
1
+ #!/Users/kosyachniy/Desktop/chill/lib/env/bin/python
2
+
3
+ import sys
4
+ import json
5
+ import argparse
6
+ from pprint import pformat
7
+
8
+ import jmespath
9
+ from jmespath import exceptions
10
+
11
+
12
+ def main():
13
+ parser = argparse.ArgumentParser()
14
+ parser.add_argument('expression')
15
+ parser.add_argument('-f', '--filename',
16
+ help=('The filename containing the input data. '
17
+ 'If a filename is not given then data is '
18
+ 'read from stdin.'))
19
+ parser.add_argument('--ast', action='store_true',
20
+ help=('Pretty print the AST, do not search the data.'))
21
+ args = parser.parse_args()
22
+ expression = args.expression
23
+ if args.ast:
24
+ # Only print the AST
25
+ expression = jmespath.compile(args.expression)
26
+ sys.stdout.write(pformat(expression.parsed))
27
+ sys.stdout.write('\n')
28
+ return 0
29
+ if args.filename:
30
+ with open(args.filename, 'r') as f:
31
+ data = json.load(f)
32
+ else:
33
+ data = sys.stdin.read()
34
+ data = json.loads(data)
35
+ try:
36
+ sys.stdout.write(json.dumps(
37
+ jmespath.search(expression, data), indent=4, ensure_ascii=False))
38
+ sys.stdout.write('\n')
39
+ except exceptions.ArityError as e:
40
+ sys.stderr.write("invalid-arity: %s\n" % e)
41
+ return 1
42
+ except exceptions.JMESPathTypeError as e:
43
+ sys.stderr.write("invalid-type: %s\n" % e)
44
+ return 1
45
+ except exceptions.UnknownFunctionError as e:
46
+ sys.stderr.write("unknown-function: %s\n" % e)
47
+ return 1
48
+ except exceptions.ParseError as e:
49
+ sys.stderr.write("syntax-error: %s\n" % e)
50
+ return 1
51
+
52
+
53
+ if __name__ == '__main__':
54
+ sys.exit(main())
@@ -2,6 +2,6 @@
2
2
  Initializing the Python package
3
3
  """
4
4
 
5
- __version__ = "0.95"
5
+ __version__ = "0.97"
6
6
 
7
7
  __all__ = ("__version__",)
@@ -1,5 +1,10 @@
1
- """
2
- Functionality of getting configuration
1
+ """Centralized configuration loader for LibDev consumers.
2
+
3
+ This module mirrors the behavior documented in `LIBDEV_DOCUMENTATION.md`:
4
+ it first ingests a project level ``sets.json`` file, then overlays values
5
+ from ``.env`` (via ``python-dotenv``) by translating dotted keys to
6
+ ``UPPER_SNAKE_CASE`` environment variables. Use the helpers below instead of
7
+ calling ``os.getenv`` throughout the codebase so the hierarchy stays uniform.
3
8
  """
4
9
 
5
10
  import os
@@ -19,7 +24,15 @@ if os.path.isfile(".env"):
19
24
 
20
25
 
21
26
  def cfg(name, default=None):
22
- """Get config value by key"""
27
+ """Return a config value stored in ``sets.json``/``.env``.
28
+
29
+ The lookup walks dotted paths inside the parsed JSON structure and, when a
30
+ key is missing, falls back to an environment variable where dots are
31
+ replaced with underscores and the string is upper-cased (``api.base`` →
32
+ ``API_BASE``). Environment values are JSON-decoded automatically so booleans
33
+ and numeric strings turn into native Python types. ``default`` is returned
34
+ when a key is absent in both sources.
35
+ """
23
36
 
24
37
  keys = name.split(".")
25
38
  data = sets
@@ -44,7 +57,13 @@ def cfg(name, default=None):
44
57
 
45
58
 
46
59
  def set_cfg(name, value):
47
- """Set config value"""
60
+ """Mutate the in-memory ``sets`` dictionary for tests or overrides.
61
+
62
+ Writes scoped dotted keys back into the ``sets`` mapping without touching
63
+ disk. This mirrors the behavior in consumer repos that temporarily adjust
64
+ configuration for integration tests or AI agents. Changes live only for the
65
+ current process and should be reset between tests.
66
+ """
48
67
 
49
68
  array_name = name.split(".")
50
69
  dictionary = {}
@@ -239,4 +239,5 @@ def get_url(data: str) -> str | None:
239
239
 
240
240
 
241
241
  def clear_text(data, extra=".,"):
242
+ """Strip all characters except alphanumerics, space, and ``extra`` chars."""
242
243
  return re.sub(rf"[^\w {extra}]", "", data).strip()
@@ -0,0 +1,29 @@
1
+ """Development-environment helpers tied to LibDev guidelines.
2
+
3
+ Currently exposes public IP validation logic that mirrors the rules documented
4
+ in ``LIBDEV_DOCUMENTATION.md`` for analytics and logging pipelines. Extend this
5
+ module instead of sprinkling regex checks throughout consumer projects.
6
+ """
7
+
8
+ import re
9
+
10
+
11
+ def check_public_ip(ip):
12
+ """Return ``ip`` if it is routable on the public internet.
13
+
14
+ Private (RFC1918), loopback, and carrier-grade NAT subnets are filtered
15
+ out, ensuring only analyzable public addresses pass downstream. ``None`` is
16
+ returned for empty inputs or addresses that match reserved ranges.
17
+ """
18
+
19
+ if not ip:
20
+ return None
21
+
22
+ return (
23
+ None
24
+ if re.match(
25
+ r"^(172\.(1[6-9]\.|2[0-9]\.|3[0-1]\.)|192\.168\.|10\.|127\.)",
26
+ ip,
27
+ )
28
+ else ip
29
+ )
@@ -0,0 +1,29 @@
1
+ """Utility helpers for dealing with document/JSON serialization.
2
+
3
+ These functions are referenced by the integration guide to make sure assets
4
+ and structured logs look the same across repositories (e.g., ``log.json`` uses
5
+ ``to_json`` under the hood).
6
+ """
7
+
8
+ import base64
9
+ import json
10
+
11
+
12
+ def to_base64(image, mime="image/jpg"):
13
+ """Return a ``data:`` URL for the given file-like ``image``.
14
+
15
+ Reads the stream, base64-encodes the bytes, and prefixes it with the MIME
16
+ Type so downstream clients (frontends, bots) can embed the payload directly
17
+ without touching disk.
18
+ """
19
+ data = base64.b64encode(image.read())
20
+ return f"data:{mime};base64,{data.decode('utf-8')}"
21
+
22
+
23
+ def to_json(data):
24
+ """Serialize ``data`` to a UTF-8 friendly JSON string.
25
+
26
+ Uses tab indentation and ``ensure_ascii=False`` to preserve Cyrillic or
27
+ emoji content mentioned in ``LIBDEV_DOCUMENTATION.md``.
28
+ """
29
+ return json.dumps(data, indent="\t", ensure_ascii=False)
@@ -1,5 +1,8 @@
1
- """
2
- Numbers functionality
1
+ """Numeric normalization and presentation helpers used across LibDev.
2
+
3
+ Implements the opinionated formatting rules discussed in the integration
4
+ guide: deterministic rounding, removal of floating-point artifacts, thousands
5
+ separators, and zero-compression for compact analytical displays.
3
6
  """
4
7
 
5
8
  import re
@@ -22,7 +25,7 @@ def is_float(value: str) -> bool:
22
25
 
23
26
 
24
27
  def to_num(value) -> bool:
25
- """Convert value to int or float"""
28
+ """Convert an incoming scalar to ``int``/``float`` while preserving intent."""
26
29
 
27
30
  if value is None:
28
31
  return None
@@ -80,7 +83,11 @@ def get_whole(value):
80
83
 
81
84
 
82
85
  def simplify_value(value, decimals=4):
83
- """Get the significant part of a number"""
86
+ """Return the significant digits of ``value`` capped by ``decimals``.
87
+
88
+ Used by analytics pipelines to produce short strings that still encode the
89
+ important portion of very large or tiny numbers.
90
+ """
84
91
 
85
92
  if value is None:
86
93
  return None
@@ -126,7 +133,13 @@ def pretty(
126
133
  zeros=4,
127
134
  compress=None,
128
135
  ):
129
- """Decorate the number beautifully"""
136
+ """Format ``value`` according to LibDev UI/metrics rules.
137
+
138
+ Supports optional rounding to a target precision, manual sign prefixing,
139
+ swapping the thousands separator symbol, and compressing leading/trailing
140
+ zeros (see ``compress_zeros``). This helper is the canonical way to build
141
+ user-facing number strings.
142
+ """
130
143
 
131
144
  if value is None:
132
145
  return None
@@ -282,6 +295,8 @@ def to_step(value, step=1, side=False):
282
295
 
283
296
 
284
297
  def to_plain(value) -> str:
298
+ """Convert ``value`` to a normalized decimal string without notation."""
299
+
285
300
  if value is None:
286
301
  return None
287
302
  try:
@@ -311,11 +326,17 @@ def _round_to_decimals(x, decimals):
311
326
 
312
327
 
313
328
  def compress_zeros(x, zeros=2, round=None) -> str:
314
- """
315
- 0.000012 -> '0.0₄12'
316
- 1.000045 -> '1.0₄45'
317
- round: number of digits after the zero block (rounds).
318
- zeros: minimum count of consecutive zeros to compress (default: 2).
329
+ """Compress zero runs using the subscript notation referenced in the docs.
330
+
331
+ Examples::
332
+
333
+ 0.000012 -> "0.0₄12"
334
+ 1.000045 -> "1.0₄45"
335
+
336
+ ``round`` controls how many digits remain after the compressed block, while
337
+ ``zeros`` sets the minimum run length required before a compression occurs.
338
+ Returns a string that can be passed to ``pretty`` or directly displayed in
339
+ dashboards.
319
340
  """
320
341
 
321
342
  if x is None:
@@ -1,5 +1,9 @@
1
- """
2
- Provides an asynchronous function to fetch data from a URL using aiohttp
1
+ """Async HTTP gateway used across LibDev powered projects.
2
+
3
+ Centralizes ``aiohttp`` usage so upstream services benefit from the same request
4
+ construction (JSON vs form payloads, multipart file uploads) and response
5
+ parsing rules described in ``LIBDEV_DOCUMENTATION.md``. Always ``await`` the
6
+ helpers in this module to stay inside the async boundary.
3
7
  """
4
8
 
5
9
  import aiohttp
@@ -14,24 +18,15 @@ async def fetch(
14
18
  headers=None,
15
19
  timeout=None,
16
20
  ):
17
- """
18
- Fetch data from a URL using aiohttp.
19
-
20
- Args:
21
- url (str): The URL to fetch data from.
22
- payload (dict, optional): The payload to send with the request.
23
- Defaults to None.
24
- type_req (str, optional): The type of request (e.g., 'post', 'put',
25
- 'delete', etc.). Defaults to 'post'.
26
- type_data (str, optional): The type of data (e.g., 'json', 'data').
27
- Defaults to 'json'.
28
- headers (dict, optional): The headers to include with the request.
29
- Defaults to None.
30
- timeout (float, optional): The timeout for the request in seconds.
31
- Defaults to None.
21
+ """Perform an HTTP request and normalize the response payload.
32
22
 
33
- Returns:
34
- tuple: A tuple containing the status code and the response data.
23
+ Parameters mirror the rules from the integration guide: ``files`` may be a
24
+ mapping of field name to bytes/file-like objects (forcing multipart form
25
+ uploads), ``type_data`` controls whether the ``payload`` is supplied via the
26
+ ``json`` or ``data`` keyword, and ``type_req`` is the lowercase HTTP verb. A
27
+ status code integer and the decoded response body (JSON dict, plain text, or
28
+ raw bytes) are returned. Callers are expected to provide their own retries
29
+ or circuit breaking logic.
35
30
  """
36
31
  if payload is None:
37
32
  payload = {}
@@ -1,5 +1,8 @@
1
- """
2
- Time functionality
1
+ """Datetime parsing/formatting helpers aligned with LibDev localization rules.
2
+
3
+ The functions below implement the Russian month parsing, timezone handling, and
4
+ delta formatting conventions cited in ``LIBDEV_DOCUMENTATION.md`` so every
5
+ project surfaces dates the same way.
3
6
  """
4
7
 
5
8
  # TODO: Учитывать летнее / зимнее время в прошлых датах, которого теперь нет
@@ -51,13 +54,15 @@ def to_tz(hours):
51
54
  return datetime.timezone(datetime.timedelta(hours=hours))
52
55
 
53
56
 
54
- def get_time(data=None, template="%d.%m.%Y %H:%M:%S", tz=0):
57
+ def get_time(data=None, template="%d.%m.%Y %H:%M:%S", tz=None):
55
58
  """Get time from timestamp"""
56
59
 
57
60
  if data is None:
58
61
  data = time.time()
59
62
  if isinstance(data, str):
60
63
  return data
64
+ if tz is None:
65
+ tz = 0
61
66
 
62
67
  # TODO: smart TZ
63
68
 
@@ -67,18 +72,20 @@ def get_time(data=None, template="%d.%m.%Y %H:%M:%S", tz=0):
67
72
  return time.strftime(template, time.gmtime(data + tz * 3600))
68
73
 
69
74
 
70
- def get_date(data=None, template="%d.%m.%Y", tz=0):
75
+ def get_date(data=None, template="%d.%m.%Y", tz=None):
71
76
  """Get date from timestamp"""
72
77
  return get_time(data, template, tz)
73
78
 
74
79
 
75
- def decode_time(data=None, template="%d.%m.%Y %H:%M:%S", tz=0):
80
+ def decode_time(data=None, template="%d.%m.%Y %H:%M:%S", tz=None):
76
81
  """Get timestamp from time"""
77
82
 
78
83
  if not data:
79
84
  return None
80
85
  if isinstance(data, int):
81
86
  return data
87
+ if tz is None:
88
+ tz = 0
82
89
 
83
90
  try:
84
91
  data = datetime.datetime.strptime(data, template)
@@ -90,17 +97,20 @@ def decode_time(data=None, template="%d.%m.%Y %H:%M:%S", tz=0):
90
97
  return int(data.timestamp())
91
98
 
92
99
 
93
- def decode_date(data=None, template="%d.%m.%Y", tz=0):
100
+ def decode_date(data=None, template="%d.%m.%Y", tz=None):
94
101
  """Get timestamp from date"""
95
102
  return decode_time(data, template, tz)
96
103
 
97
104
 
98
105
  # pylint: disable=too-many-branches,too-many-statements
99
- def parse_time(data: str, tz=0):
106
+ def parse_time(data: str, tz=None):
100
107
  """Parse time"""
101
108
 
102
109
  # TODO: 16 year -> 2016 year
103
110
 
111
+ if tz is None:
112
+ tz = 0
113
+
104
114
  data = data.lower()
105
115
 
106
116
  # Cut special characters
@@ -264,7 +274,7 @@ def format_delta(sec, short=False, locale="en"):
264
274
  return delta
265
275
 
266
276
 
267
- def get_midnight(timestamp=None, tz=0):
277
+ def get_midnight(timestamp=None, tz=None):
268
278
  """
269
279
  Get the start of the day (midnight) for a given timestamp in a specified timezone.
270
280
 
@@ -275,14 +285,19 @@ def get_midnight(timestamp=None, tz=0):
275
285
  Returns:
276
286
  float: The timestamp for the start of the day (midnight) in the specified timezone.
277
287
  """
288
+
278
289
  if timestamp is None:
279
290
  timestamp = time.time()
291
+ if tz is None:
292
+ tz = 0
293
+
280
294
  dt_local = datetime.datetime.fromtimestamp(timestamp, tz=to_tz(tz))
281
295
  start_day = dt_local.replace(hour=0, minute=0, second=0, microsecond=0)
296
+
282
297
  return int(start_day.timestamp())
283
298
 
284
299
 
285
- def get_month_start(timestamp=None, tz=0):
300
+ def get_month_start(timestamp=None, tz=None):
286
301
  """
287
302
  Get the start of the month (midnight on the first day of the month) for a given timestamp in a specified timezone.
288
303
 
@@ -293,14 +308,25 @@ def get_month_start(timestamp=None, tz=0):
293
308
  Returns:
294
309
  float: The timestamp for the start of the month in the specified timezone.
295
310
  """
311
+
296
312
  if timestamp is None:
297
313
  timestamp = time.time()
314
+ if tz is None:
315
+ tz = 0
316
+
298
317
  dt_local = datetime.datetime.fromtimestamp(timestamp, tz=to_tz(tz))
299
318
  start_month = dt_local.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
319
+
300
320
  return int(start_month.timestamp())
301
321
 
302
322
 
303
- def get_week_start(timestamp=None, tz=0):
323
+ def get_previous_month(timestamp=None, tz=None):
324
+ current_period = get_month_start(timestamp, tz)
325
+ one_month_ago = get_month_start(current_period - 1, tz)
326
+ return one_month_ago
327
+
328
+
329
+ def get_week_start(timestamp=None, tz=None):
304
330
  """
305
331
  Get the start of the week (midnight on Monday) for a given timestamp in a specified timezone.
306
332
 
@@ -311,17 +337,23 @@ def get_week_start(timestamp=None, tz=0):
311
337
  Returns:
312
338
  float: The timestamp for the start of the week (Monday at midnight) in the specified timezone.
313
339
  """
340
+
314
341
  if timestamp is None:
315
342
  timestamp = time.time()
343
+ if tz is None:
344
+ tz = 0
345
+
316
346
  dt_local = datetime.datetime.fromtimestamp(timestamp, tz=to_tz(tz))
317
347
  # Calculate days to subtract to get to Monday (weekday() returns 0 for Monday, 6 for Sunday)
318
348
  days_since_monday = dt_local.weekday()
349
+
319
350
  start_week = dt_local - datetime.timedelta(days=days_since_monday)
320
351
  start_week = start_week.replace(hour=0, minute=0, second=0, microsecond=0)
352
+
321
353
  return int(start_week.timestamp())
322
354
 
323
355
 
324
- def get_next_day(timestamp=None, tz=0):
356
+ def get_next_day(timestamp=None, tz=None):
325
357
  """
326
358
  Get the start of the next day (midnight) for a given timestamp in a specified timezone.
327
359
 
@@ -332,17 +364,22 @@ def get_next_day(timestamp=None, tz=0):
332
364
  Returns:
333
365
  float: The timestamp for the start of the next day (midnight) in the specified timezone.
334
366
  """
367
+
335
368
  if timestamp is None:
336
369
  timestamp = time.time()
370
+ if tz is None:
371
+ tz = 0
372
+
337
373
  dt_local = datetime.datetime.fromtimestamp(timestamp, tz=to_tz(tz))
338
374
  next_day = (dt_local + datetime.timedelta(days=1)).replace(
339
375
  hour=0, minute=0, second=0, microsecond=0
340
376
  )
377
+
341
378
  return int(next_day.timestamp())
342
379
 
343
380
 
344
381
  # TODO: get previous month (params=-1 +1)
345
- def get_next_month(timestamp=None, tz=0):
382
+ def get_next_month(timestamp=None, tz=None):
346
383
  """
347
384
  Get the start of the next month (midnight on the first day of the next month) for a given timestamp in a specified timezone.
348
385
 
@@ -356,6 +393,8 @@ def get_next_month(timestamp=None, tz=0):
356
393
 
357
394
  if timestamp is None:
358
395
  timestamp = time.time()
396
+ if tz is None:
397
+ tz = 0
359
398
 
360
399
  dt_local = datetime.datetime.fromtimestamp(timestamp, tz=to_tz(tz))
361
400
 
@@ -0,0 +1,94 @@
1
+ Metadata-Version: 2.4
2
+ Name: libdev
3
+ Version: 0.97
4
+ Summary: Set of standard functions for development
5
+ Home-page: https://github.com/chilleco/lib
6
+ Author: Alex Poloz
7
+ Author-email: Alex Poloz <alexypoloz@gmail.com>
8
+ License: MIT License
9
+
10
+ Copyright (c) 2021 Alexey Poloz
11
+
12
+ Permission is hereby granted, free of charge, to any person obtaining a copy
13
+ of this software and associated documentation files (the "Software"), to deal
14
+ in the Software without restriction, including without limitation the rights
15
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16
+ copies of the Software, and to permit persons to whom the Software is
17
+ furnished to do so, subject to the following conditions:
18
+
19
+ The above copyright notice and this permission notice shall be included in all
20
+ copies or substantial portions of the Software.
21
+
22
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28
+ SOFTWARE.
29
+
30
+ Project-URL: Source, https://github.com/chilleco/lib
31
+ Keywords: standard,lib,dev,development,cfg,config,generate,codes,tokens,ids,passwords,generator,ciphers,time,formatter,nlp,natural language,aws,s3,upload file,file server
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
36
+ Classifier: License :: OSI Approved :: MIT License
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3 :: Only
39
+ Classifier: Programming Language :: Python :: 3.10
40
+ Classifier: Programming Language :: Python :: 3.11
41
+ Classifier: Programming Language :: Python :: 3.12
42
+ Classifier: Programming Language :: Python :: 3.13
43
+ Classifier: Operating System :: OS Independent
44
+ Requires-Python: >=3.10, <4
45
+ Description-Content-Type: text/markdown
46
+ License-File: LICENSE
47
+ Requires-Dist: aiohttp>=3.13.2
48
+ Requires-Dist: python-dotenv>=1.2.1
49
+ Requires-Dist: boto3>=1.42.0
50
+ Requires-Dist: Pillow>=12.0.0
51
+ Requires-Dist: loguru>=0.7.3
52
+ Provides-Extra: dev
53
+ Requires-Dist: build>=1.3.0; extra == "dev"
54
+ Requires-Dist: setuptools>=80.9.0; extra == "dev"
55
+ Requires-Dist: twine>=6.2.0; extra == "dev"
56
+ Requires-Dist: pylint>=4.0.4; extra == "dev"
57
+ Requires-Dist: pytest>=9.0.1; extra == "dev"
58
+ Requires-Dist: pytest-asyncio>=1.3.0; extra == "dev"
59
+ Dynamic: author
60
+ Dynamic: home-page
61
+ Dynamic: license-file
62
+ Dynamic: requires-python
63
+
64
+ # LibDev
65
+ Development library — Set of standard functions for development
66
+
67
+ [GitHub](https://github.com/chilleco/lib)
68
+ | [PyPI](https://pypi.org/project/libdev/)
69
+
70
+ ## Requirements
71
+ - Python 3.10+ (dependencies are 3.14-ready)
72
+
73
+ ## Installation
74
+ - Runtime: `pip install .`
75
+ - Dev / tests: `pip install .[dev]` or `make setup-dev`
76
+
77
+ ## Submodules
78
+ Stream | Submodule | Description
79
+ ---|---|---
80
+ System | ` libdev.cfg ` | Configuration getting
81
+ &nbsp; | ` libdev.req ` | AsyncIO requests (AIOHTTP wrapper)
82
+ &nbsp; | ` libdev.log ` | Logger (Loguru wrapper)
83
+ Data Format | ` libdev.num ` | Numeric conversions & handlers
84
+ &nbsp; | ` libdev.time ` | Time processing
85
+ Transforms | ` libdev.gen ` | Code & token generators
86
+ &nbsp; | ` libdev.codes ` | Ciphers: langs & flags / networks / user statuses
87
+ &nbsp; | ` libdev.check ` | Validation functions
88
+ &nbsp; | ` libdev.crypt ` | Encryption and decryption functions
89
+ Fields | ` libdev.dev ` | Development tools
90
+ &nbsp; | ` libdev.fin ` | Financial codes and tools
91
+ &nbsp; | ` libdev.lang ` | Natural language formatters
92
+ Files | ` libdev.doc ` | Base64 / JSON handlers
93
+ &nbsp; | ` libdev.s3 ` | S3 file server functions
94
+ &nbsp; | ` libdev.img ` | Image processing
@@ -1,6 +1,8 @@
1
1
  LICENSE
2
2
  README.md
3
+ pyproject.toml
3
4
  setup.py
5
+ env/bin/jp.py
4
6
  libdev/__init__.py
5
7
  libdev/cfg.py
6
8
  libdev/check.py
@@ -0,0 +1,13 @@
1
+ aiohttp>=3.13.2
2
+ python-dotenv>=1.2.1
3
+ boto3>=1.42.0
4
+ Pillow>=12.0.0
5
+ loguru>=0.7.3
6
+
7
+ [dev]
8
+ build>=1.3.0
9
+ setuptools>=80.9.0
10
+ twine>=6.2.0
11
+ pylint>=4.0.4
12
+ pytest>=9.0.1
13
+ pytest-asyncio>=1.3.0
@@ -0,0 +1,4 @@
1
+ dist
2
+ docs
3
+ env
4
+ libdev
@@ -0,0 +1,75 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80.9", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "libdev"
7
+ dynamic = ["version"]
8
+ description = "Set of standard functions for development"
9
+ readme = { file = "README.md", content-type = "text/markdown" }
10
+ requires-python = ">=3.10, <4"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Alex Poloz", email = "alexypoloz@gmail.com" }]
13
+ keywords = [
14
+ "standard",
15
+ "lib",
16
+ "dev",
17
+ "development",
18
+ "cfg",
19
+ "config",
20
+ "generate",
21
+ "codes",
22
+ "tokens",
23
+ "ids",
24
+ "passwords",
25
+ "generator",
26
+ "ciphers",
27
+ "time",
28
+ "formatter",
29
+ "nlp",
30
+ "natural language",
31
+ "aws",
32
+ "s3",
33
+ "upload file",
34
+ "file server",
35
+ ]
36
+ classifiers = [
37
+ "Development Status :: 4 - Beta",
38
+ "Environment :: Console",
39
+ "Intended Audience :: Developers",
40
+ "Topic :: Software Development :: Libraries :: Application Frameworks",
41
+ "License :: OSI Approved :: MIT License",
42
+ "Programming Language :: Python :: 3",
43
+ "Programming Language :: Python :: 3 :: Only",
44
+ "Programming Language :: Python :: 3.10",
45
+ "Programming Language :: Python :: 3.11",
46
+ "Programming Language :: Python :: 3.12",
47
+ "Programming Language :: Python :: 3.13",
48
+ "Operating System :: OS Independent",
49
+ ]
50
+ dependencies = [
51
+ "aiohttp>=3.13.2",
52
+ "python-dotenv>=1.2.1",
53
+ "boto3>=1.42.0",
54
+ "Pillow>=12.0.0",
55
+ "loguru>=0.7.3",
56
+ ]
57
+
58
+ [project.optional-dependencies]
59
+ dev = [
60
+ "build>=1.3.0",
61
+ "setuptools>=80.9.0",
62
+ "twine>=6.2.0",
63
+ "pylint>=4.0.4",
64
+ "pytest>=9.0.1",
65
+ "pytest-asyncio>=1.3.0",
66
+ ]
67
+
68
+ [project.urls]
69
+ Source = "https://github.com/chilleco/lib"
70
+
71
+ [tool.setuptools.dynamic]
72
+ version = { attr = "libdev.__version__" }
73
+
74
+ [tool.setuptools.packages.find]
75
+ exclude = ["tests", "tests.*"]
@@ -4,31 +4,31 @@ Setup the Python package
4
4
 
5
5
  import pathlib
6
6
  import re
7
- from setuptools import setup, find_packages
8
7
 
8
+ from setuptools import find_packages, setup
9
9
 
10
- with open("README.md", "r", encoding="utf-8") as file:
11
- long_description = file.read()
12
10
 
13
11
  WORK_DIR = pathlib.Path(__file__).parent
14
12
 
13
+ with open(WORK_DIR / "README.md", "r", encoding="utf-8") as file:
14
+ LONG_DESCRIPTION = file.read()
15
+
15
16
 
16
17
  def get_version():
17
- """Get version"""
18
+ """Extract version from package init."""
18
19
 
19
20
  txt = (WORK_DIR / "libdev" / "__init__.py").read_text("utf-8")
20
-
21
- try:
22
- return re.findall(r"^__version__ = \"([^\"]+)\"\r?$", txt, re.M)[0]
23
- except IndexError as e:
24
- raise RuntimeError("Unable to determine version") from e
21
+ match = re.search(r'^__version__ = "([^"]+)"', txt, re.M)
22
+ if not match:
23
+ raise RuntimeError("Unable to determine version")
24
+ return match.group(1)
25
25
 
26
26
 
27
27
  setup(
28
28
  name="libdev",
29
29
  version=get_version(),
30
30
  description="Set of standard functions for development",
31
- long_description=long_description,
31
+ long_description=LONG_DESCRIPTION,
32
32
  long_description_content_type="text/markdown",
33
33
  url="https://github.com/chilleco/lib",
34
34
  author="Alex Poloz",
@@ -40,6 +40,11 @@ setup(
40
40
  "Topic :: Software Development :: Libraries :: Application Frameworks",
41
41
  "License :: OSI Approved :: MIT License",
42
42
  "Programming Language :: Python :: 3",
43
+ "Programming Language :: Python :: 3 :: Only",
44
+ "Programming Language :: Python :: 3.10",
45
+ "Programming Language :: Python :: 3.11",
46
+ "Programming Language :: Python :: 3.12",
47
+ "Programming Language :: Python :: 3.13",
43
48
  "Operating System :: OS Independent",
44
49
  ],
45
50
  keywords=(
@@ -48,14 +53,13 @@ setup(
48
53
  "natural language, aws, s3, upload file, file server"
49
54
  ),
50
55
  packages=find_packages(exclude=("tests",)),
51
- python_requires=">=3.7, <4",
56
+ python_requires=">=3.10, <4",
52
57
  install_requires=[
53
- # NOTE: Without lib versions because of conflicts with main repo
54
- "aiohttp",
55
- "python-dotenv",
56
- "boto3",
57
- "Pillow",
58
- "loguru",
58
+ "aiohttp>=3.13.2",
59
+ "python-dotenv>=1.2.1",
60
+ "boto3>=1.42.0",
61
+ "Pillow>=12.0.0",
62
+ "loguru>=0.7.3",
59
63
  ],
60
64
  project_urls={
61
65
  "Source": "https://github.com/chilleco/lib",
@@ -157,6 +157,7 @@ def test_pretty():
157
157
  assert pretty(123.456, 1) == "123"
158
158
  assert pretty(123.456, 1, True) == "+123"
159
159
  assert pretty(12345.6, 3, True) == "+12’346"
160
+ assert pretty(1046012.4859999998, 0) == "1’046’012"
160
161
  assert pretty(-0.000000235235, zeros=None, compress=None) == "-0.000000235235"
161
162
  assert pretty(-0.000000235235, zeros=4, compress=2) == "-0.0₆24"
162
163
 
@@ -13,6 +13,7 @@ from libdev.time import (
13
13
  format_delta,
14
14
  get_midnight,
15
15
  get_month_start,
16
+ get_previous_month,
16
17
  get_next_day,
17
18
  get_next_month,
18
19
  get_delta_days,
@@ -121,6 +122,12 @@ def test_get_month_start():
121
122
  assert get_month_start(1704060061, tz=3) == 1704056400
122
123
 
123
124
 
125
+ def test_get_previous_month():
126
+ assert get_previous_month(1764497920.160952) == 1759276800
127
+ assert get_previous_month(1764497920, tz=3) == 1759266000
128
+ assert get_previous_month(1760648400, 1) == 1756681200
129
+
130
+
124
131
  def test_get_next_day():
125
132
  assert get_next_day(1704060061) == 1704067200
126
133
  assert get_next_day(1704060061, tz=3) == 1704142800
libdev-0.95/PKG-INFO DELETED
@@ -1,50 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: libdev
3
- Version: 0.95
4
- Summary: Set of standard functions for development
5
- Home-page: https://github.com/chilleco/lib
6
- Author: Alex Poloz
7
- Author-email: alexypoloz@gmail.com
8
- License: MIT
9
- Project-URL: Source, https://github.com/chilleco/lib
10
- Keywords: standard,lib,dev,development,cfg,config,generate,codes,tokens,ids,passwords,generator,ciphers,time,formatter,nlp,natural language,aws,s3,upload file,file server
11
- Classifier: Development Status :: 4 - Beta
12
- Classifier: Environment :: Console
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
15
- Classifier: License :: OSI Approved :: MIT License
16
- Classifier: Programming Language :: Python :: 3
17
- Classifier: Operating System :: OS Independent
18
- Requires-Python: >=3.7, <4
19
- Description-Content-Type: text/markdown
20
- License-File: LICENSE
21
- Requires-Dist: aiohttp
22
- Requires-Dist: python-dotenv
23
- Requires-Dist: boto3
24
- Requires-Dist: Pillow
25
- Requires-Dist: loguru
26
-
27
- # LibDev
28
- Development library — Set of standard functions for development
29
-
30
- [GitHub](https://github.com/chilleco/lib)
31
- | [PyPI](https://pypi.org/project/libdev/)
32
-
33
- ## Submodules
34
- Stream | Submodule | Description
35
- ---|---|---
36
- System | ` libdev.cfg ` | Configuration getting
37
- &nbsp; | ` libdev.req ` | AsyncIO requests (AIOHTTP wrapper)
38
- &nbsp; | ` libdev.log ` | Logger (Loguru wrapper)
39
- Data Format | ` libdev.num ` | Numeric conversions & handlers
40
- &nbsp; | ` libdev.time ` | Time processing
41
- Transforms | ` libdev.gen ` | Code & token generators
42
- &nbsp; | ` libdev.codes ` | Ciphers: langs & flags / networks / user statuses
43
- &nbsp; | ` libdev.check ` | Validation functions
44
- &nbsp; | ` libdev.crypt ` | Encryption and decryption functions
45
- Fields | ` libdev.dev ` | Development tools
46
- &nbsp; | ` libdev.fin ` | Financial codes and tools
47
- &nbsp; | ` libdev.lang ` | Natural language formatters
48
- Files | ` libdev.doc ` | Base64 / JSON handlers
49
- &nbsp; | ` libdev.s3 ` | S3 file server functions
50
- &nbsp; | ` libdev.img ` | Image processing
libdev-0.95/libdev/dev.py DELETED
@@ -1,21 +0,0 @@
1
- """
2
- Development tools
3
- """
4
-
5
- import re
6
-
7
-
8
- def check_public_ip(ip):
9
- """Check if the IP address is public"""
10
-
11
- if not ip:
12
- return None
13
-
14
- return (
15
- None
16
- if re.match(
17
- r"^(172\.(1[6-9]\.|2[0-9]\.|3[0-1]\.)|192\.168\.|10\.|127\.)",
18
- ip,
19
- )
20
- else ip
21
- )
libdev-0.95/libdev/doc.py DELETED
@@ -1,17 +0,0 @@
1
- """
2
- Documents processing functionality
3
- """
4
-
5
- import base64
6
- import json
7
-
8
-
9
- def to_base64(image, mime="image/jpg"):
10
- """Convert image to base64"""
11
- data = base64.b64encode(image.read())
12
- return f"data:{mime};base64,{data.decode('utf-8')}"
13
-
14
-
15
- def to_json(data):
16
- """Convert object to json"""
17
- return json.dumps(data, indent="\t", ensure_ascii=False)
@@ -1,50 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: libdev
3
- Version: 0.95
4
- Summary: Set of standard functions for development
5
- Home-page: https://github.com/chilleco/lib
6
- Author: Alex Poloz
7
- Author-email: alexypoloz@gmail.com
8
- License: MIT
9
- Project-URL: Source, https://github.com/chilleco/lib
10
- Keywords: standard,lib,dev,development,cfg,config,generate,codes,tokens,ids,passwords,generator,ciphers,time,formatter,nlp,natural language,aws,s3,upload file,file server
11
- Classifier: Development Status :: 4 - Beta
12
- Classifier: Environment :: Console
13
- Classifier: Intended Audience :: Developers
14
- Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
15
- Classifier: License :: OSI Approved :: MIT License
16
- Classifier: Programming Language :: Python :: 3
17
- Classifier: Operating System :: OS Independent
18
- Requires-Python: >=3.7, <4
19
- Description-Content-Type: text/markdown
20
- License-File: LICENSE
21
- Requires-Dist: aiohttp
22
- Requires-Dist: python-dotenv
23
- Requires-Dist: boto3
24
- Requires-Dist: Pillow
25
- Requires-Dist: loguru
26
-
27
- # LibDev
28
- Development library — Set of standard functions for development
29
-
30
- [GitHub](https://github.com/chilleco/lib)
31
- | [PyPI](https://pypi.org/project/libdev/)
32
-
33
- ## Submodules
34
- Stream | Submodule | Description
35
- ---|---|---
36
- System | ` libdev.cfg ` | Configuration getting
37
- &nbsp; | ` libdev.req ` | AsyncIO requests (AIOHTTP wrapper)
38
- &nbsp; | ` libdev.log ` | Logger (Loguru wrapper)
39
- Data Format | ` libdev.num ` | Numeric conversions & handlers
40
- &nbsp; | ` libdev.time ` | Time processing
41
- Transforms | ` libdev.gen ` | Code & token generators
42
- &nbsp; | ` libdev.codes ` | Ciphers: langs & flags / networks / user statuses
43
- &nbsp; | ` libdev.check ` | Validation functions
44
- &nbsp; | ` libdev.crypt ` | Encryption and decryption functions
45
- Fields | ` libdev.dev ` | Development tools
46
- &nbsp; | ` libdev.fin ` | Financial codes and tools
47
- &nbsp; | ` libdev.lang ` | Natural language formatters
48
- Files | ` libdev.doc ` | Base64 / JSON handlers
49
- &nbsp; | ` libdev.s3 ` | S3 file server functions
50
- &nbsp; | ` libdev.img ` | Image processing
@@ -1,5 +0,0 @@
1
- aiohttp
2
- python-dotenv
3
- boto3
4
- Pillow
5
- loguru
@@ -1 +0,0 @@
1
- libdev
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes