sysnet-pyutils 1.0.7__py3-none-any.whl → 1.1.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.
@@ -0,0 +1,323 @@
1
+ from datetime import date, datetime
2
+ from typing import Union, List, Any
3
+
4
+ import pytz
5
+
6
+ from utils import is_valid_email, TZ
7
+
8
+
9
+ def get_dict_value(data: dict, item_name: str) -> Union[Any, None]:
10
+ """
11
+ Extrahuje hodnotu ze slovníku. Používá se pro load dat JSON do objektů
12
+
13
+ :param data: Slovník s daty JSON
14
+ :param item_name: Název položky
15
+ :return: Hodnota
16
+ """
17
+ if data is None or item_name in [None, '']:
18
+ return None
19
+ if item_name in data:
20
+ return data[item_name]
21
+ return None
22
+
23
+
24
+ def get_dict_value_string(data: dict, item_name: str) -> str:
25
+ """
26
+ Extrahuje textovou hodnotu ze slovníku. Pokud je vstupní hodnota None, vrací prázdný string.
27
+
28
+ :param data: Slovník s daty JSON
29
+ :param item_name: Název položky
30
+ :return: Hodnota
31
+ """
32
+ out = ''
33
+ if data is None or item_name in [None, '']:
34
+ return out
35
+ v = get_dict_value(data, item_name)
36
+ if v not in [None, '']:
37
+ out = str(v)
38
+ return out
39
+
40
+
41
+ def get_dict_value_email(data: dict, item_name: str) -> Union[Any, None]:
42
+ """
43
+ Extrahuje emailovou adresu ze slovníku.
44
+
45
+ :param data: Slovník s daty JSON
46
+ :param item_name: Název položky
47
+ :return: Hodnota
48
+ """
49
+ if data is None or item_name in [None, '']:
50
+ return None
51
+ out = get_dict_value(data, item_name)
52
+ if not is_valid_email(out):
53
+ return None
54
+ return out
55
+
56
+
57
+ def get_dict_value_bool(data: dict, item_name: str) -> bool:
58
+ """
59
+ Extrahuje logickou hodnotu ze slovníku
60
+
61
+ :param data: Slovník s daty JSON
62
+ :param item_name: Název položky
63
+ :return: Hodnota
64
+ """
65
+ if data is None or item_name in [None, '']:
66
+ return False
67
+ v = get_dict_value(data, item_name)
68
+ if v in [None, '']:
69
+ return False
70
+ if v.lower() in ('true', '1', 't'):
71
+ return True
72
+ return False
73
+
74
+
75
+ def get_dict_value_int(data: dict, item_name: str, spare_item_name: Union[str, None] = None) -> int:
76
+ """
77
+ Extrahuje celočíselnou hodnotu ze slovníku. Pokud nenajde hlavní položku, hledá záložní.
78
+
79
+ :param data: Slovník s daty JSON
80
+ :param item_name: Název položky
81
+ :param spare_item_name: Název záložní položky
82
+ :return: Hodnota
83
+ """
84
+ if data is None or item_name in [None, '']:
85
+ return 0
86
+ v = get_dict_value(data, item_name)
87
+ out = 0
88
+ if v is not None:
89
+ try:
90
+ out = int(v)
91
+ except (ValueError, TypeError):
92
+ out = 0
93
+ if (out == 0) and (spare_item_name is not None):
94
+ v1 = get_dict_value(data, spare_item_name)
95
+ if v1 is not None:
96
+ try:
97
+ out = int(v1)
98
+ except (ValueError, TypeError):
99
+ out = 0
100
+ return out
101
+
102
+
103
+ def get_dict_value_list(data: dict, item_name: str, spare_item_name: str = None) -> Union[List[str], None]:
104
+ v = get_dict_value(data, item_name)
105
+ if v in [None, '']:
106
+ v = get_dict_value(data, spare_item_name)
107
+ if v in [None, '']:
108
+ return None
109
+ out = [i.strip() for i in v[1:-1].replace('"',"").split(';')]
110
+ if len(out) == 1 and out[0] == '':
111
+ out = []
112
+ return out
113
+
114
+
115
+ def get_dict_value_float(data: dict, item_name: str, spare_item_name: str = None) -> Union[float, None]:
116
+ v = get_dict_value(data, item_name)
117
+ out: float = float(0)
118
+ if v is not None:
119
+ try:
120
+ if isinstance(v, str):
121
+ v = v.replace(',', '.')
122
+ out = float(v)
123
+ except (ValueError, TypeError):
124
+ out = float(0)
125
+ if (out == float(0)) and (spare_item_name is not None):
126
+ v1 = get_dict_value(data, spare_item_name)
127
+ if v1 is not None:
128
+ try:
129
+ out = float(v1)
130
+ except (ValueError, TypeError):
131
+ out = float(0)
132
+ return out
133
+
134
+
135
+ def get_dict_value_date(data: dict, item_name: str) -> Union[date, None]:
136
+ """
137
+ Konvertuje ISO nebo český formát do data
138
+
139
+ :param data:
140
+ :param item_name:
141
+ :return:
142
+ """
143
+ v = get_dict_value(data, item_name)
144
+ if v is None:
145
+ return None
146
+ out = convert_iso_to_date(v)
147
+ if out is None:
148
+ out = convert_cz_to_date(v)
149
+ return out
150
+
151
+
152
+ def convert_iso_to_date(text: str) -> Union[date, None]:
153
+ try:
154
+ out = date.fromisoformat(text)
155
+ return out
156
+ except (ValueError, TypeError):
157
+ return None
158
+
159
+
160
+ def convert_iso_to_datetime(text: str) -> Union[datetime, None]:
161
+ try:
162
+ out = datetime.fromisoformat(text)
163
+ local_tz = pytz.timezone(TZ)
164
+ out = out.astimezone(local_tz)
165
+ return out
166
+ except (ValueError, TypeError):
167
+ return None
168
+
169
+
170
+ def convert_cz_to_date(text: str) -> Union[date, None]:
171
+ try:
172
+ out = datetime.strptime(text, '%d.%m.%Y').date()
173
+ return out
174
+ except (ValueError, TypeError):
175
+ return None
176
+
177
+
178
+ def convert_cz_to_datetime(text: str) -> Union[datetime, None]:
179
+ try:
180
+ out = datetime.strptime(text, '%d.%m.%Y %H:%M:%S')
181
+ local_tz = pytz.timezone(TZ)
182
+ out = out.astimezone(local_tz)
183
+ return out
184
+ except (ValueError, TypeError):
185
+ return None
186
+
187
+
188
+ def get_dict_value_datetime(data: dict, item_name: str) -> Union[datetime, None]:
189
+ """
190
+ Konvertuje ISO nebo český formát do datatime
191
+
192
+ :param data:
193
+ :param item_name:
194
+ :return:
195
+ """
196
+ v = get_dict_value(data, item_name)
197
+ out = None
198
+ if v is None:
199
+ return None
200
+ try:
201
+ if isinstance(v, datetime):
202
+ return v
203
+ elif isinstance(v, date):
204
+ gmt_tz = pytz.timezone('GMT')
205
+ return datetime(year=v.year, month=v.month, day=v.day, tzinfo=gmt_tz)
206
+ elif isinstance(v, str):
207
+ out = convert_iso_to_datetime(v)
208
+ if out is None:
209
+ out = convert_cz_to_datetime(v)
210
+ return out
211
+ except (ValueError, TypeError):
212
+ return None
213
+
214
+
215
+ def get_object_attr(obj: Any, attr: str) -> Union[Any, None]:
216
+ """
217
+ Získa hodnotu atributu z datového objektu
218
+
219
+ :param obj:
220
+ :param attr:
221
+ :return:
222
+ """
223
+ if obj is None:
224
+ return None
225
+ if hasattr(obj, attr):
226
+ return getattr(obj, attr)
227
+ return None
228
+
229
+
230
+ def get_dict_item_value_list(data: dict, item_name: str, alt_item_names: List[str] = None) -> Union[list, None]:
231
+ out = []
232
+ v = get_dict_item_value(data=data, item_name=item_name, alt_item_names=alt_item_names, blank=False)
233
+ if v is None:
234
+ return out
235
+ if isinstance(v, list):
236
+ out = v
237
+ else:
238
+ out.append(v)
239
+ return out
240
+
241
+
242
+ def get_dict_item_value(data: dict, item_name: str, alt_item_names: List[str] = None, blank=True) -> Union[Any, None]:
243
+ out = None
244
+ if blank:
245
+ out = ''
246
+ if (data is None) or (item_name is None):
247
+ return out
248
+ if item_name in data:
249
+ out = data[item_name]
250
+ elif alt_item_names is not None:
251
+ if alt_item_names:
252
+ for name in alt_item_names:
253
+ if name in data:
254
+ out = data[name]
255
+ break
256
+ return out
257
+
258
+
259
+ def get_dict_code_value_list(data: dict, item_name_code: str, item_name_value: str) -> Union[list[tuple[Any, Any]], None]:
260
+ """
261
+ Vrátí z dvojice položek slovníku tuple code/value
262
+
263
+ :param data:
264
+ :param item_name_code:
265
+ :param item_name_value:
266
+ :return:
267
+ """
268
+ codes = get_dict_value_list(data, item_name_code)
269
+ values = get_dict_value_list(data, item_name_value)
270
+ if not codes or not values:
271
+ return None
272
+ if len(codes) != len(values):
273
+ return None
274
+ out = []
275
+ i = 0
276
+ for c in codes:
277
+ v = values[i]
278
+ i += 1
279
+ out.append((c,v))
280
+ return out
281
+
282
+ def adjust_datetime_to_utc(date_value: Union[date, datetime], for_store: bool = False) -> Union[datetime, date]:
283
+ """
284
+ Nastavení času pro uložení. Použije se časová zóna UTF
285
+
286
+ :param date_value: Datová hodnota
287
+ :param for_store: Pro uložení (převede se vždy na datetime)
288
+ :return: nastavená hodnota
289
+ """
290
+ if date_value in [None, '']:
291
+ return date_value
292
+ if for_store:
293
+ if isinstance(date_value, date):
294
+ return datetime(year=date_value.year, month=date_value.month, day=date_value.day, tzinfo=pytz.UTC)
295
+ if isinstance(date_value, datetime):
296
+ if date_value.tzinfo is None:
297
+ date_value.replace(tzinfo=pytz.UTC)
298
+ return date(year=date_value.year, month=date_value.month, day=date_value.day)
299
+ return date_value
300
+
301
+
302
+ def dict_convert_date_to_str(data: dict):
303
+ """
304
+ Rekurzivně převede všechny časové položky ve slovníku na ISO text
305
+
306
+ :param data: dictionary
307
+ :return:
308
+ """
309
+ if isinstance(data, dict):
310
+ for k, v in data.items():
311
+ if isinstance(v, datetime):
312
+ if v.tzinfo is None:
313
+ v_gmt = v.replace(tzinfo=pytz.utc)
314
+ else:
315
+ v_gmt = v.astimezone(pytz.utc)
316
+ data[k] = v_gmt.strftime('%Y-%m-%dT%H:%M:%SZ')
317
+ elif isinstance(v, dict):
318
+ dict_convert_date_to_str(v)
319
+ elif isinstance(v, list):
320
+ for item in v:
321
+ dict_convert_date_to_str(item)
322
+ else:
323
+ pass
sysnet_pyutils/ident.py CHANGED
@@ -53,7 +53,7 @@ def generate_tiny_uuid():
53
53
  return out[-ID_LENGTH:]
54
54
 
55
55
 
56
- def generate_id12(three_char_prefix):
56
+ def generate_id12(three_char_prefix: str) -> str:
57
57
  """
58
58
  Vygeneruje 12místný alfanumerický identifikátor s pevným prefixem
59
59
 
@@ -70,7 +70,7 @@ def generate_id12(three_char_prefix):
70
70
  return correct_pid(out)
71
71
 
72
72
 
73
- def check_pid(pid):
73
+ def check_pid(pid: str) -> bool:
74
74
  """
75
75
  Kontroluje správnost PID pomocí kontrolního součtu
76
76
 
@@ -88,7 +88,7 @@ def check_pid(pid):
88
88
  return out
89
89
 
90
90
 
91
- def correct_pid(pid):
91
+ def correct_pid(pid: str) -> str:
92
92
  """
93
93
  Opraví PID do korektní podoby. Doplní kontrolní součet.
94
94
 
@@ -103,7 +103,7 @@ def correct_pid(pid):
103
103
  return out
104
104
 
105
105
 
106
- def generate_pid():
106
+ def generate_pid() -> str:
107
107
  """
108
108
  Vybeneruje nový PID
109
109
 
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ File name:
6
+ Author: "SYSNET s.r.o."<rjaeger@sysnet.cz>
7
+ Created:
8
+ Version: 1.0.0
9
+ Description:
10
+ """
@@ -0,0 +1,262 @@
1
+ from datetime import datetime
2
+ from enum import Enum
3
+ from typing import Optional, List, Tuple, Any
4
+ from uuid import UUID
5
+
6
+ from pydantic import BaseModel, Field, EmailStr
7
+
8
+ from sysnet_pyutils.utils import local_now
9
+
10
+
11
+ class ApiError(Exception):
12
+ def __init__(self, code: int = 500, message: str = None):
13
+ self.code = code
14
+ self.message = message
15
+
16
+
17
+ class ErrorModel(BaseModel):
18
+ code: int
19
+ message: str
20
+
21
+
22
+ class UserType(BaseModel):
23
+ identifier: Optional[str] = Field(
24
+ default=None,
25
+ description='identifikátor uživatele (PID nebo UUID)',
26
+ examples=['ABC123456789'],
27
+ )
28
+ name: Optional[str] = Field(
29
+ default=None, description='Jméno uživatele', examples=['Jiří Novák']
30
+ )
31
+ dn: Optional[str] = Field(
32
+ default=None,
33
+ description='Příznačné jméno (distinguished name) LDAP',
34
+ examples=['cn=Jiří Novák, o=AOPK, c=CZ'],
35
+ )
36
+ email: Optional[EmailStr] = Field(default=None, description='Adresa elektronické pošty', examples=['jiri.novak@aopk.cz'])
37
+ phone: Optional[str] = Field(default=None, description='Telefonní číslo uživatele')
38
+ name_first: Optional[str] = Field(default=None, description='Křestní jméno uživatele', examples=['Jiří'])
39
+ name_last: Optional[str] = Field(default=None, description='Příjmení uživatele', examples=['Novák'])
40
+ name_full: Optional[str] = Field(default=None, description='Úplné jméno uživatele', examples=['MUDr. Jiří Novák, PhD.'])
41
+
42
+
43
+ class AclLevelEnum(Enum):
44
+ READ = 'R'
45
+ WRITE = 'W'
46
+ MANAGE = 'M'
47
+
48
+ @classmethod
49
+ def has_value(cls, value):
50
+ return value in cls._value2member_map_
51
+
52
+
53
+ class CodeValueType(BaseModel):
54
+ # kód/hodnota
55
+ code: Optional[str] = Field(default=None, description='Kód položky', examples=['CZ'])
56
+ value: Optional[str] = Field(default=None, description='Hodnota položky', examples=['Česká republika / Czech republic'])
57
+
58
+ def __eq__(self, other):
59
+ if not isinstance(other, CodeValueType):
60
+ return NotImplemented
61
+ return self.code == other.code and self.value == other.value
62
+
63
+ def load_data(self, data: Tuple[Any, Any]):
64
+ self.code = data[0]
65
+ self.value = data[1]
66
+ return self
67
+
68
+ class RegionalValueType(CodeValueType):
69
+ # kód/hodnota/rok/kraj
70
+ year: Optional[int] = Field(default=None, description='Rok platnotsi položky', examples=[2022])
71
+ region: Optional[str] = Field(default=None, description='Kraj platnosti položky', examples=['Středočeský kraj'])
72
+
73
+
74
+ class TimeLimitedType(CodeValueType):
75
+ # kód/hodnota
76
+ date_from: Optional[datetime] = Field(default=None, description='Platí od data')
77
+ date_to: Optional[datetime] = Field(default=None, description='Platí do data')
78
+
79
+
80
+ class LogItemType(BaseModel):
81
+ # položka logu
82
+ timestamp: datetime = Field(default=local_now(), description='Časová značka logu')
83
+ originator: Optional[str] = Field(default='SYSTEM', description='Zdroj logu', examples=['<NAME>'])
84
+ message: Optional[str] = Field(default=None, description='Zpráva logu', examples=['Autorizováno'])
85
+
86
+
87
+ class ContainerHistoryItemType(BaseModel):
88
+ # položka historie zařazení do kontejnerů
89
+ timestamp: datetime = Field(default=local_now(), description='Časová značka logu')
90
+ originator: Optional[str] = Field(default='SYSTEM', description='Zdroj logu', examples=['<NAME>'])
91
+ container: Optional[UUID] = Field(default=None, description='Identifikátor kontejneru')
92
+ message: Optional[str] = Field(default=None, description='Zpráva logu', examples=['Autorizováno'])
93
+
94
+
95
+ class AclType(BaseModel):
96
+ name: Optional[str] = Field(
97
+ default=None,
98
+ description='Uživatelské jméno nebo název role',
99
+ examples=['jan.novak@email.com'],
100
+ )
101
+ level: Optional[AclLevelEnum] = Field(
102
+ default=None, description='Úroveň přístupu (reader, writer, manager)'
103
+ )
104
+ can_delete: Optional[bool] = Field(
105
+ default=False, description='Oprávnění odstraňovat dokumenty'
106
+ )
107
+
108
+
109
+ class MetadataTypeEntry(BaseModel):
110
+ title: Optional[str] = Field(default=None, description='Název dokumentu')
111
+ id_no: Optional[str] = Field(default=None, description='Číslo dokumentu', examples=['23CZ123456'])
112
+ unid: Optional[str] = Field(default=None, description='Domino universal ID', examples=['3005277CB984B7FFC12587890060E2BF'])
113
+ pid: Optional[str] = Field(default=None, description='Unique identifier', examples=['MBOA7HNBDJTR'])
114
+ uuid: Optional[UUID] = Field(default=None, description='Unique identifier')
115
+ form: Optional[str] = Field(default=None, description='Formulář', examples=['certificate'])
116
+ authorized: Optional[bool] = Field(default=False, description='Dokument byl autorizován')
117
+ archived: Optional[bool] = Field(default=False, description='Dokument byl archivován')
118
+ deleted: Optional[bool] = Field(default=False, description='Dokument byl odstraněn')
119
+
120
+
121
+ class MetadataTypeBase(BaseModel):
122
+ title: Optional[str] = Field(default=None, description='Název dokumentu')
123
+ id_no: Optional[str] = Field(default=None, description='Číslo dokumentu', examples=['23CZ123456'])
124
+ id_no_local: Optional[str] = Field(default=None, description='Lokální číslo dokumentu', examples=['23CZ123456'])
125
+ id_no_list: Optional[List[str]] = Field(default=None, description='Seznam všech čísel dokumentu', examples=['23CZ123456'])
126
+ creator: Optional[str] = Field(
127
+ default=None,
128
+ description='Tvůrce dokumentu - Subjekt primárně odpovědný za vytvoření dokument.',
129
+ examples=['CN=Jan Novák/O=CITES/C=CZ'],
130
+ )
131
+ created_by_official: Optional[bool] = Field(default=False, description='Vytvořeno úředníkem')
132
+ contributor: Optional[UserType] = Field(default=None, description='Přispěvatel (podílí se na obsahu dokumentu)')
133
+ acl: Optional[List[AclType]] = Field(default=None, description='seznam přístupových práv')
134
+
135
+
136
+ class MetadataType(MetadataTypeBase):
137
+ date_created: Optional[datetime] = Field(
138
+ default=local_now(),
139
+ description='Datum a čas vytvoření dokumentu',
140
+ examples=['2023-04-20T05:12:03Z'],
141
+ )
142
+ date_modified: Optional[datetime] = Field(
143
+ default=local_now(),
144
+ description='Datum a čas poslední úpravy dokumentu',
145
+ examples=['2023-04-20T05:12:03Z'],
146
+ )
147
+ date_authorized: Optional[datetime] = Field(
148
+ default=None,
149
+ description='Datum a čas autorizace',
150
+ examples=['2023-04-20T05:12:03Z'],
151
+ )
152
+ date_archived: Optional[datetime] = Field(
153
+ default=None,
154
+ description='Datum a čas archivace',
155
+ examples=['2023-04-20T05:12:03Z'],
156
+ )
157
+ date_deleted: Optional[datetime] = Field(
158
+ default=None,
159
+ description='Datum a čas odstranění',
160
+ examples=['2023-04-20T05:12:03Z'],
161
+ )
162
+ unid: Optional[str] = Field(default=None, description='Domino universal ID', examples=['3005277CB984B7FFC12587890060E2BF'])
163
+ pid: Optional[str] = Field(default=None, description='Unique identifier', examples=['MBOA7HNBDJTR'])
164
+ uuid: Optional[UUID] = Field(default=None, description='Unique identifier')
165
+ form: Optional[str] = Field(default=None, description='Formulář', examples=['certificate'])
166
+ authorized: Optional[bool] = Field(default=False, description='Dokument byl autorizován')
167
+ archived: Optional[bool] = Field(default=False, description='Dokument byl archivován')
168
+ deleted: Optional[bool] = Field(default=False, description='Dokument byl odstraněn')
169
+ has_attachments: Optional[bool] = Field(default=False, description='Dokument má/nemá přílohy')
170
+ container: Optional[UUID] = Field(default=None, description='Identifikátor kontejneru, do kterého je dokument zařazen.')
171
+ container_history: Optional[List[ContainerHistoryItemType]] = Field(default=None, description='Historie kontejnerů')
172
+
173
+
174
+ class ListTypeBase(BaseModel):
175
+ start: Optional[int] = Field(default=None, description='Počáteční dokument na stránce', examples=[0])
176
+ page_size: Optional[int] = Field(default=None, description='Velikost stránky', examples=[10])
177
+ page: Optional[int] = Field(default=None, description='Požadovaná stránka', examples=[0])
178
+ count: Optional[int] = Field(default=None, description='celkový počet vrácených položek', examples=[25])
179
+
180
+
181
+ class LinkedType(BaseModel):
182
+ # Identifikace pevně provázaného dokumemtu (nadřízený nebo jinak provázaný)
183
+ title: Optional[str] = Field(default=None, description='Název provázaného dokumentu', examples=['Žádost o vydání permitu'])
184
+ code: Optional[str] = Field(default=None, description='Kód vazby', examples=['CRŽP', 'CITS', 'IPPC'])
185
+ id: Optional[str] = Field(default=None, description='Hlavní identifikátor', examples=['0c282c62-1918-4fbe-ad2c-e49a021f4801'])
186
+ unid: Optional[str] = Field(default=None, description='Domino universal ID', examples=['3005277CB984B7FFC12587890060E2BF'])
187
+ pid: Optional[str] = Field(default=None, description='PID (dvanáctimístný identifikátor', examples=['MBOA7HNBDJTR'])
188
+ uuid: Optional[UUID] = Field(default=None, description='Jednoznačný identifikátor', examples=['0c282c62-1918-4fbe-ad2c-e49a021f4801'])
189
+
190
+
191
+ class GeoPointJtskType(BaseModel):
192
+ x: Optional[float] = Field(default=None, description='JTSK - X', examples=[-1182833.13])
193
+ y: Optional[float] = Field(default=None, description='JTSK - Y', examples=[-784886.70])
194
+
195
+
196
+ class GeoPointType(BaseModel):
197
+ lat: Optional[float] = Field(default=None, description='WGS84 - latitude', examples=[-4.3202115])
198
+ lon: Optional[float] = Field(default=None, description='WGS84 - longitude', examples=[55.7520211])
199
+
200
+
201
+ class MapSheet50Type(BaseModel):
202
+ # objekt mapový list 1:50000
203
+ id: Optional[str] = Field(default=None, description='Identifikátor mapového listu', examples=['03-44'])
204
+ name: Optional[str] = Field(default=None, description='Název mapového listu', examples=['Dvůr Králové'])
205
+
206
+
207
+ class BasinType(BaseModel):
208
+ # objekt povodí
209
+ id: Optional[int] = Field(default=None, description='Identifikátor', examples=[4236])
210
+ id_1: Optional[int] = Field(default=None, description='Identifikátor', examples=[1])
211
+ id_2: Optional[int] = Field(default=None, description='Identifikátor', examples=[11])
212
+ id_3: Optional[int] = Field(default=None, description='Identifikátor', examples=[49])
213
+ chp: Optional[str] = Field(default=None, description='', examples=['1-11-04-0300-0-00'])
214
+ chp_d: Optional[str] = Field(default=None, description='', examples=['1-11-04-0300-0-00'])
215
+ chp_u: Optional[str] = Field(default=None, description='', examples=['1-11-04-0300-0-00'])
216
+ basin_name_1: Optional[str] = Field(default=None, description='naz_pov_1', examples=['povodí Labe'])
217
+ basin_name_2: Optional[str] = Field(default=None, description='naz_pov_2', examples=['Berounka od Úslavy po ústí'])
218
+ basin_name_3: Optional[str] = Field(default=None, description='naz_pov_3', examples=['Litavka a Berounka od Litavky po Loděnici'])
219
+ stream_name: Optional[str] = Field(default=None, description='naz_tok', examples=['Červený potok'])
220
+ stream_name_2: Optional[str] = Field(default=None, description='naz_tok_2', examples=[''])
221
+
222
+
223
+ class LocationType(BaseModel):
224
+ # Lokalita
225
+ ruian_adm: Optional[int] = Field(default=None, description='Kód adresního místa RUIAN', examples=[21844895])
226
+ ruian_adm_name: Optional[str] = Field(default=None, description='Název adresního místa RUIAN', examples=['Kaplanova 1931/1, 14800 Praha 11'])
227
+ basin: Optional[BasinType] = Field(default=None, description='Povodí')
228
+ sheet50: Optional[MapSheet50Type] = Field(default=None, description='Mapový list')
229
+ street: Optional[str] = Field(default=None, description='Ulice nebo část obce a číslo popisné, evidenční, orientační', examples=['Kolmá 53/1230'])
230
+ city: Optional[str] = Field(default=None, description='Název obce', examples=['Slepičí Lhota'])
231
+ zip: Optional[str] = Field(default=None, description='PSČ', examples=['987 22'])
232
+ region: Optional[str] = Field(default=None, description='Kraj', examples=['Středočeský kraj'])
233
+ country: Optional[CodeValueType] = Field(default=None, description='Stát', examples=[{'code': 'SK', 'value': 'Slovensko'}])
234
+ address_list: Optional[list[str]] = Field(default=None, description='Seznam adresních položek', examples=['Kolmá 53/1230', 'Slepičí Lhota', '987 22', 'CZ'])
235
+ note: Optional[str] = Field(default=None, description='Poznámka', examples=['Parcela číslo 113/7'])
236
+ wgs: Optional[GeoPointType] = Field(default=None, description='WGS84')
237
+ jtsk: Optional[GeoPointJtskType] = Field(default=None, description='JTSK')
238
+
239
+
240
+ class PersonBaseType(BaseModel):
241
+ # Osoba z Registru osob
242
+ unid: Optional[str] = Field(default=None, description='Domino universal ID', examples=['3005277CB984B7FFC12587890060E2BF'])
243
+ pid: Optional[str] = Field(default=None, description='Unique identifier', examples=['MBOA7HNBDJTR'])
244
+ uuid: Optional[UUID] = Field(default=None, description='Unique identifier')
245
+ ico: Optional[str] = Field(default=None, description='IČO osoby')
246
+ name: Optional[str] = Field(default=None, description='Název osoby', examples=['B.A.R. Reptofilia'])
247
+ email: Optional[EmailStr] = Field(default=None, description='Email osoby')
248
+ address: Optional[str] = Field(default=None, description='Adresa osoby', examples=['Ulice Závodu Míru 2\n87423 Otrokovice'])
249
+ country: Optional[CodeValueType] = Field(default=None, description='Země adresy osoby')
250
+ main_person: Optional[LinkedType] = Field(default=None, description='Odkaz na hlavní osobu do registru')
251
+ linked_persons: Optional[list[LinkedType]] = Field(default=None, description='Odkaz na další osoby do registru')
252
+
253
+
254
+ class WorkflowType(BaseModel):
255
+ # Položka životního cyklu
256
+ node_code: Optional[str] = Field(default=None, description='Kód schvalovacího uzlu (APPROVE, AUTHORIZE, REJECT, ...)', examples=['APPROVE', 'AUTHORIZE', 'REJECT'])
257
+ node_name: Optional[str] = Field(default=None, description='Název schvalovacího uzlu (schválení, autorizace, ...)', examples=['Schválení'])
258
+ responsible: Optional[PersonBaseType] = Field(default=None, description='Odpovědná osoba')
259
+ date_execution: Optional[datetime] = Field(default=local_now(), description='Datum provedení')
260
+ executor: Optional[UserType] = Field(default='SYSTEM', description='Uživatel, který provedl událost')
261
+ status_from: Optional[str] = Field(default=None, description='Předchozí stav')
262
+ status_to: Optional[str] = Field(default=None, description='Následný stav')
sysnet_pyutils/utils.py CHANGED
@@ -6,9 +6,10 @@ import re
6
6
  import secrets
7
7
  import sys
8
8
  import traceback
9
- import uuid
10
9
  from datetime import datetime, timedelta, date
10
+ from typing import Tuple, Union, List, Any
11
11
  from urllib.parse import quote
12
+ from uuid import UUID, uuid4, uuid1
12
13
 
13
14
  import dateutil.parser
14
15
  import pytz
@@ -125,7 +126,7 @@ class Config(object, metaclass=Singleton):
125
126
  self.store()
126
127
 
127
128
 
128
- def url_safe(url):
129
+ def url_safe(url: str) -> str:
129
130
  """
130
131
  Upraví URL, aby neobsahovalo nepovolené znaky
131
132
 
@@ -135,7 +136,7 @@ def url_safe(url):
135
136
  return quote(url, safe='/:?=&')
136
137
 
137
138
 
138
- def who_am_i():
139
+ def who_am_i() -> str:
139
140
  """
140
141
  Vrátí název funkce
141
142
 
@@ -143,10 +144,10 @@ def who_am_i():
143
144
  """
144
145
  stack = traceback.extract_stack()
145
146
  file_name, code_line, func_name, text = stack[-2]
146
- return func_name
147
+ return str(func_name)
147
148
 
148
149
 
149
- def unique_list(input_list):
150
+ def unique_list(input_list: list) -> list:
150
151
  """
151
152
  Vyřadí opakující se položky ze seznamu
152
153
 
@@ -162,7 +163,7 @@ def unique_list(input_list):
162
163
  return out
163
164
 
164
165
 
165
- def api_keys_init(agenda='main', amount=4):
166
+ def api_keys_init(agenda: str='main', amount: int =4) -> List[dict]:
166
167
  """
167
168
  Vygeneruje klíče pro API
168
169
 
@@ -176,7 +177,7 @@ def api_keys_init(agenda='main', amount=4):
176
177
  return out
177
178
 
178
179
 
179
- def uuid_next(uuid_type=4):
180
+ def uuid_next(uuid_type: int = 4) -> UUID:
180
181
  """
181
182
  Vygeneruje UUID
182
183
 
@@ -184,13 +185,13 @@ def uuid_next(uuid_type=4):
184
185
  :return: uuid
185
186
  """
186
187
  if uuid_type == 4:
187
- out = uuid.uuid4()
188
+ out = uuid4()
188
189
  else:
189
- out = uuid.uuid1()
190
+ out = uuid1()
190
191
  return out
191
192
 
192
193
 
193
- def pid_next():
194
+ def pid_next() -> str:
194
195
  """
195
196
  Vygeneruje korektní PID
196
197
 
@@ -199,7 +200,7 @@ def pid_next():
199
200
  return generate_pid()
200
201
 
201
202
 
202
- def pid_check(pid):
203
+ def pid_check(pid: str) -> bool:
203
204
  """
204
205
  Zkontroluje korektnost PID
205
206
 
@@ -209,7 +210,7 @@ def pid_check(pid):
209
210
  return check_pid(pid)
210
211
 
211
212
 
212
- def pid_correct(pid):
213
+ def pid_correct(pid: str) -> str:
213
214
  """
214
215
  Opraví PID
215
216
 
@@ -219,7 +220,7 @@ def pid_correct(pid):
219
220
  return correct_pid(pid)
220
221
 
221
222
 
222
- def id12_next(three_char_prefix=None):
223
+ def id12_next(three_char_prefix: Union[str, None]=None) -> str:
223
224
  """
224
225
  Vygeneruje korektní 12místný alfanumerický identifikátor s pevným prefixem
225
226
 
@@ -229,7 +230,7 @@ def id12_next(three_char_prefix=None):
229
230
  return generate_id12(three_char_prefix=three_char_prefix)
230
231
 
231
232
 
232
- def api_key_next(name, length=16):
233
+ def api_key_next(name: Union[str, None], length: int = 16) -> dict:
233
234
  """
234
235
  Vygeneruje slovník API key {<API Key>: <name>}
235
236
 
@@ -237,11 +238,13 @@ def api_key_next(name, length=16):
237
238
  :param length: Délka API klíče
238
239
  :return: Slovník {<API Key>: <name>}
239
240
  """
241
+ if name in [None, '']:
242
+ name = 'main'
240
243
  out = {api_key_generate(length=length): name}
241
244
  return out
242
245
 
243
246
 
244
- def api_key_generate(length: int):
247
+ def api_key_generate(length: int = 16) -> Union[str, None]:
245
248
  """
246
249
  vygeneruje API klíč
247
250
 
@@ -251,7 +254,7 @@ def api_key_generate(length: int):
251
254
  return secrets.token_urlsafe(length)
252
255
 
253
256
 
254
- def hash_md5(text):
257
+ def hash_md5(text: str) -> Union[str, None]:
255
258
  """
256
259
  Vytvoří md5 checksum ze zdrojového textu
257
260
  :param text:
@@ -259,28 +262,46 @@ def hash_md5(text):
259
262
  """
260
263
  if text is None:
261
264
  return None
262
- return hashlib.md5(text.encode("utf-8")).hexdigest()
265
+ return str(hashlib.md5(text.encode("utf-8")).hexdigest())
263
266
 
264
267
 
265
- def hash_sha1(text):
268
+ def hash_sha1(text: str) -> Union[str, None]:
269
+ """
270
+ Vytvoří sha1 checksum ze zdrojového textu
271
+
272
+ :param text:
273
+ :return:
274
+ """
266
275
  if text is None:
267
276
  return None
268
- return hashlib.sha1(text.encode("utf-8")).hexdigest()
277
+ return str(hashlib.sha1(text.encode("utf-8")).hexdigest())
269
278
 
270
279
 
271
- def hash_sha256(text):
280
+ def hash_sha256(text: str) -> Union[str, None]:
281
+ """
282
+ Vytvoří sha265 checksum ze zdrojového textu
283
+
284
+ :param text:
285
+ :return:
286
+ """
272
287
  if text is None:
273
288
  return None
274
289
  return hashlib.sha256(text.encode("utf-8")).hexdigest()
275
290
 
276
291
 
277
- def hash_sha384(text):
292
+ def hash_sha384(text: str) -> Union[str, None]:
293
+ """
294
+ Vytvoří sha265 checksum ze zdrojového textu
295
+
296
+ :param text:
297
+ :return:
298
+ """
278
299
  if text is None:
279
300
  return None
280
301
  return hashlib.sha384(text.encode("utf-8")).hexdigest()
281
302
 
282
303
 
283
- def is_valid_unid(unid):
304
+ def is_valid_unid(unid: str) -> bool:
284
305
  """
285
306
  Kontrola validity HCL Notes UNIID
286
307
 
@@ -300,7 +321,7 @@ def is_valid_unid(unid):
300
321
  return False
301
322
 
302
323
 
303
- def is_valid_uuid(value):
324
+ def is_valid_uuid(value: Union[UUID, str]) -> bool:
304
325
  """
305
326
  Kontrola validity uuid
306
327
 
@@ -308,13 +329,13 @@ def is_valid_uuid(value):
308
329
  :return:
309
330
  """
310
331
  try:
311
- uuid.UUID(str(value))
332
+ UUID(str(value))
312
333
  return True
313
334
  except ValueError:
314
335
  return False
315
336
 
316
337
 
317
- def is_valid_pid(value):
338
+ def is_valid_pid(value: str) -> bool:
318
339
  """
319
340
  Kontrola validity PID
320
341
  :param value:
@@ -324,7 +345,7 @@ def is_valid_pid(value):
324
345
  return bool(re.search(pattern, value))
325
346
 
326
347
 
327
- def is_valid_ico(ico):
348
+ def is_valid_ico(ico: str) -> bool:
328
349
  """
329
350
  Kontrola validity IČO
330
351
 
@@ -350,7 +371,20 @@ def is_valid_ico(ico):
350
371
  return True
351
372
 
352
373
 
353
- def repair_ico(ico):
374
+ def is_valid_email(email: str) -> bool:
375
+ """
376
+ Kontrola validity emailové adresy
377
+
378
+ :param email:
379
+ :return:
380
+ """
381
+ if email is None:
382
+ return False
383
+ out = bool(re.search(r"^[\w.+\-]+@\w+\.[a-z]{2,3}$", email))
384
+ return out
385
+
386
+
387
+ def repair_ico(ico: str) -> Union[str, None]:
354
388
  """
355
389
  Opraví IČO
356
390
 
@@ -376,7 +410,7 @@ def repair_ico(ico):
376
410
  return ico
377
411
 
378
412
 
379
- def iso_to_local_datetime(isodate):
413
+ def iso_to_local_datetime(isodate: str) -> Union[datetime, None]:
380
414
  """
381
415
  ISO string datum do lokálního datetime
382
416
 
@@ -391,18 +425,21 @@ def iso_to_local_datetime(isodate):
391
425
  return out
392
426
 
393
427
 
394
- def convert_hex_to_int(id_hex):
428
+ def convert_hex_to_int(id_hex: str) -> Union[int, None]:
395
429
  """
396
430
  Konvertuje hex string na int
397
431
 
398
432
  :param id_hex: Hexadecimální string
399
433
  :return: int
400
434
  """
401
- id_int = int(id_hex, base=16)
402
- return id_int
435
+ try:
436
+ id_int = int(id_hex, base=16)
437
+ return id_int
438
+ except ValueError:
439
+ return None
403
440
 
404
441
 
405
- def increment_date(date_str=None, days=1):
442
+ def increment_date(date_str: str =None, days: int = 1) -> Union[str, None]:
406
443
  """
407
444
  Inkrementuje datum v textovém formátu ISO o daný počet dní
408
445
 
@@ -413,13 +450,16 @@ def increment_date(date_str=None, days=1):
413
450
  if date_str is None:
414
451
  return None
415
452
  if days is None:
416
- return date_str
417
- d = datetime.strptime(date_str, '%Y-%m-%d')
418
- out = d + timedelta(days=days)
419
- return out.date().isoformat()
453
+ days = 1
454
+ try:
455
+ d = datetime.strptime(date_str, '%Y-%m-%d')
456
+ out = d + timedelta(days=days)
457
+ return out.date().isoformat()
458
+ except ValueError:
459
+ return None
420
460
 
421
461
 
422
- def today():
462
+ def today() -> str:
423
463
  """
424
464
  Vrací ISO 8601 datum dnešního dne
425
465
 
@@ -429,7 +469,7 @@ def today():
429
469
  return out.date().isoformat()
430
470
 
431
471
 
432
- def tomorrow():
472
+ def tomorrow() -> str:
433
473
  """
434
474
  Vrací ISO 8601 datum zítřejšího dne
435
475
 
@@ -438,7 +478,7 @@ def tomorrow():
438
478
  return increment_date(date_str=today(), days=1)
439
479
 
440
480
 
441
- def cs_bool(value=None):
481
+ def cs_bool(value=None) -> str:
442
482
  """
443
483
  Vrátí českou textovou hodnotu 'ano'/'ne' pokud je bool(value) True/False
444
484
 
@@ -451,7 +491,7 @@ def cs_bool(value=None):
451
491
  return out
452
492
 
453
493
 
454
- def cron_to_dict(cron):
494
+ def cron_to_dict(cron: str) -> Union[dict, None]:
455
495
  """
456
496
  Konvertuje cron text do do slovníku
457
497
 
@@ -471,10 +511,11 @@ def cron_to_dict(cron):
471
511
  return out
472
512
 
473
513
 
474
- def date_to_datetime(date_value):
514
+ def date_to_datetime(date_value: Union[date, datetime]) -> Union[datetime, None]:
475
515
  """
476
516
  Konvertuje date na datetime v lokální časové zóně
477
- :param date_value: hodnota
517
+
518
+ :param date_value: datum/datum a čas
478
519
  :return: hodnota date v lokální časové zóně
479
520
  """
480
521
  if date_value is None:
@@ -488,12 +529,12 @@ def date_to_datetime(date_value):
488
529
  return out
489
530
 
490
531
 
491
- def date_to_datetime_utc(date_value):
532
+ def date_to_datetime_utc(date_value: Union[date, datetime]) -> Union[datetime, None]:
492
533
  """
493
534
  Konvertuje datum na tatum a čas v UTC.
494
535
  Vhodné pro MongoDB pro ukládání položek typu datum.
495
536
 
496
- :param date_value: hodnota
537
+ :param date_value: datum/datum a čas
497
538
  :return: hodnota date v UTC
498
539
  """
499
540
  if date_value is None:
@@ -508,7 +549,7 @@ def date_to_datetime_utc(date_value):
508
549
  return None
509
550
 
510
551
 
511
- def date_to_iso(date_value):
552
+ def date_to_iso(date_value: Union[date, datetime]) -> Union[str, None]:
512
553
  """
513
554
  Konvertuje hodnotu typu date nebo datetime na ISO string
514
555
 
@@ -522,7 +563,7 @@ def date_to_iso(date_value):
522
563
  return None
523
564
 
524
565
 
525
- def remove_empty(source_list):
566
+ def remove_empty(source_list: List[Any]):
526
567
  """
527
568
  Odstraní prázdné položky ze seznamu
528
569
 
@@ -533,13 +574,12 @@ def remove_empty(source_list):
533
574
  return None
534
575
  target_list = []
535
576
  for item in source_list:
536
- if item is not None:
537
- if bool(item):
538
- target_list.append(item)
577
+ if bool(item):
578
+ target_list.append(item)
539
579
  return target_list
540
580
 
541
581
 
542
- def is_base64(body):
582
+ def is_base64(body: Union[str, bytes]) -> bool:
543
583
  """
544
584
  Kontrola, zda jsou data kódována base64
545
585
 
@@ -548,7 +588,7 @@ def is_base64(body):
548
588
  """
549
589
  try:
550
590
  if isinstance(body, str):
551
- # If there's any unicode here, an exception will be thrown and the function will return false
591
+ # If there's any Unicode here, an exception will be thrown and the function will return false
552
592
  sb_bytes = bytes(body, 'ascii')
553
593
  elif isinstance(body, bytes):
554
594
  sb_bytes = body
@@ -560,7 +600,7 @@ def is_base64(body):
560
600
  return False
561
601
 
562
602
 
563
- def to_base64(body):
603
+ def to_base64(body: Union[str, bytes]) -> Union[bytes, None]:
564
604
  """
565
605
  Zajistí, aby data byla v base64
566
606
 
@@ -571,10 +611,10 @@ def to_base64(body):
571
611
  return body
572
612
  try:
573
613
  if isinstance(body, str):
574
- # If there's any unicode here, an exception will be thrown and the function will return false
575
- sb_bytes = bytes(body, 'ascii')
614
+ # If there's any Unicode here, an exception will be thrown and the function will return false
615
+ sb_bytes: bytes = bytes(body, 'ascii')
576
616
  elif isinstance(body, bytes):
577
- sb_bytes = body
617
+ sb_bytes: bytes = body
578
618
  else:
579
619
  raise ValueError("Argument must be string or bytes")
580
620
  return base64.b64encode(sb_bytes)
@@ -583,7 +623,7 @@ def to_base64(body):
583
623
  return None
584
624
 
585
625
 
586
- def encode_string_b64(data: str, encoding='utf-8'):
626
+ def encode_string_b64(data: str, encoding='utf-8') -> Union[str, None]:
587
627
  """
588
628
  Zakóduje string do base64
589
629
 
@@ -597,7 +637,7 @@ def encode_string_b64(data: str, encoding='utf-8'):
597
637
  return out
598
638
 
599
639
 
600
- def decode_b64_string(b64_data: str, encoding='utf-8'):
640
+ def decode_b64_string(b64_data: str, encoding='utf-8') -> Union[str, None]:
601
641
  """
602
642
  Dekóduje base64 data na string
603
643
 
@@ -625,7 +665,7 @@ def encode_file_b64(filepath, encoding='utf-8'):
625
665
  return out
626
666
 
627
667
 
628
- def decode_b64_to_file(b64_data: str, filepath, encoding='utf-8'):
668
+ def decode_b64_to_file(b64_data: str, filepath: str, encoding='utf-8') -> Union[str, None]:
629
669
  """
630
670
  Uloží base64 data do souboru
631
671
 
@@ -682,13 +722,13 @@ class Log(object, metaclass=Singleton):
682
722
  self.logger = ext_logger
683
723
 
684
724
 
685
- def to_camel(s):
725
+ def to_camel(s: str) -> str:
686
726
  temp = re.split('_+', s)
687
727
  out = temp[0] + ''.join(map(lambda x: x.title(), temp[1:]))
688
728
  return out
689
729
 
690
730
 
691
- def to_snake(s):
731
+ def to_snake(s: str) -> str:
692
732
  # return re.sub('([A-Z]\w+$)', '_\\1', s).lower()
693
733
  return re.sub(r'([A-Z]\w+$)', '_\\1', s).lower()
694
734
 
@@ -705,7 +745,7 @@ def to_camel_dict(d):
705
745
  return {to_camel(a): to_camel_dict(b) if isinstance(b, (dict, list)) else b for a, b in d.items()}
706
746
 
707
747
 
708
- def xml_to_dict(xml_text):
748
+ def xml_to_dict(xml_text: str) -> Union[dict, None]:
709
749
  """
710
750
  Parsuje XML string do XML dictionary
711
751
  :param xml_text: XML text
@@ -714,7 +754,7 @@ def xml_to_dict(xml_text):
714
754
  return xmltodict.parse(xml_text)
715
755
 
716
756
 
717
- def dict_to_xml(xml_dict):
757
+ def dict_to_xml(xml_dict: dict) -> Union[str, None]:
718
758
  """
719
759
  Parsuje XML dict do XML textu
720
760
 
@@ -730,11 +770,11 @@ ORDER_BASE = 26
730
770
  CHAR_BASE = 65
731
771
 
732
772
 
733
- def order_to_cites(order: int):
773
+ def order_to_cites(order: int) -> str:
734
774
  """
735
775
  Konvertuje celočíselnou hodnotu na písmennou
736
776
 
737
- :param order: celočíselná hodnota např. 1458
777
+ :param order: Celočíselná hodnota např. 1458
738
778
  :return: znaková hodnota např. 'BDB'
739
779
  """
740
780
  if order is None:
@@ -760,11 +800,11 @@ def order_to_cites(order: int):
760
800
  return out
761
801
 
762
802
 
763
- def cites_to_order(cites: str):
803
+ def cites_to_order(cites: str) -> int:
764
804
  """
765
805
  Konvertuje písmennou hodnotu na celočíselnou
766
806
 
767
- :param cites: znaková hodnota např. 'BDB'
807
+ :param cites: Znaková hodnota např. 'BDB'
768
808
  :return: celočíselná hodnota např. 1458
769
809
  """
770
810
  if cites is None:
@@ -784,7 +824,7 @@ def cites_to_order(cites: str):
784
824
  return out
785
825
 
786
826
 
787
- def local_now():
827
+ def local_now() -> datetime:
788
828
  """
789
829
  Vrací aktuální časovou značku v lokální časové zóně.
790
830
 
@@ -794,7 +834,7 @@ def local_now():
794
834
  return datetime.now(tz=pytz.timezone(TZ))
795
835
 
796
836
 
797
- def gmt_now():
837
+ def gmt_now() -> datetime:
798
838
  """
799
839
  Vrací aktuální časovou značku ve světovém čase.
800
840
 
@@ -804,7 +844,7 @@ def gmt_now():
804
844
  return datetime.now(tz=pytz.utc)
805
845
 
806
846
 
807
- def datetime_now(tz='Europe/Prague'):
847
+ def datetime_now(tz='Europe/Prague') -> datetime:
808
848
  """
809
849
  Vrací aktuální časovou značku ve vybrané časové zóně.
810
850
 
@@ -813,15 +853,19 @@ def datetime_now(tz='Europe/Prague'):
813
853
  return datetime.now(tz=pytz.timezone(tz))
814
854
 
815
855
 
816
- def timestamp():
856
+ def timestamp(local=False) -> str:
817
857
  """
818
858
  Vrací textovou podobu časové značky. Vhodné pro názvy souborů.
859
+
860
+ :param local: Lokální časová zóna
819
861
  """
820
862
  out = gmt_now()
863
+ if local:
864
+ out = local_now()
821
865
  return out.strftime('%Y%m%d%H%M%S')
822
866
 
823
867
 
824
- def local_datetime(value=None):
868
+ def local_datetime(value=None) -> datetime:
825
869
  """
826
870
  Vrací datum a čas v lokální
827
871
 
@@ -833,3 +877,33 @@ def local_datetime(value=None):
833
877
  return value
834
878
  local_tz = pytz.timezone(TZ)
835
879
  return value.astimezone(local_tz)
880
+
881
+
882
+ def parse_ldap_name(ldap_name: str) -> Tuple[Union[str, None], Union[str, None]]:
883
+ """
884
+ Parsuje LDAP jméno do CN.
885
+
886
+ :param ldap_name:
887
+ :return: Tuple CN a původní jméno.
888
+ """
889
+ if ldap_name in [None, '']:
890
+ return None, None
891
+ if 'cn=' not in ldap_name.lower():
892
+ return ldap_name, None
893
+ if ',' in ldap_name:
894
+ ldap = ldap_name.split(',')
895
+ elif ', ' in ldap_name:
896
+ ldap = ldap_name.split(', ')
897
+ elif '/' in ldap_name:
898
+ ldap = ldap_name.split('/')
899
+ else:
900
+ ldap = [ldap_name]
901
+ cn = None
902
+ for item in ldap:
903
+ if 'cn=' in item:
904
+ cn = item.split('=')[-1]
905
+ break
906
+ if 'CN=' in item:
907
+ cn = item.split('=')[-1]
908
+ break
909
+ return cn, ldap_name
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: sysnet-pyutils
3
- Version: 1.0.7
3
+ Version: 1.1.0
4
4
  Summary: Python Utilities
5
5
  Author-email: Data Developer <info@sysnet.cz>
6
6
  Project-URL: Homepage, https://github.com/SYSNET-CZ/pyutils
@@ -14,13 +14,14 @@ Classifier: Topic :: Software Development :: Libraries
14
14
  Requires-Python: >=3.9
15
15
  Description-Content-Type: text/markdown
16
16
  License-File: LICENSE
17
- Requires-Dist: PyYAML >=6.0.1
18
- Requires-Dist: pytz >=2023.3
19
- Requires-Dist: python-dateutil >=2.8.2
20
- Requires-Dist: xmltodict >=0.13.0
21
- Requires-Dist: boto3 >=1.34.34
22
- Requires-Dist: botocore >=1.34.34
23
- Requires-Dist: pymongo >=4.7.2
17
+ Requires-Dist: PyYAML>=6.0.1
18
+ Requires-Dist: pytz>=2023.3
19
+ Requires-Dist: python-dateutil>=2.8.2
20
+ Requires-Dist: xmltodict>=0.13.0
21
+ Requires-Dist: boto3>=1.34.34
22
+ Requires-Dist: botocore>=1.34.34
23
+ Requires-Dist: pymongo>=4.7.2
24
+ Requires-Dist: pydantic>=2.10.6
24
25
 
25
26
  # sysnet-pyutils
26
27
 
@@ -311,6 +312,26 @@ Vhodné pro MongoDB pro ukládání položek typu datum.
311
312
  * #### S konfiguračním souborem YAML se nyní pracuje v _UTF-8_
312
313
 
313
314
  * #### Nová třída _LoggedObject_
315
+ --------------------------------------------------------------------------------------------------------------------------------
316
+
317
+ ### verze 1.0.8
318
+
319
+ * #### Nové utility pro práci s daty JSON _data_utils_
320
+ --------------------------------------------------------------------------------------------------------------------------------
321
+
322
+ #### is_valid_email(email: str) -> bool:
323
+ Kontrola validity emailové adresy
324
+ * param email: hodnota
325
+ * return: True/False
326
+ --------------------------------------------------------------------------------------------------------------------------------
327
+
328
+ ### verze 1.1.0
329
+
330
+ * #### Přidán obecný datový slovník SYSNET do balíku models.general
331
+
332
+ Datový slovník je vytvořen pomocí pydantic a je plně kompatibilní s FastAPI.
333
+ Obsahuje základní datové typy, které se používají ve všech aplikacích SYSNET.
334
+
314
335
 
315
336
 
316
337
  ## Systémové proměnné
@@ -0,0 +1,17 @@
1
+ sysnet_pyutils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ sysnet_pyutils/barcode.py,sha256=5dM1ISvVVP966JQxGiZBUYJoPx_jgzWEpEQ2uIOxTd4,2622
3
+ sysnet_pyutils/data_utils.py,sha256=isIlaEKIGK2_7my06oTAcvxCwTMCXy0g83HPbAl-V_Y,9660
4
+ sysnet_pyutils/domino.py,sha256=dGmg9d1PMPOyA_ysXBHVu_zabKGCJEuno3Yw3DexExQ,2671
5
+ sysnet_pyutils/geo.py,sha256=smAkRfobvKqjr3_UIjU5huDbnkb3_edD_xmv4R0r5Q0,2938
6
+ sysnet_pyutils/ident.py,sha256=GyNPF_LNqssMtMzuegpL1GK-0B-ysDiH18kYAdiE2hg,2807
7
+ sysnet_pyutils/log.py,sha256=SFuCPvFTg31LFvnyG24hCTe73FonfS0_FaAHRBhEvlw,2165
8
+ sysnet_pyutils/ses.py,sha256=WJzs0y2QnF4XGDGjls_W0p0v6DJ4fZ4_97m3XbzpaFw,2713
9
+ sysnet_pyutils/tools.py,sha256=ZioHvUIufrhuJyZLdPnuMUD8Li5LTljSMSCxqRnKIi4,377
10
+ sysnet_pyutils/utils.py,sha256=Y95MyEuZlSlTVsQ2rOArdkTN7xqcGsCA7RA6VoBHSSk,23257
11
+ sysnet_pyutils/models/__init__.py,sha256=oozOr_DKhenkM9BDaPOmtbLXhP5vtMUCjBPEjZDW4GQ,167
12
+ sysnet_pyutils/models/general.py,sha256=jqvPoKa6jKXfPLubNSSJZpSpIUG5Sw8A_zwDRlEp8VQ,14706
13
+ sysnet_pyutils-1.1.0.dist-info/LICENSE,sha256=bx5iLIKjgAdYQ7sISn7DsfHRKkoCUm1154sJJKhgqnU,35184
14
+ sysnet_pyutils-1.1.0.dist-info/METADATA,sha256=0JaJMhUht0BhXw9nadGcc8-GNwTT7wO3aXzLFhLDqFg,14744
15
+ sysnet_pyutils-1.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
16
+ sysnet_pyutils-1.1.0.dist-info/top_level.txt,sha256=ZKTltQWbLlWBXw4oovo1w7ui-JQ1WoyECqMSWdBj6XE,15
17
+ sysnet_pyutils-1.1.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.2.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,14 +0,0 @@
1
- sysnet_pyutils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- sysnet_pyutils/barcode.py,sha256=5dM1ISvVVP966JQxGiZBUYJoPx_jgzWEpEQ2uIOxTd4,2622
3
- sysnet_pyutils/domino.py,sha256=dGmg9d1PMPOyA_ysXBHVu_zabKGCJEuno3Yw3DexExQ,2671
4
- sysnet_pyutils/geo.py,sha256=smAkRfobvKqjr3_UIjU5huDbnkb3_edD_xmv4R0r5Q0,2938
5
- sysnet_pyutils/ident.py,sha256=HDEN1WZy0jE4nP3TugOsexeoNSO75o4Cc6TjUpLml0I,2763
6
- sysnet_pyutils/log.py,sha256=SFuCPvFTg31LFvnyG24hCTe73FonfS0_FaAHRBhEvlw,2165
7
- sysnet_pyutils/ses.py,sha256=WJzs0y2QnF4XGDGjls_W0p0v6DJ4fZ4_97m3XbzpaFw,2713
8
- sysnet_pyutils/tools.py,sha256=ZioHvUIufrhuJyZLdPnuMUD8Li5LTljSMSCxqRnKIi4,377
9
- sysnet_pyutils/utils.py,sha256=DsCvc3nvv2M-tbO1KgWPNh5E_kzch8H2dxo1HSY42G0,20668
10
- sysnet_pyutils-1.0.7.dist-info/LICENSE,sha256=bx5iLIKjgAdYQ7sISn7DsfHRKkoCUm1154sJJKhgqnU,35184
11
- sysnet_pyutils-1.0.7.dist-info/METADATA,sha256=13mQkJNZQbktrSyPQfcLIdnKBUsoAFsA7yw3BGB2p-I,13847
12
- sysnet_pyutils-1.0.7.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
13
- sysnet_pyutils-1.0.7.dist-info/top_level.txt,sha256=ZKTltQWbLlWBXw4oovo1w7ui-JQ1WoyECqMSWdBj6XE,15
14
- sysnet_pyutils-1.0.7.dist-info/RECORD,,