python-plugins 0.1.2__py3-none-any.whl → 0.1.4__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.
@@ -1 +1 @@
1
- __version__ = "0.1.2"
1
+ __version__ = "0.1.4"
@@ -0,0 +1,2 @@
1
+ from .datetime_str import datetime2str, str2datetime
2
+ from .xml import xml2dict
@@ -0,0 +1,15 @@
1
+ from datetime import datetime
2
+
3
+ date_fmt = "%Y-%m-%d"
4
+ datetime_fmt = "%Y-%m-%d %H:%M:%S"
5
+
6
+ # datetime.isoformat()
7
+ # datetime.fromisoformat(str)
8
+
9
+
10
+ def datetime2str(dt):
11
+ return datetime.strftime(dt, datetime_fmt)
12
+
13
+
14
+ def str2datetime(s):
15
+ return datetime.strptime(s, datetime_fmt)
@@ -0,0 +1,7 @@
1
+ import xml.etree.cElementTree as ET
2
+
3
+
4
+ def xml2dict(xmlstr):
5
+ xml_tree = ET.fromstring(xmlstr)
6
+ xmldict = {k.tag: k.text for k in xml_tree}
7
+ return xmldict
@@ -0,0 +1 @@
1
+ from .fernet import generate_fernet_key,fernet_encrypt,fernet_decrypt
@@ -0,0 +1,41 @@
1
+ import base64
2
+ from cryptography.hazmat.primitives import padding
3
+ from cryptography.fernet import Fernet
4
+
5
+ # Fernet文档 : https://github.com/fernet/spec/blob/master/Spec.md
6
+
7
+
8
+ def generate_fernet_key(key) -> bytes:
9
+ """see cryptography.fernet.Fernet.generate_key()
10
+
11
+ :param key: _description_
12
+ :raises ValueError: _description_
13
+ :return: _description_
14
+ """
15
+ if isinstance(key, str):
16
+ key = key.encode("utf-8")
17
+ if not isinstance(key, bytes):
18
+ raise ValueError
19
+ if len(key) < 32:
20
+ padder = padding.PKCS7(32 * 8).padder()
21
+ key = padder.update(key) + padder.finalize()
22
+ fernet_key = key[0:16] + key[16:32]
23
+ return base64.urlsafe_b64encode(fernet_key)
24
+
25
+
26
+ def fernet_encrypt(key, txt) -> str:
27
+ if isinstance(txt, str):
28
+ txt = txt.encode("utf-8")
29
+ fernet_key = generate_fernet_key(key)
30
+ f = Fernet(fernet_key)
31
+ token = f.encrypt(txt)
32
+ return token.decode("utf-8")
33
+
34
+
35
+ def fernet_decrypt(key, token) -> str:
36
+ if isinstance(token, str):
37
+ token = token.encode("utf-8")
38
+ fernet_key = generate_fernet_key(key)
39
+ f = Fernet(fernet_key)
40
+ decrypt_data = f.decrypt(token)
41
+ return decrypt_data.decode("utf-8")
@@ -0,0 +1,91 @@
1
+ import base64
2
+ import os
3
+ import random
4
+ from cryptography.fernet import Fernet
5
+ from cryptography.hazmat.primitives import hashes
6
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
7
+ from ..random import rand_letter
8
+
9
+
10
+ def bytes_to_url64str(bstr: bytes):
11
+ s = base64.urlsafe_b64encode(bstr).rstrip(b"=").decode()
12
+ return s
13
+
14
+
15
+ def url64str_to_bytes(s):
16
+ _, r = divmod(len(s), 4)
17
+ bstr = base64.urlsafe_b64decode((s + "=" * r).encode())
18
+ return bstr
19
+
20
+
21
+ def get_key(password, safe_salt=None, times=None):
22
+ if isinstance(password, str):
23
+ password = password.encode()
24
+ if safe_salt is None:
25
+ salt = os.urandom(16)
26
+ safe_salt = bytes_to_url64str(salt)
27
+ else:
28
+ salt = url64str_to_bytes(safe_salt)
29
+ if times is None:
30
+ times = random.randint(100, 100000)
31
+
32
+ kdf = PBKDF2HMAC(
33
+ algorithm=hashes.SHA256(),
34
+ length=32,
35
+ salt=salt,
36
+ iterations=times,
37
+ )
38
+ key = base64.urlsafe_b64encode(kdf.derive(password))
39
+ return (key, safe_salt, times)
40
+
41
+
42
+ def str_randsplit_to_list(s, n1=10, n2=30):
43
+ r = []
44
+ while s:
45
+ if len(s) < 40:
46
+ r.append(s)
47
+ break
48
+ k = random.randint(n1, n2)
49
+ r.append(s[:k])
50
+ if k < len(s):
51
+ s = s[k:]
52
+ else:
53
+ s = ""
54
+ return r
55
+
56
+
57
+ def encrypt_str_to_list(s: str, password=None, prefix=None):
58
+ if password is None:
59
+ password = rand_letter(random.randint(6, 16))
60
+ out_password = password
61
+ else:
62
+ out_password = "-"
63
+ if prefix is not None:
64
+ password = str(prefix) + password
65
+
66
+ key, safe_salt, times = get_key(password)
67
+
68
+ cipher_suite = Fernet(key)
69
+ encrypted_data = cipher_suite.encrypt(s.encode())
70
+ safe_data = bytes_to_url64str(encrypted_data)
71
+
72
+ list_out = [out_password, safe_salt, str(times)] + str_randsplit_to_list(safe_data)
73
+
74
+ return list_out
75
+
76
+
77
+ def decrypt_list_to_str(list_in, password=None, prefix=None):
78
+ _password, safe_salt, _times, *_data = list_in
79
+ if password is None:
80
+ password = _password
81
+ else:
82
+ password = password
83
+ if prefix is not None:
84
+ password = str(prefix) + password
85
+
86
+ times = int(_times)
87
+ s = "".join(_data)
88
+ key, _, _ = get_key(password, safe_salt, times)
89
+ cipher_suite = Fernet(key)
90
+ decrypted_bytes = cipher_suite.decrypt(url64str_to_bytes(s))
91
+ return decrypted_bytes.decode()
@@ -0,0 +1,2 @@
1
+ from .postgresql_dump import pg_dump
2
+ from .postgresql_dump import remove_ndays_ago
@@ -0,0 +1,31 @@
1
+ import subprocess
2
+ import sys
3
+
4
+
5
+ def pg_dump(dump_dir, username, dbname, tbname):
6
+ """pg_dump
7
+
8
+ :param dir: dump dir
9
+ :param username: db user
10
+ :param dbname: db name
11
+ :param tbname: table name
12
+ """
13
+ pgdump_cmd = (
14
+ f"dump_user={username};dump_db={dbname};dump_tb={tbname};dump_dir={dump_dir};"
15
+ "pg_dump -U ${dump_user} --no-password -d ${dump_db} -t ${dump_tb} | gzip > ${dump_dir}/${dump_db}.${dump_tb}-`date +'%Y%m%d'`.gz;"
16
+ "cp ${dump_dir}/${dump_db}.${dump_tb}-`date +'%Y%m%d'`.gz ${dump_dir}/${dump_db}.${dump_tb}.gz;"
17
+ )
18
+ if sys.platform == "linux":
19
+ r = subprocess.run(pgdump_cmd, shell=True)
20
+ else:
21
+ r = f"not pg_dump because sys.platform is {sys.platform}"
22
+ return r
23
+
24
+
25
+ def remove_ndays_ago(dir, days=30):
26
+ remove_cmd = f"rm -f {dir}/*`date +'%Y%m%d' -d'-{days} days'`.gz"
27
+ if sys.platform == "linux":
28
+ r = subprocess.run(remove_cmd, shell=True)
29
+ else:
30
+ r = f"not remove files because sys.platform is {sys.platform}"
31
+ return r
@@ -0,0 +1 @@
1
+ from .hash import hash_file, hash_text
@@ -0,0 +1,26 @@
1
+ import hashlib
2
+ import os.path
3
+
4
+
5
+ def hash_file(filename, algorithm="sha1"):
6
+ if os.path.isfile(filename) is False:
7
+ raise Exception("File not found for hash operation")
8
+
9
+ sha_func = getattr(hashlib, algorithm)
10
+ sha_obj = sha_func()
11
+
12
+ with open(filename, "rb") as f:
13
+ chunk = 0
14
+ while chunk != b"":
15
+ chunk = f.read(1024)
16
+ sha_obj.update(chunk)
17
+
18
+ return sha_obj.hexdigest()
19
+
20
+
21
+ def hash_text(text, algorithm="sha1"):
22
+ # hashlib.md5(text).hexdigest() # simple
23
+ sha_func = getattr(hashlib, algorithm)
24
+ sha_obj = sha_func()
25
+ sha_obj.update(text)
26
+ return sha_obj.hexdigest()
@@ -0,0 +1 @@
1
+ from .jwt import jwt_encode, jwt_decode
@@ -0,0 +1,37 @@
1
+ import jwt
2
+ import datetime
3
+
4
+
5
+ def jwt_encode(payload: dict, key: str, delta: int = None, algorithm="HS256"):
6
+ """encode payload.
7
+
8
+ :param payload: _description_
9
+ :param key: _description_
10
+ :param delta: _description_, defaults to None
11
+ :param algorithm: _description_, defaults to "HS256"
12
+ :return: An encoded access token
13
+ """
14
+ if delta and delta > 0:
15
+ exp = datetime.datetime.now(tz=datetime.timezone.utc) + datetime.timedelta(
16
+ seconds=delta
17
+ )
18
+ payload |= {"exp": exp}
19
+
20
+ token = jwt.encode(payload, key, algorithm)
21
+ return token
22
+
23
+
24
+ def jwt_decode(encoded, key: str, algorithm="HS256"):
25
+ """decode jwt."""
26
+
27
+ payload = jwt.decode(encoded, key, algorithm)
28
+ return payload
29
+
30
+
31
+ # try:
32
+ # ...
33
+ # except Exception as e:
34
+ # # import sys
35
+ # # print(sys.exc_info())
36
+ # # return None,str(e)
37
+ # return None
@@ -0,0 +1,33 @@
1
+ def update_obj(db, old_obj, new_data: dict, NewClass, force=None):
2
+ """insert or update object
3
+
4
+ :param db: sqlalchemy db
5
+ :param old_obj: old object
6
+ :param new_data: new dict
7
+ :param NewClass: object class
8
+ :param force: update= update old object with new attribute
9
+ """
10
+ # 1. old is not exist
11
+ if old_obj is None:
12
+ new_obj = NewClass()
13
+ for k in new_data:
14
+ if hasattr(new_obj, k):
15
+ setattr(new_obj, k, new_data.get(k))
16
+ db.session.add(new_obj)
17
+ db.session.commit()
18
+ print(f"{new_obj} inserted")
19
+ return
20
+
21
+ # 2. old is exist
22
+ match force:
23
+ case None:
24
+ print(f"{old_obj} exists")
25
+ case "update":
26
+ # update old
27
+ for k in new_data:
28
+ if hasattr(old_obj, k):
29
+ setattr(old_obj, k, new_data.get(k))
30
+ db.session.commit()
31
+ print(f"{old_obj} updated")
32
+ case _:
33
+ raise Exception
@@ -0,0 +1,2 @@
1
+ from .sub_process import run_process
2
+ from .python_venv_process import run_process_in_venv
@@ -0,0 +1,18 @@
1
+ import subprocess
2
+ import os.path
3
+ import json
4
+
5
+
6
+ def run_process_in_venv(dir: str, cmd: str, params):
7
+ if not (os.path.exists(dir) and os.path.isdir(dir)):
8
+ return f"dir {dir} not exists"
9
+
10
+ cmd = [
11
+ os.path.join(dir, "venv/bin/python"),
12
+ os.path.join(dir, cmd),
13
+ json.dumps(params) if isinstance(params, dict) else str(params),
14
+ ]
15
+ # print(cmd)
16
+ completedProcess = subprocess.run(cmd, capture_output=True)
17
+ r = str(completedProcess)
18
+ return r
@@ -0,0 +1,12 @@
1
+ import subprocess
2
+ import json
3
+
4
+
5
+ def run_process(cmd: str, params=None,shell=False):
6
+ cmd_args = [
7
+ cmd,
8
+ json.dumps(params) if isinstance(params, dict) else str(params),
9
+ ]
10
+ completedProcess = subprocess.run(cmd_args, capture_output=True,shell=shell)
11
+ r = str(completedProcess)
12
+ return r
@@ -0,0 +1,4 @@
1
+ from .random_str import rand_digit
2
+ from .random_str import rand_letter
3
+ from .random_str import rand_sentence
4
+ from .random_str import secret_token, secret_token_16
@@ -0,0 +1,46 @@
1
+ import random
2
+ import string
3
+ import os
4
+ import base64
5
+ import uuid
6
+ import secrets
7
+
8
+ # random.sample # unique
9
+ # random.choices # not unique
10
+
11
+
12
+ def rand_digit(n):
13
+ """随机数字"""
14
+ return "".join(random.choices(string.digits, k=n))
15
+
16
+
17
+ def rand_letter(n: int):
18
+ return "".join(random.choices(string.ascii_letters + string.digits, k=n))
19
+
20
+
21
+ def rand_sentence(n):
22
+ return "".join(
23
+ random.choices(string.ascii_letters + string.digits + " " * 10, k=n)
24
+ ).strip()
25
+
26
+
27
+ def rand_uuid4():
28
+ return str(uuid.uuid4())
29
+
30
+
31
+ def rand_token():
32
+ return uuid.uuid4().hex
33
+
34
+
35
+ def secret_token():
36
+ return secrets.token_hex(32)
37
+
38
+
39
+ def secret_token_16():
40
+ return secrets.token_hex(16)
41
+
42
+
43
+ def rand_token_2(n):
44
+ # replace '+/' with '1a'
45
+ token = base64.b64encode(os.urandom(n), b"1a").decode()[0:n]
46
+ return token
@@ -0,0 +1,13 @@
1
+ import os
2
+ import shutil
3
+
4
+ def remove_pycache(dir_path):
5
+ for root, dirs, files in os.walk(dir_path):
6
+ if "venv" in root or "git" in root:
7
+ continue
8
+ for dir in dirs:
9
+ if dir == "__pycache__":
10
+ pycache_path = os.path.join(root, dir)
11
+ print(f"Removing {pycache_path}")
12
+ shutil.rmtree(pycache_path)
13
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-plugins
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: A collection of Python functions and classes.
5
5
  Project-URL: Documentation, https://python-plugins.readthedocs.io
6
6
  Project-URL: Source, https://github.com/ojso/python-plugins
@@ -40,6 +40,8 @@ Classifier: Topic :: Software Development :: Build Tools
40
40
  Requires-Python: >=3.10
41
41
  Provides-Extra: cryptography
42
42
  Requires-Dist: cryptography; extra == 'cryptography'
43
+ Provides-Extra: jwt
44
+ Requires-Dist: pyjwt; extra == 'jwt'
43
45
  Provides-Extra: pillow
44
46
  Requires-Dist: pillow; extra == 'pillow'
45
47
  Provides-Extra: qrcode
@@ -0,0 +1,33 @@
1
+ python_plugins/__about__.py,sha256=Wzf5T3NBDfhQoTnhnRNHSlAsE0XMqbclXG-M81Vas70,22
2
+ python_plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
3
+ python_plugins/convert/__init__.py,sha256=UwzPhcQLaHEvcssbrcCymWujBV_BOmfYCIJxGPyJdbY,79
4
+ python_plugins/convert/datetime_str.py,sha256=bmC9d1W7XKA1ED9XO9reUiUyfQcM_BqGoGyOF21RW9A,282
5
+ python_plugins/convert/xml.py,sha256=RUxqDt6NKzwbuodTxKVoiR4dP-vNbmL77dztLx_9UzY,164
6
+ python_plugins/crypto/__init__.py,sha256=jteDuT_b2kS4anlgn1jr8DysuV837cFiZafLaDSquu0,70
7
+ python_plugins/crypto/fernet.py,sha256=UgEAHJGBtmH9AacD-IOyr9dR8T5PKTWL8kH5yj2wKqI,1191
8
+ python_plugins/crypto/str_to_list.py,sha256=PpIcfQqkD01huBsxbYYGvwPfCmrFvBJNXLq7SAXsWCU,2401
9
+ python_plugins/dumps/__init__.py,sha256=TLPuPLIAuULFkiIbFfTCsuhH0CQhPRMUjBmcsr0mtqA,83
10
+ python_plugins/dumps/postgresql_dump.py,sha256=zN5aLYLxpon2y9_5gKizRjlrRUlkAO-dG-BuKpJ4F3U,1030
11
+ python_plugins/email/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ python_plugins/email/smtp.py,sha256=weSfLVPzROFqwlxDaVhjem522NVEp31lc6PFkbZE1ok,854
13
+ python_plugins/hashes/__init__.py,sha256=PQbx8f4klFMg5Q8kehSHz1itj_djWV5hkBT4AMNNUn0,39
14
+ python_plugins/hashes/hash.py,sha256=uSF3ohZRD7b2VAIvjjpTWC0SlY7QsFhsFZUejINrRGU,640
15
+ python_plugins/jwt/__init__.py,sha256=GS27VK4uk1FXsmju5xpHu0p4FNSwW-tkeJ3hCSaW1rY,40
16
+ python_plugins/jwt/jwt.py,sha256=g1wfg6euVUbaF5CvAWvu29U_KQKd1u2RvfAdkcOJbNA,908
17
+ python_plugins/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ python_plugins/models/update.py,sha256=cIwhR0iKkB7cVx7km_oA9ya97MSkJlLPb8pZWaEePmE,991
19
+ python_plugins/models/mixins/__init__.py,sha256=s1S9jtS8W3xbvbshFkh4WvJBqbjScSvN27Chn8_D_Pw,204
20
+ python_plugins/models/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
21
+ python_plugins/models/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQCnU9dvl6g6GHitYtlA,154
22
+ python_plugins/models/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
23
+ python_plugins/models/mixins/user_minxin.py,sha256=D-N45bunicBuuwKs--s_tyDxxLC3mkxV9Tva8JAhsko,579
24
+ python_plugins/process/__init__.py,sha256=1rNYaujG3SI6Pgt2er-txyXd5XdQEZRXkRxrTdodD0I,90
25
+ python_plugins/process/python_venv_process.py,sha256=yRgaKfPQ-TC_Kn2tuDqoTJZ__216BC-8LijymolUMaI,490
26
+ python_plugins/process/sub_process.py,sha256=OwjPb2-xEnE6fiXVL0Jv5R9aE_6cmr_1zcRAmCOykcc,317
27
+ python_plugins/random/__init__.py,sha256=V0qSIG6LiAkOK1xT6r6yezgKMMWh6ynoSe6Pt_yxG3I,163
28
+ python_plugins/random/random_str.py,sha256=d3y96cQmiKfwtxvT0fTlOdq9gclbMF2_g_6ud__2ueE,819
29
+ python_plugins/utils/remove_pycache.py,sha256=aKCkmSRVWioV6PZmjJOzXUtMUsewTbWFEgL2OUPF26I,380
30
+ python_plugins-0.1.4.dist-info/METADATA,sha256=IhpDIx3ozu1GRH6PPKloIOenaIVacjxrrbfqmDcDTZY,2811
31
+ python_plugins-0.1.4.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
32
+ python_plugins-0.1.4.dist-info/licenses/LICENSE.rst,sha256=d9ee1DxacJqITSYaORZy85rWGNZyZbDNv_r-lY2RQ9s,1099
33
+ python_plugins-0.1.4.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- python_plugins/__about__.py,sha256=YvuYzWnKtqBb-IqG8HAu-nhIYAsgj9Vmc_b9o7vO-js,22
2
- python_plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
3
- python_plugins/email/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- python_plugins/email/smtp.py,sha256=weSfLVPzROFqwlxDaVhjem522NVEp31lc6PFkbZE1ok,854
5
- python_plugins/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- python_plugins/models/mixins/__init__.py,sha256=s1S9jtS8W3xbvbshFkh4WvJBqbjScSvN27Chn8_D_Pw,204
7
- python_plugins/models/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
8
- python_plugins/models/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQCnU9dvl6g6GHitYtlA,154
9
- python_plugins/models/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
10
- python_plugins/models/mixins/user_minxin.py,sha256=D-N45bunicBuuwKs--s_tyDxxLC3mkxV9Tva8JAhsko,579
11
- python_plugins-0.1.2.dist-info/METADATA,sha256=uDCEUZwFeovFz8pcWx08SpG-WTn6TNwiw1SeDVl_a3Y,2754
12
- python_plugins-0.1.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
13
- python_plugins-0.1.2.dist-info/licenses/LICENSE.rst,sha256=d9ee1DxacJqITSYaORZy85rWGNZyZbDNv_r-lY2RQ9s,1099
14
- python_plugins-0.1.2.dist-info/RECORD,,