invesytoolbox 0.0.21__tar.gz → 0.0.23__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 (30) hide show
  1. invesytoolbox-0.0.23/HISTORY.md +100 -0
  2. {invesytoolbox-0.0.21/src/invesytoolbox.egg-info → invesytoolbox-0.0.23}/PKG-INFO +31 -3
  3. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/setup.cfg +4 -1
  4. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_data.py +106 -34
  5. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_date_time.py +154 -21
  6. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_email_phone.py +20 -10
  7. invesytoolbox-0.0.23/src/invesytoolbox/itb_html.py +63 -0
  8. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_locales.py +52 -21
  9. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_restricted_python.py +1 -2
  10. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_security.py +0 -1
  11. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_text_name.py +76 -13
  12. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/itb_www.py +4 -4
  13. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23/src/invesytoolbox.egg-info}/PKG-INFO +31 -3
  14. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox.egg-info/SOURCES.txt +1 -0
  15. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_data.py +50 -9
  16. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_date_time.py +4 -0
  17. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_html.py +7 -0
  18. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_locales.py +79 -22
  19. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_text_name.py +81 -1
  20. invesytoolbox-0.0.21/src/invesytoolbox/itb_html.py +0 -63
  21. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/LICENSE.txt +0 -0
  22. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/README.md +0 -0
  23. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/setup.py +0 -0
  24. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox/__init__.py +0 -0
  25. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox.egg-info/dependency_links.txt +0 -0
  26. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox.egg-info/requires.txt +0 -0
  27. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/invesytoolbox.egg-info/top_level.txt +0 -0
  28. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/__init__.py +0 -0
  29. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_email_phone.py +0 -0
  30. {invesytoolbox-0.0.21 → invesytoolbox-0.0.23}/src/tests/test_www.py +0 -0
@@ -0,0 +1,100 @@
1
+ # History
2
+ ## 0.0.23 (2024-07-22)
3
+ * **adjust_spaces_on_punctuation**: inserts narrow (or normal spaces) for certain languages
4
+ * **value_2datatype**:
5
+ - default fmt changed to None (hopefully it doesn't break somewhere, but this is necessary)
6
+ - 'pendulum' is now an option for the parameter
7
+ - default for parameter **fmt** changed to None (this is necessary for the new pendulum conversion in **value_2datatype** to work) for
8
+ - **dict_2datatypes**
9
+ - **dictlist_2datatypes**
10
+
11
+ ## 0.0.22 (2023-10-14)
12
+ * **normalize_name** and **could_be_a_name** now have the boolean parameter *lastname* that indicates that a single-word name is to be treated as a last name, not a first name.
13
+ * **get_locale**: locale can be only the language, without the country.
14
+ * if get_locale fails to get the locale from the system (because invesytoolbox may be imported from a program called from an applicatio rather than the termial), it defaults to `language: 'de'` and `country: 'AT'`.
15
+ * added support for pendulum DateTime
16
+ * **create_email_message**: fixed MIMEMultipart settings
17
+
18
+ ## 0.0.21 (2023-05-21)
19
+ * New function **unravel_duration**: turns a duration string (for ex. '5T23:05:20') into a list or dictionary.
20
+
21
+ ## 0.0.20 (2023-05-06)
22
+ * New function **add_time**: adds (or subtracts) time to (or from) datetime and DateTime
23
+
24
+ ## 0.0.19 (2023-04-07)
25
+ * Corrected bug in **fetch_holidays** (argument *length* resulted in an error)
26
+
27
+ ## 0.0.18 (2023-04-07)
28
+ * new function **change_h_tags** (in new module **itb_html**)
29
+
30
+ ## 0.0.17 (2023-03-01)
31
+ * new function *compare_phonenumbers*: compares two phone numbers after normalizing them (*process_phonenumber*).
32
+
33
+ ## 0.0.16
34
+ * *map_special_chars*: works now.
35
+
36
+ ## 0.0.15
37
+ * *could_be_a_name*: can now handle names with multiple parts like "Robert De La Mancha". Per word, 2 capitals are allowed (i.e. "MacArthur" or "DeLa Cruz)
38
+
39
+ ## 0.0.14
40
+ * *could_be_a_name* and *sort_names*: now working also with prename-only and prenames including a hyphen.
41
+
42
+ ## 0.0.13
43
+ * *get_dateformat* now also processes time
44
+ * *str_to_dt* now checks for valid string
45
+ * *is_valid_datetime_string*: wrapper for checking with *str_to_dt*
46
+ * *remove_time* from datetime or DateTime
47
+
48
+ ## 0.0.12
49
+ * removed documentation from the README file, instead a link to the gitlab pages
50
+ * *map_specialChars* now recognizes Unicode character U+0308 (UTF-8 cc 88 = "COMBINING DIAERESIS").
51
+ * *any_2boolean*
52
+ * *get_dateformat*: argument *checkonly*
53
+ * data functions: argument *json_data* changed to *metadata* (it's a dictionary)
54
+
55
+ ## 0.0.11
56
+ * BeautifulSoup and nameparser added to requirements.txt
57
+ * Removed "Date" conversions (modified DateTime) because it's a bad idea
58
+ * *normalize_name* (using nameparser) added to *itb_text_name*
59
+ * *capitalize_name* rewritten (now quasi a wrapper for normalize_name)
60
+ * *could_be_a_name* rewritten using *normalize_name* (nameparser)
61
+
62
+ ## 0.0.10
63
+ * *check_spam* for web forms
64
+ * *dictlist_2datatypes*: iterates through a list of dictionaries and applies *dict_2datatypes*
65
+ * *prettify_html*: provides *prettify* from BeautifulSoup, because it can't be used directly from restricted Python.
66
+ * *could_be_a_name*: checks if a string could be a name
67
+
68
+ ## 0.0.9
69
+ * *change\_query\_string* respects Zope parameter converters (like `paramname:int`)
70
+
71
+ ## 0.0.8
72
+ * New submodule www
73
+ * *change\_query\_string*
74
+
75
+ ## 0.0.7
76
+ * shorter submodule names (no _tools suffix)
77
+ * *is_holiday* works without argument
78
+ * *create\_email\_message*: new argument **encoding**
79
+ * *process_phonenumbers*: cleaned up arguments
80
+ * *DT_date*: strip a DateTime of its time (get a "naked" date)
81
+ * *could\_be\_a\_name*: check if a string could possibly be a name
82
+
83
+ ## 0.0.6
84
+ * renamed *capitalize\_text* to *capitalize_name* and removed name argument
85
+ * added Sphinx documentation
86
+
87
+ ## 0.0.5 (2022-06-11)
88
+ * removed **terminal_tools** (will be included in a separate package)
89
+
90
+ ## 0.0.4 (2022-06-09)
91
+ * better formatted README
92
+
93
+ ## 0.0.3 (2022-06-09)
94
+ * updated README (list of functions and a short description)
95
+
96
+ ## 0.0.2 (2022-06-09)
97
+ * removed VERSION file
98
+
99
+ ## 0.0.1 (2022-06-09)
100
+ * first version
@@ -1,22 +1,35 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: invesytoolbox
3
- Version: 0.0.21
3
+ Version: 0.0.23
4
4
  Summary: Tools for Python scripts or terminal
5
5
  Home-page: https://gitlab.com/Rastaf/invesytoolbox
6
6
  Author: Georg Pfolz
7
7
  Author-email: georg.pfolz@invesy.at
8
8
  License: MIT License
9
9
  Project-URL: Bug Tracker, https://gitlab.com/Rastaf/invesytoolbox/-/issues
10
- Platform: UNKNOWN
10
+ Project-URL: Documentation, https://rastaf.gitlab.io/invesytoolbox/
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Programming Language :: Python :: 3.7
13
13
  Classifier: Programming Language :: Python :: 3.8
14
14
  Classifier: Programming Language :: Python :: 3.9
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
15
17
  Classifier: License :: OSI Approved :: MIT License
16
18
  Classifier: Operating System :: OS Independent
17
19
  Requires-Python: >=3.7
18
20
  Description-Content-Type: text/markdown
19
21
  License-File: LICENSE.txt
22
+ Requires-Dist: bs4
23
+ Requires-Dist: babel
24
+ Requires-Dist: colorama
25
+ Requires-Dist: DateTime
26
+ Requires-Dist: gender_guesser
27
+ Requires-Dist: holidays>0.13
28
+ Requires-Dist: nameparser
29
+ Requires-Dist: phonenumbers
30
+ Requires-Dist: pycountry
31
+ Requires-Dist: unidecode
32
+ Requires-Dist: vobject
20
33
 
21
34
  # invesytoolbox
22
35
 
@@ -31,6 +44,22 @@ That's also why all date and time functions also take into account the old DateT
31
44
  The documentation can be found [here](https://rastaf.gitlab.io/invesytoolbox/).
32
45
 
33
46
  # History
47
+ ## 0.0.23 (2024-07-22)
48
+ * **adjust_spaces_on_punctuation**: inserts narrow (or normal spaces) for certain languages
49
+ * **value_2datatype**:
50
+ - default fmt changed to None (hopefully it doesn't break somewhere, but this is necessary)
51
+ - 'pendulum' is now an option for the parameter
52
+ - default for parameter **fmt** changed to None (this is necessary for the new pendulum conversion in **value_2datatype** to work) for
53
+ - **dict_2datatypes**
54
+ - **dictlist_2datatypes**
55
+
56
+ ## 0.0.22 (2023-10-14)
57
+ * **normalize_name** and **could_be_a_name** now have the boolean parameter *lastname* that indicates that a single-word name is to be treated as a last name, not a first name.
58
+ * **get_locale**: locale can be only the language, without the country.
59
+ * if get_locale fails to get the locale from the system (because invesytoolbox may be imported from a program called from an applicatio rather than the termial), it defaults to `language: 'de'` and `country: 'AT'`.
60
+ * added support for pendulum DateTime
61
+ * **create_email_message**: fixed MIMEMultipart settings
62
+
34
63
  ## 0.0.21 (2023-05-21)
35
64
  * New function **unravel_duration**: turns a duration string (for ex. '5T23:05:20') into a list or dictionary.
36
65
 
@@ -114,4 +143,3 @@ The documentation can be found [here](https://rastaf.gitlab.io/invesytoolbox/).
114
143
 
115
144
  ## 0.0.1 (2022-06-09)
116
145
  * first version
117
-
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = invesytoolbox
3
- version = 0.0.21
3
+ version = 0.0.23
4
4
  author = Georg Pfolz
5
5
  author_email = georg.pfolz@invesy.at
6
6
  description = Tools for Python scripts or terminal
@@ -11,11 +11,14 @@ license_files = LICENSE.txt
11
11
  url = https://gitlab.com/Rastaf/invesytoolbox
12
12
  project_urls =
13
13
  Bug Tracker = https://gitlab.com/Rastaf/invesytoolbox/-/issues
14
+ Documentation = https://rastaf.gitlab.io/invesytoolbox/
14
15
  classifiers =
15
16
  Programming Language :: Python :: 3
16
17
  Programming Language :: Python :: 3.7
17
18
  Programming Language :: Python :: 3.8
18
19
  Programming Language :: Python :: 3.9
20
+ Programming Language :: Python :: 3.10
21
+ Programming Language :: Python :: 3.11
19
22
  License :: OSI Approved :: MIT License
20
23
  Operating System :: OS Independent
21
24
 
@@ -1,14 +1,14 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- ==========
4
3
  data_tools
5
4
  ==========
6
5
  """
7
6
 
8
- from typing import Union
7
+ from typing import Union, List, Dict, Any, Optional
9
8
  import DateTime
10
9
  import datetime
11
10
  import vobject
11
+ import pendulum
12
12
  from dateutil.parser import parse
13
13
  from itb_date_time import convert_datetime, str_to_date, str_to_DT, get_dateformat
14
14
  from itb_email_phone import process_phonenumber
@@ -19,7 +19,7 @@ time_chars = set('1234567890:')
19
19
 
20
20
 
21
21
  def any_2boolean(
22
- value
22
+ value: Any
23
23
  ) -> bool:
24
24
  """ return a boolean for any value
25
25
 
@@ -34,14 +34,12 @@ def any_2boolean(
34
34
 
35
35
 
36
36
  def dict_from_dict_list(
37
- dict_list: list,
38
- key,
39
- single_value: bool = None,
40
- include_key: str = False
37
+ dict_list: List[dict],
38
+ key: str,
39
+ single_value: Optional[bool] = None,
40
+ include_key: Optional[bool] = False
41
41
  ) -> dict:
42
- """Create a dictionary from a list of dictionaries
43
-
44
- .. note:: The annotated return type is not true if a single_value argument is given.
42
+ """ Create a dictionary from a list of dictionaries
45
43
 
46
44
  :param dictList: the list of dictionaries to be converted
47
45
  :param key: the key of the dictionaries to use as key for the new dictionary.
@@ -68,10 +66,10 @@ def dict_from_dict_list(
68
66
 
69
67
 
70
68
  def create_vcard(
71
- data: dict,
69
+ data: Dict[str, str],
72
70
  returning: str = 'vcard'
73
71
  ) -> str:
74
- """create a vCard from a dictionary
72
+ """ create a vCard from a dictionary
75
73
 
76
74
  .. note:: The serialized vcard has Windows line-breaks, which is fine, I guess
77
75
  .. note:: colons in notes are escaped in vobject
@@ -132,10 +130,10 @@ def create_vcard(
132
130
 
133
131
 
134
132
  def dict_2unicode(
135
- d: dict,
133
+ d: Dict[Union[str, bytes], Any],
136
134
  encoding: str = 'utf-8'
137
135
  ) -> dict:
138
- """ Converts all keys and values in a dictionary from bytes to unicode
136
+ """ Convert all keys and values in a dictionary from bytes to unicode
139
137
 
140
138
  All keys and values are changed from bytes to unicode, if applicable.
141
139
  Other data types are left unchaged, including other compound data types.
@@ -153,13 +151,31 @@ def dict_2unicode(
153
151
 
154
152
  def dict_2datatypes(
155
153
  d: dict,
156
- metadata: dict = {},
154
+ metadata: Dict[str, str] = {},
157
155
  convert_keys: bool = False,
158
156
  convert_to_unicode: bool = False,
159
157
  dt: str = 'datetime',
160
- fmt: str = '%d.%m.%Y'
161
- ) -> dict:
162
- """ convert all data of a dictionary to specific (json metadata) or guessed types """
158
+ fmt: str = None
159
+ ) -> Dict[Any, Any]:
160
+ """ Convert all data of a dictionary to specific (json metadata) or guessed types
161
+
162
+ :param d: dictionary
163
+ :param metadata: dictionary containing types for the keys:
164
+ - boolean
165
+ - int
166
+ - float
167
+ - date
168
+ - datetime: date and time
169
+ - time: conversion or not based on dt
170
+ :param convert_keys: convert keys to unicode
171
+ :param convert_to_unicode: convert all bytes to unicode in the process
172
+ :param dt: - datetime or dt
173
+ - DateTime or DT
174
+ - ignore or string
175
+ - pendulum
176
+ - default: datetime, because it's Python's default
177
+ :param fmt: format for datetime parsing
178
+ """
163
179
 
164
180
  if convert_keys:
165
181
  return {
@@ -193,20 +209,40 @@ def dict_2datatypes(
193
209
 
194
210
 
195
211
  def dictlist_2datatypes(
196
- dictlist: str,
197
- metadata: dict = {},
212
+ dictlist: List[Dict[Any, Any]],
213
+ metadata: Dict[Any, Any] = {},
198
214
  convert_keys: bool = False,
199
215
  convert_to_unicode: bool = False,
200
216
  dt: str = 'datetime',
201
- fmt: str = '%d.%m.%Y'
217
+ fmt: str = None
202
218
  ) -> list:
219
+ """ Convert all data of a list of dictionaries to specific (json metadata) or guessed types
220
+
221
+ :param dictList: list of dictionaries
222
+ :param metadata: dictionary containing types for the keys:
223
+ - boolean
224
+ - int
225
+ - float
226
+ - date
227
+ - datetime: date and time
228
+ - time: conversion or not based on dt
229
+ :param convert_keys: convert keys to unicode
230
+ :param convert_to_unicode: convert all bytes to unicode in the process
231
+ :param dt: - datetime or dt
232
+ - DateTime or DT
233
+ - ignore or string
234
+ - pendulum
235
+ - default: datetime, because it's Python's default
236
+ :param fmt: format for datetime parsing
237
+ """
203
238
  return [
204
239
  dict_2datatypes(
205
240
  d=dic,
206
241
  metadata=metadata,
207
242
  convert_keys=convert_keys,
208
243
  convert_to_unicode=convert_to_unicode,
209
- dt=dt
244
+ dt=dt,
245
+ fmt=fmt
210
246
  )
211
247
  for dic
212
248
  in dictlist
@@ -214,8 +250,8 @@ def dictlist_2datatypes(
214
250
 
215
251
 
216
252
  def sort_dictlist(
217
- dictlist: list,
218
- keys: (str, list),
253
+ dictlist: List[dict],
254
+ keys: Union[str, List[str]],
219
255
  reverse: bool = False
220
256
  ) -> list:
221
257
  """ Sorts a list of dictionaries
@@ -259,17 +295,18 @@ def value_2datatype(
259
295
  convert_to_unicode: bool = False,
260
296
  encoding: str = 'utf-8',
261
297
  dt: str = 'datetime',
262
- fmt: str = '%d.%m.%Y', # only for datetime
263
- UTC: bool = False
298
+ fmt: str = None,
299
+ timezone: str = 'local'
264
300
  ) -> Union[str, int, float]:
265
301
  """ Convert a value to a datatype
266
302
 
267
303
  this function has two modes:
268
304
 
269
- 1. it is provided a type for the conversion
305
+ 1. a type is provided for the conversion
270
306
  2. it makes educated guesses in converting a string
271
307
 
272
308
  :param value:
309
+ :param typ: type for the conversion
273
310
  :param metadata: dictionary containing types for the keys:
274
311
  - boolean
275
312
  - int
@@ -282,7 +319,10 @@ def value_2datatype(
282
319
  :param encoding: if bytes are present, use this encoding to convert them to unicode
283
320
  :param dt: - datetime or dt
284
321
  - DateTime or DT
322
+ - ignore or string
323
+ - pendulum
285
324
  - default: datetime, because it's Python's default
325
+ :param timezone: default is 'local', other options are 'UTC' or 'Europe/Vienna'
286
326
  """
287
327
  if typ:
288
328
  if typ == 'boolean':
@@ -312,6 +352,17 @@ def value_2datatype(
312
352
  value,
313
353
  datefmt='international'
314
354
  ) + 0.5 # to avoid day-shifting due to timezones, use 12am
355
+ elif dt == 'pendulum':
356
+ if fmt:
357
+ p_dt = pendulum.from_format(value, fmt)
358
+ else:
359
+ p_dt = pendulum.parse(value)
360
+
361
+ if p_dt.tzinfo == 'UTC' and timezone == 'local':
362
+ return p_dt.in_tz(pendulum.local_timezone())
363
+ elif timezone:
364
+ return p_dt.in_tz(timezone)
365
+ return p_dt.date()
315
366
  elif dt in ('ignore', 'string'):
316
367
  return value
317
368
  else:
@@ -328,6 +379,17 @@ def value_2datatype(
328
379
  )
329
380
  except DateTime.interfaces.SyntaxError:
330
381
  return value
382
+ elif dt == 'pendulum':
383
+ if fmt:
384
+ p_dt = pendulum.from_format(value, fmt)
385
+ else:
386
+ p_dt = pendulum.parse(value)
387
+
388
+ if p_dt.tzinfo == 'UTC' and timezone == 'local':
389
+ return p_dt.in_tz(pendulum.local_timezone())
390
+ elif timezone:
391
+ return p_dt.in_tz(timezone)
392
+ return p_dt
331
393
  elif dt in ('ignore', 'string'):
332
394
  return value
333
395
  else:
@@ -340,7 +402,6 @@ def value_2datatype(
340
402
  return value # DT: return the string
341
403
 
342
404
  else:
343
-
344
405
  if isinstance(value, (bool, int, float)):
345
406
  return value
346
407
 
@@ -374,12 +435,7 @@ def value_2datatype(
374
435
  datestring=value,
375
436
  checkonly=True
376
437
  ):
377
- if ':' in value:
378
- return convert_datetime(
379
- date=value,
380
- convert_to=dt
381
- )
382
- elif dt in ('datetime', 'dt'):
438
+ if dt in ('datetime', 'dt'):
383
439
  return str_to_date(
384
440
  datestring=value
385
441
  )
@@ -387,6 +443,22 @@ def value_2datatype(
387
443
  return str_to_DT(
388
444
  datestring=value
389
445
  )
446
+ elif dt == 'pendulum':
447
+ if fmt:
448
+ p_dt = pendulum.from_format(value, fmt)
449
+ else:
450
+ p_dt = pendulum.parse(value)
451
+
452
+ if p_dt.tzinfo == 'UTC' and timezone == 'local':
453
+ return p_dt.in_tz(pendulum.local_timezone())
454
+ elif timezone:
455
+ return p_dt.in_tz(timezone)
456
+ return p_dt
457
+ else:
458
+ return convert_datetime(
459
+ date=value,
460
+ convert_to=dt
461
+ )
390
462
 
391
463
  except Exception:
392
464
  # in case it's a subset of datetime_chars but not a date or datetime or time