tdrpa.tdworker 1.2.13.2__py312-none-win_amd64.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.
- tdrpa/_tdxlwings/__init__.py +193 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/__init__.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_win32patch.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/_xlwindows.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/apps.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/base_classes.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/com_server.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/constants.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/expansion.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/main.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/udfs.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-311.pyc +0 -0
- tdrpa/_tdxlwings/__pycache__/utils.cpython-38.pyc +0 -0
- tdrpa/_tdxlwings/_win32patch.py +90 -0
- tdrpa/_tdxlwings/_xlmac.py +2240 -0
- tdrpa/_tdxlwings/_xlwindows.py +2518 -0
- tdrpa/_tdxlwings/addin/Dictionary.cls +474 -0
- tdrpa/_tdxlwings/addin/IWebAuthenticator.cls +71 -0
- tdrpa/_tdxlwings/addin/WebClient.cls +772 -0
- tdrpa/_tdxlwings/addin/WebHelpers.bas +3203 -0
- tdrpa/_tdxlwings/addin/WebRequest.cls +875 -0
- tdrpa/_tdxlwings/addin/WebResponse.cls +453 -0
- tdrpa/_tdxlwings/addin/xlwings.xlam +0 -0
- tdrpa/_tdxlwings/apps.py +35 -0
- tdrpa/_tdxlwings/base_classes.py +1092 -0
- tdrpa/_tdxlwings/cli.py +1306 -0
- tdrpa/_tdxlwings/com_server.py +385 -0
- tdrpa/_tdxlwings/constants.py +3080 -0
- tdrpa/_tdxlwings/conversion/__init__.py +103 -0
- tdrpa/_tdxlwings/conversion/framework.py +147 -0
- tdrpa/_tdxlwings/conversion/numpy_conv.py +34 -0
- tdrpa/_tdxlwings/conversion/pandas_conv.py +184 -0
- tdrpa/_tdxlwings/conversion/standard.py +321 -0
- tdrpa/_tdxlwings/expansion.py +83 -0
- tdrpa/_tdxlwings/ext/__init__.py +3 -0
- tdrpa/_tdxlwings/ext/sql.py +73 -0
- tdrpa/_tdxlwings/html/xlwings-alert.html +71 -0
- tdrpa/_tdxlwings/js/xlwings.js +577 -0
- tdrpa/_tdxlwings/js/xlwings.ts +729 -0
- tdrpa/_tdxlwings/mac_dict.py +6399 -0
- tdrpa/_tdxlwings/main.py +5205 -0
- tdrpa/_tdxlwings/mistune/__init__.py +63 -0
- tdrpa/_tdxlwings/mistune/block_parser.py +366 -0
- tdrpa/_tdxlwings/mistune/inline_parser.py +216 -0
- tdrpa/_tdxlwings/mistune/markdown.py +84 -0
- tdrpa/_tdxlwings/mistune/renderers.py +220 -0
- tdrpa/_tdxlwings/mistune/scanner.py +121 -0
- tdrpa/_tdxlwings/mistune/util.py +41 -0
- tdrpa/_tdxlwings/pro/__init__.py +40 -0
- tdrpa/_tdxlwings/pro/_xlcalamine.py +536 -0
- tdrpa/_tdxlwings/pro/_xlofficejs.py +146 -0
- tdrpa/_tdxlwings/pro/_xlremote.py +1293 -0
- tdrpa/_tdxlwings/pro/custom_functions_code.js +150 -0
- tdrpa/_tdxlwings/pro/embedded_code.py +60 -0
- tdrpa/_tdxlwings/pro/udfs_officejs.py +549 -0
- tdrpa/_tdxlwings/pro/utils.py +199 -0
- tdrpa/_tdxlwings/quickstart.xlsm +0 -0
- tdrpa/_tdxlwings/quickstart_addin.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_addin_ribbon.xlam +0 -0
- tdrpa/_tdxlwings/quickstart_fastapi/main.py +47 -0
- tdrpa/_tdxlwings/quickstart_fastapi/requirements.txt +3 -0
- tdrpa/_tdxlwings/quickstart_standalone.xlsm +0 -0
- tdrpa/_tdxlwings/reports.py +12 -0
- tdrpa/_tdxlwings/rest/__init__.py +1 -0
- tdrpa/_tdxlwings/rest/api.py +368 -0
- tdrpa/_tdxlwings/rest/serializers.py +103 -0
- tdrpa/_tdxlwings/server.py +14 -0
- tdrpa/_tdxlwings/udfs.py +775 -0
- tdrpa/_tdxlwings/utils.py +777 -0
- tdrpa/_tdxlwings/xlwings-0.31.6.applescript +30 -0
- tdrpa/_tdxlwings/xlwings.bas +2061 -0
- tdrpa/_tdxlwings/xlwings_custom_addin.bas +2042 -0
- tdrpa/_tdxlwings/xlwingslib.cp38-win_amd64.pyd +0 -0
- tdrpa/tdworker/__init__.pyi +12 -0
- tdrpa/tdworker/_clip.pyi +50 -0
- tdrpa/tdworker/_excel.pyi +743 -0
- tdrpa/tdworker/_file.pyi +77 -0
- tdrpa/tdworker/_img.pyi +226 -0
- tdrpa/tdworker/_network.pyi +94 -0
- tdrpa/tdworker/_os.pyi +47 -0
- tdrpa/tdworker/_sp.pyi +21 -0
- tdrpa/tdworker/_w.pyi +129 -0
- tdrpa/tdworker/_web.pyi +995 -0
- tdrpa/tdworker/_winE.pyi +228 -0
- tdrpa/tdworker/_winK.pyi +74 -0
- tdrpa/tdworker/_winM.pyi +117 -0
- tdrpa/tdworker.cp312-win_amd64.pyd +0 -0
- tdrpa_tdworker-1.2.13.2.dist-info/METADATA +38 -0
- tdrpa_tdworker-1.2.13.2.dist-info/RECORD +101 -0
- tdrpa_tdworker-1.2.13.2.dist-info/WHEEL +5 -0
- tdrpa_tdworker-1.2.13.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,549 @@
|
|
1
|
+
"""
|
2
|
+
Required Notice: Copyright (C) Zoomer Analytics GmbH.
|
3
|
+
|
4
|
+
xlwings PRO is dual-licensed under one of the following licenses:
|
5
|
+
|
6
|
+
* PolyForm Noncommercial License 1.0.0 (for noncommercial use):
|
7
|
+
https://polyformproject.org/licenses/noncommercial/1.0.0
|
8
|
+
* xlwings PRO License (for commercial use):
|
9
|
+
https://github.com/xlwings/xlwings/blob/main/LICENSE_PRO.txt
|
10
|
+
|
11
|
+
Commercial licenses can be purchased at https://www.xlwings.org
|
12
|
+
"""
|
13
|
+
|
14
|
+
import asyncio
|
15
|
+
import inspect
|
16
|
+
import logging
|
17
|
+
import os
|
18
|
+
from functools import wraps
|
19
|
+
from pathlib import Path
|
20
|
+
from textwrap import dedent
|
21
|
+
|
22
|
+
from .. import XlwingsError, __version__, conversion
|
23
|
+
|
24
|
+
logger = logging.getLogger(__name__)
|
25
|
+
|
26
|
+
# Tasks started by streaming functions
|
27
|
+
background_tasks = {}
|
28
|
+
|
29
|
+
|
30
|
+
def func_sig(f):
|
31
|
+
sig = inspect.signature(f)
|
32
|
+
vararg = None
|
33
|
+
args = []
|
34
|
+
defaults = []
|
35
|
+
for param in sig.parameters.values():
|
36
|
+
if param.kind is inspect.Parameter.POSITIONAL_OR_KEYWORD:
|
37
|
+
args.append(param.name)
|
38
|
+
if param.default is not inspect.Signature.empty:
|
39
|
+
defaults.append(param.default)
|
40
|
+
elif param.kind is inspect.Parameter.VAR_POSITIONAL:
|
41
|
+
args.append(param.name)
|
42
|
+
vararg = param.name
|
43
|
+
else:
|
44
|
+
raise XlwingsError("xlwings does not support UDFs with keyword arguments")
|
45
|
+
return {"args": args, "defaults": defaults, "vararg": vararg}
|
46
|
+
|
47
|
+
|
48
|
+
def check_bool(kw, default, **func_kwargs):
|
49
|
+
if kw in func_kwargs:
|
50
|
+
check = func_kwargs.pop(kw)
|
51
|
+
if isinstance(check, bool):
|
52
|
+
return check
|
53
|
+
raise XlwingsError(f'{kw} only takes boolean values. ("{check}" provided).')
|
54
|
+
return default
|
55
|
+
|
56
|
+
|
57
|
+
def xlfunc(f=None, **kwargs):
|
58
|
+
def inner(f):
|
59
|
+
if not hasattr(f, "__xlfunc__"):
|
60
|
+
xlf = f.__xlfunc__ = {}
|
61
|
+
xlf["name"] = f.__name__
|
62
|
+
xlargs = xlf["args"] = []
|
63
|
+
xlargmap = xlf["argmap"] = {}
|
64
|
+
sig = func_sig(f)
|
65
|
+
num_args = len(sig["args"])
|
66
|
+
num_defaults = len(sig["defaults"])
|
67
|
+
num_required_args = num_args - num_defaults
|
68
|
+
if sig["vararg"] and num_defaults > 0:
|
69
|
+
raise XlwingsError(
|
70
|
+
"xlwings does not support UDFs "
|
71
|
+
"with both optional and variable length arguments"
|
72
|
+
)
|
73
|
+
for var_pos, var_name in enumerate(sig["args"]):
|
74
|
+
arg_info = {
|
75
|
+
"name": var_name,
|
76
|
+
"pos": var_pos,
|
77
|
+
"doc": f"Positional argument {var_pos + 1}",
|
78
|
+
"vararg": var_name == sig["vararg"],
|
79
|
+
"options": {},
|
80
|
+
}
|
81
|
+
if var_pos >= num_required_args:
|
82
|
+
arg_info["optional"] = sig["defaults"][var_pos - num_required_args]
|
83
|
+
xlargs.append(arg_info)
|
84
|
+
xlargmap[var_name] = xlargs[-1]
|
85
|
+
xlf["ret"] = {
|
86
|
+
"doc": (
|
87
|
+
f.__doc__
|
88
|
+
if f.__doc__ is not None
|
89
|
+
else f"Python function '{f.__name__}'"
|
90
|
+
),
|
91
|
+
"options": {},
|
92
|
+
}
|
93
|
+
f.__xlfunc__["volatile"] = check_bool("volatile", default=False, **kwargs)
|
94
|
+
# If there's a global namespace defined in the manifest, this will be the
|
95
|
+
# sub-namespace, i.e. NAMESPACE.SUBNAMESPACE.FUNCTIONNAME
|
96
|
+
f.__xlfunc__["namespace"] = kwargs.get("namespace")
|
97
|
+
f.__xlfunc__["help_url"] = kwargs.get("help_url")
|
98
|
+
return f
|
99
|
+
|
100
|
+
if f is None:
|
101
|
+
return inner
|
102
|
+
else:
|
103
|
+
return inner(f)
|
104
|
+
|
105
|
+
|
106
|
+
def xlret(convert=None, **kwargs):
|
107
|
+
if convert is not None:
|
108
|
+
kwargs["convert"] = convert
|
109
|
+
|
110
|
+
def inner(f):
|
111
|
+
xlf = xlfunc(f).__xlfunc__
|
112
|
+
xlr = xlf["ret"]
|
113
|
+
xlr["options"].update(kwargs)
|
114
|
+
return f
|
115
|
+
|
116
|
+
return inner
|
117
|
+
|
118
|
+
|
119
|
+
def xlarg(arg, convert=None, **kwargs):
|
120
|
+
if convert is not None:
|
121
|
+
kwargs["convert"] = convert
|
122
|
+
|
123
|
+
def inner(f):
|
124
|
+
xlf = xlfunc(f).__xlfunc__
|
125
|
+
if arg.lstrip("*") not in xlf["argmap"]:
|
126
|
+
raise Exception(f"Invalid argument name '{arg}'.")
|
127
|
+
xla = xlf["argmap"][arg.lstrip("*")]
|
128
|
+
if "doc" in kwargs:
|
129
|
+
xla["doc"] = kwargs.pop("doc")
|
130
|
+
xla["options"].update(kwargs)
|
131
|
+
return f
|
132
|
+
|
133
|
+
return inner
|
134
|
+
|
135
|
+
|
136
|
+
def to_scalar(arg):
|
137
|
+
if isinstance(arg, (list, tuple)) and len(arg) == 1:
|
138
|
+
if isinstance(arg[0], (list, tuple)) and len(arg[0]) == 1:
|
139
|
+
arg = arg[0][0]
|
140
|
+
else:
|
141
|
+
arg = arg[0]
|
142
|
+
return arg
|
143
|
+
|
144
|
+
|
145
|
+
def convert(result, ret_info, data):
|
146
|
+
if "date_format" not in ret_info["options"]:
|
147
|
+
date_format = os.getenv("XLWINGS_DATE_FORMAT") or locale_to_shortdate.get(
|
148
|
+
data["content_language"].lower()
|
149
|
+
)
|
150
|
+
if date_format is None:
|
151
|
+
logger.warning(
|
152
|
+
f"Locale {data['content_language'].lower()} not found, so custom "
|
153
|
+
"functions won't format dates automatically. Please open an issue with "
|
154
|
+
"this warning on https://github.com/xlwings/xlwings/issues. In the "
|
155
|
+
"meantime, you can set the XLWINGS_DATE_FORMAT env var to fix that."
|
156
|
+
)
|
157
|
+
ret_info["options"]["date_format"] = date_format
|
158
|
+
ret_info["options"]["runtime"] = data["runtime"]
|
159
|
+
result = conversion.write(result, None, ret_info["options"], engine_name="officejs")
|
160
|
+
return result
|
161
|
+
|
162
|
+
|
163
|
+
async def custom_functions_call(data, module, sio=None):
|
164
|
+
"""
|
165
|
+
sio : socketio.AsyncServer instance
|
166
|
+
"""
|
167
|
+
func_name = data["func_name"]
|
168
|
+
args = data["args"]
|
169
|
+
func = getattr(module, func_name)
|
170
|
+
func_info = func.__xlfunc__
|
171
|
+
args_info = func_info["args"]
|
172
|
+
ret_info = func_info["ret"]
|
173
|
+
|
174
|
+
if data["version"] != __version__:
|
175
|
+
raise XlwingsError(
|
176
|
+
"xlwings version mismatch: please restart Excel or "
|
177
|
+
"right-click on the task pane and select 'reload'!"
|
178
|
+
)
|
179
|
+
|
180
|
+
# Turn varargs into regular arguments
|
181
|
+
args = list(args)
|
182
|
+
new_args = []
|
183
|
+
new_args_info = []
|
184
|
+
for i, arg in enumerate(args):
|
185
|
+
arg_info = args_info[min(i, len(args_info) - 1)]
|
186
|
+
if arg_info["vararg"]:
|
187
|
+
new_args.extend(arg)
|
188
|
+
for _ in range(len(arg)):
|
189
|
+
new_args_info.append(arg_info)
|
190
|
+
else:
|
191
|
+
new_args.append(arg)
|
192
|
+
new_args_info.append(arg_info)
|
193
|
+
args = new_args
|
194
|
+
args_info = new_args_info
|
195
|
+
|
196
|
+
for i, arg in enumerate(args):
|
197
|
+
arg_info = args_info[i]
|
198
|
+
arg = to_scalar(arg)
|
199
|
+
if arg is None:
|
200
|
+
args[i] = arg_info.get("optional", None)
|
201
|
+
else:
|
202
|
+
args[i] = conversion.read(
|
203
|
+
None, arg, arg_info["options"], engine_name="officejs"
|
204
|
+
)
|
205
|
+
if inspect.isasyncgenfunction(func):
|
206
|
+
# Streaming functions
|
207
|
+
task_key = data["task_key"]
|
208
|
+
|
209
|
+
async def task():
|
210
|
+
try:
|
211
|
+
async for result in func(*args):
|
212
|
+
result = convert(result, ret_info, data)
|
213
|
+
await sio.emit(
|
214
|
+
f"xlwings:set-result-{task_key}",
|
215
|
+
{"result": result},
|
216
|
+
)
|
217
|
+
except Exception as e: # noqa: E722
|
218
|
+
await sio.emit(
|
219
|
+
f"xlwings:set-result-{task_key}",
|
220
|
+
{"result": [[f"ERROR: {repr(e)}"]]},
|
221
|
+
)
|
222
|
+
logger.exception(f"Error in custom function '{func_name}'")
|
223
|
+
raise
|
224
|
+
|
225
|
+
if task_key not in background_tasks:
|
226
|
+
mytask = asyncio.create_task(task(), name=f"xlwings-{task_key}")
|
227
|
+
background_tasks[task_key] = mytask
|
228
|
+
|
229
|
+
def on_task_done(t):
|
230
|
+
if not t.cancelled() and t.exception() is not None:
|
231
|
+
t.cancel()
|
232
|
+
logger.info(
|
233
|
+
f"Task {t.get_name()} cancelled as it failed with exception: {t.exception()}"
|
234
|
+
)
|
235
|
+
del background_tasks[task_key]
|
236
|
+
|
237
|
+
mytask.add_done_callback(on_task_done)
|
238
|
+
return mytask
|
239
|
+
|
240
|
+
elif inspect.iscoroutinefunction(func):
|
241
|
+
ret = await func(*args)
|
242
|
+
else:
|
243
|
+
ret = func(*args)
|
244
|
+
|
245
|
+
ret = convert(ret, ret_info, data)
|
246
|
+
return ret
|
247
|
+
|
248
|
+
|
249
|
+
def custom_functions_code(
|
250
|
+
module, custom_functions_call_path="/xlwings/custom-functions-call"
|
251
|
+
):
|
252
|
+
js = (Path(__file__).parent / "custom_functions_code.js").read_text()
|
253
|
+
# format string would require to double all curly braces
|
254
|
+
js = js.replace("placeholder_xlwings_version", __version__).replace(
|
255
|
+
"placeholder_custom_functions_call_path", custom_functions_call_path
|
256
|
+
)
|
257
|
+
for name, obj in inspect.getmembers(module):
|
258
|
+
if hasattr(obj, "__xlfunc__"):
|
259
|
+
xlfunc = obj.__xlfunc__
|
260
|
+
func_name = xlfunc["name"]
|
261
|
+
streaming = "true" if inspect.isasyncgenfunction(obj) else "false"
|
262
|
+
js += dedent(
|
263
|
+
f"""\
|
264
|
+
async function {func_name}() {{
|
265
|
+
let args = ["{func_name}", {streaming}]
|
266
|
+
args.push.apply(args, arguments);
|
267
|
+
return await base.apply(null, args);
|
268
|
+
}}
|
269
|
+
CustomFunctions.associate("{func_name.upper()}", {func_name});
|
270
|
+
"""
|
271
|
+
)
|
272
|
+
return js
|
273
|
+
|
274
|
+
|
275
|
+
def custom_functions_meta(module):
|
276
|
+
funcs = []
|
277
|
+
for name, obj in inspect.getmembers(module):
|
278
|
+
if hasattr(obj, "__xlfunc__"):
|
279
|
+
xlfunc = obj.__xlfunc__
|
280
|
+
func = {}
|
281
|
+
func["description"] = xlfunc["ret"]["doc"]
|
282
|
+
if xlfunc["help_url"]:
|
283
|
+
func["helpUrl"] = xlfunc["help_url"]
|
284
|
+
func["id"] = xlfunc["name"].upper()
|
285
|
+
if xlfunc["namespace"]:
|
286
|
+
func["name"] = f"{xlfunc['namespace'].upper()}.{xlfunc['name'].upper()}"
|
287
|
+
else:
|
288
|
+
func["name"] = xlfunc["name"].upper()
|
289
|
+
if inspect.isasyncgenfunction(obj):
|
290
|
+
func["options"] = {
|
291
|
+
"stream": True,
|
292
|
+
}
|
293
|
+
else:
|
294
|
+
func["options"] = {
|
295
|
+
"requiresAddress": True,
|
296
|
+
"requiresParameterAddresses": True,
|
297
|
+
}
|
298
|
+
if xlfunc["volatile"]:
|
299
|
+
func["options"]["volatile"] = True
|
300
|
+
func["result"] = {"dimensionality": "matrix", "type": "any"}
|
301
|
+
|
302
|
+
params = []
|
303
|
+
for arg in xlfunc["args"]:
|
304
|
+
param = {}
|
305
|
+
param["description"] = arg["doc"]
|
306
|
+
param["name"] = arg["name"]
|
307
|
+
param["dimensionality"] = "matrix"
|
308
|
+
param["type"] = "any"
|
309
|
+
if "optional" in arg:
|
310
|
+
param["optional"] = True
|
311
|
+
elif arg["vararg"]:
|
312
|
+
param["repeating"] = True
|
313
|
+
params.append(param)
|
314
|
+
func["parameters"] = params
|
315
|
+
funcs.append(func)
|
316
|
+
return {
|
317
|
+
"allowCustomDataForDataTypeAny": True,
|
318
|
+
"allowErrorForDataTypeAny": True,
|
319
|
+
"functions": funcs,
|
320
|
+
}
|
321
|
+
|
322
|
+
|
323
|
+
# Custom scripts
|
324
|
+
def script(func):
|
325
|
+
@wraps(func)
|
326
|
+
async def wrapper(*args, **kwargs):
|
327
|
+
if inspect.iscoroutinefunction(func):
|
328
|
+
await func(*args, **kwargs)
|
329
|
+
else:
|
330
|
+
func(*args, **kwargs)
|
331
|
+
return args[0]
|
332
|
+
|
333
|
+
return wrapper
|
334
|
+
|
335
|
+
|
336
|
+
async def custom_scripts_call(module, script_name, book):
|
337
|
+
func = getattr(module, script_name)
|
338
|
+
if inspect.iscoroutinefunction(func):
|
339
|
+
book = await func(book)
|
340
|
+
else:
|
341
|
+
book = func(book)
|
342
|
+
return book
|
343
|
+
|
344
|
+
|
345
|
+
# Socket.io (sid is the session ID)
|
346
|
+
task_key_to_sids = {}
|
347
|
+
task_key_to_task = {}
|
348
|
+
|
349
|
+
|
350
|
+
async def sio_connect(sid, environ, auth, sio, authenticate=None):
|
351
|
+
token = auth.get("token")
|
352
|
+
if authenticate:
|
353
|
+
try:
|
354
|
+
if inspect.iscoroutinefunction(authenticate):
|
355
|
+
current_user = await authenticate(token)
|
356
|
+
else:
|
357
|
+
current_user = authenticate(token)
|
358
|
+
logger.info(f"Socket.io: connect {sid}")
|
359
|
+
logger.info(f"Socket.io: User authenticated {current_user.name}")
|
360
|
+
except Exception as e:
|
361
|
+
logger.info(f"Socket.io: authentication failed for sid {sid}: {repr(e)}")
|
362
|
+
await sio.disconnect(sid)
|
363
|
+
logger.info(f"Socket.io: connect {sid}")
|
364
|
+
|
365
|
+
|
366
|
+
async def sio_disconnect(sid):
|
367
|
+
logger.info(f"disconnect {sid}")
|
368
|
+
try:
|
369
|
+
# Using list() to prevent the loop from changing the dict directly
|
370
|
+
for task_key in list(task_key_to_sids.keys()):
|
371
|
+
task = task_key_to_task[task_key]
|
372
|
+
task_key_to_sids[task_key].discard(sid)
|
373
|
+
if not task_key_to_sids[task_key]:
|
374
|
+
task.cancel()
|
375
|
+
logger.info(f"Cancelled task {task.get_name()}")
|
376
|
+
del task_key_to_sids[task_key]
|
377
|
+
del task_key_to_task[task_key]
|
378
|
+
except KeyError:
|
379
|
+
# Renaming functions during development can cause issues
|
380
|
+
pass
|
381
|
+
await asyncio.sleep(0) # Allow event loop to cancel the tasks
|
382
|
+
active_tasks = [
|
383
|
+
task.get_name()
|
384
|
+
for task in asyncio.all_tasks()
|
385
|
+
if task.get_name().startswith("xlwings")
|
386
|
+
]
|
387
|
+
logger.info(f"Active xlwings tasks:" f"{active_tasks}")
|
388
|
+
|
389
|
+
|
390
|
+
async def sio_custom_function_call(sid, data, custom_functions, sio):
|
391
|
+
task_key = data["task_key"]
|
392
|
+
task_key_to_sids[task_key] = task_key_to_sids.get(task_key, set()).union({sid})
|
393
|
+
task = await custom_functions_call(data, custom_functions, sio)
|
394
|
+
if task:
|
395
|
+
task_key_to_task[task_key] = task
|
396
|
+
|
397
|
+
|
398
|
+
locale_to_shortdate = {
|
399
|
+
# This is using the locales from https://github.com/OfficeDev/office-js/tree/release/dist
|
400
|
+
# matched with values from https://stackoverflow.com/a/9893752/918626
|
401
|
+
# TODO: https://metacpan.org/dist/DateTime-Locale seems to be much better than SO
|
402
|
+
# Also, office-js doesn't have all locales supported by Office, such as en-ch or
|
403
|
+
# en-ae are missing
|
404
|
+
"af-za": "yyyy/mm/dd",
|
405
|
+
"am-et": "d/m/yyyy",
|
406
|
+
"ar-ae": "dd/mm/yyyy",
|
407
|
+
"ar-bh": "dd/mm/yyyy",
|
408
|
+
"ar-dz": "dd-mm-yyyy",
|
409
|
+
"ar-eg": "dd/mm/yyyy",
|
410
|
+
"ar-iq": "dd/mm/yyyy",
|
411
|
+
"ar-jo": "dd/mm/yyyy",
|
412
|
+
"ar-kw": "dd/mm/yyyy",
|
413
|
+
"ar-lb": "dd/mm/yyyy",
|
414
|
+
"ar-ly": "dd/mm/yyyy",
|
415
|
+
"ar-ma": "dd-mm-yyyy",
|
416
|
+
"ar-om": "dd/mm/yyyy",
|
417
|
+
"ar-qa": "dd/mm/yyyy",
|
418
|
+
"ar-sa": "dd/mm/yy",
|
419
|
+
"ar-sy": "dd/mm/yyyy",
|
420
|
+
"ar-tn": "dd-mm-yyyy",
|
421
|
+
"ar-ye": "dd/mm/yyyy",
|
422
|
+
"az-latn-az": "dd.mm.yyyy",
|
423
|
+
"be-by": "dd.mm.yyyy",
|
424
|
+
"bg-bg": "dd.m.yyyy",
|
425
|
+
"bn-in": "dd-mm-yy",
|
426
|
+
"bs-latn-ba": "d.m.yyyy",
|
427
|
+
"ca-es": "dd/mm/yyyy",
|
428
|
+
"cs-cz": "d.m.yyyy",
|
429
|
+
"cy-gb": "dd/mm/yyyy",
|
430
|
+
"da-dk": "dd-mm-yyyy",
|
431
|
+
"de-at": "dd.mm.yyyy",
|
432
|
+
"de-ch": "dd.mm.yyyy",
|
433
|
+
"de-de": "dd.mm.yyyy",
|
434
|
+
"de-li": "dd.mm.yyyy",
|
435
|
+
"de-lu": "dd.mm.yyyy",
|
436
|
+
"el-gr": "d/m/yyyy",
|
437
|
+
"en-029": "mm/dd/yyyy",
|
438
|
+
"en-au": "d/mm/yyyy",
|
439
|
+
"en-bz": "dd/mm/yyyy",
|
440
|
+
"en-ca": "dd/mm/yyyy",
|
441
|
+
"en-ch": "dd.mm.yyyy",
|
442
|
+
"en-gb": "dd/mm/yyyy",
|
443
|
+
"en-ie": "dd/mm/yyyy",
|
444
|
+
"en-in": "dd-mm-yyyy",
|
445
|
+
"en-jm": "dd/mm/yyyy",
|
446
|
+
"en-my": "d/m/yyyy",
|
447
|
+
"en-nz": "d/mm/yyyy",
|
448
|
+
"en-ph": "m/d/yyyy",
|
449
|
+
"en-sg": "d/m/yyyy",
|
450
|
+
"en-tt": "dd/mm/yyyy",
|
451
|
+
"en-us": "m/d/yyyy",
|
452
|
+
"en-za": "yyyy/mm/dd",
|
453
|
+
"en-zw": "m/d/yyyy",
|
454
|
+
"en-ae": "dd/mm/yyyy",
|
455
|
+
"es-ar": "dd/mm/yyyy",
|
456
|
+
"es-bo": "dd/mm/yyyy",
|
457
|
+
"es-cl": "dd-mm-yyyy",
|
458
|
+
"es-co": "dd/mm/yyyy",
|
459
|
+
"es-cr": "dd/mm/yyyy",
|
460
|
+
"es-do": "dd/mm/yyyy",
|
461
|
+
"es-ec": "dd/mm/yyyy",
|
462
|
+
"es-es": "dd/mm/yyyy",
|
463
|
+
"es-gt": "dd/mm/yyyy",
|
464
|
+
"es-hn": "dd/mm/yyyy",
|
465
|
+
"es-mx": "dd/mm/yyyy",
|
466
|
+
"es-ni": "dd/mm/yyyy",
|
467
|
+
"es-pa": "mm/dd/yyyy",
|
468
|
+
"es-pe": "dd/mm/yyyy",
|
469
|
+
"es-pr": "dd/mm/yyyy",
|
470
|
+
"es-py": "dd/mm/yyyy",
|
471
|
+
"es-sv": "dd/mm/yyyy",
|
472
|
+
"es-us": "m/d/yyyy",
|
473
|
+
"es-uy": "dd/mm/yyyy",
|
474
|
+
"es-ve": "dd/mm/yyyy",
|
475
|
+
"et-ee": "d.mm.yyyy",
|
476
|
+
"eu-es": "yyyy/mm/dd",
|
477
|
+
"fa-ir": "mm/dd/yyyy",
|
478
|
+
"fi-fi": "d.m.yyyy",
|
479
|
+
"fil-ph": "m/d/yyyy",
|
480
|
+
"fr-be": "d/mm/yyyy",
|
481
|
+
"fr-ca": "yyyy-mm-dd",
|
482
|
+
"fr-ch": "dd.mm.yyyy",
|
483
|
+
"fr-fr": "dd/mm/yyyy",
|
484
|
+
"fr-lu": "dd/mm/yyyy",
|
485
|
+
"fr-mc": "dd/mm/yyyy",
|
486
|
+
"ga-ie": "dd/mm/yyyy",
|
487
|
+
"gl-es": "dd/mm/yy",
|
488
|
+
"gu-in": "dd-mm-yy",
|
489
|
+
"he-il": "dd/mm/yyyy",
|
490
|
+
"hi-in": "dd-mm-yyyy",
|
491
|
+
"hr-ba": "d.m.yyyy.",
|
492
|
+
"hr-hr": "d.m.yyyy",
|
493
|
+
"hu-hu": "yyyy. mm. dd.",
|
494
|
+
"hy-am": "dd.mm.yyyy",
|
495
|
+
"id-id": "dd/mm/yyyy",
|
496
|
+
"is-is": "d.m.yyyy",
|
497
|
+
"it-ch": "dd.mm.yyyy",
|
498
|
+
"it-it": "dd/mm/yyyy",
|
499
|
+
"ja-jp": "yyyy/mm/dd",
|
500
|
+
"ka-ge": "dd.mm.yyyy",
|
501
|
+
"kk-kz": "dd.mm.yyyy",
|
502
|
+
"km-kh": "yyyy-mm-dd",
|
503
|
+
"kn-in": "dd-mm-yy",
|
504
|
+
"ko-kr": "yyyy. mm. dd",
|
505
|
+
"lb-lu": "dd/mm/yyyy",
|
506
|
+
"lo-la": "dd/mm/yyyy",
|
507
|
+
"lt-lt": "yyyy.mm.dd",
|
508
|
+
"lv-lv": "yyyy.mm.dd.",
|
509
|
+
"mk-mk": "dd.mm.yyyy",
|
510
|
+
"ml-in": "dd-mm-yy",
|
511
|
+
"mn-mn": "yy.mm.dd",
|
512
|
+
"mr-in": "dd-mm-yyyy",
|
513
|
+
"ms-bn": "dd/mm/yyyy",
|
514
|
+
"ms-my": "dd/mm/yyyy",
|
515
|
+
"mt-mt": "dd/mm/yyyy",
|
516
|
+
"nb-no": "dd.mm.yyyy",
|
517
|
+
"ne-np": "m/d/yyyy",
|
518
|
+
"nl-be": "d/mm/yyyy",
|
519
|
+
"nl-nl": "d-m-yyyy",
|
520
|
+
"nn-no": "dd.mm.yyyy",
|
521
|
+
"pl-pl": "dd.mm.yyyy",
|
522
|
+
"pt-br": "d/m/yyyy",
|
523
|
+
"pt-pt": "dd-mm-yyyy",
|
524
|
+
"ro-ro": "dd.mm.yyyy",
|
525
|
+
"ru-ru": "dd.mm.yyyy",
|
526
|
+
"si-lk": "yyyy-mm-dd",
|
527
|
+
"sk-sk": "d. m. yyyy",
|
528
|
+
"sl-si": "d.m.yyyy",
|
529
|
+
"sq-al": "yyyy-mm-dd",
|
530
|
+
"sr-cyrl-cs": "d.m.yyyy",
|
531
|
+
"sr-cyrl-rs": "d.m.yyyy",
|
532
|
+
"sr-latn-cs": "d.m.yyyy",
|
533
|
+
"sr-latn-rs": "d.m.yyyy",
|
534
|
+
"sv-fi": "d.m.yyyy",
|
535
|
+
"sv-se": "yyyy-mm-dd",
|
536
|
+
"sw-ke": "m/d/yyyy",
|
537
|
+
"ta-in": "dd-mm-yyyy",
|
538
|
+
"te-in": "dd-mm-yy",
|
539
|
+
"th-th": "d/m/yyyy",
|
540
|
+
"tr-tr": "dd.mm.yyyy",
|
541
|
+
"uk-ua": "dd.mm.yyyy",
|
542
|
+
"ur-pk": "dd/mm/yyyy",
|
543
|
+
"vi-vn": "dd/mm/yyyy",
|
544
|
+
"zh-cn": "yyyy/m/d",
|
545
|
+
"zh-hk": "d/m/yyyy",
|
546
|
+
"zh-mo": "d/m/yyyy",
|
547
|
+
"zh-sg": "d/m/yyyy",
|
548
|
+
"zh-tw": "yyyy/m/d",
|
549
|
+
}
|