jk_typing 0.2024.1.3__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.
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.1
2
+ Name: jk_typing
3
+ Version: 0.2024.1.3
4
+ Summary: This module provides capabilities for type checking function arguments. (NOTE: A full type check with this module is not possible, since this is fundamentally not possible due to limitiations of Python itself.)
5
+ Keywords: typing,type-checking
6
+ Author-email: Jürgen Knauth <pubsrc@binary-overflow.de>
7
+ Maintainer-email: Jürgen Knauth <pubsrc@binary-overflow.de>
8
+ Requires-Python: >=3.8
9
+ Description-Content-Type: text/markdown
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: License :: OSI Approved :: Apache Software License
12
+ Classifier: Programming Language :: Python :: 3
13
+
14
+ jk_typing
15
+ ==========
16
+
17
+ Introduction
18
+ ------------
19
+
20
+ This module provides capabilities for type checking function arguments.
21
+
22
+ Please note that a full type check with this module is not possible, since this is fundamentally not possible due to limitiations of Python itself.
23
+
24
+ Information about this module can be found here:
25
+
26
+ * [github.org](https://github.com/jkpubsrc/python-module-jk-typing)
27
+ * [Documentation](https://github.com/jkpubsrc/python-module-jk-typing/tree/master/documentation)
28
+ * [pypi.python.org](https://pypi.python.org/pypi/jk_typing)
29
+
30
+ Why this module?
31
+ ----------------
32
+
33
+ Python nowadays is capable of managing type hints for function arguments and return values. Unfortunately Python does not perform type checking automatically. This module provides capabilities of performing type checking automatically.
34
+
35
+ For more details have a look at the [documentation](https://github.com/jkpubsrc/python-module-jk-typing/tree/master/documentation).
36
+
37
+ Requirements
38
+ ------------
39
+
40
+ This module requires Python 3.7 or later. It can not be used on older releases of Python because of limitations of module `typing`.
41
+
42
+ Limitations of this module
43
+ --------------------------
44
+
45
+ Type checking is not implemented in pure Python. Therefore it is slower as if the Python interpreter would perform type checking itself. Additionally this module has not yet a complete implementation of all kinds of types. (This will change in the future, maybe with your help.)
46
+
47
+ For more details have a look at the [documentation](https://github.com/jkpubsrc/python-module-jk-typing/tree/master/documentation).
48
+
49
+ How to use this module
50
+ ----------------------
51
+
52
+ ### Import this module
53
+
54
+ Please include this module into your application using the following code:
55
+
56
+ ```python
57
+ import jk_typing
58
+ ```
59
+
60
+ ### Define a function
61
+
62
+ Example:
63
+
64
+ ```python
65
+ @checkFunctionSignature(bDebug = True)
66
+ def someFunction(a:int, b:str) -> bool:
67
+ return str(a) == b
68
+ ```
69
+
70
+ ### Invoke the function (and perform type checking)
71
+
72
+ ```python
73
+ result = someFunction(123, "123")
74
+ print(result)
75
+ ```
76
+
77
+ Contact Information
78
+ -------------------
79
+
80
+ This work is Open Source. This enables you to use this work for free.
81
+
82
+ Please have in mind this also enables you to contribute. We, the subspecies of software developers, can create great things. But the more collaborate, the more fantastic these things can become. Therefore Feel free to contact the author(s) listed below, either for giving feedback, providing comments, hints, indicate possible collaborations, ideas, improvements. Or maybe for "only" reporting some bugs:
83
+
84
+ * Jürgen Knauth: jknauth@uni-goettingen.de, pubsrc@binary-overflow.de
85
+
86
+ License
87
+ -------
88
+
89
+ This software is provided under the following license:
90
+
91
+ * Apache Software License 2.0
92
+
93
+
94
+
95
+
@@ -0,0 +1,81 @@
1
+ jk_typing
2
+ ==========
3
+
4
+ Introduction
5
+ ------------
6
+
7
+ This module provides capabilities for type checking function arguments.
8
+
9
+ Please note that a full type check with this module is not possible, since this is fundamentally not possible due to limitiations of Python itself.
10
+
11
+ Information about this module can be found here:
12
+
13
+ * [github.org](https://github.com/jkpubsrc/python-module-jk-typing)
14
+ * [Documentation](https://github.com/jkpubsrc/python-module-jk-typing/tree/master/documentation)
15
+ * [pypi.python.org](https://pypi.python.org/pypi/jk_typing)
16
+
17
+ Why this module?
18
+ ----------------
19
+
20
+ Python nowadays is capable of managing type hints for function arguments and return values. Unfortunately Python does not perform type checking automatically. This module provides capabilities of performing type checking automatically.
21
+
22
+ For more details have a look at the [documentation](https://github.com/jkpubsrc/python-module-jk-typing/tree/master/documentation).
23
+
24
+ Requirements
25
+ ------------
26
+
27
+ This module requires Python 3.7 or later. It can not be used on older releases of Python because of limitations of module `typing`.
28
+
29
+ Limitations of this module
30
+ --------------------------
31
+
32
+ Type checking is not implemented in pure Python. Therefore it is slower as if the Python interpreter would perform type checking itself. Additionally this module has not yet a complete implementation of all kinds of types. (This will change in the future, maybe with your help.)
33
+
34
+ For more details have a look at the [documentation](https://github.com/jkpubsrc/python-module-jk-typing/tree/master/documentation).
35
+
36
+ How to use this module
37
+ ----------------------
38
+
39
+ ### Import this module
40
+
41
+ Please include this module into your application using the following code:
42
+
43
+ ```python
44
+ import jk_typing
45
+ ```
46
+
47
+ ### Define a function
48
+
49
+ Example:
50
+
51
+ ```python
52
+ @checkFunctionSignature(bDebug = True)
53
+ def someFunction(a:int, b:str) -> bool:
54
+ return str(a) == b
55
+ ```
56
+
57
+ ### Invoke the function (and perform type checking)
58
+
59
+ ```python
60
+ result = someFunction(123, "123")
61
+ print(result)
62
+ ```
63
+
64
+ Contact Information
65
+ -------------------
66
+
67
+ This work is Open Source. This enables you to use this work for free.
68
+
69
+ Please have in mind this also enables you to contribute. We, the subspecies of software developers, can create great things. But the more collaborate, the more fantastic these things can become. Therefore Feel free to contact the author(s) listed below, either for giving feedback, providing comments, hints, indicate possible collaborations, ideas, improvements. Or maybe for "only" reporting some bugs:
70
+
71
+ * Jürgen Knauth: jknauth@uni-goettingen.de, pubsrc@binary-overflow.de
72
+
73
+ License
74
+ -------
75
+
76
+ This software is provided under the following license:
77
+
78
+ * Apache Software License 2.0
79
+
80
+
81
+
@@ -0,0 +1,11 @@
1
+
2
+
3
+
4
+ __author__ = "Jürgen Knauth"
5
+ __version__ = "0.2024.1.3"
6
+
7
+
8
+
9
+ from .checkFunctionSignature import checkFunctionSignature
10
+
11
+
@@ -0,0 +1,387 @@
1
+
2
+
3
+ import collections
4
+ import sys
5
+ import typing
6
+ import inspect
7
+
8
+ from .checking.AbstractCTNode import AbstractCTNode
9
+ from .checking.CheckTypeCompiler import CheckTypeCompiler
10
+
11
+
12
+
13
+
14
+
15
+ """
16
+ def __checkUnion(value, typeSpecs:list):
17
+ for typeSpec in typeSpecs:
18
+ if _checkType(value, typeSpec):
19
+ return True
20
+ return False
21
+ #
22
+ """
23
+
24
+
25
+
26
+ #_type_checking_enabled = True
27
+
28
+ if (sys.version_info.major < 3) or (
29
+ (sys.version_info.major == 3) and (sys.version_info.minor <= 6)):
30
+ # older python implementation are not yet mature enough.
31
+ raise Exception("Python versions below 3.6 are not supported!")
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+ """
41
+ def deactiveTypeChecking():
42
+ global _type_checking_enabled
43
+ _type_checking_enabled = False
44
+ #
45
+
46
+ def isTypeCheckingEnabled() -> bool:
47
+ global _type_checking_enabled
48
+ return _type_checking_enabled
49
+ #
50
+ """
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+ #
60
+ # Do the type check.
61
+ # This function is the heart of the type checking implementation.
62
+ #
63
+ # @param any value The value to check
64
+ # @param various typeSpec The type specification such as `None`, `int`, `typing.List[int]`, etc.
65
+ # @param int indent The current indentation level to use for debugging ouptut. A negative indent disables output.
66
+ #
67
+ def _checkType(value, typeSpec, indent:int):
68
+ if indent >= 0:
69
+ print("\t"*indent + ">> checking value " + repr(value) + " against: " + repr(typeSpec))
70
+
71
+ if typeSpec is None:
72
+ return value is None
73
+
74
+ elif isinstance(typeSpec, typing._GenericAlias):
75
+ if indent >= 0:
76
+ print("\t"*indent + ">> (the condition type is generc (_name={}, __origin__={}))".format(
77
+ repr(typeSpec._name),
78
+ repr(typeSpec.__origin__)
79
+ ))
80
+
81
+ if typeSpec._name == "List":
82
+ if not isinstance(value, list):
83
+ return False
84
+ for v in value:
85
+ if not _checkType(v, typeSpec.__args__[0], indent+1):
86
+ return False
87
+ return True
88
+
89
+ elif typeSpec._name == "Tuple":
90
+ if not isinstance(value, tuple):
91
+ return False
92
+ for v in value:
93
+ if not _checkType(v, typeSpec.__args__[0], indent+1):
94
+ return False
95
+ return True
96
+
97
+ elif typeSpec._name == "Set":
98
+ if not isinstance(value, set):
99
+ return False
100
+ for v in value:
101
+ if not _checkType(v, typeSpec.__args__[0], indent+1):
102
+ return False
103
+ return True
104
+
105
+ elif typeSpec._name == "FrozenSet":
106
+ if not isinstance(value, frozenset):
107
+ return False
108
+ for v in value:
109
+ if not _checkType(v, typeSpec.__args__[0], indent+1):
110
+ return False
111
+ return True
112
+
113
+ elif typeSpec._name == "Deque":
114
+ if not isinstance(value, collections.deque):
115
+ return False
116
+ for v in value:
117
+ if not _checkType(v, typeSpec.__args__[0], indent+1):
118
+ return False
119
+ return True
120
+
121
+ elif typeSpec._name == "Dict":
122
+ if not isinstance(value, dict):
123
+ return False
124
+ for k, v in value.items():
125
+ if not _checkType(k, typeSpec.__args__[0], indent+1):
126
+ return False
127
+ if not _checkType(v, typeSpec.__args__[1], indent+1):
128
+ return False
129
+ return True
130
+
131
+ elif typeSpec.__origin__ == typing.Union:
132
+ for t in typeSpec.__args__:
133
+ if _checkType(value, t, indent+1):
134
+ return True
135
+ return False
136
+
137
+ else:
138
+ if indent >= 0:
139
+ print("\t"*indent + "WARN: Can't check this type: " + repr(typeSpec))
140
+ return True
141
+
142
+ else:
143
+ if indent >= 0:
144
+ print("\t"*indent + ">> (the condition type is primitive)")
145
+ return isinstance(value, typeSpec)
146
+ #
147
+
148
+
149
+
150
+ def _getTypeDescr(t) -> str:
151
+ if t is None:
152
+ return "void"
153
+
154
+ s = repr(t)
155
+ # s should be something like this:
156
+ # "<Parameter "abc">
157
+ # "<Parameter "abc:int">
158
+ # "<Parameter "*args">
159
+ if s.startswith("<Parameter \"*"):
160
+ s = s[13:-2]
161
+ elif s.startswith("<Parameter \""):
162
+ s = s[12:-2]
163
+ elif s.startswith("<class '"):
164
+ s = s[8:-2]
165
+ else:
166
+ return "(unknown:" + s + ")"
167
+
168
+ pos = s.find(":")
169
+ if pos > 0:
170
+ return s[pos+1:].strip()
171
+ else:
172
+ return "?"
173
+ #
174
+
175
+
176
+ def _debug_dumpObj(prefix:str, someObj, bSkipUnderscores:bool = True, names:list = None):
177
+ #print(prefix + "| " + repr(someObj))
178
+ if someObj is None:
179
+ return
180
+ if names is None:
181
+ names = dir(someObj)
182
+ for key in names:
183
+ if bSkipUnderscores and key.startswith("_"):
184
+ continue
185
+ print(prefix + "|\t" + key + ": " + str(getattr(someObj, key)))
186
+ #
187
+
188
+
189
+ #
190
+ # this is the annotation wrapper that receives arguments and returns the function that does the wrapping
191
+ #
192
+ # @param bool bDebug (optional) Enable debugging output at evaluation time.
193
+ # @param int|bool bDebugComp (optional) Enable debugging output at compile time.
194
+ # @param str logDescend (optional) Log descend message.
195
+ # @param jk_logging.EnumLoglevel logLevel (optional) Modify the standard descend log level.
196
+ # @param bool bLogWithhold (optional) Only log if a minimum log level of warning occurs.
197
+ #
198
+ def checkFunctionSignature(bDebug:bool = False, bDebugComp:typing.Union[bool,int] = False, logDescend:str = None, logLevel = None, bLogWithhold:bool = False):
199
+ assert isinstance(bDebug, bool)
200
+ assert isinstance(bDebugComp, (bool, int))
201
+ assert isinstance(bLogWithhold, bool)
202
+
203
+ # ----
204
+
205
+ # this function is executed for every function definition
206
+ def _wrap_the_function(fn):
207
+ annotations = typing.get_type_hints(fn) # receives a normal dictionary
208
+ _signature = inspect.signature(fn)
209
+ _signature_parameters = _signature.parameters # receives an ordered dictionary
210
+ _signature_return_annotation = _signature.return_annotation # receives a type annotation structure
211
+
212
+ if bDebugComp:
213
+ print("@@>> wrapping function " + fn.__qualname__ + "(..) with checkFunctionSignature() ...")
214
+ print("\t@@>> Annotations:")
215
+ for ak, av in annotations.items():
216
+ print("\t\t@@>> Annotation for " + repr(ak) + ": " + str(av))
217
+ print("\t@@>> Signature:")
218
+ for sk, sv in _signature_parameters.items():
219
+ print("\t\t@@>> Signature parameter for " + repr(sk) + ": " + repr(sv))
220
+ _debug_dumpObj("\t\t\t", sv, names = ["annotation", "default", "kind"])
221
+ # parameters are:
222
+ # str sv.name -- the name of the argument
223
+ # any sv.annotation -- the type annotation structure associated with this argument (or inspect._empty if not set)
224
+ # obj sv.default -- the defautl value (or inspect._empty if not set)
225
+ print("\t@@>> Return annotation: " + str(_signature_return_annotation))
226
+
227
+ # variables to fill during compile phase
228
+ _paramCheckers = {}
229
+ _returnChecker = None
230
+
231
+ # compile
232
+
233
+ outWarnList = [] # NOTE: we reuse this object for performance reasons
234
+ for k, t in _signature._parameters.items():
235
+ assert isinstance(t, inspect.Parameter)
236
+ c = CheckTypeCompiler.compile(k, _getTypeDescr(t), t.annotation, t.default, outWarnList, bDebugComp)
237
+ if bDebugComp:
238
+ if c is not None:
239
+ print("\t@@>> Signature parameter compilation for " + repr(k) + ":")
240
+ c.dump("\t\t|\t")
241
+ if bDebug:
242
+ if outWarnList:
243
+ for entry in outWarnList:
244
+ print("WARNING: " + fn.__qualname__ + "(), param " + repr(t.name) + " : " + entry)
245
+ outWarnList.clear()
246
+ if c is not None:
247
+ _paramCheckers[k] = c
248
+ #print("paramCheckers[" + k + "] =", c)
249
+
250
+ if _signature._return_annotation != inspect._empty:
251
+ outWarnList = []
252
+ _returnChecker = CheckTypeCompiler.compile(
253
+ None, # argName
254
+ _getTypeDescr(_signature._return_annotation), # sType
255
+ _signature._return_annotation, # typeSpec
256
+ inspect._empty, # defaultValue
257
+ outWarnList, # outWarnList
258
+ bDebugComp # nEnableDebugging
259
+ )
260
+ if bDebugComp:
261
+ if _returnChecker is not None:
262
+ print("\t@@>> Signature parameter compilation for returned values:")
263
+ _returnChecker.dump("\t\t|\t")
264
+ #print("returnChecker =", repr(returnChecker.sType))
265
+ _bIsMethod = "self" in _paramCheckers
266
+
267
+ # ----
268
+
269
+ _logDescend = None
270
+ if logDescend:
271
+ _pcLog = _paramCheckers["log"]
272
+ if _pcLog:
273
+ #_tmp = _pcLog.sType.split(".")
274
+ #if (_tmp[0] == "jk_logging") and (_tmp[-1].endswith("Logger")):
275
+ # _logDescend = logDescend
276
+ _logDescend = logDescend
277
+ if bDebug and (_logDescend is None):
278
+ print("WARNING: " + fn.__qualname__ + "() has no suitable parameter 'log' for log descent!")
279
+ if bDebug:
280
+ print("@@>> Using log descend.")
281
+ else:
282
+ if bDebug:
283
+ print("@@>> Not using log descend.")
284
+
285
+ # ----
286
+
287
+ def _wrapper(*args, **kwargs):
288
+ # bind arguments
289
+
290
+ boundedArgs = _signature.bind(*args, **kwargs)
291
+ #_pLog = _signature.parameters.get("log")
292
+ #print("@@", _pLog)
293
+ #print(dir(_pLog))
294
+
295
+ #print("\t>> " + pprint.pformat(boundedArgs))
296
+
297
+ # ----------------------------------------------------------------
298
+ # check arguments. delay raising of errors to print all error messages before raising an exception.
299
+
300
+ if bDebug:
301
+ print("@@>> Invoking function/method: " + fn.__qualname__ + "(..)")
302
+
303
+ err = None
304
+ for k, v in boundedArgs.arguments.items():
305
+ # k is the argument name
306
+ # v is the argument value
307
+ c = _paramCheckers.get(k)
308
+ if c:
309
+ if not c.__call__(v):
310
+ print("\targument " + repr(k) + ": " + c.sType + " => ✖")
311
+ if not err:
312
+ err = ValueError("Argument " + repr(k) + " for " + fn.__name__ + "() is of type '" + repr(type(v)) + "' which does not match '" + c.sType + "' as expected!")
313
+ else:
314
+ print("\targument " + repr(k) + ": " + c.sType + " => ✔")
315
+ else:
316
+ print("\targument " + repr(k) + ": no constraint specified")
317
+ if err:
318
+ raise err
319
+
320
+ else:
321
+ for k, v in boundedArgs.arguments.items():
322
+ # k is the argument name
323
+ # v is the argument value
324
+ c = _paramCheckers.get(k)
325
+ if c:
326
+ if not c.__call__(v):
327
+ raise ValueError("Argument " + repr(k) + " for " + fn.__name__ + "() is of type '" + repr(type(v)) + "' which does not match '" + c.sType + "' as expected!")
328
+
329
+ # ----------------------------------------------------------------
330
+ # invoke the function
331
+
332
+ if _logDescend:
333
+ _baLogger = boundedArgs.arguments.get("log")
334
+ if _baLogger is not None:
335
+ # a 'log' argument is a) expected and b) has been specified; this is the normal situation => descent
336
+
337
+ _baVerbose = boundedArgs.arguments.get("bVerbose")
338
+ bWithholdVerbose = _baVerbose if isinstance(_baVerbose, bool) else False
339
+
340
+ with _baLogger.descend(_logDescend.format(**boundedArgs.arguments), logLevel=logLevel, bWithhold=bLogWithhold, bWithholdVerbose=bWithholdVerbose) as log2:
341
+ boundedArgs.arguments["log"] = log2
342
+ ret = fn(*boundedArgs.args, **boundedArgs.kwargs)
343
+
344
+ else:
345
+ # a 'log' argument is a) expected and b) but has been specified; this will now result in an exception raise (= programming error by the caller)
346
+ ret = fn(*args, **kwargs)
347
+ else:
348
+ # no 'log' argument is expected => no descent
349
+ ret = fn(*args, **kwargs)
350
+
351
+ # ----------------------------------------------------------------
352
+ # check the return value.
353
+
354
+ if bDebug:
355
+ if _returnChecker:
356
+ if not _returnChecker.__call__(ret):
357
+ print("\treturn value: " + _returnChecker.sType + " => ✖")
358
+ raise ValueError("Return value for " + fn.__name__ + "() is of type '" + repr(type(ret)) + "' which does not match '" + _returnChecker.sType + "' as expected!")
359
+ else:
360
+ print("\treturn value: " + _returnChecker.sType + " => ✔")
361
+ else:
362
+ print("\treturn value: no constraint specified")
363
+
364
+ else:
365
+ if _returnChecker:
366
+ if not _returnChecker.__call__(ret):
367
+ raise ValueError("Return value for " + fn.__name__ + "() is of type '" + repr(type(ret)) + "' which does not match '" + _returnChecker.sType + "' as expected!")
368
+
369
+ # ----------------------------------------------------------------
370
+
371
+ return ret
372
+ #
373
+
374
+ _wrapper.orgName = fn.__name__
375
+ _wrapper.orgQualName = fn.__qualname__
376
+ _wrapper.orgSignature = _signature
377
+ return _wrapper
378
+ #return _FunctionWrapper(fn, signature, paramCheckers, returnChecker, bDebug)
379
+ #
380
+
381
+ return _wrap_the_function
382
+ #
383
+
384
+
385
+
386
+
387
+
@@ -0,0 +1,55 @@
1
+
2
+
3
+ import typing
4
+ import inspect
5
+
6
+
7
+
8
+
9
+
10
+ class AbstractCTNode(object):
11
+
12
+ ################################################################################################################################
13
+ ## Constructor
14
+ ################################################################################################################################
15
+
16
+ ################################################################################################################################
17
+ ## Public Properties
18
+ ################################################################################################################################
19
+
20
+ ################################################################################################################################
21
+ ## Helper Methods
22
+ ################################################################################################################################
23
+
24
+ def _printCodeLocation(self, codeFileName:str, bValue:bool):
25
+ lineNo = inspect.currentframe().f_back.f_lineno
26
+ print(f">> Returns **{bValue}** here: {codeFileName}:{lineNo}")
27
+ #
28
+
29
+ ################################################################################################################################
30
+ ## Public Methods
31
+ ################################################################################################################################
32
+
33
+ def __call__(self, value) -> bool:
34
+ raise NotImplementedError()
35
+ #
36
+
37
+ def dump(self, prefix:str = None, printFunc:typing.Callable = None):
38
+ if prefix is None:
39
+ prefix = ""
40
+ if printFunc is None:
41
+ printFunc = print
42
+
43
+ self._dump(prefix, printFunc)
44
+ #
45
+
46
+ def _dump(self, prefix:str, printFunc:typing.Callable):
47
+ raise NotImplementedError()
48
+ #
49
+
50
+ #
51
+
52
+
53
+
54
+
55
+
@@ -0,0 +1,61 @@
1
+
2
+
3
+ import typing
4
+
5
+ from .AbstractCTNode import AbstractCTNode
6
+
7
+
8
+
9
+
10
+
11
+ class CTAlwaysTrue(AbstractCTNode):
12
+
13
+ ################################################################################################################################
14
+ ## Constructor
15
+ ################################################################################################################################
16
+
17
+ #
18
+ # Constructor method.
19
+ #
20
+ def __init__(self, argName:typing.Union[str,None], sType:str, nDebug:typing.Union[bool,int]):
21
+ if argName is not None:
22
+ assert isinstance(argName, str)
23
+ assert isinstance(sType, str)
24
+ assert isinstance(nDebug, (bool, int))
25
+
26
+ # ----
27
+
28
+ self.argName = argName
29
+ self.sType = sType
30
+ self.__nDebug = nDebug
31
+ #
32
+
33
+ ################################################################################################################################
34
+ ## Public Properties
35
+ ################################################################################################################################
36
+
37
+ ################################################################################################################################
38
+ ## Helper Methods
39
+ ################################################################################################################################
40
+
41
+ ################################################################################################################################
42
+ ## Public Methods
43
+ ################################################################################################################################
44
+
45
+ def __call__(self, value) -> bool:
46
+ return True
47
+ #
48
+
49
+ def _dump(self, prefix:str, printFunc:typing.Callable):
50
+ printFunc(prefix + "CTAlwaysTrue<( argName=" + repr(self.argName) + ", sType=" + repr(self.sType))
51
+ printFunc(prefix + ")>")
52
+ #
53
+
54
+ #
55
+
56
+
57
+
58
+
59
+
60
+
61
+