first commit
This commit is contained in:
135
python3-vckonline/lib/python3.8/site-packages/pop/verify.py
Normal file
135
python3-vckonline/lib/python3.8/site-packages/pop/verify.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# Import python libs
|
||||
import inspect
|
||||
|
||||
# Import pop libs
|
||||
import pop.exc
|
||||
import pop.hub
|
||||
import pop.loader
|
||||
from typing import Any, Callable, Dict, Iterable, List
|
||||
|
||||
|
||||
def contract(
|
||||
hub: "pop.hub.Hub", # pylint: disable=unused-argument
|
||||
raws: Iterable["pop.loader.LoadedMod"],
|
||||
mod: "pop.loader.LoadedMod",
|
||||
):
|
||||
"""
|
||||
Verify module level contract - functions only
|
||||
:param hub: The redistributed pop central hub
|
||||
:param raws: A list of loaded modules with contracts
|
||||
:param mod: A loader module
|
||||
"""
|
||||
sig_errs = []
|
||||
sig_miss = []
|
||||
mname = mod.__name__
|
||||
for raw in raws:
|
||||
if isinstance(raw, pop.loader.LoadError):
|
||||
sig_errs.append(str(raw))
|
||||
continue
|
||||
else:
|
||||
for fun in raw._funcs:
|
||||
if fun.startswith("sig_"):
|
||||
tfun = fun[4:]
|
||||
if tfun not in mod._funcs:
|
||||
sig_miss.append(tfun)
|
||||
continue
|
||||
sig_errs.extend(sig(mod._funcs[tfun].func, raw._funcs[fun].func))
|
||||
if sig_errs or sig_miss:
|
||||
msg = ""
|
||||
if sig_errs:
|
||||
msg += f"Signature Errors in {mname}:\n"
|
||||
for err in sig_errs:
|
||||
msg += f"{err}\n"
|
||||
if sig_miss:
|
||||
msg += f"Signature Functions Missing in {mname}:\n"
|
||||
for err in sig_miss:
|
||||
msg += f"{err}\n"
|
||||
msg = msg.strip()
|
||||
raise pop.exc.ContractSigException(msg)
|
||||
|
||||
|
||||
def sig_map(ver: Callable) -> Dict[str, Any]:
|
||||
"""
|
||||
Generates the map dict for the signature verification
|
||||
"""
|
||||
vsig = inspect.signature(ver)
|
||||
vparams = list(vsig.parameters.values())
|
||||
vdat = {"args": [], "v_pos": -1, "kw": [], "kwargs": False, "ann": {}}
|
||||
for ind in range(len(vparams)):
|
||||
param = vparams[ind]
|
||||
val = param.kind.value
|
||||
name = param.name
|
||||
if val == 0 or val == 1:
|
||||
vdat["args"].append(name)
|
||||
if param.default != inspect._empty: # Is a KW, can be inside of **kwargs
|
||||
vdat["kw"].append(name)
|
||||
elif val == 2:
|
||||
vdat["v_pos"] = ind
|
||||
elif val == 3:
|
||||
vdat["kw"].append(name)
|
||||
elif val == 4:
|
||||
vdat["kwargs"] = ind
|
||||
if param.annotation != inspect._empty:
|
||||
vdat["ann"][name] = param.annotation
|
||||
return vdat
|
||||
|
||||
|
||||
def sig(func: Callable, ver: Callable) -> List[str]:
|
||||
"""
|
||||
Takes 2 functions, the first function is verified to have a parameter signature
|
||||
compatible with the second function
|
||||
"""
|
||||
errors = []
|
||||
fsig = inspect.signature(func)
|
||||
fparams = list(fsig.parameters.values())
|
||||
vdat = sig_map(ver)
|
||||
arg_len = len(vdat["args"])
|
||||
v_pos = False
|
||||
for ind in range(len(fparams)):
|
||||
param = fparams[ind]
|
||||
val = param.kind.value
|
||||
name = param.name
|
||||
has_default = param.default != inspect._empty
|
||||
ann = param.annotation
|
||||
vann = vdat["ann"].get(name, inspect._empty)
|
||||
if vann != ann:
|
||||
errors.append(f'Parameter, "{name}" is type "{str(ann)}" not "{str(vann)}"')
|
||||
if val == 2:
|
||||
v_pos = True
|
||||
if val == 0 or val == 1:
|
||||
if ind >= arg_len: # Past available positional args
|
||||
if not vdat["v_pos"] == -1: # Has a *args
|
||||
if ind >= vdat["v_pos"] and v_pos:
|
||||
# Invalid unless it is a kw
|
||||
if not name in vdat["kw"]:
|
||||
# Is a kw
|
||||
errors.append(f'Parameter "{name}" is invalid')
|
||||
if vdat["kwargs"] is False:
|
||||
errors.append(f'Parameter "{name}" not defined as kw only')
|
||||
continue
|
||||
elif vdat["kwargs"] is not False and not has_default:
|
||||
errors.append(
|
||||
f'Parameter "{name}" is past available positional params'
|
||||
)
|
||||
elif vdat["kwargs"] is False:
|
||||
errors.append(
|
||||
f'Parameter "{name}" is past available positional params'
|
||||
)
|
||||
else:
|
||||
v_param = vdat["args"][ind]
|
||||
if v_param != name:
|
||||
errors.append(
|
||||
f'Parameter "{name}" does not have the correct name: {v_param}'
|
||||
)
|
||||
if val == 2:
|
||||
if ind < vdat["v_pos"]:
|
||||
errors.append(
|
||||
f'Parameter "{name}" is not in the correct position for *args'
|
||||
)
|
||||
if val == 3:
|
||||
if name not in vdat["kw"] and not vdat["kwargs"]:
|
||||
errors.append(f'Parameter "{name}" is not available as a kwarg')
|
||||
if val == 4:
|
||||
if vdat["kwargs"] is False:
|
||||
errors.append(f"Kwargs are not permitted as a parameter")
|
||||
return errors
|
||||
Reference in New Issue
Block a user