python-plugins 0.2.0__tar.gz → 0.2.2__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 (90) hide show
  1. {python_plugins-0.2.0 → python_plugins-0.2.2}/CHANGES.rst +17 -3
  2. {python_plugins-0.2.0 → python_plugins-0.2.2}/PKG-INFO +3 -4
  3. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/index.rst +0 -2
  4. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/usage.rst +24 -4
  5. {python_plugins-0.2.0 → python_plugins-0.2.2}/pyproject.toml +0 -1
  6. python_plugins-0.2.2/requirements/develop.in +1 -0
  7. {python_plugins-0.2.0 → python_plugins-0.2.2}/requirements/test.in +0 -1
  8. python_plugins-0.2.2/src/python_plugins/__about__.py +1 -0
  9. python_plugins-0.2.2/src/python_plugins/utils/__init__.py +4 -0
  10. python_plugins-0.2.2/src/python_plugins/utils/update-icons.py +49 -0
  11. python_plugins-0.2.2/src/python_plugins/utils/walk_remove_dir.py +19 -0
  12. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_utils.py +1 -0
  13. python_plugins-0.2.0/docs/api.rst +0 -4
  14. python_plugins-0.2.0/docs/examples.rst +0 -1
  15. python_plugins-0.2.0/examples/README.rst +0 -17
  16. python_plugins-0.2.0/src/python_plugins/__about__.py +0 -1
  17. python_plugins-0.2.0/src/python_plugins/forms/fields/__init__.py +0 -2
  18. python_plugins-0.2.0/src/python_plugins/forms/fields/datetime.py +0 -100
  19. python_plugins-0.2.0/src/python_plugins/forms/fields/json.py +0 -19
  20. python_plugins-0.2.0/src/python_plugins/forms/fields/select.py +0 -123
  21. python_plugins-0.2.0/src/python_plugins/forms/fields/switch.py +0 -10
  22. python_plugins-0.2.0/src/python_plugins/forms/fields/taglist.py +0 -9
  23. python_plugins-0.2.0/src/python_plugins/forms/mixins/__init__.py +0 -0
  24. python_plugins-0.2.0/src/python_plugins/forms/mixins/user.py +0 -29
  25. python_plugins-0.2.0/src/python_plugins/forms/widgets/__init__.py +0 -0
  26. python_plugins-0.2.0/src/python_plugins/forms/widgets/datetime.py +0 -30
  27. python_plugins-0.2.0/src/python_plugins/forms/widgets/file.py +0 -4
  28. python_plugins-0.2.0/src/python_plugins/forms/widgets/select.py +0 -26
  29. python_plugins-0.2.0/src/python_plugins/models/__init__.py +0 -0
  30. python_plugins-0.2.0/src/python_plugins/utils/__init__.py +0 -1
  31. python_plugins-0.2.0/src/python_plugins/utils/remove_pycache.py +0 -13
  32. python_plugins-0.2.0/tests/test_forms.py +0 -65
  33. {python_plugins-0.2.0 → python_plugins-0.2.2}/.github/workflows/release.yml +0 -0
  34. {python_plugins-0.2.0 → python_plugins-0.2.2}/.gitignore +0 -0
  35. {python_plugins-0.2.0 → python_plugins-0.2.2}/.readthedocs.yaml +0 -0
  36. {python_plugins-0.2.0 → python_plugins-0.2.2}/LICENSE.rst +0 -0
  37. {python_plugins-0.2.0 → python_plugins-0.2.2}/README.rst +0 -0
  38. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/Makefile +0 -0
  39. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/changes.rst +0 -0
  40. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/conf.py +0 -0
  41. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/make.bat +0 -0
  42. {python_plugins-0.2.0 → python_plugins-0.2.2}/docs/requirements.txt +0 -0
  43. {python_plugins-0.2.0 → python_plugins-0.2.2}/requirements/build.in +0 -0
  44. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/__init__.py +0 -0
  45. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/convert/__init__.py +0 -0
  46. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/convert/datetime_str.py +0 -0
  47. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/convert/pretty.py +0 -0
  48. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/convert/xml.py +0 -0
  49. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/crypto/__init__.py +0 -0
  50. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/crypto/fernet.py +0 -0
  51. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/crypto/file_to_file.py +0 -0
  52. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/crypto/str_to_list.py +0 -0
  53. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/dumps/__init__.py +0 -0
  54. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/dumps/postgresql_dump.py +0 -0
  55. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/email/__init__.py +0 -0
  56. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/email/smtp.py +0 -0
  57. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/examples/higher_order_functions.py +0 -0
  58. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/hashes/__init__.py +0 -0
  59. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/hashes/hash.py +0 -0
  60. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/jwt/__init__.py +0 -0
  61. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/jwt/jwt.py +0 -0
  62. {python_plugins-0.2.0/src/python_plugins/forms → python_plugins-0.2.2/src/python_plugins/models}/__init__.py +0 -0
  63. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/mixins/__init__.py +0 -0
  64. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/mixins/data_mixin.py +0 -0
  65. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/mixins/primary_key_mixin.py +0 -0
  66. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/mixins/timestamp_mixin.py +0 -0
  67. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/mixins/token_minxin.py +0 -0
  68. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/mixins/user_minxin.py +0 -0
  69. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/models/update.py +0 -0
  70. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/process/__init__.py +0 -0
  71. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/process/python_venv_process.py +0 -0
  72. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/process/sub_process.py +0 -0
  73. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/random/__init__.py +0 -0
  74. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/random/random_str.py +0 -0
  75. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/weixin/biz_data_crypt.py +0 -0
  76. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/weixin/error_code.py +0 -0
  77. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/weixin/format_response.py +0 -0
  78. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/weixin/wechat.py +0 -0
  79. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/weixin/wechat_crypt.py +0 -0
  80. {python_plugins-0.2.0 → python_plugins-0.2.2}/src/python_plugins/weixin/weixin_api.py +0 -0
  81. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/__init__.py +0 -0
  82. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/conftest.py +0 -0
  83. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_crypt_file.py +0 -0
  84. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_crypto.py +0 -0
  85. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_email.py +0 -0
  86. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_jwt.py +0 -0
  87. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_process.py +0 -0
  88. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_random.py +0 -0
  89. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_sqlalchemy.py +0 -0
  90. {python_plugins-0.2.0 → python_plugins-0.2.2}/tests/test_weixin.py +0 -0
@@ -1,9 +1,23 @@
1
+ v0.2.2
2
+ ------
3
+
4
+ Released 2024-12-27
5
+
6
+ - update-icons
7
+
8
+ v0.2.1
9
+ ------
10
+
11
+ Released 2024-11-23
12
+
13
+ - utils.walk_remove_dir
14
+
1
15
  v0.2.0
2
16
  ------
3
17
 
4
18
  Released 2024-11-20
5
19
 
6
- - add forms
20
+ - add random
7
21
 
8
22
 
9
23
  v0.1.9
@@ -11,7 +25,7 @@ v0.1.9
11
25
 
12
26
  Released 2024-11-19
13
27
 
14
- - add forms
28
+ - add convert
15
29
 
16
30
 
17
31
  v0.1.8
@@ -55,7 +69,7 @@ v0.1.3
55
69
 
56
70
  Released 2024-09-19
57
71
 
58
- - support random_str,jwt,hash_file,fernet
72
+ - support hash_file,fernet
59
73
 
60
74
  v0.1.2
61
75
  ------
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: python-plugins
3
- Version: 0.2.0
3
+ Version: 0.2.2
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
@@ -27,6 +27,7 @@ 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
30
31
  Keywords: plugin,utils
31
32
  Classifier: Development Status :: 3 - Alpha
32
33
  Classifier: Intended Audience :: Developers
@@ -49,8 +50,6 @@ Provides-Extra: requests
49
50
  Requires-Dist: requests; extra == 'requests'
50
51
  Provides-Extra: sqlalchemy
51
52
  Requires-Dist: sqlalchemy; extra == 'sqlalchemy'
52
- Provides-Extra: wtforms
53
- Requires-Dist: wtforms; extra == 'wtforms'
54
53
  Description-Content-Type: text/x-rst
55
54
 
56
55
  python-plugins
@@ -8,8 +8,6 @@ Welcome to python-plugins's documentation!
8
8
  :caption: Contents:
9
9
 
10
10
  usage
11
- api
12
- examples
13
11
  changes
14
12
 
15
13
  Indices and tables
@@ -54,19 +54,39 @@ mixins
54
54
 
55
55
  db = SQLAlchemy(model_class=Base)
56
56
 
57
- class User(db.models,PrimaryKeyMixin, DataMixin, TimestampMixin, UserMixin):
57
+ class User(db.Model,PrimaryKeyMixin, DataMixin, TimestampMixin, UserMixin):
58
58
  __tablename__ = "users"
59
59
 
60
- remove_pycache
60
+ walk_remove_dir
61
61
  =======================
62
62
 
63
63
  .. code-block:: python
64
64
 
65
- from python_plugins.utils import remove_pycache
65
+ from python_plugins.utils import remove,remove_pycache,remove_ipynb_checkpoints
66
66
 
67
67
  remove_pycache() # default is "."
68
68
  remove_pycache("./tests")
69
69
 
70
+ remove(dir,rm_dir_name)
71
+
72
+
73
+ encrypt,decrypt
74
+ ================
75
+
76
+ .. code-block:: python
77
+
78
+ from python_plugins.crypto import encrypt_txtfile,decrypt_txtfile
79
+
80
+ # encrypt
81
+ encrypt_txtfile(txtfile)
82
+ encrypt_txtfile(txtfile,".")
83
+ encrypt_txtfile(txtfile, newfile, password=password)
84
+
85
+ # decrypt
86
+ decrypt_txtfile(encryptedfile)
87
+ decrypt_txtfile(encryptedfile,".")
88
+ decrypt_txtfile(encryptedfile, srcfile, password=password)
89
+
70
90
 
71
91
  weixin.wechat
72
92
  ==================
@@ -83,4 +103,4 @@ weixin.wechat
83
103
  mywechat = MyWechat("name")
84
104
  mywechat.verify(query)
85
105
  mywechat.chat(query,content)
86
-
106
+
@@ -30,7 +30,6 @@ dependencies = [
30
30
  cryptography = ["cryptography"]
31
31
  requests = ["requests"]
32
32
  sqlalchemy = ["SQLAlchemy"]
33
- wtforms = ["WTForms"]
34
33
  pillow = ["pillow"]
35
34
  qrcode = ["qrcode"]
36
35
  jwt = ["PyJWT"]
@@ -0,0 +1 @@
1
+ lxml
@@ -4,4 +4,3 @@ cryptography
4
4
  SQLAlchemy
5
5
  PyJWT
6
6
  requests
7
- WTForms
@@ -0,0 +1 @@
1
+ __version__ = "0.2.2"
@@ -0,0 +1,4 @@
1
+ from .walk_remove_dir import remove
2
+ from .walk_remove_dir import remove_pycache
3
+ from .walk_remove_dir import remove_ipynb_checkpoints
4
+
@@ -0,0 +1,49 @@
1
+ """Generate example page with overview of all icons."""
2
+
3
+ from lxml import etree
4
+
5
+
6
+ def parse(filename):
7
+ """Parse SVG file containing icons."""
8
+ symbols = set()
9
+ data = etree.parse(filename)
10
+ svg = data.getroot()
11
+ for symbol in svg:
12
+ symbols.add(symbol.attrib["id"])
13
+ return sorted(symbols)
14
+
15
+
16
+ def generate(version):
17
+ """Write the HTML template file."""
18
+ head = f"""{{% extends "base.html" %}}
19
+ {{% from 'macro/icon.html' import render_icon %}}
20
+ <!-- DO NOT EDIT! Use update-icons.py for updating this file. -->
21
+ {{% block content %}}
22
+ <h2>Icons</h2>
23
+ <p>These are all the icons which are currently supported by Bootstrap-Flask.</p>
24
+ <ul class="row row-cols-3 row-cols-sm-4 row-cols-lg-6 row-cols-xl-8 list-unstyled list">
25
+ """
26
+ names = parse(f"icons/bootstrap-icons.svg")
27
+ with open(f"bootstrap{version}/templates/icons.html", "w") as file:
28
+ file.write(head)
29
+ number = 0
30
+ for name in sorted(names):
31
+ item = f"""<li class="col mb-4">
32
+ <a class="d-block text-dark text-body-emphasis text-decoration-none" href="https://icons.getbootstrap.com/icons/{name}/">
33
+ <div class="px-3 py-4 mb-2 bg-light text-center rounded">
34
+ {{{{ render_icon('{name}', 32) }}}}
35
+ </div>
36
+ </a>
37
+ <div class="name text-body-secondary text-decoration-none text-center pt-1">{name}</div>
38
+ </li>
39
+ """
40
+ file.write(item)
41
+ number += 1
42
+ file.write("</ul>\n")
43
+ file.write(f"<p>This is a total of {number} icons.</p>\n")
44
+ file.write("{% endblock %}\n")
45
+ print(f"For Bootstrap{version}, a total of {number} icons are supported.")
46
+
47
+
48
+ for value in (4, 5):
49
+ generate(value)
@@ -0,0 +1,19 @@
1
+ import os
2
+ import shutil
3
+
4
+ def remove(dir_path,rm_dir_name):
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 == rm_dir_name:
10
+ rm_path = os.path.join(root, dir)
11
+ print(f"Removing {rm_path}")
12
+ shutil.rmtree(rm_path)
13
+
14
+ def remove_pycache(dir_path="."):
15
+ remove(dir_path,"__pycache__")
16
+
17
+ def remove_ipynb_checkpoints(dir_path="."):
18
+ remove(dir_path,".ipynb_checkpoints")
19
+
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
 
3
3
  from python_plugins.utils import remove_pycache
4
+ from python_plugins.utils import remove_ipynb_checkpoints
4
5
 
5
6
  @pytest.mark.skip
6
7
  def test_remove_pycache():
@@ -1,4 +0,0 @@
1
- API
2
- ===
3
-
4
-
@@ -1 +0,0 @@
1
- .. include:: ../examples/README.rst
@@ -1,17 +0,0 @@
1
- =============
2
- Examples
3
- =============
4
-
5
- Install
6
- =========
7
-
8
- Type these commands in the terminal:
9
-
10
- .. code-block:: bash
11
-
12
- $ git clone https://github.com/ojso/python-plugins.git
13
- $ cd python-plugins/examples
14
- $ python3 -m venv venv
15
- $ source venv/bin/activate
16
- $ pip install python-plugins
17
-
@@ -1 +0,0 @@
1
- __version__ = "0.2.0"
@@ -1,2 +0,0 @@
1
- from .json import JSONField
2
- from .datetime import DateTimeField
@@ -1,100 +0,0 @@
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
@@ -1,19 +0,0 @@
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 ""
@@ -1,123 +0,0 @@
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 ""
@@ -1,10 +0,0 @@
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)
@@ -1,9 +0,0 @@
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 ""
@@ -1,29 +0,0 @@
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")
@@ -1,30 +0,0 @@
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)
@@ -1,4 +0,0 @@
1
- from wtforms.widgets import FileInput
2
-
3
- class ImageInput(FileInput):
4
- field_flags = {"accept": "image/*"}
@@ -1,26 +0,0 @@
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)
@@ -1 +0,0 @@
1
- from .remove_pycache import remove_pycache
@@ -1,13 +0,0 @@
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,65 +0,0 @@
1
- from wtforms.form import Form
2
- from python_plugins.forms.fields import JSONField
3
- from python_plugins.forms.fields import DateTimeField
4
- from python_plugins.forms.mixins.user import LoginForm
5
- from python_plugins.forms.mixins.user import RegisterForm
6
-
7
-
8
- class DummyPostData(dict):
9
- def getlist(self, key):
10
- v = self[key]
11
- if not isinstance(v, (list, tuple)):
12
- v = [v]
13
- return v
14
-
15
-
16
- class UserLoginForm(Form, LoginForm):
17
- pass
18
-
19
-
20
- class UserRegisterForm(Form, RegisterForm):
21
- pass
22
-
23
-
24
- def test_fields():
25
- class F(Form):
26
- json_field = JSONField()
27
- datetime_field = DateTimeField()
28
-
29
- formdata = DummyPostData(
30
- json_field="[1,2,3]",
31
- datetime_field="2000-01-01 12:12:12",
32
- )
33
-
34
- f = F(formdata)
35
- assert f.validate()
36
-
37
- json_field_text = f.json_field()
38
- assert '<textarea id="json_field" name="json_field">' in json_field_text
39
- assert "[1, 2, 3]</textarea>" in json_field_text
40
-
41
- datetime_field_text = f.datetime_field()
42
- assert "<input" in datetime_field_text
43
- assert (
44
- 'data-date-format="YYYY-MM-DD HH:mm:ss" data-role="datetimepicker"'
45
- in datetime_field_text
46
- )
47
- assert 'value="2000-01-01 12:12:12"' in datetime_field_text
48
-
49
-
50
- def test_user_form():
51
- login_form = UserLoginForm()
52
-
53
- for k in login_form:
54
- # print(k.label())
55
- # print(k())
56
- assert k() is not None
57
-
58
- assert "username" in login_form.username()
59
-
60
- register_form = UserRegisterForm()
61
-
62
- for k in register_form:
63
- # print(k.label())
64
- # print(k())
65
- assert k() is not None