backio 1.0.0__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.
backio-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Asinerum Conlang Project
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
backio-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.4
2
+ Name: backio
3
+ Version: 1.0.0
4
+ Summary: Literp Fundamental IO Lib
5
+ Home-page: https://github.com/asinerum/backio
6
+ Author: Asinerum Conlang Project
7
+ Author-email: asinerum.com@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: embedize>=1.0.4
16
+ Requires-Dist: formatize>=1.0.4
17
+ Requires-Dist: fastapi>=0.122.1
18
+ Requires-Dist: python-jose>=3.5.0
19
+ Requires-Dist: pydantic>=2.12.5
20
+ Dynamic: license-file
21
+
22
+ Detailed tips, tricks, and examples, can be found at project's repository
23
+ https://github.com/asinerum/backio
24
+
25
+ (C) 2026 Asinerum Conlang Project
backio-1.0.0/README.md ADDED
@@ -0,0 +1,4 @@
1
+ Detailed tips, tricks, and examples, can be found at project's repository
2
+ https://github.com/asinerum/backio
3
+
4
+ (C) 2026 Asinerum Conlang Project
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
backio-1.0.0/setup.cfg ADDED
@@ -0,0 +1,34 @@
1
+ [metadata]
2
+ name = backio
3
+ version = 1.0.0
4
+ author = Asinerum Conlang Project
5
+ author_email = asinerum.com@gmail.com
6
+ description = Literp Fundamental IO Lib
7
+ long_description = file: README.md
8
+ long_description_content_type = text/markdown
9
+ url = https://github.com/asinerum/backio
10
+ license = MIT
11
+ classifiers =
12
+ Programming Language :: Python :: 3
13
+ License :: OSI Approved :: MIT License
14
+ Operating System :: OS Independent
15
+
16
+ [options]
17
+ package_dir =
18
+ = src
19
+ packages = find:
20
+ python_requires = >=3.7
21
+ install_requires =
22
+ embedize >= 1.0.4
23
+ formatize >= 1.0.4
24
+ fastapi >= 0.122.1
25
+ python-jose >= 3.5.0
26
+ pydantic >= 2.12.5
27
+
28
+ [options.packages.find]
29
+ where = src
30
+
31
+ [egg_info]
32
+ tag_build =
33
+ tag_date = 0
34
+
@@ -0,0 +1,3 @@
1
+ from .io import *
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,846 @@
1
+ from datetime import datetime, timedelta
2
+ from typing import Optional, Callable
3
+ from jose import JWTError, jwt
4
+ from pydantic import BaseModel
5
+ from fastapi import Response
6
+ import sys, os, json, types
7
+ import inspect
8
+
9
+ from formatize.const import *
10
+
11
+ from formatize.form import\
12
+ ADMIN, ACCOUNTING,\
13
+ APP_PATH, DBA_PATH,\
14
+ PARAMS, EMPTY, SPACE,\
15
+ add_models_from_yaml,\
16
+ add_consts_from_yaml,\
17
+ get_modules_from_yaml,\
18
+ param_load_from_request,\
19
+ data_load_from_json_file,\
20
+ data_load_from_yaml_file,\
21
+ function_module2,\
22
+ function_module,\
23
+ import_module,\
24
+ get_module,\
25
+ load_yaml,\
26
+ dump_yaml,\
27
+ dump_csv,\
28
+ popattr,\
29
+ popfunc,\
30
+ uid,\
31
+ sha,\
32
+ lds,\
33
+ hstr,\
34
+ dicts,\
35
+ integer,\
36
+ default,\
37
+ flatten,\
38
+ extract,\
39
+ to_upper,\
40
+ err_input,\
41
+ is_numeric,\
42
+ str_to_list,\
43
+ check_list,\
44
+ merge_list,\
45
+ data_dict,\
46
+ sort_dict,\
47
+ dict_sort,\
48
+ dict_assign,\
49
+ parse_doc_date,\
50
+ prepare_model,\
51
+ prepare_info,\
52
+ prepare_password,\
53
+ prepare_worktime,\
54
+ prepare_workinterval,\
55
+ prepare_hash_password
56
+
57
+ from embedize import\
58
+ ARRAY,\
59
+ ERROR,\
60
+ RESULT,\
61
+ UNKNOWN,\
62
+ BADZONEID,\
63
+ ERRORINPUT,\
64
+ NOROWCOUNT,\
65
+ DEFPASSWORD,\
66
+ ADMINZONENAME,\
67
+ ADMINUSERNAME,\
68
+ ADMINZONE,\
69
+ ADMINUSER,\
70
+ NOENTRIES,\
71
+ NOBALANCE,\
72
+ COL_ID,\
73
+ COL_UUID,\
74
+ COL_NAME,\
75
+ COL_ZONE,\
76
+ COL_ZADM,\
77
+ COL_PASS,\
78
+ COL_OPWD,\
79
+ COL_NPWD,\
80
+ COL_INFO,\
81
+ COL_ZONEID,\
82
+ COL_ZONEIDN,\
83
+ COL_CONUSER,\
84
+ COL_USERIDN,\
85
+ COL_CREATOR,\
86
+ COL_MODIFIER,\
87
+ COL_CREDIT,\
88
+ COL_DEBIT,\
89
+ COL_DATED,\
90
+ COL_USER,\
91
+ COL_CODE,\
92
+ COL_ACCOUNT,\
93
+ COL_ACCOUNTCODE,\
94
+ duckdb,\
95
+ sqlite3,\
96
+ set_engine,\
97
+ set_connect,\
98
+ connect_duckdb,\
99
+ connect_sqlite,\
100
+ error_unexpect,\
101
+ error_database,\
102
+ dicts_items,\
103
+ dict_result,\
104
+ check_admin,\
105
+ get_zoneid,\
106
+ zonedb,\
107
+ callup,\
108
+ batch,\
109
+ db_exist,\
110
+ first_row,\
111
+ import_zone_database,\
112
+ export_zone_database,\
113
+ export_database_tables,\
114
+ resultset_first_row,\
115
+ resultset_is_empty,\
116
+ select_value,\
117
+ select_dict,\
118
+ select_list,\
119
+ delete_one,\
120
+ insert_one,\
121
+ update_one,\
122
+ delete_many,\
123
+ insert_many,\
124
+ update_many,\
125
+ create_admin_zones,\
126
+ create_admin_users,\
127
+ duck_create_admin_zones,\
128
+ duck_create_admin_users,\
129
+ create_zone_roles,\
130
+ create_zone_specs,\
131
+ create_zone_specroles,\
132
+ create_zone_userroles,\
133
+ create_zone_userspecs,\
134
+ create_zone_groups,\
135
+ create_zone_roots,\
136
+ create_zone_accounts,\
137
+ create_zone_subs,\
138
+ create_zone_items,\
139
+ create_zone_txs,\
140
+ duck_create_zone_roles,\
141
+ duck_create_zone_specs,\
142
+ duck_create_zone_specroles,\
143
+ duck_create_zone_userspecs,\
144
+ duck_create_zone_userroles,\
145
+ duck_create_zone_groups,\
146
+ duck_create_zone_roots,\
147
+ duck_create_zone_accounts,\
148
+ duck_create_zone_subs,\
149
+ duck_create_zone_items,\
150
+ duck_create_zone_txs,\
151
+ multi_holders
152
+
153
+ LIBPATH = 'lib.db.query'
154
+
155
+ ROLE_WORKING = 'User login required'
156
+ ROLE_ADMIN = 'System admin privileges required'
157
+ ROLE_MANAGER = 'Client admin or system moderator or registered user access only'
158
+ ROLE_MODERATOR = 'System moderator privileges required'
159
+ ROLE_ZONE_ADMIN = 'Client admin privileges required'
160
+ ROLE_ZONE_MANAGER = 'Client admin or system moderator privileges required'
161
+ ROLE_ZONE_STAFF = 'Personnel login required'
162
+ ROLE_ADDITIONAL = 'Additional privileges required'
163
+ ROLE_CREATOR = 'Action dedicated for system admin on system zone and system moderator on client zones'
164
+ ROLE_USER = 'Action not authorized'
165
+
166
+ ROLE_FinancialRecordkeeping = 100100
167
+ ROLE_TransactionProcessing = 100150
168
+ ROLE_FinancialReporting = 100200
169
+ ROLE_AccountReconciliation = 100250
170
+ ROLE_TaxCompliance = 100300
171
+ ROLE_BudgetingForecasting = 100350
172
+ ROLE_Auditing = 100400
173
+ ROLE_FinancialAnalysis = 100450
174
+ ROLE_Compliance = 100500
175
+ ROLE_CostManagement = 100550
176
+ ROLE_AccountsPayableReceivable = 100600
177
+ ROLE_PayrollProcessing = 100650
178
+ ROLE_CommunicationCollaboration = 100700
179
+ ROLE_RecordReportReviewing = 100900
180
+
181
+ SPEC_StaffAccountant = 101100
182
+ SPEC_AccountingAssistant = 101150
183
+ SPEC_AccountingClerk = 101200
184
+ SPEC_FinancialAccountant = 101250
185
+ SPEC_TaxAccountant = 101300
186
+ SPEC_AuditAccountant = 101350
187
+ SPEC_ChiefAccountant = 101800
188
+ SPEC_FinancialOfficer = 101850
189
+ SPEC_Reviewer = 101900
190
+
191
+ ## Overrode by IO.YAML config vars
192
+ edata_spec_specs = [SPEC_FinancialOfficer]
193
+ edata_role_specs = [SPEC_ChiefAccountant, SPEC_FinancialOfficer]
194
+ edata_sub_specs = [SPEC_StaffAccountant, SPEC_AccountingClerk, SPEC_FinancialAccountant, SPEC_TaxAccountant, SPEC_ChiefAccountant, SPEC_FinancialOfficer]
195
+ edata_txp_roles = [ROLE_TransactionProcessing]
196
+ edata_frk_roles = [ROLE_FinancialRecordkeeping]
197
+
198
+ ENV_SECRET = 'SECRET_KEY'
199
+ TOKENTYPE = 'token_type'
200
+ TOKEN = 'access_token'
201
+ RTOKEN = 'refresh_token'
202
+ TOKENID = 'sub'
203
+ BEARER = 'Bearer'
204
+ USERNAME = 'user'
205
+ MESSAGE = 'message'
206
+
207
+ ERR_DBASE = 'Database already exists'
208
+ ERR_NODBASE = 'Database does not exist'
209
+ ERR_OLDPASS = 'Incorrect given password'
210
+ ERR_USERNAME = 'Incorrect user name or status'
211
+ ERR_USERPASS = 'Incorrect user login password'
212
+ ERR_VALIDATES = 'Could not validate credentials'
213
+ ERR_AUTHLOGIN = 'Not authorized or login failed'
214
+ ERR_BADZONEID = 'Invalid zone ID'
215
+
216
+ ERR_INPUT = 'Invalid input parameters'
217
+ ERR_FUNCTION = 'App module or function not found'
218
+ ERR_JSONDATA = 'JSON input data processing failed'
219
+ ERR_LOADJSON = 'JSON data loading failed'
220
+ ERR_LOADYAML = 'YAML data loading failed'
221
+
222
+ JAFARG = 'afarg'
223
+ JMODEL = 'model'
224
+ JDFUNC = 'dfunc'
225
+ JDBMOD = 'dbmod'
226
+ JDBQUE = 'dbque'
227
+ JQUEID = 'queid'
228
+
229
+ json_role = lambda module: f'lib/json/{module}/role.json'
230
+ json_account = lambda module: f'lib/json/{module}/account.json'
231
+ yaml_transaction = lambda module: f'lib/yaml/{module}/transaction.yaml'
232
+ yaml_report = lambda module: f'lib/yaml/{module}/report.yaml'
233
+ yaml_rich = lambda module: f'lib/yaml/{module}/rich.yaml'
234
+
235
+ get_userid = lambda params: params.get(COL_USER)
236
+ get_idname = lambda params: params.get(COL_NAME) or params.get(COL_ID)
237
+ get_nameid = lambda params: params.get(COL_ID) or params.get(COL_NAME)
238
+
239
+ pseudo = lambda data: (lambda anything=None: data)
240
+ do_none = lambda access_token=None, param=None, ok=True: (ok, None, None)
241
+
242
+ popthis = lambda attr: popattr(this, attr)
243
+ get_attr = lambda attr: (lambda object: object.get(attr))
244
+
245
+ getfunc = lambda funcname, field, defval=None, finval=None, pop=popthis, module=None: pop(x[funcname].get(field) if type(x:=(y:=module or module_access).get(function_module2(y, funcname))) is dict and funcname in x else defval) or finval
246
+
247
+ get_afunc = lambda funcname, field='afunc', defval=None, finval=None, pop=popthis: getfunc(funcname, field, defval, finval, pop)
248
+ get_pfunc = lambda funcname, defval=get_idname, field='afarg': defval if not (x:=get_afunc(funcname, field=field, pop=hstr)) else (lambda p: p.get(x))
249
+ get_wfunc = lambda funcname, defval=prepare_password: get_afunc(funcname, field='wfunc', finval=defval if defval else prepare_password)
250
+ get_ifunc = lambda funcname, defval=prepare_info: get_afunc(funcname, field='ifunc', finval=defval if defval else prepare_info)
251
+ get_dfunc = lambda funcname, defval=select_dict: get_afunc(funcname, field='dfunc', finval=defval if defval else select_dict)
252
+ get_model = lambda funcname, defval=None, afunc=get_afunc: afunc(funcname, field='model', defval=defval, finval=popthis('DbUni'))
253
+ get_token = lambda funcname, defval=None: get_pfunc(funcname, defval=defval, field='token')
254
+ get_bfunc = lambda funcname, defval=None: get_afunc(funcname, field='bfunc', finval=defval)
255
+ get_rfunc = lambda funcname, defval=None: get_afunc(funcname, field='rfunc', finval=defval)
256
+ get_mfunc = lambda funcname, defval=None: get_afunc(funcname, field='mfunc', finval=defval)
257
+ get_minfo = lambda funcname, defval=None: get_afunc(funcname, field='minfo', finval=defval)
258
+ get_mdele = lambda funcname, defval=None: get_afunc(funcname, field='mdele', finval=defval)
259
+ get_erole = lambda funcname, defval=None: get_afunc(funcname, field='erole', finval=defval)
260
+ get_edata = lambda funcname, defval=None: get_afunc(funcname, field='edata', finval=defval)
261
+ get_build = lambda funcname, defval=None: get_afunc(funcname, field='build', defval=defval, finval=popthis('DbUni'))
262
+ get_query = lambda funcname, querypath, libpath=LIBPATH: popattr(get_module(querypath, path=f'{libpath}.'), funcname)
263
+ get_qpath = lambda funcname, defval=None, field='qpath': get_afunc(funcname, field=field, defval=EMPTY, finval=defval, pop=hstr)
264
+ get_rpath = lambda funcname, defval=None: get_qpath(funcname, defval, field='rpath')
265
+ get_rquid = lambda funcname, defval=None: get_qpath(funcname, defval, field='rquid')
266
+ get_afarg = lambda funcname, defval=None: get_qpath(funcname, defval, field='afarg')
267
+ get_mprep = lambda funcname, defval=None: get_afunc(funcname, field='mprep', finval=defval)
268
+ get_ufunc = lambda funcname, defval=None: get_afunc(funcname, field='ufunc', finval=defval)
269
+ get_cfunc = lambda funcname, defval=None: get_afunc(funcname, field='cfunc', finval=defval)
270
+ get_cemsg = lambda funcname, defval=None: get_afunc(funcname, field='cemsg', finval=defval)
271
+ get_cattr = lambda funcname, defval=None: get_qpath(funcname, defval, field='cattr')
272
+ get_vfunc = lambda funcname, defval=None: get_afunc(funcname, field='vfunc', finval=defval)
273
+ get_vattr = lambda funcname, defval=None: get_qpath(funcname, defval, field='vattr')
274
+
275
+ pick_afunc = lambda funcname, field='afunc', defval=None, finval=None, pop=popthis: getfunc(funcname, field, defval, finval, pop, module=module_dbase)
276
+ pick_dfunc = lambda funcname, defval=select_dict: pick_afunc(funcname, field='dfunc', finval=defval if defval else select_dict)
277
+ pick_qpath = lambda funcname, defval=None, field='qpath': pick_afunc(funcname, field=field, defval=EMPTY, finval=defval, pop=hstr)
278
+ pick_layer = lambda funcname, defval=None: x if (x:=integer(pick_qpath(funcname, defval, field='layer'))) > 0 else defval
279
+ pick_ufunc = lambda funcname, defval=None: pick_afunc(funcname, field='ufunc', finval=defval)
280
+ pick_model = lambda funcname, defval=None: get_model(funcname, defval, afunc=pick_afunc)
281
+ pick_rpath = lambda funcname, defval=None: pick_qpath(funcname, defval, field='rpath')
282
+ pick_rquid = lambda funcname, defval=None: pick_qpath(funcname, defval, field='rquid')
283
+
284
+ check_idname = lambda model, idname: False if not idname else (str(idname) if not is_numeric(idname, int) else str(idname)).strip().lower() in [str(model.id).lower(), str(model.name).lower()]
285
+ check_nameid = lambda obj, idname: False if not idname else (str(idname) if not is_numeric(idname, int) else str(idname)).strip().lower() in [str(obj.get('name')).lower(),str(obj.get('id')).lower()]
286
+ check_nameids = lambda obj, idnames: False if type(idnames) is not list else check_list([str(x).lower() for x in idnames], [str(obj.get('name')).lower(),str(obj.get('id')).lower()])
287
+ check_idnames = lambda lst, idnames: False if type(idnames) is not list else check_list([str(x).strip().lower() for x in idnames], [str(x).strip().lower() for x in lst])
288
+
289
+ get_yaml_querid = lambda module, querid: data_load_from_yaml_file(yaml_rich(module))[PARAMS].get(querid)
290
+ get_rich_query = lambda params, que='querid', mod='module': '' if not (mod:=params.get(mod)) or not (que:=params.get(que)) else get_yaml_querid(mod,que)
291
+ get_rich_retquery = lambda params, que='requerid', mod='module': get_rich_query(params, que, mod)
292
+
293
+ def access_function(caller: str, model: BaseModel=None, dfunc: Callable=None, layer=5, access=True) -> tuple:
294
+ model = model or get_model(caller) if access else pick_model(caller)
295
+ dfunc = dfunc or get_dfunc(caller) if access else pick_dfunc(caller)
296
+ query = get_query(caller, get_qpath(caller) if access else pick_qpath(caller))
297
+ retquery = get_query(get_rquid(caller), get_rpath(caller)) if access else get_query(pick_rquid(caller), pick_rpath(caller))
298
+ dbfunc = lambda modelval, zoneid=None, query=query: dfunc(query=query, retquery=retquery, model=modelval, db_path=zonedb(zoneid), layer=layer)
299
+ valid = model and dfunc and query and True
300
+ return dbfunc, valid, query
301
+
302
+ def dbase_function(caller: str, model: BaseModel=None, dfunc: Callable=None, layer=5) -> tuple:
303
+ return access_function(caller=caller, model=model, dfunc=dfunc, layer=layer, access=False)
304
+
305
+ def access_function0(*a, **kw):
306
+ f, v, q = access_function(*a, **kw)
307
+ return f if v else None
308
+
309
+ def dbase_function0(*a, **kw):
310
+ f, v, q = dbase_function(*a, **kw)
311
+ return f if v else None
312
+
313
+ """ Usage
314
+ def select_system_moderator(model, zoneid=None):
315
+ f, v, q = dbase_function(callup(1), layer=4)
316
+ return f(model, zoneid) if v else None
317
+ select_system_moderator(DbUser(name='admin'))
318
+ """
319
+
320
+ def create_module(name: str):
321
+ new_module = types.ModuleType(name)
322
+ sys.modules[name] = new_module
323
+ return sys.modules[name]
324
+
325
+ def create_dbase_functions(moduledict: dict):
326
+ for item in moduledict:
327
+ exec(
328
+ f'''def {item} (model=[], zoneid=None, layer={pick_layer(item) or 4}):
329
+ f, v, q = dbase_function(callup(1), layer=layer)
330
+ return f(model, zoneid) if v else None''',
331
+ globals())
332
+
333
+ dbexist = lambda zoneid=0: db_exist(zonedb(zoneid))
334
+ errnodb = lambda: error_database(ERR_NODBASE)
335
+ errdb = lambda: error_database(ERR_DBASE)
336
+
337
+ genesis_zone = lambda: DbZone(**{'id':ADMINZONE, 'name':ADMINZONENAME, 'active':True})
338
+ genesis_user = lambda adminpass=DEFPASSWORD: DbUser(**{'zone':ADMINZONE, 'name':ADMINUSERNAME, 'hpwd':prepare_hash_password(adminpass), 'active':True, 'zadmin':True, 'creator':None})
339
+ adminzone = lambda zone: str(zone).strip().upper() in [str(ADMINZONE), str(ADMINZONENAME)]
340
+
341
+ base_origins = lambda base, ports: [base]+[base+':'+str(x) for x in ports] if type(base) is not list else base+[y+':'+str(x) for x in ports for y in base]
342
+ checkonly = lambda params={}: params.get('checkonly')
343
+ je = lambda data: data.get(ERROR)
344
+
345
+ load_data = lambda jsonfile: data_load_from_json_file(jsonfile)
346
+ get_roles = lambda module, data: data[PARAMS]['modules'][module]['roles']
347
+ get_specs = lambda module, data: data[PARAMS]['modules'][module]['specs']
348
+
349
+ get_groups = lambda module, data: data[PARAMS]['modules'][module]['accounts']
350
+ get_accounts = lambda groupcode, groups: groups[groupcode]['data']
351
+
352
+ group_roots = lambda groupcode, groups: [{'id': x['id'], 'grup': groups[groupcode]['id'], 'code': str(x['code']) if x['code'] else str(x['id']), 'name': x['name'], 'note': x['note'], 'active': x['active']} for x in get_accounts(groupcode, groups)]
353
+ root_accounts = lambda groupcode, groups: [{'id': x['id'], 'root': x['id'], 'code': str(x['code']) if x['code'] else str(x['id']), 'name': x['name'], 'note': x['note'], 'subs': [{'id': y['id'], 'root': x['id'], 'code': y['code'] if y['code'] else str(y['id']), 'name': y['name'], 'note': y['note'], 'active': y['active']} for y in x['subs']], 'active': x['active']} for x in get_accounts(groupcode, groups)]
354
+ code_accounts = lambda groupcode, groups: flatten([row['subs'] if row['subs'] else [{'id': row['id'], 'root': row['id'], 'code': str(row['id']), 'name': row['name'], 'note': row['note'], 'active': row['active']}] for row in root_accounts(groupcode, groups)])
355
+
356
+ groups_scalar_data = lambda groups: [{'id':groups[x]['id'], 'code':x, 'name':groups[x]['name']} for x in groups]
357
+ roots_scalar_data = lambda groups: flatten([group_roots(x, groups) for x in groups])
358
+ accounts_scalar_data = lambda groups: flatten([code_accounts(x, groups) for x in groups])
359
+
360
+ check_user_at_spec = lambda user, spec, zoneid: not resultset_is_empty(select_userspec(DbUserspec(user=user, spec=spec), zoneid))
361
+ check_user_at_role = lambda user, role, zoneid: not resultset_is_empty(select_userrole(DbUserrole(user=user, role=role), zoneid))
362
+ check_user_of_specs = lambda user, specs, zoneid: check_list(select_user_specs(DbUserspec(user=user), zoneid)[RESULT], specs)
363
+ check_user_of_roles = lambda user, roles, zoneid: check_list(select_user_roles(DbUserrole(user=user), zoneid)[RESULT], roles)
364
+
365
+ under_specs = lambda user, specs: user.active and check_user_of_specs(user.id, specs, user.zone)
366
+ under_roles = lambda user, roles: user.active and check_user_of_roles(user.id, roles, user.zone)
367
+ granted_specs = lambda user, spec: user.active and check_user_at_spec(user.id, spec, user.zone)
368
+ granted_roles = lambda user, role: user.active and check_user_at_role(user.id, role, user.zone)
369
+
370
+ is_under_specs = under_specs
371
+ is_under_roles = under_roles
372
+ is_granted_specs = granted_specs
373
+ is_granted_roles = granted_roles
374
+
375
+ MODULE = ACCOUNTING
376
+ JSON_ROLE = json_role(MODULE)
377
+ JSON_ACCOUNT = json_account(MODULE)
378
+ YAML_TRANSACTION = yaml_transaction(MODULE)
379
+ YAML_REPORT = yaml_report(MODULE)
380
+ YAML_RICH = yaml_rich(MODULE)
381
+
382
+ load_roles = lambda: load_data(JSON_ROLE)
383
+ load_accounts = lambda: load_data(JSON_ACCOUNT)
384
+
385
+ roles_lst = lambda json=None: get_roles(MODULE, json if json else load_roles())
386
+ specs_lst = lambda json=None: get_specs(MODULE, json if json else load_roles())
387
+ roles_specs_lst = lambda json=None: [roles_lst(json), specs_lst(json)]
388
+
389
+ specs_inc_roles = lambda data=None: [{'spec': s['id'], 'roles': s['roles']} for s in (data if data else roles_specs_lst())[1]]
390
+ specs_roles_cls = lambda data=None: [DbSpecrole(spec=x['spec'], role=y) for x in specs_inc_roles(data) for y in x['roles']]
391
+
392
+ roles_cls = lambda data=None: [DbRole(**r) for r in (data if data else roles_specs_lst())[0]]
393
+ specs_cls = lambda data=None: [DbSpec(**s) for s in (data if data else roles_specs_lst())[1]]
394
+ roles_specs_cls = lambda data=None: (roles_cls(data), specs_cls(data))
395
+
396
+ role_and_spec_models = roles_specs_cls
397
+ specrole_pair_models = specs_roles_cls
398
+
399
+ account_groups = lambda: get_groups(MODULE, load_accounts())
400
+
401
+ groups_data = lambda: groups_scalar_data(account_groups())
402
+ roots_data = lambda: roots_scalar_data(account_groups())
403
+ accounts_data = lambda: accounts_scalar_data(account_groups())
404
+
405
+ account_group_models = lambda: [DbGroup(**r) for r in groups_data()]
406
+ accounts_root_models = lambda: [DbRoot(**r) for r in roots_data()]
407
+ plain_account_models = lambda: [DbAccount(**r) for r in accounts_data()]
408
+
409
+ dicts_userspecs = lambda us: [{'user': us.user, 'spec': x} for x in us.specs]
410
+ dicts_userroles = lambda ur: [{'user': ur.user, 'role': x} for x in ur.roles]
411
+
412
+ execmany_uni_model = lambda model, BuildModel: prepare_model(model, BuildModel, DbUni)
413
+ execmany_userspec_model = lambda model: DbUni(user=model.user, array=dicts_userspecs(model))
414
+ execmany_userrole_model = lambda model: DbUni(user=model.user, array=dicts_userroles(model))
415
+ execmany_accountitem_model = lambda model: DbUni(array=dicts_items(model))
416
+
417
+ dicts_specs = lambda specs: prepare_model(dicts(specs), DbSpec, DbUni)
418
+ dicts_roles = lambda roles: prepare_model(dicts(roles), DbRole, DbUni)
419
+ dicts_specroles = lambda specroles: prepare_model(dicts(specroles), DbSpecrole, DbUni)
420
+ dicts_accounts = lambda accounts: prepare_model(dicts(accounts), DbAccount, DbUni)
421
+ dicts_groups = lambda groups: prepare_model(dicts(groups), DbGroup, DbUni)
422
+ dicts_roots = lambda roots: prepare_model(dicts(roots), DbRoot, DbUni)
423
+
424
+ ## INIT BEGIN
425
+
426
+ try:
427
+ this = sys.modules[__name__]
428
+ add_models_from_yaml(this)
429
+ add_consts_from_yaml(this)
430
+ add_consts_from_yaml(this, 'dbase.yaml') ## module_dbase
431
+ add_consts_from_yaml(this, 'access.yaml') ## module_access
432
+ create_dbase_functions(module_dbase[ADMIN])
433
+ create_dbase_functions(module_dbase[ACCOUNTING])
434
+ app_consts = data_load_from_yaml_file()[PARAMS]
435
+ except:
436
+ print('Literp environment required, program exits')
437
+ sys.exit()
438
+
439
+ ## INIT END
440
+
441
+ token_expire_minutes = app_consts.setdefault('token_expire_minutes', token_expire_minutes)
442
+ NOINIT = app_consts.get('NOINIT')
443
+
444
+ login_user = select_check_login_user
445
+ working_login_user = select_working_login_user
446
+ system_moderator = select_system_moderator
447
+ system_admin = select_system_admin
448
+ zone_admin = select_zone_admin
449
+ zone_admin_or_very_user = select_zone_admin_or_very_user
450
+ system_moderator_or_zone_admin = select_system_moderator_or_zone_admin
451
+ system_moderator_or_zone_admin_or_very_user = select_system_moderator_or_zone_admin_or_very_user
452
+
453
+ ## BASIC IO
454
+
455
+ def dump_database_tables(zoneidn: str, access_token: str) -> dict:
456
+ ok, x, x = user_is_zone_admin(access_token, zoneidn)
457
+ if not ok: return error_unexpect(f'EXPORT TABLES: {ROLE_ZONE_ADMIN}')
458
+ return export_database_tables(zoneidn)
459
+
460
+ def dump_zone_database(zoneidn: str, table: str, access_token: str, idr: list=[]) -> dict:
461
+ ok, x, x = user_is_zone_admin(access_token, zoneidn)
462
+ if not ok: return error_unexpect(f'EXPORT DATABASE: {ROLE_ZONE_ADMIN}')
463
+ return export_zone_database(zoneidn, table, idr=idr)
464
+
465
+ def load_zone_database(csvdata: str, zoneidn: str, table: str, access_token: str) -> dict:
466
+ ok, x, x = user_is_zone_admin(access_token, zoneidn)
467
+ if not ok: return error_unexpect(f'IMPORT DATABASE: {ROLE_ZONE_ADMIN}')
468
+ return import_zone_database(zoneidn, table, {'data': csvdata})
469
+
470
+ def init_admin_database(adminpass: str=DEFPASSWORD) -> dict:
471
+ if NOINIT: return error_unexpect('NOINIT flag is set', 'Install')
472
+ task = batch([create_admin_zones, create_admin_users])
473
+ if je(task): return task
474
+ owner = insert_zone(genesis_zone())
475
+ if je(owner): return owner
476
+ admin = insert_user(genesis_user(adminpass))
477
+ if je(admin): return admin
478
+ return dict_result([{'Zone':owner, 'User':admin}])
479
+
480
+ def init_zone_database(zoneid: int, access_token: str) -> dict:
481
+ ok, x, x = user_is_system_admin(access_token)
482
+ if not ok: return error_unexpect(f'INSTALL CLIENT DATABASE: {ROLE_ADMIN}')
483
+ if get_zoneid(zoneid) in [ADMINZONE, None]: return error_database(ERR_INPUT)
484
+ if client_port_not_allowed(zoneid): return error_database(ERR_BADZONEID)
485
+ task = batch([
486
+ create_zone_roles,
487
+ create_zone_specs,
488
+ create_zone_specroles,
489
+ create_zone_userspecs,
490
+ create_zone_userroles,
491
+ create_zone_groups,
492
+ create_zone_roots,
493
+ create_zone_accounts,
494
+ create_zone_subs,
495
+ create_zone_items,
496
+ create_zone_txs,
497
+ ], zonedb(zoneid))
498
+ if je(task): return task
499
+ return dict_result([{}])
500
+
501
+ def init_accounting_database(zoneid: int, access_token: str) -> dict:
502
+ ok, x, x = user_is_system_admin(access_token)
503
+ if not ok: return error_unexpect(f'INSTALL MODULE DATABASE: {ROLE_ADMIN}')
504
+ if get_zoneid(zoneid) in [ADMINZONE, None]: return error_database(ERR_INPUT)
505
+ if not dbexist(zoneid): return errnodb()
506
+ roles, specs = role_and_spec_models()
507
+ specroles = specrole_pair_models()
508
+ groups = account_group_models()
509
+ roots = accounts_root_models()
510
+ accounts = plain_account_models()
511
+ task = insert_zone_roles(dicts_roles(roles), zoneid)
512
+ if je(task): return task
513
+ task = insert_zone_specs(dicts_specs(specs), zoneid)
514
+ if je(task): return task
515
+ task = insert_zone_specroles(dicts_specroles(specroles), zoneid)
516
+ if je(task): return task
517
+ task = insert_zone_groups(dicts_groups(groups), zoneid)
518
+ if je(task): return task
519
+ task = insert_zone_roots(dicts_roots(roots), zoneid)
520
+ if je(task): return task
521
+ task = insert_zone_accounts(dicts_accounts(accounts), zoneid)
522
+ if je(task): return task
523
+ return dict_result([{}])
524
+
525
+ ## CREDENTIALS
526
+
527
+ def user_under_specs(access_token: str, specs: list) -> bool:
528
+ user = get_current_user(access_token)
529
+ return under_specs(user, specs)
530
+
531
+ def user_under_roles(access_token: str, roles: list) -> bool:
532
+ user = get_current_user(access_token)
533
+ return under_roles(user, roles)
534
+
535
+ def user_granted_spec(access_token: str, spec: int) -> bool:
536
+ user = get_current_user(access_token)
537
+ return granted_specs(user, spec)
538
+
539
+ def user_granted_role(access_token: str, role: int) -> bool:
540
+ user = get_current_user(access_token)
541
+ return granted_roles(user, role)
542
+
543
+ def user_is_under_specs(access_token: str, specs: list) -> (bool, int, int):
544
+ user = get_current_user(access_token)
545
+ return under_specs(user, specs), user.id, user.zone
546
+
547
+ def user_is_under_roles(access_token: str, roles: list) -> (bool, int, int):
548
+ user = get_current_user(access_token)
549
+ return under_roles(user, roles), user.id, user.zone
550
+
551
+ def user_is_working(access_token: str, addict=None) -> (bool, int, int):
552
+ user = get_current_user(access_token)
553
+ return user.found, user.id, user.zone
554
+
555
+ def user_is_system_admin(access_token: str, addict=None) -> (bool, int, int):
556
+ user = get_current_user(access_token, system_admin)
557
+ return user.found, user.id, user.zone
558
+
559
+ def user_is_system_moderator(access_token: str, addict=None) -> (bool, int, int):
560
+ user = get_current_user(access_token, system_moderator)
561
+ return user.found, user.id, user.zone
562
+
563
+ def user_is_zone_admin(access_token: str, zoneidn: str) -> (bool, int, int):
564
+ user = get_current_user(access_token, zone_admin, {COL_ZONEIDN: zoneidn, COL_CONUSER: None})
565
+ return user.found, user.id, user.zoneidn
566
+
567
+ def user_is_ones_admin(access_token: str, conuser: str) -> (bool, int, int):
568
+ user = get_current_user(access_token, zone_admin, {COL_CONUSER: conuser, COL_ZONEIDN: None})
569
+ return user.found, user.id, user.zoneidn
570
+
571
+ user_is_zone_admin_of = user_is_ones_admin
572
+
573
+ def user_is_zone_manager(access_token: str, zoneidn: str) -> (bool, int, int):
574
+ user = get_current_user(access_token, system_moderator_or_zone_admin, {COL_ZONEIDN: zoneidn, COL_CONUSER: None})
575
+ return user.found, user.id, user.zoneidn
576
+
577
+ def user_is_ones_manager(access_token: str, conuser: str) -> (bool, int, int):
578
+ user = get_current_user(access_token, system_moderator_or_zone_admin, {COL_CONUSER: conuser, COL_ZONEIDN: None})
579
+ return user.found, user.id, user.zoneidn
580
+
581
+ user_is_zone_manager_of = user_is_ones_manager
582
+
583
+ def user_can_controll(access_token: str, useridn: str) -> (bool, int, int):
584
+ user = get_current_user(access_token, zone_admin_or_very_user, {COL_USERIDN: useridn, COL_ZONEIDN: None})
585
+ return user.found, user.id, user.zoneidn
586
+
587
+ def user_can_access(access_token: str, useridn: str) -> (bool, int, int):
588
+ user = get_current_user(access_token, system_moderator_or_zone_admin_or_very_user, {COL_USERIDN: useridn, COL_ZONEIDN: None})
589
+ return user.found, user.id, user.zoneidn
590
+
591
+ ## Derivatives
592
+ def user_is_zone_creator(access_token: str, zoneidn: str) -> (bool, int, int):
593
+ return user_is_system_admin(access_token) if adminzone(zoneidn) else user_is_system_moderator(access_token)
594
+
595
+ def self_is_admin(access_token: str, addict=None) -> (bool, int, int):
596
+ user = get_current_user(access_token)
597
+ return user.zadmin, user.id, user.zoneidn
598
+
599
+ def self_is_manager(access_token: str, addict=None) -> (bool, int, int):
600
+ user = get_current_user(access_token)
601
+ return (user.zadmin or user.zone==ADMINZONE), user.id, user.zoneidn
602
+
603
+ def self_is_creator(access_token: str, addict=None) -> (bool, int, int):
604
+ user = get_current_user(access_token)
605
+ return (user.zone==ADMINZONE), user.id, user.zoneidn
606
+
607
+ ## ACTIONS
608
+
609
+ def check_login(hpwd: str, idname: str) -> (bool, int, int):
610
+ data = first_row(login_user(DbUser(id=integer(idname), name=idname, hpwd=hpwd)))
611
+ return (True, data[COL_ID], data[COL_ZONE]) if data else (False, None, None)
612
+
613
+ def get_user(model: DbUser, task: Callable=working_login_user, addict: dict={}) -> dict:
614
+ if addict:
615
+ model = model.model_dump()
616
+ model.update(addict)
617
+ model = DbUser(**model)
618
+ return first_row(task(model))
619
+
620
+ def get_current_user(access_token: str, task: Callable=working_login_user, addict: dict={}) -> User:
621
+ credentials_exception = User(name=ERR_VALIDATES)
622
+ other_fatal_exception = User(name=ERR_AUTHLOGIN)
623
+ try:
624
+ payload = jwt.decode(access_token, os.environ[ENV_SECRET], algorithms=[token_crypto_algorithm])
625
+ username = payload.get(TOKENID)
626
+ if not username:
627
+ return credentials_exception
628
+ user = get_user(DbUser(name=username), task, addict)
629
+ if not user:
630
+ return credentials_exception
631
+ user = User(**user)
632
+ user.found = True
633
+ return user
634
+ except JWTError:
635
+ return credentials_exception
636
+ except Exception:
637
+ return other_fatal_exception
638
+
639
+ def authenticate_user(username: str, md5_password: str) -> dict:
640
+ user = get_user(DbUser(name=username))
641
+ if not user:
642
+ return {ERROR: ERR_USERNAME}
643
+ if not verify_password(md5_password, user[COL_PASS]):
644
+ return {ERROR: ERR_USERPASS}
645
+ return user
646
+
647
+ def verify_password(md5_password: str, sha256_password: str) -> bool:
648
+ return sha(md5_password)==sha256_password
649
+
650
+ def create_access_token(data: dict, expires_delta: Optional[timedelta]=None, algorithm: str=token_crypto_algorithm, expire_minutes: int=token_expire_minutes) -> str:
651
+ to_encode = data.copy()
652
+ if expires_delta:
653
+ expire = datetime.utcnow() + expires_delta
654
+ else:
655
+ expire = datetime.utcnow() + timedelta(minutes=expire_minutes)
656
+ to_encode['exp'] = expire
657
+ return jwt.encode(to_encode, os.environ[ENV_SECRET], algorithm=algorithm)
658
+
659
+ def login(username: str, md5_password: str) -> Token.model_dump:
660
+ user = authenticate_user(username, md5_password)
661
+ if user.get(ERROR):
662
+ return {TOKEN: ERROR, TOKENTYPE: user[ERROR]}
663
+ access_token_expires = timedelta(minutes=token_expire_minutes)
664
+ access_token = create_access_token(
665
+ data={TOKENID: user[COL_NAME]},
666
+ expires_delta=access_token_expires,
667
+ algorithm=token_crypto_algorithm,
668
+ expire_minutes=token_expire_minutes)
669
+ return Token(user=user[COL_NAME], id=user[COL_ID], zone=user[COL_ZONE], zadmin=user[COL_ZADM], access_token=access_token, token_type=BEARER).model_dump()
670
+
671
+ ## MISC
672
+
673
+ def http_allowed_origins(url: str=cors_base_url) -> list:
674
+ zones = existing_zones_list()
675
+ addrs = base_origins(url, zones)
676
+ olist = merge_list(addrs, cors_allowed_origins())
677
+ lanbase = app_consts.get('cors_lan_url')
678
+ wanbase = app_consts.get('cors_wan_url')
679
+ lanbases = [] if not lanbase else base_origins(lanbase, zones)
680
+ wanbases = [] if not wanbase else base_origins(wanbase, zones)
681
+ return merge_list(olist, lanbases+wanbases)
682
+
683
+ def existing_zones_list() -> list:
684
+ defzones = [port_for_admin, port_for_api]
685
+ extzones = select_all_zone_ids()
686
+ if resultset_is_empty(extzones): return defzones
687
+ return merge_list(defzones, extzones[RESULT])
688
+
689
+ def get_params(jsondata: str) -> dict:
690
+ if je(data:=param_load_from_request(jsondata)): raise ValueError(ERR_JSONDATA)
691
+ return data[PARAMS]
692
+
693
+ ## API BASIS
694
+
695
+ def hello() -> dict:
696
+ return {MESSAGE: 'cool' if dbexist() else 'poor'}
697
+
698
+ def hello_zone(zoneid: int) -> dict:
699
+ return {MESSAGE: 'great' if dbexist(zoneid) else 'sucks'}
700
+
701
+ def what_module(modules: dict, funcname: str) -> dict:
702
+ return {MESSAGE: function_module(modules, funcname)}
703
+
704
+ def do_login(username: str, md5_password: str, response: Response) -> Token:
705
+ res = login(username, md5_password)
706
+ response.set_cookie(key=TOKEN, value=res[TOKEN])
707
+ return res
708
+
709
+ def do_logout(response: Response) -> dict:
710
+ response.set_cookie(key=TOKEN, value='', expires=0)
711
+ return {MESSAGE: 'You are logged out'}
712
+
713
+ ## API IO
714
+
715
+ def set_afunc(funcname: str, value: any, field: str='edata') -> bool:
716
+ module = function_module2(module_access, funcname)
717
+ if not module: return False
718
+ dict_assign(module_access, f'{module}.{funcname}.{field}', value=value, add=True)
719
+ return True
720
+
721
+ def update_afunc(field: str='edata') -> dict:
722
+ data = load_yaml(f'{field}.yaml')[field]
723
+ for f in data: set_afunc(f, data[f][field], field)
724
+ return module_access
725
+
726
+ def sort_module_access():
727
+ modules = app_consts.get('modules')
728
+ for module in modules: dict_sort(module_access, module)
729
+
730
+ ## DB BASIS
731
+
732
+ def wrapvals(model: DbTxs) -> list:
733
+ data = model.data ## [model] list
734
+ if (count:=len(data))<2: return False
735
+ vals = []
736
+ for i in range (count):
737
+ data[i].uuid = model.uuid if i==0 else uid()
738
+ data[i].tx = model.uuid
739
+ data[i].dated = model.dated
740
+ data[i].creator = model.creator
741
+ vals.append(data[i])
742
+ valdicts = dicts(vals) ## [{}] list
743
+ if lds(valdicts, COL_DEBIT) != lds(valdicts, COL_CREDIT): return None
744
+ return vals ## [model] list
745
+
746
+ def wraptx(model: DbTxs) -> dict:
747
+ vals = wrapvals(model)
748
+ if vals is False: raise(Exception(NOENTRIES))
749
+ if vals is None: raise(Exception(NOBALANCE))
750
+ model = DbUni(array=dicts(vals))
751
+ return model
752
+
753
+ def bind_values(query: str, modelval: DbUni(), vfunc: Callable, vattr: str, sfunc: Callable=str_to_list, outdict: bool=False) -> tuple:
754
+ values = sfunc(getattr(modelval, vattr))
755
+ query = vfunc(query, values)
756
+ return {'query': query, 'values': values} if outdict else (query, values)
757
+
758
+ ## HTTP
759
+
760
+ def reload_edata(edata: dict=EDATA):
761
+ for e in edata:
762
+ globals()[e] = EDATA[e]
763
+ setattr(this, e, EDATA[e])
764
+
765
+ def prepare_inputs(params: dict, passfunc: Callable=prepare_password) -> dict:
766
+ passfunc(params, COL_PASS)
767
+ passfunc(params, COL_OPWD)
768
+ passfunc(params, COL_NPWD)
769
+ return params
770
+
771
+ def prepare_params(params: dict, userid: int, quelibid: str=None, dbfuncid: str=None, modelid: str=None, moduleid: str=None, InfoModel: DbUni=None, infofunc: Callable=prepare_info) -> dict:
772
+ params[COL_CREATOR] = userid
773
+ params[COL_MODIFIER] = userid
774
+ if modelid: params[JMODEL] = modelid
775
+ if moduleid: params[JDBMOD] = moduleid
776
+ if quelibid: params[JDBQUE] = quelibid
777
+ if dbfuncid: params[JDFUNC] = dbfuncid
778
+ params['query'] = get_rich_query(params)
779
+ params['retquery'] = get_rich_retquery(params)
780
+ params[COL_DATED] = parse_doc_date(params.get(COL_DATED))
781
+ if infofunc and InfoModel: infofunc(params, COL_INFO, InfoModel)
782
+ return params
783
+
784
+ def prepare_param_array(params: dict, userid: int) -> dict:
785
+ if params.get(ARRAY):
786
+ params[ARRAY] = [prepare_params(x, userid) for x in params[ARRAY]]
787
+ return params
788
+
789
+ def prepare_jsondata(jsondata: str, back: bool=False, layer: int=3, jafarg: any=None):
790
+ params = get_params(jsondata)
791
+ default(params, JAFARG, jafarg)
792
+ default(params, JMODEL, 'DbUni')
793
+ default(params, JDBQUE, 'select')
794
+ default(params, JDBMOD, 'accounting')
795
+ default(params, JDFUNC, 'select_dict')
796
+ default(params, JQUEID, callup(layer))
797
+ default(params, COL_UUID, uid())
798
+ if not back: return params
799
+ return json.dumps(params)
800
+
801
+ def appdb(
802
+ access_token,
803
+ jsondata: str,
804
+ modelid: str='DbUni',
805
+ InfoModel: any=None,
806
+ DelModel: any=None,
807
+ pwdfunc: Callable=None,
808
+ prefunc: Callable=None,
809
+ delfunc: Callable=None,
810
+ parfunc: Callable=get_idname,
811
+ errfunc: Callable=error_unexpect,
812
+ caller: str=None) -> dict: ## QueryIdName
813
+ if not caller: caller = callup() ## FName
814
+ model = get_model(caller, defval=modelid)
815
+ afunc = get_afunc(caller, finval=do_none)
816
+ erole = get_erole(caller)
817
+ edata = get_edata(caller)
818
+ qpath = get_qpath(caller)
819
+ dfunc = get_dfunc(caller)
820
+ build = get_build(caller)
821
+ mfunc = get_mfunc(caller)
822
+ dbfunc, valid, query = access_function(caller, model, dfunc)
823
+ if not valid: return errfunc(f'{ERR_FUNCTION}: {caller}')
824
+ pwdfunc = get_wfunc(caller, defval=pwdfunc)
825
+ prefunc = get_ifunc(caller, defval=prefunc)
826
+ parfunc = get_pfunc(caller, defval=parfunc)
827
+ delfunc = get_bfunc(caller, defval=delfunc)
828
+ DelModel = get_mdele(caller, defval=DelModel)
829
+ InfoModel = get_minfo(caller, defval=InfoModel)
830
+ access_token = get_token(caller, defval=access_token)
831
+ prepare_inputs(params:=prepare_jsondata(jsondata), passfunc=pwdfunc or prepare_password)
832
+ ok, userid, zoneid = afunc(access_token if not callable(access_token) else access_token(params), edata or (parfunc(params) if parfunc else None))
833
+ if not ok: return errfunc(f'{this.MSG.get(caller) or to_upper(caller)}: {erole}{SPACE+str(edata) if edata else ""}')
834
+ if checkonly(params): return dict_result([{}])
835
+ prepare_params(params, userid, InfoModel=InfoModel, infofunc=prefunc)
836
+ prepare_param_array(params, userid) ## prepare for ExecuteMany data action
837
+ if (bad:=get_cfunc(caller)) and bad(params.get(get_cattr(caller))): return errfunc(get_cemsg(caller))
838
+ if delfunc and DelModel: delfunc(DelModel(name=get_idname(params)), zoneid)
839
+ if mfunc: return dbfunc(mfunc(params.get(ARRAY), build, DbUni), zoneid)
840
+ values = model(**params)
841
+ if up:=get_ufunc(caller): up(values)
842
+ if pm:=get_mprep(caller): values = pm(values)
843
+ query, values = bind_values(query, values, vfunc, get_vattr(caller)) if (vfunc:=get_vfunc(caller)) else (query, values)
844
+ return dbfunc(values, zoneid, query=query)
845
+
846
+ reload_edata()
@@ -0,0 +1,25 @@
1
+ Metadata-Version: 2.4
2
+ Name: backio
3
+ Version: 1.0.0
4
+ Summary: Literp Fundamental IO Lib
5
+ Home-page: https://github.com/asinerum/backio
6
+ Author: Asinerum Conlang Project
7
+ Author-email: asinerum.com@gmail.com
8
+ License: MIT
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.7
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: embedize>=1.0.4
16
+ Requires-Dist: formatize>=1.0.4
17
+ Requires-Dist: fastapi>=0.122.1
18
+ Requires-Dist: python-jose>=3.5.0
19
+ Requires-Dist: pydantic>=2.12.5
20
+ Dynamic: license-file
21
+
22
+ Detailed tips, tricks, and examples, can be found at project's repository
23
+ https://github.com/asinerum/backio
24
+
25
+ (C) 2026 Asinerum Conlang Project
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.cfg
5
+ src/backio/__init__.py
6
+ src/backio/io.py
7
+ src/backio.egg-info/PKG-INFO
8
+ src/backio.egg-info/SOURCES.txt
9
+ src/backio.egg-info/dependency_links.txt
10
+ src/backio.egg-info/requires.txt
11
+ src/backio.egg-info/top_level.txt
@@ -0,0 +1,5 @@
1
+ embedize>=1.0.4
2
+ formatize>=1.0.4
3
+ fastapi>=0.122.1
4
+ python-jose>=3.5.0
5
+ pydantic>=2.12.5
@@ -0,0 +1 @@
1
+ backio