Esempio n. 1
0
    def pop(self, key, *args, to=None):
        """if key is in the dictionary, remove it and return its value, else
        return default.  if default is not given and key is not in the dictionary,
        a KeyError is raised."""

        if len(args) > 1:
            raise TypeError(f"function takes one or two position arguments")
        if to is None:
            to = self.to_type

        var = f"{self.tcl_array}({key})"
        if exists(var):
            val = getvar(var, to=to)
            call("unset", var)
            return val
        if len(args) == 0:
            raise KeyError(key)
        if args[0] is None:
            return None
        return convert(args[0], to=to)
Esempio n. 2
0
    def passthrough_trampoline(self, args, kwargs):
        """passthrough trampoline function is for calling C functions on the tcl
        side where we don't know anything about what arguments it takes so we
        treat everything as positional and pass through exactly what we get

        but we still support the to= conversion... :-)"""
        if "to" in kwargs:
            to_type = kwargs["to"]
            del kwargs["to"]
        else:
            to_type = self.to_type

        if len(kwargs) > 0:
            raise TypeError(
                f"can't specify named parameters to a tcl function that isn't a proc: '{self.proc}'"
            )
        return call(self.proc, *args, to=to_type)
Esempio n. 3
0
def tcl_stdout_to_python():
    """redirect tcl's stdout to python"""
    call("tohil::redirect_stdout_to_python")
Esempio n. 4
0
    def trampoline(self, args, kwargs):
        """trampoline function takes our proc probe data, positional parameters
        and named parameters, figures out if everything's there that the proc
        needs and calls the proc, or generates an exception for missing parameters,
        too many parameters, unrecognized parameters, etc

        if performance becomes an issue, this should be able to be converted to
        C without great difficulty.  it's good in python while we figure it all out.
        """
        final = dict()

        # print(f"trampoline invoked, self '{self}', args '{args}', kwargs '{kwargs}', defaults '{self.defaults}'")

        if "to" in kwargs:
            to_type = kwargs["to"]
            del kwargs["to"]
            # print(f"set aside to  of {to_type}")
        else:
            to_type = self.to_type

        nargs = len(args)
        if nargs + len(kwargs) > len(
                self.proc_args) and self.proc_args[-1] != "args":
            raise TypeError(
                f"too many arguments specified to be passed to tcl proc '{self.proc}'"
            )

        # pump any named parameters into the "final" dict
        # print("checking named parameters")
        for arg_name, arg in kwargs.items():
            if arg_name in final:
                raise TypeError(
                    f"parameter '{arg_name}' specified multiple times -- can only specify it once"
                )
            if arg_name not in self.proc_args:
                raise TypeError(
                    f"named parameter '{arg_name}' is not a valid arument for proc '{self.proc}'"
                )
            # print(f"trampoline filling in named parameter {arg_name}, '{repr(arg)}'")
            final[arg_name] = arg

        # pump the positional arguments into the "final" dict
        # these args are positional from the python side; python already split out
        # named parameters into kwargs before calling us.
        #
        # advance, matching the tcl arg names to the args tuple, but if an
        # arg name is already in the final array due to having come from
        # a named parameter, advance to the next argument, without advancing
        # the args list.
        # print("checking positional parameters")
        pos = 0
        # for arg_name, arg in zip(self.proc_args, args):
        for arg_name in self.proc_args:
            if pos >= nargs:
                break
            if arg_name != "args":
                if arg_name not in final:
                    # a position parameter has been fulfilled
                    final[arg_name] = args[pos]
                    # print(f"trampoline filling in position arg {arg_name}, '{repr(args[pos])}'")
                else:
                    # already have this from a named parameter, skip but
                    # keep the current positional parameter for the next arg
                    continue
            else:
                # this argument is the tcl-special "args",
                # grab the remainder of the arg list into args and stop iterating.
                # we'll make use of this to handle args correctly in our call to tcl.
                final[arg_name] = args[pos:]
                break
            pos += 1

        # pump any default values, if needed, by checking for the existence
        # of the default values' var names in the final array.  if it isn't
        # there, put it there.  if it is there, the default isn't needed.
        # print("checking defaults")
        for arg_name, def_value in self.defaults.items():
            if arg_name not in final:
                # print(f"trampoline filling in default value {arg_name}, '{def_value}'")
                final[arg_name] = def_value

        # make sure we've got something for each of the proc's argument - if anything are
        # missing, it's an error.
        for arg_name in self.proc_args:
            # it's ok if args is missing
            if not arg_name in final and arg_name != "args":
                raise TypeError(f"required arg '{arg_name}' missing")

        # assemble the final argument list in the correct order for the proc
        final_arg_list = list()
        for arg_name in self.proc_args:
            if arg_name != "args":
                final_arg_list.append(final[arg_name])
            else:
                # it's "args". if we have args (because we may not, if there
                # weren't enough arguments specified to have there be one), extend
                # the final_arg_list with them, i.e. add them flat instead of nested,
                # the way tcl will expect the args args
                if "args" in final:
                    final_arg_list.extend(final[arg_name])

        # ...and invoke the proc
        # print(f"trampoline calling {self.proc} with final of '{repr(final_arg_list)}'")
        return call(self.proc, *final_arg_list, to=to_type)
Esempio n. 5
0
def info_default(proc, var):
    """wrapper for 'info default'"""
    return call("safe_info_default", proc, var, to=tuple)
Esempio n. 6
0
def namespace_children(namespace):
    """wrapper for 'namespace children'"""
    return sorted(call("namespace", "children", namespace, to=list))
Esempio n. 7
0
def info_body(proc):
    """wrapper for 'info body'"""
    return call("info", "body", proc, to=str)
Esempio n. 8
0
 def __repr__(self):
     """return a representation of the shadow dict"""
     return str(call("array", "get", self.tcl_array, to=dict))
Esempio n. 9
0
def info_args(proc):
    """wrapper for 'info args'"""
    return call("info", "args", proc, to=list)
Esempio n. 10
0
 def flush(self):
     """flush tcl's stdout"""
     call("flush", "stdout")
Esempio n. 11
0
 def write(self, string):
     """write a string, to Tcl"""
     call("puts", "-nonewline", string)
Esempio n. 12
0
 def keys(self):
     """return a view of the ShadowDict's keys.  unlike dicts in later 3.x
     python, there come back in hash traversal i.e. basically random order"""
     return call("array", "names", self.tcl_array)
Esempio n. 13
0
 def clear(self):
     """remove all items from the shadow dictionary (unset the tcl array)"""
     call("array", "unset", self.tcl_array)
Esempio n. 14
0
def interact():
    """start interacting with the tcl interpreter"""
    eval("package require Tclx")
    call("commandloop", "-prompt1", 'return  " % "', "-prompt2", 'return "> "')
Esempio n. 15
0
def info_procs(pattern=None, what="procs"):
    """wrapper for 'info procs' or whatever"""
    if pattern is None:
        return sorted(call("info", what, to=list))
    else:
        return sorted(call("info", what, pattern, to=list))
Esempio n. 16
0
 def __init__(self, tcl_array):
     self.keys = call("array", "names", tcl_array, to=list)
     self.keys.sort()
Esempio n. 17
0
 def __len__(self):
     """return the length of the shadow dict i.e. the size of the tcl array"""
     return call("array", "size", self.tcl_array, to=int)