python-plugins 0.1.7__py3-none-any.whl → 0.2.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.
@@ -1 +1 @@
1
- __version__ = "0.1.7"
1
+ __version__ = "0.2.0"
@@ -1 +1 @@
1
- from .utils.remove_pycache import remove_pycache
1
+
@@ -1,2 +1,3 @@
1
1
  from .datetime_str import datetime2str, str2datetime
2
2
  from .xml import xml2dict
3
+ from .pretty import prettify_class_name
@@ -1 +1,2 @@
1
- from .fernet import generate_fernet_key,fernet_encrypt,fernet_decrypt
1
+ from .fernet import generate_fernet_key, fernet_encrypt, fernet_decrypt
2
+ from .file_to_file import encrypt_txtfile, decrypt_txtfile
@@ -1,20 +1,12 @@
1
- from .str_to_list import encrypt_bytes_to_list
1
+ import re
2
+ from getpass import getpass
2
3
  from .str_to_list import encrypt_str_to_list
3
- from .str_to_list import decrypt_list_to_bytes
4
4
  from .str_to_list import decrypt_list_to_str
5
- from getpass import getpass
6
-
7
-
8
- def bytes_from_file(fin) -> bytes:
9
- with open(fin, "rb") as f:
10
- s = f.read()
11
- return s
12
-
13
-
14
- def bytes_to_file(s: bytes, fout):
15
- with open(fout, "wb") as f:
16
- f.write(s)
17
5
 
6
+ def get_prompts_line(s, pattern=r"prompts\((\d+)\)"):
7
+ match = re.search(pattern, s)
8
+ if match:
9
+ return int(match[1])
18
10
 
19
11
  def str_from_txtfile(fin) -> str:
20
12
  with open(fin, encoding="utf-8") as f:
@@ -22,91 +14,57 @@ def str_from_txtfile(fin) -> str:
22
14
  return s
23
15
 
24
16
 
25
- def str_to_txtfile(s: str, fout):
26
- with open(fout, "w", encoding="utf-8") as f:
27
- f.write(s)
28
-
29
-
30
- def bytes_to_file(s, fout):
31
- with open(fout, "wb") as f:
32
- f.write(s)
17
+ def str_to_txtfile(s: str, fout=None):
18
+ if fout is None:
19
+ print(s)
20
+ else:
21
+ with open(fout, "w", encoding="utf-8") as f:
22
+ f.write(s)
33
23
 
24
+ def encrypt_txtfile(fin, fout=None, password=None, prompt='prompts(1)'):
25
+ s = str_from_txtfile(fin)
34
26
 
35
- def encrypt_txt(s: str, prompt=None, accept_password=False):
36
27
  if not prompt:
37
28
  prompt = input("input prompt=")
38
- password = None
39
- if accept_password:
29
+
30
+ if password == "[input]":
40
31
  password = getpass("input password=")
32
+
41
33
  if password:
42
34
  encrypted_list = encrypt_str_to_list(s, password)
43
35
  encrypted_list[0] = "-"
44
36
  else:
45
37
  encrypted_list = encrypt_str_to_list(s)
46
- s2 = "\n".join([prompt] + encrypted_list)
47
- return s2
48
-
49
-
50
- def decrypt_txt(s: str):
51
- encrypted_list = s.split("\n")
52
- prompt = encrypted_list[0]
53
- if encrypted_list[1] == "-":
54
- print(prompt)
55
- password = getpass("input password=")
56
- s2 = decrypt_list_to_str(encrypted_list[1:], password)
57
- else:
58
- s2 = decrypt_list_to_str(encrypted_list[1:])
59
-
60
- return s2
61
38
 
39
+ s2 = "\n".join([prompt] + encrypted_list)
62
40
 
63
- def encrypt_txtfile(fin, fout, prompt=None, accept_password=False):
64
- s = str_from_txtfile(fin)
65
- s2 = encrypt_txt(s, prompt, accept_password)
41
+ if fout == ".":
42
+ fout = fin+"_1"
43
+
66
44
  str_to_txtfile(s2, fout)
67
45
 
68
46
 
69
- def decrypt_txtfile(fin, fout):
47
+ def decrypt_txtfile(fin, fout=None, password=None):
70
48
  s = str_from_txtfile(fin)
71
- s2 = decrypt_txt(s)
72
- str_to_txtfile(s2, fout)
73
-
74
-
75
- def encrypt_bytes(s: bytes, prompt=None, accept_password=False):
76
- if not prompt:
77
- prompt = input("input prompt=")
78
- password = None
79
- if accept_password:
49
+ if password == "[input]":
80
50
  password = getpass("input password=")
81
- if password:
82
- encrypted_list = encrypt_bytes_to_list(s, password)
83
- encrypted_list[0] = "-"
51
+ s_list = s.split("\n")
52
+ prompts = get_prompts_line(s_list[0])
53
+ if prompts is None:
54
+ prompts_line = 1
84
55
  else:
85
- encrypted_list = encrypt_bytes_to_list(s)
86
- s2 = "\n".join([prompt] + encrypted_list)
87
- return s2
88
-
56
+ prompts_line = prompts
57
+ encrypted_list = s_list[prompts_line:]
89
58
 
90
- def decrypt_bytes(s: str):
91
- encrypted_list = s.split("\n")
92
- prompt = encrypted_list[0]
93
- if encrypted_list[1] == "-":
94
- print(prompt)
59
+ if encrypted_list[0] == "-" and password is None:
95
60
  password = getpass("input password=")
96
- s2 = decrypt_list_to_bytes(encrypted_list[1:], password)
97
- else:
98
- s2 = decrypt_list_to_bytes(encrypted_list[1:])
99
-
100
- return s2
101
61
 
102
-
103
- def encrypt_file(fin, fout, prompt=None, accept_password=False):
104
- s = bytes_from_file(fin)
105
- s2 = encrypt_bytes(s, prompt, accept_password)
62
+ if password is None:
63
+ s2 = decrypt_list_to_str(encrypted_list)
64
+ else:
65
+ s2 = decrypt_list_to_str(encrypted_list, password)
66
+
67
+ if fout == ".":
68
+ fout = fin+"_2"
106
69
  str_to_txtfile(s2, fout)
107
70
 
108
-
109
- def decrypt_file(fin, fout):
110
- s = str_from_txtfile(fin)
111
- s2 = decrypt_bytes(s)
112
- bytes_to_file(s2, fout)
@@ -1,10 +1,13 @@
1
1
  import base64
2
2
  import os
3
3
  import random
4
+ import string
4
5
  from cryptography.fernet import Fernet
5
6
  from cryptography.hazmat.primitives import hashes
6
7
  from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
7
- from ..random import rand_letter
8
+
9
+ def rand_letter(n: int):
10
+ return "".join(random.choices(string.ascii_letters + string.digits, k=n))
8
11
 
9
12
 
10
13
  def bytes_to_url64str(bstr: bytes):
@@ -54,34 +57,26 @@ def str_randsplit_to_list(s, n1=10, n2=30):
54
57
  return r
55
58
 
56
59
 
57
- def encrypt_bytes_to_list(s: bytes, password=None, prefix=None):
60
+ def encrypt_bytes_to_list(s: bytes, password=None):
58
61
  if password is None:
59
62
  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
63
  key, safe_salt, times = get_key(password)
67
64
 
68
65
  cipher_suite = Fernet(key)
69
66
  encrypted_data = cipher_suite.encrypt(s)
70
67
  safe_data = bytes_to_url64str(encrypted_data)
71
68
 
72
- list_out = [out_password, safe_salt, str(times)] + str_randsplit_to_list(safe_data)
69
+ list_out = [password, safe_salt, str(times)] + str_randsplit_to_list(safe_data)
73
70
 
74
71
  return list_out
75
72
 
76
73
 
77
- def decrypt_list_to_bytes(list_in, password=None, prefix=None) -> bytes:
74
+ def decrypt_list_to_bytes(list_in, password=None) -> bytes:
78
75
  _password, safe_salt, _times, *_data = list_in
79
76
  if password is None:
80
77
  password = _password
81
78
  else:
82
79
  password = password
83
- if prefix is not None:
84
- password = str(prefix) + password
85
80
 
86
81
  times = int(_times)
87
82
  s = "".join(_data)
@@ -91,11 +86,11 @@ def decrypt_list_to_bytes(list_in, password=None, prefix=None) -> bytes:
91
86
  return decrypted_bytes
92
87
 
93
88
 
94
- def encrypt_str_to_list(s: str, password=None, prefix=None):
95
- arr = encrypt_bytes_to_list(s.encode(), password, prefix)
89
+ def encrypt_str_to_list(s: str, password=None):
90
+ arr = encrypt_bytes_to_list(s.encode(), password)
96
91
  return arr
97
92
 
98
93
 
99
- def decrypt_list_to_str(list_in, password=None, prefix=None):
100
- decrypted_bytes = decrypt_list_to_bytes(list_in, password, prefix)
94
+ def decrypt_list_to_str(list_in, password=None):
95
+ decrypted_bytes = decrypt_list_to_bytes(list_in, password)
101
96
  return decrypted_bytes.decode()
@@ -0,0 +1,40 @@
1
+ import functools
2
+
3
+ # lambda parameters: expression
4
+
5
+ lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
6
+
7
+ print(lst)
8
+
9
+ # map(function, iterable, *iterables) -> iterable
10
+
11
+ lst_2 = list(map(lambda i: i**2, lst))
12
+
13
+ print(lst_2)
14
+
15
+ print([i**2 for i in lst])
16
+
17
+ lst_3 = list(map(lambda x, y: x + y, lst, lst_2))
18
+
19
+ print(lst_3)
20
+
21
+ # filter(function, iterable) -> iterable
22
+
23
+ result = list(filter(lambda x: x % 2 == 0, lst))
24
+
25
+ print(result)
26
+
27
+ print([item for item in lst if item % 2 == 0])
28
+
29
+
30
+ # reduce(function, iterable[, initializer])
31
+
32
+ result = functools.reduce(lambda x, y: x + y, lst)
33
+
34
+ print(result)
35
+
36
+
37
+ # zip(*iterables)
38
+
39
+ # sorted(iterable, key=None, reverse=False)
40
+
File without changes
@@ -0,0 +1,2 @@
1
+ from .json import JSONField
2
+ from .datetime import DateTimeField
@@ -0,0 +1,100 @@
1
+ import time
2
+ import datetime
3
+ import wtforms.fields
4
+ from ..widgets.datetime import DateTimePickerWidget
5
+ from ..widgets.datetime import TimePickerWidget
6
+
7
+ class DateTimeField(wtforms.fields.DateTimeField):
8
+ """
9
+ Allows modifying the datetime format of a DateTimeField using form_args.
10
+ """
11
+
12
+ widget = DateTimePickerWidget()
13
+
14
+ def __init__(self, label=None, validators=None, format=None, **kwargs):
15
+ """Constructor
16
+
17
+ :param label:
18
+ Label
19
+ :param validators:
20
+ Field validators
21
+ :param format:
22
+ Format for text to date conversion. Defaults to '%Y-%m-%d %H:%M:%S'
23
+ :param kwargs:
24
+ Any additional parameters
25
+ """
26
+ super().__init__(
27
+ label, validators, format or "%Y-%m-%d %H:%M:%S", **kwargs
28
+ )
29
+
30
+
31
+ class TimeField(wtforms.fields.Field):
32
+ """
33
+ A text field which stores a `datetime.time` object.
34
+ Accepts time string in multiple formats: 20:10, 20:10:00, 10:00 am, 9:30pm, etc.
35
+ """
36
+
37
+ widget = TimePickerWidget()
38
+
39
+ def __init__(
40
+ self,
41
+ label=None,
42
+ validators=None,
43
+ formats=None,
44
+ default_format=None,
45
+ widget_format=None,
46
+ **kwargs
47
+ ):
48
+ """
49
+ Constructor
50
+
51
+ :param label:
52
+ Label
53
+ :param validators:
54
+ Field validators
55
+ :param formats:
56
+ Supported time formats, as a enumerable.
57
+ :param default_format:
58
+ Default time format. Defaults to '%H:%M:%S'
59
+ :param kwargs:
60
+ Any additional parameters
61
+ """
62
+ super().__init__(label, validators, **kwargs)
63
+
64
+ self.formats = formats or (
65
+ "%H:%M:%S",
66
+ "%H:%M",
67
+ "%I:%M:%S%p",
68
+ "%I:%M%p",
69
+ "%I:%M:%S %p",
70
+ "%I:%M %p",
71
+ )
72
+
73
+ self.default_format = default_format or "%H:%M:%S"
74
+
75
+ def _value(self):
76
+ if self.raw_data:
77
+ return " ".join(self.raw_data)
78
+ elif self.data is not None:
79
+ return self.data.strftime(self.default_format)
80
+ else:
81
+ return ""
82
+
83
+ def process_formdata(self, valuelist):
84
+ if valuelist:
85
+ date_str = " ".join(valuelist)
86
+
87
+ if date_str.strip():
88
+ for format in self.formats:
89
+ try:
90
+ timetuple = time.strptime(date_str, format)
91
+ self.data = datetime.time(
92
+ timetuple.tm_hour, timetuple.tm_min, timetuple.tm_sec
93
+ )
94
+ return
95
+ except ValueError:
96
+ pass
97
+
98
+ raise ValueError(self.gettext("Invalid time format"))
99
+ else:
100
+ self.data = None
@@ -0,0 +1,19 @@
1
+ import json
2
+ from wtforms.fields import TextAreaField
3
+
4
+ class JSONField(TextAreaField):
5
+ def process_formdata(self, valuelist):
6
+ if valuelist:
7
+ if not valuelist[0]:
8
+ self.data = None
9
+ return
10
+ try:
11
+ self.data = json.loads(valuelist[0])
12
+ except ValueError:
13
+ raise ValueError(self.gettext("Invalid JSON"))
14
+
15
+ def _value(self):
16
+ if self.data:
17
+ return json.dumps(self.data, ensure_ascii=False)
18
+ else:
19
+ return ""
@@ -0,0 +1,123 @@
1
+ import re
2
+ import wtforms.fields
3
+ from ..widgets.select import Select2Widget
4
+ from ..widgets.select import Select2TagsWidget
5
+
6
+
7
+ class Select2Field(wtforms.fields.SelectField):
8
+ """
9
+ `Select2 <https://github.com/ivaynberg/select2>`_ styled select widget.
10
+
11
+ You must include select2.js, form-x.x.x.js and select2 stylesheet for it to
12
+ work.
13
+ """
14
+
15
+ widget = Select2Widget()
16
+
17
+ def __init__(
18
+ self,
19
+ label=None,
20
+ validators=None,
21
+ coerce=str,
22
+ choices=None,
23
+ allow_blank=False,
24
+ blank_text=None,
25
+ **kwargs
26
+ ):
27
+ super(Select2Field, self).__init__(label, validators, coerce, choices, **kwargs)
28
+ self.allow_blank = allow_blank
29
+ self.blank_text = blank_text or " "
30
+
31
+ def iter_choices(self):
32
+ if self.allow_blank:
33
+ yield ("__None", self.blank_text, self.data is None)
34
+
35
+ for choice in self.choices:
36
+ if isinstance(choice, tuple):
37
+ yield (choice[0], choice[1], self.coerce(choice[0]) == self.data)
38
+ else:
39
+ yield (
40
+ choice.value,
41
+ choice.name,
42
+ self.coerce(choice.value) == self.data,
43
+ )
44
+
45
+ def process_data(self, value):
46
+ if value is None:
47
+ self.data = None
48
+ else:
49
+ try:
50
+ self.data = self.coerce(value)
51
+ except (ValueError, TypeError):
52
+ self.data = None
53
+
54
+ def process_formdata(self, valuelist):
55
+ if valuelist:
56
+ if valuelist[0] == "__None":
57
+ self.data = None
58
+ else:
59
+ try:
60
+ self.data = self.coerce(valuelist[0])
61
+ except ValueError:
62
+ raise ValueError(self.gettext("Invalid Choice: could not coerce"))
63
+
64
+ def pre_validate(self, form):
65
+ if self.allow_blank and self.data is None:
66
+ return
67
+
68
+ super(Select2Field, self).pre_validate(form)
69
+
70
+
71
+ class Select2TagsField(wtforms.fields.StringField):
72
+ """`Select2 <http://ivaynberg.github.com/select2/#tags>`_ styled text field.
73
+ You must include select2.js, form-x.x.x.js and select2 stylesheet for it to work.
74
+ """
75
+
76
+ widget = Select2TagsWidget()
77
+ _strip_regex = re.compile(
78
+ r"#\d+(?:(,)|\s$)"
79
+ ) # e.g., 'tag#123, anothertag#425 ' => 'tag, anothertag'
80
+
81
+ def __init__(
82
+ self,
83
+ label=None,
84
+ validators=None,
85
+ save_as_list=False,
86
+ coerce=str,
87
+ allow_duplicates=False,
88
+ **kwargs
89
+ ):
90
+ """Initialization
91
+
92
+ :param save_as_list:
93
+ If `True` then populate ``obj`` using list else string
94
+ :param allow_duplicates
95
+ If `True` then duplicate tags are allowed in the field.
96
+ """
97
+ self.save_as_list = save_as_list
98
+ self.allow_duplicates = allow_duplicates
99
+ self.coerce = coerce
100
+
101
+ super(Select2TagsField, self).__init__(label, validators, **kwargs)
102
+
103
+ def process_formdata(self, valuelist):
104
+ if valuelist:
105
+ entrylist = valuelist[0]
106
+ if self.allow_duplicates and entrylist.endswith(" "):
107
+ # This means this is an allowed duplicate (see form.js, `createSearchChoice`), so its ID was modified.
108
+ # Hence, we need to restore the original IDs.
109
+ entrylist = re.sub(self._strip_regex, "\\1", entrylist)
110
+ if self.save_as_list:
111
+ self.data = [
112
+ self.coerce(v.strip()) for v in entrylist.split(",") if v.strip()
113
+ ]
114
+ else:
115
+ self.data = self.coerce(entrylist)
116
+
117
+ def _value(self):
118
+ if isinstance(self.data, (list, tuple)):
119
+ return ",".join(v for v in self.data)
120
+ elif self.data:
121
+ return self.data
122
+ else:
123
+ return ""
@@ -0,0 +1,10 @@
1
+ from wtforms.fields import BooleanField
2
+
3
+
4
+ class SwitchField(BooleanField):
5
+ """
6
+ A wrapper field for ``BooleanField`` that renders as a Bootstrap switch.
7
+ """
8
+
9
+ def __init__(self, label=None, **kwargs):
10
+ super().__init__(label, **kwargs)
@@ -0,0 +1,9 @@
1
+ from wtforms.fields import StringField
2
+
3
+ class TagListField(StringField):
4
+ def process_formdata(self, valuelist):
5
+ if valuelist:
6
+ self.data = [x.strip() for x in valuelist[0].split(",")]
7
+
8
+ def _value(self):
9
+ return ",".join(self.data) if self.data is not None else ""
File without changes
@@ -0,0 +1,29 @@
1
+ from wtforms import StringField
2
+ from wtforms import PasswordField
3
+ from wtforms import BooleanField
4
+ from wtforms import SubmitField
5
+ from wtforms.validators import ValidationError
6
+ from wtforms.validators import DataRequired
7
+ from wtforms.validators import EqualTo
8
+ from wtforms.validators import Length
9
+
10
+
11
+ class LoginForm:
12
+ username = StringField("Username", validators=[DataRequired()])
13
+ password = PasswordField("Password", validators=[DataRequired()])
14
+ remember_me = BooleanField("Remember Me")
15
+ submit = SubmitField("login")
16
+
17
+
18
+ class RegisterForm:
19
+ username = StringField(
20
+ "Username", validators=[DataRequired(), Length(min=6, max=50)]
21
+ )
22
+ email = StringField("Email", validators=[DataRequired()])
23
+ password = PasswordField(
24
+ "Password", validators=[DataRequired(), Length(min=8, max=50)]
25
+ )
26
+ password_repeat = PasswordField(
27
+ "Repeat Password", validators=[DataRequired(), EqualTo("password")]
28
+ )
29
+ submit = SubmitField("Register")
File without changes
@@ -0,0 +1,30 @@
1
+ from wtforms.widgets import TextInput
2
+
3
+
4
+ class DatePickerWidget(TextInput):
5
+ """Date picker widget."""
6
+
7
+ def __call__(self, field, **kwargs):
8
+ kwargs.setdefault("data-role", "datepicker")
9
+ kwargs.setdefault("data-date-format", "YYYY-MM-DD")
10
+
11
+ self.date_format = kwargs["data-date-format"]
12
+ return super().__call__(field, **kwargs)
13
+
14
+
15
+ class DateTimePickerWidget(TextInput):
16
+ """Datetime picker widget."""
17
+
18
+ def __call__(self, field, **kwargs):
19
+ kwargs.setdefault("data-role", "datetimepicker")
20
+ kwargs.setdefault("data-date-format", "YYYY-MM-DD HH:mm:ss")
21
+ return super().__call__(field, **kwargs)
22
+
23
+
24
+ class TimePickerWidget(TextInput):
25
+ """Date picker widget."""
26
+
27
+ def __call__(self, field, **kwargs):
28
+ kwargs.setdefault("data-role", "timepicker")
29
+ kwargs.setdefault("data-date-format", "HH:mm:ss")
30
+ return super().__call__(field, **kwargs)
@@ -0,0 +1,4 @@
1
+ from wtforms.widgets import FileInput
2
+
3
+ class ImageInput(FileInput):
4
+ field_flags = {"accept": "image/*"}
@@ -0,0 +1,26 @@
1
+ from wtforms.widgets import Select
2
+ from wtforms.widgets import TextInput
3
+
4
+
5
+ class Select2Widget(Select):
6
+ """Select2 Widget."""
7
+
8
+ def __call__(self, field, **kwargs):
9
+ kwargs.setdefault("data-role", "select2")
10
+ allow_blank = getattr(field, "allow_blank", False)
11
+ if allow_blank and not self.multiple:
12
+ kwargs["data-allow-blank"] = "1"
13
+
14
+ return super().__call__(field, **kwargs)
15
+
16
+
17
+ class Select2TagsWidget(TextInput):
18
+ """Select2Tags Widget."""
19
+
20
+ def __call__(self, field, **kwargs):
21
+ kwargs.setdefault("data-role", "select2-tags")
22
+ kwargs.setdefault(
23
+ "data-allow-duplicate-tags",
24
+ "true" if getattr(field, "allow_duplicates", False) else "false",
25
+ )
26
+ return super().__call__(field, **kwargs)
python_plugins/jwt/jwt.py CHANGED
@@ -26,12 +26,3 @@ def jwt_decode(encoded, key: str, algorithm="HS256"):
26
26
 
27
27
  payload = jwt.decode(encoded, key, algorithm)
28
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
@@ -1,7 +1,10 @@
1
1
  from typing import Optional
2
2
  from sqlalchemy.orm import Mapped
3
3
  from sqlalchemy.orm import mapped_column
4
- from ...random.random_str import secret_token
4
+ import secrets
5
+
6
+ def secret_token():
7
+ return secrets.token_hex(32)
5
8
 
6
9
 
7
10
  class TokenMixin:
@@ -0,0 +1 @@
1
+ from .remove_pycache import remove_pycache
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: python-plugins
3
- Version: 0.1.7
3
+ Version: 0.2.0
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
7
7
  Project-URL: Homepage, https://github.com/ojso/python-plugins
8
- Author-email: huadong <david.dong.hua@gmail.com>
8
+ Author-email: David Hua <david.dong.hua@gmail.com>
9
9
  License: MIT License
10
10
 
11
- Copyright (c) 2024-present huadong <david.dong.hua@gmail.com>
11
+ Copyright (c) 2024-present DavidDongHua <david.dong.hua@gmail.com>
12
12
 
13
13
  Permission is hereby granted, free of charge, to any person obtaining a copy
14
14
  of this software and associated documentation files (the "Software"), to deal
@@ -27,7 +27,6 @@ License: MIT License
27
27
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
28
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
29
  SOFTWARE.
30
- License-File: LICENSE.rst
31
30
  Keywords: plugin,utils
32
31
  Classifier: Development Status :: 3 - Alpha
33
32
  Classifier: Intended Audience :: Developers
@@ -50,6 +49,8 @@ Provides-Extra: requests
50
49
  Requires-Dist: requests; extra == 'requests'
51
50
  Provides-Extra: sqlalchemy
52
51
  Requires-Dist: sqlalchemy; extra == 'sqlalchemy'
52
+ Provides-Extra: wtforms
53
+ Requires-Dist: wtforms; extra == 'wtforms'
53
54
  Description-Content-Type: text/x-rst
54
55
 
55
56
  python-plugins
@@ -1,34 +1,49 @@
1
- python_plugins/__about__.py,sha256=YpKDcdV7CqL8n45u267wKtyloM13FSVbOdrqgNZnSLM,22
2
- python_plugins/__init__.py,sha256=K3pMvS_BsKnB8yLH5siB1hmFkC2tq3e8rzZXO4CFPmk,49
3
- python_plugins/convert/__init__.py,sha256=UwzPhcQLaHEvcssbrcCymWujBV_BOmfYCIJxGPyJdbY,79
1
+ python_plugins/__about__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
2
+ python_plugins/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
3
+ python_plugins/convert/__init__.py,sha256=mQeBTbhjuTJkyG4DhXkoX9CNP1TDEgPBFIJ2TQNl2NM,119
4
4
  python_plugins/convert/datetime_str.py,sha256=bmC9d1W7XKA1ED9XO9reUiUyfQcM_BqGoGyOF21RW9A,282
5
5
  python_plugins/convert/pretty.py,sha256=igN4uq67AADcPOiy_h3_M-oEwgc1i3gJScbKtkf6d-k,211
6
6
  python_plugins/convert/xml.py,sha256=RUxqDt6NKzwbuodTxKVoiR4dP-vNbmL77dztLx_9UzY,164
7
- python_plugins/crypto/__init__.py,sha256=jteDuT_b2kS4anlgn1jr8DysuV837cFiZafLaDSquu0,70
7
+ python_plugins/crypto/__init__.py,sha256=2Snt9AIwVsQ-qLNno8qGWs8IyL-AvTImvqkRFO8nowQ,131
8
8
  python_plugins/crypto/fernet.py,sha256=UgEAHJGBtmH9AacD-IOyr9dR8T5PKTWL8kH5yj2wKqI,1191
9
- python_plugins/crypto/file_to_file.py,sha256=2xRKz_kv56Taj7QdWlfLHvR9mh3zIxFoHiYf5IK36-A,2844
10
- python_plugins/crypto/str_to_list.py,sha256=pctrpu73QfTX_SNtH7JAneAUAQAHPQ_mCB1wBkbhN5Y,2709
9
+ python_plugins/crypto/file_to_file.py,sha256=mS9llG3j0emhCB4NY6IlKew6wpoLyVW-008ZXN1v3iw,1764
10
+ python_plugins/crypto/str_to_list.py,sha256=T2I4p6bcZuiCsEve4XsOb1q9hFxeVPITstjPyTVoATE,2514
11
11
  python_plugins/dumps/__init__.py,sha256=TLPuPLIAuULFkiIbFfTCsuhH0CQhPRMUjBmcsr0mtqA,83
12
12
  python_plugins/dumps/postgresql_dump.py,sha256=zN5aLYLxpon2y9_5gKizRjlrRUlkAO-dG-BuKpJ4F3U,1030
13
13
  python_plugins/email/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
14
14
  python_plugins/email/smtp.py,sha256=weSfLVPzROFqwlxDaVhjem522NVEp31lc6PFkbZE1ok,854
15
+ python_plugins/examples/higher_order_functions.py,sha256=cBewE3cDkzaNHR6CQzdfWny0r_V4PgcUeZpHEdCp-E0,633
16
+ python_plugins/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ python_plugins/forms/fields/__init__.py,sha256=2g00xLZZhjORFECO8oG9tZeTL2HiGozA-d42Udv0LuU,64
18
+ python_plugins/forms/fields/datetime.py,sha256=WXiX4STSN97R3hIPxJUftCRFvrUYCN66qi0GIWs6qRI,2779
19
+ python_plugins/forms/fields/json.py,sha256=UzkZxzEZFqd2ONPfj0ZphbQoEAjY2ZS1cMioGuHpivQ,546
20
+ python_plugins/forms/fields/select.py,sha256=I0_b-Z31LF0_CTXIcPSopMLdM-0fH_QTP83DzBMXREw,3855
21
+ python_plugins/forms/fields/switch.py,sha256=3JmbKm9-nEoBcCPqvgjsWZ14xUTznoFbIDh2RomPh1A,257
22
+ python_plugins/forms/fields/taglist.py,sha256=z_miMSyrzjYOD6y1Xs22qPVXZpF5yGOTXpBLLzycdZs,298
23
+ python_plugins/forms/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
+ python_plugins/forms/mixins/user.py,sha256=KSTABFHcWyFgqfUENDXHJuU72nu6gEoKzzif_qFbFCM,988
25
+ python_plugins/forms/widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ python_plugins/forms/widgets/datetime.py,sha256=5nE-1OhtNdqwIaHts_0yNkA5HbsfEiH_zGRSwL6YlaI,925
27
+ python_plugins/forms/widgets/file.py,sha256=P2wcN7W8ju12x4UMax5sCc58f23hSIfB-9pmzNQS4Iw,108
28
+ python_plugins/forms/widgets/select.py,sha256=ITmmXWe72YokxN7MyxpcURV2PnoEkTI8-fo7zAObs4k,792
15
29
  python_plugins/hashes/__init__.py,sha256=PQbx8f4klFMg5Q8kehSHz1itj_djWV5hkBT4AMNNUn0,39
16
30
  python_plugins/hashes/hash.py,sha256=uSF3ohZRD7b2VAIvjjpTWC0SlY7QsFhsFZUejINrRGU,640
17
31
  python_plugins/jwt/__init__.py,sha256=GS27VK4uk1FXsmju5xpHu0p4FNSwW-tkeJ3hCSaW1rY,40
18
- python_plugins/jwt/jwt.py,sha256=g1wfg6euVUbaF5CvAWvu29U_KQKd1u2RvfAdkcOJbNA,908
32
+ python_plugins/jwt/jwt.py,sha256=yIpz-jwnRjYZwWtzqGLey9DyVnCL2Sx2RS9vgQJXTTk,742
19
33
  python_plugins/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
34
  python_plugins/models/update.py,sha256=cIwhR0iKkB7cVx7km_oA9ya97MSkJlLPb8pZWaEePmE,991
21
35
  python_plugins/models/mixins/__init__.py,sha256=l4dJVgUFI7aISA7X-CcVBOp19rXBgqyyhHwtuQnSgR0,241
22
36
  python_plugins/models/mixins/data_mixin.py,sha256=HCc1uvF6_O4yjK38uWAsqysEedLWgc7wtds3NjQTMZ8,366
23
37
  python_plugins/models/mixins/primary_key_mixin.py,sha256=QUO-7ZmYtAMMi7ReRQDYV0uwQCnU9dvl6g6GHitYtlA,154
24
38
  python_plugins/models/mixins/timestamp_mixin.py,sha256=u9rIu0IrzdCRRbnMk4IN4nTlNNiVPB8yPnTcHjQC1KU,547
25
- python_plugins/models/mixins/token_minxin.py,sha256=CpPeegw_ER7Msz442pZe7_5BQ5zyyiHdgkTWmqcCn9U,253
39
+ python_plugins/models/mixins/token_minxin.py,sha256=SxNftZXS-hCwqxov7whF_tBtlayuoi3LUPtu-ofMmdg,276
26
40
  python_plugins/models/mixins/user_minxin.py,sha256=D-N45bunicBuuwKs--s_tyDxxLC3mkxV9Tva8JAhsko,579
27
41
  python_plugins/process/__init__.py,sha256=1rNYaujG3SI6Pgt2er-txyXd5XdQEZRXkRxrTdodD0I,90
28
42
  python_plugins/process/python_venv_process.py,sha256=yRgaKfPQ-TC_Kn2tuDqoTJZ__216BC-8LijymolUMaI,490
29
43
  python_plugins/process/sub_process.py,sha256=OwjPb2-xEnE6fiXVL0Jv5R9aE_6cmr_1zcRAmCOykcc,317
30
44
  python_plugins/random/__init__.py,sha256=V0qSIG6LiAkOK1xT6r6yezgKMMWh6ynoSe6Pt_yxG3I,163
31
45
  python_plugins/random/random_str.py,sha256=d3y96cQmiKfwtxvT0fTlOdq9gclbMF2_g_6ud__2ueE,819
46
+ python_plugins/utils/__init__.py,sha256=l-U6Roo52hH66CfcPGZjy3oVpYLlEQPyPWVZO0d7228,43
32
47
  python_plugins/utils/remove_pycache.py,sha256=y3MXZHQ5MMjCxKMK3Jz8mYX_SGBRI5wbTKqD2ZbdkQ4,384
33
48
  python_plugins/weixin/biz_data_crypt.py,sha256=a-p9H25a_24x23i0vRWguUbWRs97osOpGBrhFt6LN_Q,2298
34
49
  python_plugins/weixin/error_code.py,sha256=822kuDDfFaXYqU8-g43dukjLwu205MQ-RN2ktjvwxf0,918
@@ -36,7 +51,7 @@ python_plugins/weixin/format_response.py,sha256=Eml9R1jYYOCtfXORyEWfHbCL8gauWeg2
36
51
  python_plugins/weixin/wechat.py,sha256=D6KHZSNj_19vCs5rxLSrHt5XkjkM4ZoD2z6VWD0a_b4,4296
37
52
  python_plugins/weixin/wechat_crypt.py,sha256=YOCy4F5ycfZFOJYtKSzhiFSfNb_MsQnN2Qy9u_FfZSU,4717
38
53
  python_plugins/weixin/weixin_api.py,sha256=xtnWBovJKNMdm-jXmIM7QHnMye-fZN4a4U_efejRarE,3286
39
- python_plugins-0.1.7.dist-info/METADATA,sha256=eil2DMtJn1URkJ4IIpzy6igo9XHRlFrqqGs_MLtCIB0,2881
40
- python_plugins-0.1.7.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
41
- python_plugins-0.1.7.dist-info/licenses/LICENSE.rst,sha256=d9ee1DxacJqITSYaORZy85rWGNZyZbDNv_r-lY2RQ9s,1099
42
- python_plugins-0.1.7.dist-info/RECORD,,
54
+ python_plugins-0.2.0.dist-info/METADATA,sha256=DoRticFoAGWJtjExNEXLriv9xHT09T-g1uopY_ajyvc,2929
55
+ python_plugins-0.2.0.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
56
+ python_plugins-0.2.0.dist-info/licenses/LICENSE.rst,sha256=X5eLIsAn1yAKd88LWTYkXUe0PmVK_Z5SD7_5NheGR-s,1104
57
+ python_plugins-0.2.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.25.0
2
+ Generator: hatchling 1.26.3
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024-present huadong <david.dong.hua@gmail.com>
3
+ Copyright (c) 2024-present DavidDongHua <david.dong.hua@gmail.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal