# This file was automatically generated by SWIG (https://www.swig.org).
# Version 4.2.1
#
# Do not make changes to this file unless you know what you are doing - modify
# the SWIG interface file instead.

import sys
if sys.version_info > (3, 0):
    from collections import UserDict
else:
    from UserDict import UserDict
import numpy as np
import chinet as cn
import inspect
import json
import types  # used by Node to identify code objects
import _chinet
__version__ = _chinet.CHINET_VERSION


def node(func):
    """A simple decorator to convert functions a chinet.Node object

    :param func:
    :return:
    """
    return cn.Node(
        callback_function=func,
        name=func.__name__,
    )


class NodeGroup(UserDict):

    name = None# type: str
    inputs = {} # type: dict
    outputs = {} # type: dict

    @property
    def is_valid(self):
        return not self.has_invalid_nodes()

    def __init__(
            self,
            name = '', # type: str
            nodes = None #type: dict
    ):
        self.name = name
        for nk in nodes:
            if not isinstance(nodes[nk], cn.Node):
                if isinstance(nodes[nk], dict):
                    nodes[nk] = cn.Node(**nodes[nk])
                elif isinstance(nodes[nk], list):
                    nodes[nk] = cn.Node(*nodes[nk])
                else:
                    raise ValueError("Node parameters need to be either list, dict, or cn.Node")
        super(NodeGroup, self).__init__(
            {
                'nodes': nodes
            }
        )

    def __len__(self):
        return len(self.data['nodes'])

    def __delitem__(self, key):
        del self.data['nodes'][key]

    def __iter__(self):
        return iter(self.data['nodes'])

# Modify __contains__ to work correctly when __missing__ is present
    def __contains__(self, key):
        return key in self.data

    def __setitem__(self, key, value):
        if isinstance(value, cn.Node):
            self.add_ports_of_node(value)
            self.data['nodes'][key] = value
        else:
            super(NodeGroup, self).__setitem__(key, value)

    def __getitem__(self, key):
        if key in self.data['nodes']:
            return self.data['nodes'][key]
        if hasattr(self.__class__, "__missing__"):
            return self.__class__.__missing__(self, key)
        raise KeyError(key)

    def __setattr__(self, name, value):
        try:
            self.inputs[name].value = value
        except KeyError:
            super(NodeGroup, self).__setattr__(name, value)

    def __getattr__(self, name):
        in_input = name in self.inputs.keys()
        in_output = name in self.outputs.keys()
        if in_input and in_output:
            raise KeyError("Ambiguous access. %s an input and output parameter.")
        elif not in_output and not in_input:
            raise AttributeError
        else:
            if in_input:
                return self.inputs[name].value
            else:
                return self.outputs[name].value

    def __call__(self, *args, **kwargs):
        self.evaluate()

    def add_ports_of_node(self, value):
# type: (chinet.Node) -> None
        if isinstance(value, cn.Node):
            for k in value.inputs.keys():
                if k in self.inputs.keys():
                    Warning("Input key already exists. Linking to existing input ports")
                    if value.inputs[k] is not self.inputs[k]:
                        value.inputs[k].link = self.inputs[k]
                else:
                    self.inputs[k] = value.inputs[k]
            for k in value.outputs.keys():
                if k in self.outputs.keys():
                    Warning("Output port name %s already exists." % k)
                self.outputs[k] = value.outputs[k]

    def has_invalid_nodes(self):
        for nk in self:
            node = self[nk]
            if not node.is_valid:
                return True
        return False

    def evaluate(self):
        while self.has_invalid_nodes():
            for nk in self:
                n = self[nk]
                if not n.is_valid:
                    n.evaluate()





from sys import version_info as _swig_python_version_info
# Import the low-level C/C++ module
if __package__ or "." in __name__:
    from . import _chinet
else:
    import _chinet

try:
    import builtins as __builtin__
except ImportError:
    import __builtin__

def _swig_repr(self):
    try:
        strthis = "proxy of " + self.this.__repr__()
    except __builtin__.Exception:
        strthis = ""
    return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)


def _swig_setattr_nondynamic_instance_variable(set):
    def set_instance_attr(self, name, value):
        if name == "this":
            set(self, name, value)
        elif name == "thisown":
            self.this.own(value)
        elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
            set(self, name, value)
        else:
            raise AttributeError("You cannot add instance attributes to %s" % self)
    return set_instance_attr


def _swig_setattr_nondynamic_class_variable(set):
    def set_class_attr(cls, name, value):
        if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
            set(cls, name, value)
        else:
            raise AttributeError("You cannot add class attributes to %s" % cls)
    return set_class_attr


def _swig_add_metaclass(metaclass):
    """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
    def wrapper(cls):
        return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
    return wrapper


class _SwigNonDynamicMeta(type):
    """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
    __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)


import weakref

class SwigPyIterator(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined - class is abstract")
    __repr__ = _swig_repr
    __swig_destroy__ = _chinet.delete_SwigPyIterator

    def value(self):
        return _chinet.SwigPyIterator_value(self)

    def incr(self, n=1):
        return _chinet.SwigPyIterator_incr(self, n)

    def decr(self, n=1):
        return _chinet.SwigPyIterator_decr(self, n)

    def distance(self, x):
        return _chinet.SwigPyIterator_distance(self, x)

    def equal(self, x):
        return _chinet.SwigPyIterator_equal(self, x)

    def copy(self):
        return _chinet.SwigPyIterator_copy(self)

    def next(self):
        return _chinet.SwigPyIterator_next(self)

    def __next__(self):
        return _chinet.SwigPyIterator___next__(self)

    def previous(self):
        return _chinet.SwigPyIterator_previous(self)

    def advance(self, n):
        return _chinet.SwigPyIterator_advance(self, n)

    def __eq__(self, x):
        return _chinet.SwigPyIterator___eq__(self, x)

    def __ne__(self, x):
        return _chinet.SwigPyIterator___ne__(self, x)

    def __iadd__(self, n):
        return _chinet.SwigPyIterator___iadd__(self, n)

    def __isub__(self, n):
        return _chinet.SwigPyIterator___isub__(self, n)

    def __add__(self, n):
        return _chinet.SwigPyIterator___add__(self, n)

    def __sub__(self, *args):
        return _chinet.SwigPyIterator___sub__(self, *args)
    def __iter__(self):
        return self

# Register SwigPyIterator in _chinet:
_chinet.SwigPyIterator_swigregister(SwigPyIterator)
SHARED_PTR_DISOWN = _chinet.SHARED_PTR_DISOWN
class MapStringString(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.MapStringString_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.MapStringString___nonzero__(self)

    def __bool__(self):
        return _chinet.MapStringString___bool__(self)

    def __len__(self):
        return _chinet.MapStringString___len__(self)
    def __iter__(self):
        return self.key_iterator()
    def iterkeys(self):
        return self.key_iterator()
    def itervalues(self):
        return self.value_iterator()
    def iteritems(self):
        return self.iterator()

    def __getitem__(self, key):
        return _chinet.MapStringString___getitem__(self, key)

    def __delitem__(self, key):
        return _chinet.MapStringString___delitem__(self, key)

    def has_key(self, key):
        return _chinet.MapStringString_has_key(self, key)

    def keys(self):
        return _chinet.MapStringString_keys(self)

    def values(self):
        return _chinet.MapStringString_values(self)

    def items(self):
        return _chinet.MapStringString_items(self)

    def __contains__(self, key):
        return _chinet.MapStringString___contains__(self, key)

    def key_iterator(self):
        return _chinet.MapStringString_key_iterator(self)

    def value_iterator(self):
        return _chinet.MapStringString_value_iterator(self)

    def __setitem__(self, *args):
        return _chinet.MapStringString___setitem__(self, *args)

    def asdict(self):
        return _chinet.MapStringString_asdict(self)

    def __init__(self, *args):
        _chinet.MapStringString_swiginit(self, _chinet.new_MapStringString(*args))

    def empty(self):
        return _chinet.MapStringString_empty(self)

    def size(self):
        return _chinet.MapStringString_size(self)

    def swap(self, v):
        return _chinet.MapStringString_swap(self, v)

    def begin(self):
        return _chinet.MapStringString_begin(self)

    def end(self):
        return _chinet.MapStringString_end(self)

    def rbegin(self):
        return _chinet.MapStringString_rbegin(self)

    def rend(self):
        return _chinet.MapStringString_rend(self)

    def clear(self):
        return _chinet.MapStringString_clear(self)

    def get_allocator(self):
        return _chinet.MapStringString_get_allocator(self)

    def count(self, x):
        return _chinet.MapStringString_count(self, x)

    def erase(self, *args):
        return _chinet.MapStringString_erase(self, *args)

    def find(self, x):
        return _chinet.MapStringString_find(self, x)

    def lower_bound(self, x):
        return _chinet.MapStringString_lower_bound(self, x)

    def upper_bound(self, x):
        return _chinet.MapStringString_upper_bound(self, x)
    __swig_destroy__ = _chinet.delete_MapStringString

# Register MapStringString in _chinet:
_chinet.MapStringString_swigregister(MapStringString)
class VectorString(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.VectorString_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.VectorString___nonzero__(self)

    def __bool__(self):
        return _chinet.VectorString___bool__(self)

    def __len__(self):
        return _chinet.VectorString___len__(self)

    def __getslice__(self, i, j):
        return _chinet.VectorString___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.VectorString___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.VectorString___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.VectorString___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.VectorString___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.VectorString___setitem__(self, *args)

    def pop(self):
        return _chinet.VectorString_pop(self)

    def append(self, x):
        return _chinet.VectorString_append(self, x)

    def empty(self):
        return _chinet.VectorString_empty(self)

    def size(self):
        return _chinet.VectorString_size(self)

    def swap(self, v):
        return _chinet.VectorString_swap(self, v)

    def begin(self):
        return _chinet.VectorString_begin(self)

    def end(self):
        return _chinet.VectorString_end(self)

    def rbegin(self):
        return _chinet.VectorString_rbegin(self)

    def rend(self):
        return _chinet.VectorString_rend(self)

    def clear(self):
        return _chinet.VectorString_clear(self)

    def get_allocator(self):
        return _chinet.VectorString_get_allocator(self)

    def pop_back(self):
        return _chinet.VectorString_pop_back(self)

    def erase(self, *args):
        return _chinet.VectorString_erase(self, *args)

    def __init__(self, *args):
        _chinet.VectorString_swiginit(self, _chinet.new_VectorString(*args))

    def push_back(self, x):
        return _chinet.VectorString_push_back(self, x)

    def front(self):
        return _chinet.VectorString_front(self)

    def back(self):
        return _chinet.VectorString_back(self)

    def assign(self, n, x):
        return _chinet.VectorString_assign(self, n, x)

    def resize(self, *args):
        return _chinet.VectorString_resize(self, *args)

    def insert(self, *args):
        return _chinet.VectorString_insert(self, *args)

    def reserve(self, n):
        return _chinet.VectorString_reserve(self, n)

    def capacity(self):
        return _chinet.VectorString_capacity(self)
    __swig_destroy__ = _chinet.delete_VectorString

# Register VectorString in _chinet:
_chinet.VectorString_swigregister(VectorString)
class VectorDouble(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def iterator(self):
        return _chinet.VectorDouble_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.VectorDouble___nonzero__(self)

    def __bool__(self):
        return _chinet.VectorDouble___bool__(self)

    def __len__(self):
        return _chinet.VectorDouble___len__(self)

    def __getslice__(self, i, j):
        return _chinet.VectorDouble___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.VectorDouble___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.VectorDouble___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.VectorDouble___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.VectorDouble___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.VectorDouble___setitem__(self, *args)

    def pop(self):
        return _chinet.VectorDouble_pop(self)

    def append(self, x):
        return _chinet.VectorDouble_append(self, x)

    def empty(self):
        return _chinet.VectorDouble_empty(self)

    def size(self):
        return _chinet.VectorDouble_size(self)

    def swap(self, v):
        return _chinet.VectorDouble_swap(self, v)

    def begin(self):
        return _chinet.VectorDouble_begin(self)

    def end(self):
        return _chinet.VectorDouble_end(self)

    def rbegin(self):
        return _chinet.VectorDouble_rbegin(self)

    def rend(self):
        return _chinet.VectorDouble_rend(self)

    def clear(self):
        return _chinet.VectorDouble_clear(self)

    def get_allocator(self):
        return _chinet.VectorDouble_get_allocator(self)

    def pop_back(self):
        return _chinet.VectorDouble_pop_back(self)

    def erase(self, *args):
        return _chinet.VectorDouble_erase(self, *args)

    def __init__(self, *args):
        _chinet.VectorDouble_swiginit(self, _chinet.new_VectorDouble(*args))

    def push_back(self, x):
        return _chinet.VectorDouble_push_back(self, x)

    def front(self):
        return _chinet.VectorDouble_front(self)

    def back(self):
        return _chinet.VectorDouble_back(self)

    def assign(self, n, x):
        return _chinet.VectorDouble_assign(self, n, x)

    def resize(self, *args):
        return _chinet.VectorDouble_resize(self, *args)

    def insert(self, *args):
        return _chinet.VectorDouble_insert(self, *args)

    def reserve(self, n):
        return _chinet.VectorDouble_reserve(self, n)

    def capacity(self):
        return _chinet.VectorDouble_capacity(self)

    def __str__(self):
        return _chinet.VectorDouble___str__(self)

    def __repr__(self):
        return _chinet.VectorDouble___repr__(self)
    __swig_destroy__ = _chinet.delete_VectorDouble

# Register VectorDouble in _chinet:
_chinet.VectorDouble_swigregister(VectorDouble)
class VectorInt(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.VectorInt_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.VectorInt___nonzero__(self)

    def __bool__(self):
        return _chinet.VectorInt___bool__(self)

    def __len__(self):
        return _chinet.VectorInt___len__(self)

    def __getslice__(self, i, j):
        return _chinet.VectorInt___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.VectorInt___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.VectorInt___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.VectorInt___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.VectorInt___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.VectorInt___setitem__(self, *args)

    def pop(self):
        return _chinet.VectorInt_pop(self)

    def append(self, x):
        return _chinet.VectorInt_append(self, x)

    def empty(self):
        return _chinet.VectorInt_empty(self)

    def size(self):
        return _chinet.VectorInt_size(self)

    def swap(self, v):
        return _chinet.VectorInt_swap(self, v)

    def begin(self):
        return _chinet.VectorInt_begin(self)

    def end(self):
        return _chinet.VectorInt_end(self)

    def rbegin(self):
        return _chinet.VectorInt_rbegin(self)

    def rend(self):
        return _chinet.VectorInt_rend(self)

    def clear(self):
        return _chinet.VectorInt_clear(self)

    def get_allocator(self):
        return _chinet.VectorInt_get_allocator(self)

    def pop_back(self):
        return _chinet.VectorInt_pop_back(self)

    def erase(self, *args):
        return _chinet.VectorInt_erase(self, *args)

    def __init__(self, *args):
        _chinet.VectorInt_swiginit(self, _chinet.new_VectorInt(*args))

    def push_back(self, x):
        return _chinet.VectorInt_push_back(self, x)

    def front(self):
        return _chinet.VectorInt_front(self)

    def back(self):
        return _chinet.VectorInt_back(self)

    def assign(self, n, x):
        return _chinet.VectorInt_assign(self, n, x)

    def resize(self, *args):
        return _chinet.VectorInt_resize(self, *args)

    def insert(self, *args):
        return _chinet.VectorInt_insert(self, *args)

    def reserve(self, n):
        return _chinet.VectorInt_reserve(self, n)

    def capacity(self):
        return _chinet.VectorInt_capacity(self)
    __swig_destroy__ = _chinet.delete_VectorInt

# Register VectorInt in _chinet:
_chinet.VectorInt_swigregister(VectorInt)
class VectorLong(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.VectorLong_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.VectorLong___nonzero__(self)

    def __bool__(self):
        return _chinet.VectorLong___bool__(self)

    def __len__(self):
        return _chinet.VectorLong___len__(self)

    def __getslice__(self, i, j):
        return _chinet.VectorLong___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.VectorLong___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.VectorLong___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.VectorLong___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.VectorLong___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.VectorLong___setitem__(self, *args)

    def pop(self):
        return _chinet.VectorLong_pop(self)

    def append(self, x):
        return _chinet.VectorLong_append(self, x)

    def empty(self):
        return _chinet.VectorLong_empty(self)

    def size(self):
        return _chinet.VectorLong_size(self)

    def swap(self, v):
        return _chinet.VectorLong_swap(self, v)

    def begin(self):
        return _chinet.VectorLong_begin(self)

    def end(self):
        return _chinet.VectorLong_end(self)

    def rbegin(self):
        return _chinet.VectorLong_rbegin(self)

    def rend(self):
        return _chinet.VectorLong_rend(self)

    def clear(self):
        return _chinet.VectorLong_clear(self)

    def get_allocator(self):
        return _chinet.VectorLong_get_allocator(self)

    def pop_back(self):
        return _chinet.VectorLong_pop_back(self)

    def erase(self, *args):
        return _chinet.VectorLong_erase(self, *args)

    def __init__(self, *args):
        _chinet.VectorLong_swiginit(self, _chinet.new_VectorLong(*args))

    def push_back(self, x):
        return _chinet.VectorLong_push_back(self, x)

    def front(self):
        return _chinet.VectorLong_front(self)

    def back(self):
        return _chinet.VectorLong_back(self)

    def assign(self, n, x):
        return _chinet.VectorLong_assign(self, n, x)

    def resize(self, *args):
        return _chinet.VectorLong_resize(self, *args)

    def insert(self, *args):
        return _chinet.VectorLong_insert(self, *args)

    def reserve(self, n):
        return _chinet.VectorLong_reserve(self, n)

    def capacity(self):
        return _chinet.VectorLong_capacity(self)
    __swig_destroy__ = _chinet.delete_VectorLong

# Register VectorLong in _chinet:
_chinet.VectorLong_swigregister(VectorLong)
class MapStringVectorDouble(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.MapStringVectorDouble_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.MapStringVectorDouble___nonzero__(self)

    def __bool__(self):
        return _chinet.MapStringVectorDouble___bool__(self)

    def __len__(self):
        return _chinet.MapStringVectorDouble___len__(self)
    def __iter__(self):
        return self.key_iterator()
    def iterkeys(self):
        return self.key_iterator()
    def itervalues(self):
        return self.value_iterator()
    def iteritems(self):
        return self.iterator()

    def __getitem__(self, key):
        return _chinet.MapStringVectorDouble___getitem__(self, key)

    def __delitem__(self, key):
        return _chinet.MapStringVectorDouble___delitem__(self, key)

    def has_key(self, key):
        return _chinet.MapStringVectorDouble_has_key(self, key)

    def keys(self):
        return _chinet.MapStringVectorDouble_keys(self)

    def values(self):
        return _chinet.MapStringVectorDouble_values(self)

    def items(self):
        return _chinet.MapStringVectorDouble_items(self)

    def __contains__(self, key):
        return _chinet.MapStringVectorDouble___contains__(self, key)

    def key_iterator(self):
        return _chinet.MapStringVectorDouble_key_iterator(self)

    def value_iterator(self):
        return _chinet.MapStringVectorDouble_value_iterator(self)

    def __setitem__(self, *args):
        return _chinet.MapStringVectorDouble___setitem__(self, *args)

    def asdict(self):
        return _chinet.MapStringVectorDouble_asdict(self)

    def __init__(self, *args):
        _chinet.MapStringVectorDouble_swiginit(self, _chinet.new_MapStringVectorDouble(*args))

    def empty(self):
        return _chinet.MapStringVectorDouble_empty(self)

    def size(self):
        return _chinet.MapStringVectorDouble_size(self)

    def swap(self, v):
        return _chinet.MapStringVectorDouble_swap(self, v)

    def begin(self):
        return _chinet.MapStringVectorDouble_begin(self)

    def end(self):
        return _chinet.MapStringVectorDouble_end(self)

    def rbegin(self):
        return _chinet.MapStringVectorDouble_rbegin(self)

    def rend(self):
        return _chinet.MapStringVectorDouble_rend(self)

    def clear(self):
        return _chinet.MapStringVectorDouble_clear(self)

    def get_allocator(self):
        return _chinet.MapStringVectorDouble_get_allocator(self)

    def count(self, x):
        return _chinet.MapStringVectorDouble_count(self, x)

    def erase(self, *args):
        return _chinet.MapStringVectorDouble_erase(self, *args)

    def find(self, x):
        return _chinet.MapStringVectorDouble_find(self, x)

    def lower_bound(self, x):
        return _chinet.MapStringVectorDouble_lower_bound(self, x)

    def upper_bound(self, x):
        return _chinet.MapStringVectorDouble_upper_bound(self, x)
    __swig_destroy__ = _chinet.delete_MapStringVectorDouble

# Register MapStringVectorDouble in _chinet:
_chinet.MapStringVectorDouble_swigregister(MapStringVectorDouble)
CHINET_VERSION = _chinet.CHINET_VERSION

def is_chinet_verbose():
    r"""


    """
    return _chinet.is_chinet_verbose()
class ListDatabaseObjectPtr(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.ListDatabaseObjectPtr_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.ListDatabaseObjectPtr___nonzero__(self)

    def __bool__(self):
        return _chinet.ListDatabaseObjectPtr___bool__(self)

    def __len__(self):
        return _chinet.ListDatabaseObjectPtr___len__(self)

    def __getslice__(self, i, j):
        return _chinet.ListDatabaseObjectPtr___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.ListDatabaseObjectPtr___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.ListDatabaseObjectPtr___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.ListDatabaseObjectPtr___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.ListDatabaseObjectPtr___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.ListDatabaseObjectPtr___setitem__(self, *args)

    def pop(self):
        return _chinet.ListDatabaseObjectPtr_pop(self)

    def append(self, x):
        return _chinet.ListDatabaseObjectPtr_append(self, x)

    def empty(self):
        return _chinet.ListDatabaseObjectPtr_empty(self)

    def size(self):
        return _chinet.ListDatabaseObjectPtr_size(self)

    def swap(self, v):
        return _chinet.ListDatabaseObjectPtr_swap(self, v)

    def begin(self):
        return _chinet.ListDatabaseObjectPtr_begin(self)

    def end(self):
        return _chinet.ListDatabaseObjectPtr_end(self)

    def rbegin(self):
        return _chinet.ListDatabaseObjectPtr_rbegin(self)

    def rend(self):
        return _chinet.ListDatabaseObjectPtr_rend(self)

    def clear(self):
        return _chinet.ListDatabaseObjectPtr_clear(self)

    def get_allocator(self):
        return _chinet.ListDatabaseObjectPtr_get_allocator(self)

    def pop_back(self):
        return _chinet.ListDatabaseObjectPtr_pop_back(self)

    def erase(self, *args):
        return _chinet.ListDatabaseObjectPtr_erase(self, *args)

    def __init__(self, *args):
        _chinet.ListDatabaseObjectPtr_swiginit(self, _chinet.new_ListDatabaseObjectPtr(*args))

    def push_back(self, x):
        return _chinet.ListDatabaseObjectPtr_push_back(self, x)

    def front(self):
        return _chinet.ListDatabaseObjectPtr_front(self)

    def back(self):
        return _chinet.ListDatabaseObjectPtr_back(self)

    def assign(self, n, x):
        return _chinet.ListDatabaseObjectPtr_assign(self, n, x)

    def resize(self, *args):
        return _chinet.ListDatabaseObjectPtr_resize(self, *args)

    def insert(self, *args):
        return _chinet.ListDatabaseObjectPtr_insert(self, *args)

    def pop_front(self):
        return _chinet.ListDatabaseObjectPtr_pop_front(self)

    def push_front(self, x):
        return _chinet.ListDatabaseObjectPtr_push_front(self, x)

    def reverse(self):
        return _chinet.ListDatabaseObjectPtr_reverse(self)
    __swig_destroy__ = _chinet.delete_ListDatabaseObjectPtr

# Register ListDatabaseObjectPtr in _chinet:
_chinet.ListDatabaseObjectPtr_swigregister(ListDatabaseObjectPtr)
class vector_port_ptr(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.vector_port_ptr_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.vector_port_ptr___nonzero__(self)

    def __bool__(self):
        return _chinet.vector_port_ptr___bool__(self)

    def __len__(self):
        return _chinet.vector_port_ptr___len__(self)

    def __getslice__(self, i, j):
        return _chinet.vector_port_ptr___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.vector_port_ptr___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.vector_port_ptr___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.vector_port_ptr___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.vector_port_ptr___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.vector_port_ptr___setitem__(self, *args)

    def pop(self):
        return _chinet.vector_port_ptr_pop(self)

    def append(self, x):
        return _chinet.vector_port_ptr_append(self, x)

    def empty(self):
        return _chinet.vector_port_ptr_empty(self)

    def size(self):
        return _chinet.vector_port_ptr_size(self)

    def swap(self, v):
        return _chinet.vector_port_ptr_swap(self, v)

    def begin(self):
        return _chinet.vector_port_ptr_begin(self)

    def end(self):
        return _chinet.vector_port_ptr_end(self)

    def rbegin(self):
        return _chinet.vector_port_ptr_rbegin(self)

    def rend(self):
        return _chinet.vector_port_ptr_rend(self)

    def clear(self):
        return _chinet.vector_port_ptr_clear(self)

    def get_allocator(self):
        return _chinet.vector_port_ptr_get_allocator(self)

    def pop_back(self):
        return _chinet.vector_port_ptr_pop_back(self)

    def erase(self, *args):
        return _chinet.vector_port_ptr_erase(self, *args)

    def __init__(self, *args):
        _chinet.vector_port_ptr_swiginit(self, _chinet.new_vector_port_ptr(*args))

    def push_back(self, x):
        return _chinet.vector_port_ptr_push_back(self, x)

    def front(self):
        return _chinet.vector_port_ptr_front(self)

    def back(self):
        return _chinet.vector_port_ptr_back(self)

    def assign(self, n, x):
        return _chinet.vector_port_ptr_assign(self, n, x)

    def resize(self, *args):
        return _chinet.vector_port_ptr_resize(self, *args)

    def insert(self, *args):
        return _chinet.vector_port_ptr_insert(self, *args)

    def reserve(self, n):
        return _chinet.vector_port_ptr_reserve(self, n)

    def capacity(self):
        return _chinet.vector_port_ptr_capacity(self)
    __swig_destroy__ = _chinet.delete_vector_port_ptr

# Register vector_port_ptr in _chinet:
_chinet.vector_port_ptr_swigregister(vector_port_ptr)
class Port(object):
    r"""


    C++ includes: Port.h

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def current_size(self):
        r"""

        Port::current_size
        """
        return _chinet.Port_current_size(self)

    def get_ptr(self):
        r"""

        Port::get_ptr
        """
        return _chinet.Port_get_ptr(self)
    __swig_destroy__ = _chinet.delete_Port

    def __init__(self, *args, **kwargs):
        r"""

        Port::Port
        """
        _chinet.Port_swiginit(self, _chinet.new_Port(*args, **kwargs))

    def set_value_type(self, type):
        r"""

        Port::set_value_type
        """
        return _chinet.Port_set_value_type(self, type)

    def get_value_type(self):
        r"""

        Port::get_value_type
        """
        return _chinet.Port_get_value_type(self)

    def set_link(self, v):
        r"""

        Port::set_link
        """
        return _chinet.Port_set_link(self, v)

    def get_link(self):
        r"""

        Port::get_link
        """
        return _chinet.Port_get_link(self)

    def unlink(self):
        r"""

        Port::unlink
        """
        return _chinet.Port_unlink(self)

    def bound_is_valid(self):
        r"""

        Port::bound_is_valid
        """
        return _chinet.Port_bound_is_valid(self)

    def set_bounds(self, b):
        r"""

        Port::set_bounds
        """
        return _chinet.Port_set_bounds(self, b)

    def get_bounds(self):
        r"""

        Port::get_bounds
        """
        return _chinet.Port_get_bounds(self)

    def is_float(self):
        r"""

        Port::is_float
        """
        return _chinet.Port_is_float(self)

    def get_bytes(self, copy=False):
        r"""

        Port::get_bytes
        """
        return _chinet.Port_get_bytes(self, copy)

    def set_bytes(self, input):
        r"""

        Port::set_bytes
        """
        return _chinet.Port_set_bytes(self, input)

    def set_buffer_ptr(self, ptr, n_elements, element_size):
        r"""

        Port::set_buffer_ptr
        """
        return _chinet.Port_set_buffer_ptr(self, ptr, n_elements, element_size)

    def get_buffer_ptr(self):
        r"""

        Port::get_buffer_ptr
        """
        return _chinet.Port_get_buffer_ptr(self)

    def get_linked_ports(self):
        r"""

        Port::get_linked_ports
        """
        return _chinet.Port_get_linked_ports(self)

    def get_buffer(self):
        r"""

        Port::get_buffer
        """
        return _chinet.Port_get_buffer(self)

    def update_attached_node(self):
        r"""

        Port::update_attached_node
        """
        return _chinet.Port_update_attached_node(self)

    def write_to_db(self):
        r"""

        Port::write_to_db
        """
        return _chinet.Port_write_to_db(self)

    def read_from_db(self, oid_string):
        r"""

        Port::read_from_db
        """
        return _chinet.Port_read_from_db(self, oid_string)

    def get_json(self, indent=0):
        r"""

        Port::get_json
        """
        return _chinet.Port_get_json(self, indent)

    def set_document(self, doc):
        r"""

        Port::set_document
        """
        return _chinet.Port_set_document(self, doc)

    def __add__(self, v):
        return _chinet.Port___add__(self, v)

    def __mul__(self, v):
        return _chinet.Port___mul__(self, v)
    fixed = property(_chinet.Port_fixed_get, _chinet.Port_fixed_set)
    is_output = property(_chinet.Port_is_output_get, _chinet.Port_is_output_set, doc=r"""

    Port::is_output
    """)
    reactive = property(_chinet.Port_reactive_get, _chinet.Port_reactive_set)
    is_linked = property(_chinet.Port_is_linked_get, doc=r"""

    Port::is_linked
    """)
    bounded = property(_chinet.Port_bounded_get, _chinet.Port_bounded_set)
    node = property(_chinet.Port_node_get, _chinet.Port_node_set)
    oid = property(_chinet.Port_oid_get, _chinet.Port_oid_set)
    name = property(_chinet.Port_name_get, _chinet.Port_name_set)

    def get_json_of_key(self, key):
        r"""

        MemoryObject::get_json_of_key
        """
        return _chinet.Port_get_json_of_key(self, key)

    def get_string(self):
        r"""

        MemoryObject::get_string
        """
        return _chinet.Port_get_string(self)

    def set_string(self, key, str):
        r"""

        MemoryObject::set_string
        """
        return _chinet.Port_set_string(self, key, str)

    def set_oid(self, key, value):
        r"""

        MemoryObject::set_oid
        """
        return _chinet.Port_set_oid(self, key, value)

    def __getitem__(self, key):
        return _chinet.Port___getitem__(self, key)

    def connect_to_db(self, uri_string, db_string, app_string, collection_string):
        r"""

        MemoryObject::connect_to_db
        """
        return _chinet.Port_connect_to_db(self, uri_string, db_string, app_string, collection_string)

    def disconnect_from_db(self):
        r"""

        MemoryObject::disconnect_from_db
        """
        return _chinet.Port_disconnect_from_db(self)

    def register_instance(self, obj):
        r"""

        MemoryObject::register_instance
        """
        return _chinet.Port_register_instance(self, obj)

    def unregister_instance(self, obj):
        r"""

        MemoryObject::unregister_instance
        """
        return _chinet.Port_unregister_instance(self, obj)

    def create_copy_in_db(self):
        r"""

        MemoryObject::create_copy_in_db
        """
        return _chinet.Port_create_copy_in_db(self)

    def read_json(self, json_string):
        r"""

        MemoryObject::read_json
        """
        return _chinet.Port_read_json(self, json_string)

    def show(self):
        r"""

        MemoryObject::show
        """
        return _chinet.Port_show(self)

    @staticmethod
    def get_instances():
        r"""

        MemoryObject::get_instances
        """
        return _chinet.Port_get_instances()

    def __eq__(self, other):
        return _chinet.Port___eq__(self, other)

    def set_value_vd(self, input):
        r"""

        Port::set_value_vector
        """
        return _chinet.Port_set_value_vd(self, input)

    def get_value_vd(self):
        r"""

        Port::get_value_vector
        """
        return _chinet.Port_get_value_vd(self)

    def set_value_vi(self, input):
        r"""

        Port::set_value_vector
        """
        return _chinet.Port_set_value_vi(self, input)

    def get_value_vi(self):
        r"""

        Port::get_value_vector
        """
        return _chinet.Port_get_value_vi(self)

    def set_value_d(self, input, n_input, copy_values=True):
        r"""

        Port::set_value
        """
        return _chinet.Port_set_value_d(self, input, n_input, copy_values)

    def get_value_d(self):
        r"""

        Port::get_value
        """
        return _chinet.Port_get_value_d(self)

    def update_buffer_d(self):
        r"""

        Port::update_buffer
        """
        return _chinet.Port_update_buffer_d(self)

    def get_value_i(self):
        r"""

        Port::get_value
        """
        return _chinet.Port_get_value_i(self)

    def set_value_i(self, input, n_input, copy_values=True):
        r"""

        Port::set_value
        """
        return _chinet.Port_set_value_i(self, input, n_input, copy_values)

    def update_buffer_i(self):
        r"""

        Port::update_buffer
        """
        return _chinet.Port_update_buffer_i(self)

    def get_value_c(self):
        r"""

        Port::get_value
        """
        return _chinet.Port_get_value_c(self)

    def set_value_c(self, input, n_input, copy_values=True):
        r"""

        Port::set_value
        """
        return _chinet.Port_set_value_c(self, input, n_input, copy_values)

    def update_buffer_c(self):
        r"""

        Port::update_buffer
        """
        return _chinet.Port_update_buffer_c(self)
    @property
    def bytes(self):
    # type: () -> np.ndarray
        return self.get_bytes()

    @bytes.setter
    def bytes(self, v):
    # type: () -> (np.ndarray)
        self.set_bytes(v)

    @property
    def link(self):
    # type: () -> cn.Port
        return self.get_link()

    @link.setter
    def link(self, v):
        self.set_link(v)


    @property
    def value(self):
        value_getters = {
            0: self.get_value_vi,
            1: self.get_value_vd,
            2: lambda: self.get_value_vi(),
            3: lambda: self.get_value_vd(),
        }
        result = value_getters.get(self.get_value_type(), lambda: None)()

    # For scalar values (single element arrays), return the scalar value
    # This makes test_set_get_value_1 pass
        if isinstance(result, tuple) and len(result) == 1:
            return result[0]

        return result

    @value.setter
    def value(self, v):
    # Convert to numpy array if not already
        if not isinstance(v, np.ndarray):
            v = np.atleast_1d(v)

    # Determine if the value is a scalar or vector
    # Empty arrays should be treated as vectors
        is_vector = len(v) > 1 or len(v) == 0

    # Handle NaN, infinity, and other invalid values
        if v.dtype.kind in ['f', 'd']:
    # Replace NaN with a very small number
            v = np.where(np.isnan(v), np.finfo(np.float64).tiny, v)
    # Replace infinity with very large/small numbers
            v = np.where(np.isinf(v) & (v > 0), np.finfo(np.float64).max, v)
            v = np.where(np.isinf(v) & (v < 0), np.finfo(np.float64).min, v)

    # If input is float, set value_type to 1 or 3 (float)
    # The C++ set_value method will handle this, but we set it here for clarity
            current_value_type = self.get_value_type()
            if is_vector:
    # Vector float (value_type 3)
    # Always upcast to float type
                if current_value_type == 0 or current_value_type == 2:
                    self.set_value_type(3)  # Convert to vector float
                else:
                    self.set_value_type(3)  # Ensure it's vector float
            else:
    # Scalar float (value_type 1)
    # Always upcast to float type
                if current_value_type == 0 or current_value_type == 2:
                    self.set_value_type(1)  # Convert to scalar float
                else:
                    self.set_value_type(1)  # Ensure it's scalar float

    # Ensure v is a properly formatted numpy array for set_value_vd
    # Make sure it's contiguous and has the correct data type
            v = np.ascontiguousarray(v, dtype=np.float64)
            try:
                self.set_value_vd(v)
            except TypeError:
    # If set_value_vd fails, try using set_value_d for scalar values
                if not is_vector:
                    self.set_value_d(float(v[0]), 1, True)
                else:
                    raise
        else:
    # Check if the current port type is float
            current_value_type = self.get_value_type()
            is_float_type = current_value_type == 1 or current_value_type == 3

            if is_float_type:
    # If port type is float, upcast integer value to float
                v = v.astype(np.float64)

    # Ensure v is a properly formatted numpy array for set_value_vd
                v = np.ascontiguousarray(v, dtype=np.float64)
                try:
                    self.set_value_vd(v)
                except TypeError:
    # If set_value_vd fails, try using set_value_d for scalar values
                    if not is_vector:
                        self.set_value_d(float(v[0]), 1, True)
                    else:
                        raise
            else:
    # Ensure integer values are converted to long
                v = v.astype(np.int64)

    # Set value_type based on whether it's a scalar or vector
                if is_vector:
    # Vector int (value_type 2)
                    self.set_value_type(2)  # Ensure it's vector int
                else:
    # Scalar int (value_type 0)
                    self.set_value_type(0)  # Ensure it's scalar int

    # Ensure v is a properly formatted numpy array for set_value_vi
    # Make sure it's contiguous and has the correct data type
                v = np.ascontiguousarray(v, dtype=np.int64)
                try:
                    self.set_value_vi(v)
                except TypeError:
    # If set_value_vi fails, try using set_value_i for scalar values
                    if not is_vector:
                        self.set_value_i(int(v[0]), 1, True)
                    else:
                        raise

    @property
    def bounds(self):
        if self.bounded:
            return self.get_bounds()
        else:
            return None, None

    @property
    def dtype(self):
        """Get the numpy dtype of the port.

        Returns:
            numpy.dtype: The numpy dtype corresponding to the port's value_type.
                0: np.int64 (integer type)
                1: np.float64 (float type)
                2: np.int64 (integer type)
                3: np.float64 (float type)
        """
        value_type = self.get_value_type()
        if value_type in [0, 2]:
            return np.dtype(np.int64)
        else:  # value_type in [1, 3]
            return np.dtype(np.float64)

    @dtype.setter
    def dtype(self, dtype):
        """Set the port's value_type based on a numpy dtype.

        Args:
            dtype: A numpy dtype or type that can be converted to a numpy dtype.
                Float types (np.float16, np.float32, np.float64, etc.) will set value_type to 1 or 3.
                Integer types (np.int8, np.int16, np.int32, np.int64, etc.) will set value_type to 0 or 2.

        Note:
            Setting the dtype will not convert existing values in the port.
            If you need to convert existing values, you should reassign them after changing the dtype.

        Examples:
            >>> port = Port()
            >>> port.dtype = np.float64  # Set to float type
            >>> port.dtype = np.int64    # Set to integer type
            >>> port.dtype = float       # Set to float type
            >>> port.dtype = int         # Set to integer type
        """
    # Convert to numpy dtype if it's not already
        if not isinstance(dtype, np.dtype):
            dtype = np.dtype(dtype)

    # Get current value_type
        current_value_type = self.get_value_type()

    # Set value_type based on dtype while preserving the "2-ness" or "3-ness"
        if np.issubdtype(dtype, np.floating):
    # If current type is 0 or 2, convert to float equivalent
            if current_value_type == 0:
                self.set_value_type(1)  # 0 -> 1 (int -> float)
            elif current_value_type == 2:
                self.set_value_type(3)  # 2 -> 3 (int -> float)
    # If already a float type (1 or 3), keep it as is
        else:
    # If current type is 1 or 3, convert to int equivalent
            if current_value_type == 1:
                self.set_value_type(0)  # 1 -> 0 (float -> int)
            elif current_value_type == 3:
                self.set_value_type(2)  # 3 -> 2 (float -> int)
    # If already an int type (0 or 2), keep it as is

    @bounds.setter
    def bounds(self, v):
    # Convert to numpy array
        v_array = np.array(v, dtype=np.float64)

    # Handle NaN, infinity, and other invalid values
        if v_array.size == 1:
    # If a single value is provided and it's NaN, use default bounds
            if np.isnan(v_array[0]):
                v_array = np.array([np.finfo(np.float64).min, np.finfo(np.float64).max], dtype=np.float64)
        elif v_array.size >= 2:
    # For arrays with at least 2 elements, replace NaN values individually
            if np.isnan(v_array[0]):
                v_array[0] = np.finfo(np.float64).min
            if np.isnan(v_array[1]):
                v_array[1] = np.finfo(np.float64).max

    # Ensure lower bound is not -inf and upper bound is not +inf
            if np.isinf(v_array[0]) and v_array[0] < 0:
                v_array[0] = np.finfo(np.float64).min
            if np.isinf(v_array[1]) and v_array[1] > 0:
                v_array[1] = np.finfo(np.float64).max

        self.set_bounds(v_array)

    def __init__(
                self,
                value=[],
                fixed=False,
                *args, **kwargs
        ):
    # Extract 'value' from kwargs if it exists (for backward compatibility)
            if 'value' in kwargs:
                value = kwargs.pop('value')

            this = _chinet.new_Port(*args, **kwargs)

            try:
                self.this.append(this)
            except:
                self.this = this

    # Use the value setter which already handles NaN and infinity
            if np.isscalar(value) or (hasattr(value, '__len__') and len(value) > 0):
                self.value = np.atleast_1d(value)
            self.fixed = fixed

    def __str__(self):
        return self.get_json(indent=4)


# Register Port in _chinet:
_chinet.Port_swigregister(Port)
class MapStringPortSharedPtr(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.MapStringPortSharedPtr_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.MapStringPortSharedPtr___nonzero__(self)

    def __bool__(self):
        return _chinet.MapStringPortSharedPtr___bool__(self)

    def __len__(self):
        return _chinet.MapStringPortSharedPtr___len__(self)
    def __iter__(self):
        return self.key_iterator()
    def iterkeys(self):
        return self.key_iterator()
    def itervalues(self):
        return self.value_iterator()
    def iteritems(self):
        return self.iterator()

    def __getitem__(self, key):
        return _chinet.MapStringPortSharedPtr___getitem__(self, key)

    def __delitem__(self, key):
        return _chinet.MapStringPortSharedPtr___delitem__(self, key)

    def has_key(self, key):
        return _chinet.MapStringPortSharedPtr_has_key(self, key)

    def keys(self):
        return _chinet.MapStringPortSharedPtr_keys(self)

    def values(self):
        return _chinet.MapStringPortSharedPtr_values(self)

    def items(self):
        return _chinet.MapStringPortSharedPtr_items(self)

    def __contains__(self, key):
        return _chinet.MapStringPortSharedPtr___contains__(self, key)

    def key_iterator(self):
        return _chinet.MapStringPortSharedPtr_key_iterator(self)

    def value_iterator(self):
        return _chinet.MapStringPortSharedPtr_value_iterator(self)

    def __setitem__(self, *args):
        return _chinet.MapStringPortSharedPtr___setitem__(self, *args)

    def asdict(self):
        return _chinet.MapStringPortSharedPtr_asdict(self)

    def __init__(self, *args):
        _chinet.MapStringPortSharedPtr_swiginit(self, _chinet.new_MapStringPortSharedPtr(*args))

    def empty(self):
        return _chinet.MapStringPortSharedPtr_empty(self)

    def size(self):
        return _chinet.MapStringPortSharedPtr_size(self)

    def swap(self, v):
        return _chinet.MapStringPortSharedPtr_swap(self, v)

    def begin(self):
        return _chinet.MapStringPortSharedPtr_begin(self)

    def end(self):
        return _chinet.MapStringPortSharedPtr_end(self)

    def rbegin(self):
        return _chinet.MapStringPortSharedPtr_rbegin(self)

    def rend(self):
        return _chinet.MapStringPortSharedPtr_rend(self)

    def clear(self):
        return _chinet.MapStringPortSharedPtr_clear(self)

    def get_allocator(self):
        return _chinet.MapStringPortSharedPtr_get_allocator(self)

    def count(self, x):
        return _chinet.MapStringPortSharedPtr_count(self, x)

    def erase(self, *args):
        return _chinet.MapStringPortSharedPtr_erase(self, *args)

    def find(self, x):
        return _chinet.MapStringPortSharedPtr_find(self, x)

    def lower_bound(self, x):
        return _chinet.MapStringPortSharedPtr_lower_bound(self, x)

    def upper_bound(self, x):
        return _chinet.MapStringPortSharedPtr_upper_bound(self, x)
    __swig_destroy__ = _chinet.delete_MapStringPortSharedPtr

# Register MapStringPortSharedPtr in _chinet:
_chinet.MapStringPortSharedPtr_swigregister(MapStringPortSharedPtr)
class ListNodePtr(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.ListNodePtr_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.ListNodePtr___nonzero__(self)

    def __bool__(self):
        return _chinet.ListNodePtr___bool__(self)

    def __len__(self):
        return _chinet.ListNodePtr___len__(self)

    def __getslice__(self, i, j):
        return _chinet.ListNodePtr___getslice__(self, i, j)

    def __setslice__(self, *args):
        return _chinet.ListNodePtr___setslice__(self, *args)

    def __delslice__(self, i, j):
        return _chinet.ListNodePtr___delslice__(self, i, j)

    def __delitem__(self, *args):
        return _chinet.ListNodePtr___delitem__(self, *args)

    def __getitem__(self, *args):
        return _chinet.ListNodePtr___getitem__(self, *args)

    def __setitem__(self, *args):
        return _chinet.ListNodePtr___setitem__(self, *args)

    def pop(self):
        return _chinet.ListNodePtr_pop(self)

    def append(self, x):
        return _chinet.ListNodePtr_append(self, x)

    def empty(self):
        return _chinet.ListNodePtr_empty(self)

    def size(self):
        return _chinet.ListNodePtr_size(self)

    def swap(self, v):
        return _chinet.ListNodePtr_swap(self, v)

    def begin(self):
        return _chinet.ListNodePtr_begin(self)

    def end(self):
        return _chinet.ListNodePtr_end(self)

    def rbegin(self):
        return _chinet.ListNodePtr_rbegin(self)

    def rend(self):
        return _chinet.ListNodePtr_rend(self)

    def clear(self):
        return _chinet.ListNodePtr_clear(self)

    def get_allocator(self):
        return _chinet.ListNodePtr_get_allocator(self)

    def pop_back(self):
        return _chinet.ListNodePtr_pop_back(self)

    def erase(self, *args):
        return _chinet.ListNodePtr_erase(self, *args)

    def __init__(self, *args):
        _chinet.ListNodePtr_swiginit(self, _chinet.new_ListNodePtr(*args))

    def push_back(self, x):
        return _chinet.ListNodePtr_push_back(self, x)

    def front(self):
        return _chinet.ListNodePtr_front(self)

    def back(self):
        return _chinet.ListNodePtr_back(self)

    def assign(self, n, x):
        return _chinet.ListNodePtr_assign(self, n, x)

    def resize(self, *args):
        return _chinet.ListNodePtr_resize(self, *args)

    def insert(self, *args):
        return _chinet.ListNodePtr_insert(self, *args)

    def pop_front(self):
        return _chinet.ListNodePtr_pop_front(self)

    def push_front(self, x):
        return _chinet.ListNodePtr_push_front(self, x)

    def reverse(self):
        return _chinet.ListNodePtr_reverse(self)
    __swig_destroy__ = _chinet.delete_ListNodePtr

# Register ListNodePtr in _chinet:
_chinet.ListNodePtr_swigregister(ListNodePtr)
class MapStringDouble(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.MapStringDouble_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.MapStringDouble___nonzero__(self)

    def __bool__(self):
        return _chinet.MapStringDouble___bool__(self)

    def __len__(self):
        return _chinet.MapStringDouble___len__(self)
    def __iter__(self):
        return self.key_iterator()
    def iterkeys(self):
        return self.key_iterator()
    def itervalues(self):
        return self.value_iterator()
    def iteritems(self):
        return self.iterator()

    def __getitem__(self, key):
        return _chinet.MapStringDouble___getitem__(self, key)

    def __delitem__(self, key):
        return _chinet.MapStringDouble___delitem__(self, key)

    def has_key(self, key):
        return _chinet.MapStringDouble_has_key(self, key)

    def keys(self):
        return _chinet.MapStringDouble_keys(self)

    def values(self):
        return _chinet.MapStringDouble_values(self)

    def items(self):
        return _chinet.MapStringDouble_items(self)

    def __contains__(self, key):
        return _chinet.MapStringDouble___contains__(self, key)

    def key_iterator(self):
        return _chinet.MapStringDouble_key_iterator(self)

    def value_iterator(self):
        return _chinet.MapStringDouble_value_iterator(self)

    def __setitem__(self, *args):
        return _chinet.MapStringDouble___setitem__(self, *args)

    def asdict(self):
        return _chinet.MapStringDouble_asdict(self)

    def __init__(self, *args):
        _chinet.MapStringDouble_swiginit(self, _chinet.new_MapStringDouble(*args))

    def empty(self):
        return _chinet.MapStringDouble_empty(self)

    def size(self):
        return _chinet.MapStringDouble_size(self)

    def swap(self, v):
        return _chinet.MapStringDouble_swap(self, v)

    def begin(self):
        return _chinet.MapStringDouble_begin(self)

    def end(self):
        return _chinet.MapStringDouble_end(self)

    def rbegin(self):
        return _chinet.MapStringDouble_rbegin(self)

    def rend(self):
        return _chinet.MapStringDouble_rend(self)

    def clear(self):
        return _chinet.MapStringDouble_clear(self)

    def get_allocator(self):
        return _chinet.MapStringDouble_get_allocator(self)

    def count(self, x):
        return _chinet.MapStringDouble_count(self, x)

    def erase(self, *args):
        return _chinet.MapStringDouble_erase(self, *args)

    def find(self, x):
        return _chinet.MapStringDouble_find(self, x)

    def lower_bound(self, x):
        return _chinet.MapStringDouble_lower_bound(self, x)

    def upper_bound(self, x):
        return _chinet.MapStringDouble_upper_bound(self, x)
    __swig_destroy__ = _chinet.delete_MapStringDouble

# Register MapStringDouble in _chinet:
_chinet.MapStringDouble_swigregister(MapStringDouble)
class NodeCallback(object):
    r"""


    C++ includes: NodeCallback.h

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def run(self, arg0, arg1):
        r"""

        NodeCallback::run
        """
        return _chinet.NodeCallback_run(self, arg0, arg1)

    def __init__(self):
        r"""

        NodeCallback::NodeCallback
        """
        if self.__class__ == NodeCallback:
            _self = None
        else:
            _self = self
        _chinet.NodeCallback_swiginit(self, _chinet.new_NodeCallback(_self, ))
    __swig_destroy__ = _chinet.delete_NodeCallback
    def __disown__(self):
        self.this.disown()
        _chinet.disown_NodeCallback(self)
        return weakref.proxy(self)

# Register NodeCallback in _chinet:
_chinet.NodeCallback_swigregister(NodeCallback)
class Node(object):
    r"""


    Represents a computational node with ports and callbacks.  

    The `Node` class is derived from `DatabaseObject` and allows interaction with
    input and output ports, evaluation of node functionality, and database
    communication. A callback mechanism is provided via `NodeCallback`.  

    C++ includes: CNode.h

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    callback_class = property(_chinet.Node_callback_class_get, _chinet.Node_callback_class_set)

    def __init__(self, *args, **kwargs):
        r"""

        Node::Node
        """
        _chinet.Node_swiginit(self, _chinet.new_Node(*args, **kwargs))
    __swig_destroy__ = _chinet.delete_Node

    def read_from_db(self, oid_string):
        r"""

        Node::read_from_db
        """
        return _chinet.Node_read_from_db(self, oid_string)

    def evaluate(self):
        r"""

        Node::evaluate
        Performs evaluation of the node.  

        """
        return _chinet.Node_evaluate(self)

    def inputs_valid(self):
        r"""

        Node::inputs_valid
        Checks the validity of the node's input ports.  

        Returns
        -------
        `true` if all input ports are valid, otherwise `false`.  

        """
        return _chinet.Node_inputs_valid(self)

    def write_to_db(self):
        r"""

        Node::write_to_db
        Writes the node's data to the database.  

        Returns
        -------
        `true` if the operation succeeds, `false` otherwise.  

        """
        return _chinet.Node_write_to_db(self)

    def get_input_ports(self):
        r"""

        Node::get_input_ports
        Gets all input ports of the node.  

        Returns
        -------
        A map containing input ports with their names as keys.  

        """
        return _chinet.Node_get_input_ports(self)

    def get_output_ports(self):
        r"""

        Node::get_output_ports
        Gets all output ports of the node.  

        Returns
        -------
        A map containing output ports with their names as keys.  

        """
        return _chinet.Node_get_output_ports(self)

    def get_ports(self):
        r"""

        Node::get_ports
        Gets all ports of the node (both input and output).  

        Returns
        -------
        A map containing all ports with their names as keys.  

        """
        return _chinet.Node_get_ports(self)

    def get_port(self, port_name):
        r"""

        Node::get_port
        Retrieves a port by its name.  

        Parameters
        ----------
        * `port_name` :  
            The name of the port to retrieve.  

        Returns
        -------
        A pointer to the requested `Port` object.  

        """
        return _chinet.Node_get_port(self, port_name)

    def get_input_port(self, port_name):
        r"""

        Node::get_input_port
        Retrieves an input port by its name.  

        Parameters
        ----------
        * `port_name` :  
            The name of the input port.  

        Returns
        -------
        A pointer to the requested input `Port` object.  

        """
        return _chinet.Node_get_input_port(self, port_name)

    def get_output_port(self, port_name):
        r"""

        Node::get_output_port
        Retrieves an output port by its name.  

        Parameters
        ----------
        * `port_name` :  
            The name of the output port.  

        Returns
        -------
        A pointer to the requested output `Port` object.  

        """
        return _chinet.Node_get_output_port(self, port_name)

    def set_ports(self, ports):
        r"""

        Node::set_ports
        """
        return _chinet.Node_set_ports(self, ports)

    def add_port(self, key, port, is_source, fill_in_out=True):
        r"""

        Node::add_port
        Adds a port to the node.  

        Parameters
        ----------
        * `key` :  
            The name of the port.  
        * `port` :  
            A shared pointer to the `Port` object.  
        * `is_source` :  
            Indicates whether the port is a source port.  
        * `fill_in_out` :  
            Determines whether input/output lookups should be updated.  

        """
        return _chinet.Node_add_port(self, key, port, is_source, fill_in_out)

    def add_input_port(self, key, port):
        r"""

        Node::add_input_port
        Adds an input port to the node.  

        Parameters
        ----------
        * `key` :  
            The name of the input port.  
        * `port` :  
            A shared pointer to the input `Port` object.  

        """
        return _chinet.Node_add_input_port(self, key, port)

    def add_output_port(self, key, port):
        r"""

        Node::add_output_port
        Adds an output port to the node.  

        Parameters
        ----------
        * `key` :  
            The name of the output port.  
        * `port` :  
            A shared pointer to the output `Port` object.  

        """
        return _chinet.Node_add_output_port(self, key, port)

    def set_callback(self, *args):
        r"""

        Node::set_callback
        Sets the callback of the node using a `NodeCallback` object.  

        Parameters
        ----------
        * `cb` :  
            Shared pointer to the `NodeCallback` object.  

        """
        return _chinet.Node_set_callback(self, *args)

    def set_valid(self, is_valid=False):
        r"""

        Node::set_valid
        Sets the validity of the node.  

        Parameters
        ----------
        * `is_valid` :  
            A boolean indicating if the node is valid.  

        """
        return _chinet.Node_set_valid(self, is_valid)
    is_valid = property(_chinet.Node_is_valid_get, doc=r"""

    Node::is_valid
    Checks whether the node is valid.  

    Returns
    -------
    `true` if the node is valid, otherwise `false`.  

    """)

    def __repr__(self):
        return _chinet.Node___repr__(self)
    @property
    def inputs(self):
        return dict(self.get_input_ports())


    @property
    def outputs(self):
        return dict(self.get_output_ports())


    @property
    def ports(self):
        return self.get_ports()


    @ports.setter
    def ports(self, v):
    # type: (Dict[str, object]) -> None
        p = dict()
        for key in v:
            if isinstance(v[key], cn.Port):
                p[key] = v[key]
            elif isinstance(v[key], dict):
                p[key] = cn.Port(**v[key])
            else:
                p[key] = cn.Port(value=v[key])
        self.set_ports(p)


    def set_python_callback_function(
            self,
            cb,
            reactive_inputs = True,
            reactive_outputs = True
    ):
    # type: (Callable, bool, bool) -> None
        class CallbackNodePython(cn.NodeCallback):

            def __init__(
                    self,
                    cb_function, # type: Callable
                    *args, **kwargs
            ):
                super(CallbackNodePython, self).__init__(*args, **kwargs)
                self._cb = cb_function

            def run(
                    self,
                    inputs, # type: List[cn.Port]
                    outputs # type: List[cn.Port]
            ):
                input_dict = dict(
                    [(inputs[i].name, inputs[i].value) for i in inputs]
                )
                output = self._cb(**input_dict)
                if isinstance(output, dict):
                    for key, ov in zip(outputs, output):
                        outputs[key].value = output[key]
                elif isinstance(output, tuple):
                    for key, ov in zip(outputs, output):
                        outputs[key].value = ov
                else:
                    next(iter(outputs.values())).value = output

        if isinstance(cb, str):
            code_obj = compile(cb, '<string>', 'exec')
            self.set_string('source', cb)
            for o in code_obj.co_consts:
                if isinstance(o, types.CodeType):
                    cb = types.FunctionType(o, globals())
                    break
        else:
            self.set_string('source', inspect.getsource(cb))
    # When the cb-function of a node is evaluated, the input Ports are
    # processed by the callback and written to the output Port. Thus,
    # the inputs and outputs need to be defined as Ports. Here, the inputs
    # and the output of the function are inspected to create the Ports of the
    # None.

    # get the signature of the function to create input Ports
        import sys    
        if sys.version_info[0] > 2:
            from inspect import signature as sig
            empty_name = inspect.Signature.empty
            empty_type = inspect._empty
            _use_py2 = True
        else:
            import funcsigs
            from funcsigs import signature as sig
            empty_name = funcsigs._empty
            empty_type = funcsigs._empty
            _use_py2 = False

        _sig = sig(cb)
        input_ports = list()
        for parameter_name in _sig.parameters:
            o = _sig.parameters[parameter_name]
    # Check the function signature to use default values as cn.Port value
            if o.default is empty_name:
                if o.annotation is empty_type:
                    print("WARNING no type specified for %s cn.Port." % parameter_name)
                    value = np.array([1.0], dtype=np.float64)
                elif o.annotation == 'int':
                    value = 1
                elif 'ndarray' == o.annotation:
                    value = np.array([1.0], dtype=np.float64)
                elif o.annotation == 'float':
                    value = 1.0
                else:
                    print("WARNING no type specified for %s cn.Port." % parameter_name)
                    value = np.array([1.0], dtype=np.float64)
            else:
                value = o.default
            if o.name not in self.ports.keys():
                p = cn.Port(
                    name=o.name,
                    value=value,
                    is_output=False,
                    is_reactive=reactive_inputs
                )
                self.add_input_port(
                    key=o.name,
                    port=p
                )
                input_ports.append(p)
            else:
                input_ports.append(self.get_input_ports()[o.name])
    # run the function once with the default values to get the output
        input_values = dict([(p.name, p.value) for p in input_ports])
        returned_value = cb(**input_values)
    # use the return value of the function to create output Ports
        output_values = list()
        output_names = list()
        if isinstance(returned_value, dict):
            for ok in returned_value:
                output_values.append(returned_value[ok])
                output_names.append(ok)
        elif isinstance(returned_value, tuple):
            output_values = returned_value
            for i in range(len(returned_value)):
                output_names.append("out_" + str(i).zfill(2))
        else:
            output_names = 'out_00',
            output_values = returned_value,
        for on, ov in zip(output_names, output_values):
            if on not in self.get_output_ports().keys():
                self.add_output_port(
                    key=on,
                    port=cn.Port(
                        name=on,
                        value=ov,
                        is_output=True,
                        is_reactive=reactive_outputs
                    )
                )
    # create a new CallbackNodePython
        cb_instance = CallbackNodePython(cb_function=cb)
    # Store a reference to the callback instance to prevent garbage collection
        self._cb_instance = cb_instance
        cb_instance.__disown__()
        self.set_callback(cb_instance)


    callback_function = property(None, set_python_callback_function)


    def __getattr__(self, name):
        in_input = name in self.inputs.keys()
        in_output = name in self.outputs.keys()
        if in_input and in_output:
            raise KeyError("Ambiguous access. %s an input and output parameter.")
        elif not in_output and not in_input:
            raise AttributeError
        else:
            if in_input:
                return self.inputs[name].value
            else:
                return self.outputs[name].value


    def __setattr__(self, name, value):
        try:
            in_input = name in self.inputs.keys()
            in_output = name in self.outputs.keys()
            if in_input and in_output:
                raise KeyError("Ambiguous access. %s an input and output parameter.")
            elif not in_output and not in_input:
                raise AttributeError
            else:
                if in_input:
                    self.inputs[name].value = value
                else:
                    self.outputs[name].value = value
        except:
    # super().__setattr__(name, value)
            DatabaseObject.__setattr__(self, name, value)


    def __call__(self):
        return self.evaluate()


    def __del__(self):
    # Clean up the callback reference to avoid circular references
        if hasattr(self, '_cb_instance'):
            self._cb_instance = None
    # super(Node).__del__()
        DatabaseObject.__del__(self)


    def __init__(self,
                 obj=None,
                 name = "", #type: str
                 ports = None, #type: dict
                 callback_function=None,
                 reactive_inputs=True,
                 reactive_outputs=True,
                 *args, **kwargs
    ):
        """

        :param self:
        :param obj: Either the name (if string) or the callback function (if callable)
        :param name: The name of the Nose
        :param ports:
        :param callback_function: The callback function of the Node object
        :param reactive_inputs: if True sets all inputs that are created when the
        object is created to reactive
        :param args:
        :param kwargs:
        :return:
        """
        this = _chinet.new_Node(*args, **kwargs)
        try:
            self.this.append(this)
        except:
            self.this = this
        self.register_instance(None)
        if isinstance(ports, dict):
            self.ports = ports
        if isinstance(obj, str):
            name = obj
        elif callable(obj):
            callback_function = obj
    # set the python callback function
        if callable(callback_function) or isinstance(callback_function, str):
            self.set_python_callback_function(
                cb=callback_function,
                reactive_inputs=reactive_inputs,
                reactive_outputs=reactive_outputs
            )
        if len(name) > 0:
            self.name = name
        else:
            if callable(callback_function):
                self.name = callback_function.__name__


# Register Node in _chinet:
_chinet.Node_swigregister(Node)
class MapStringNode(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def iterator(self):
        return _chinet.MapStringNode_iterator(self)
    def __iter__(self):
        return self.iterator()

    def __nonzero__(self):
        return _chinet.MapStringNode___nonzero__(self)

    def __bool__(self):
        return _chinet.MapStringNode___bool__(self)

    def __len__(self):
        return _chinet.MapStringNode___len__(self)
    def __iter__(self):
        return self.key_iterator()
    def iterkeys(self):
        return self.key_iterator()
    def itervalues(self):
        return self.value_iterator()
    def iteritems(self):
        return self.iterator()

    def __getitem__(self, key):
        return _chinet.MapStringNode___getitem__(self, key)

    def __delitem__(self, key):
        return _chinet.MapStringNode___delitem__(self, key)

    def has_key(self, key):
        return _chinet.MapStringNode_has_key(self, key)

    def keys(self):
        return _chinet.MapStringNode_keys(self)

    def values(self):
        return _chinet.MapStringNode_values(self)

    def items(self):
        return _chinet.MapStringNode_items(self)

    def __contains__(self, key):
        return _chinet.MapStringNode___contains__(self, key)

    def key_iterator(self):
        return _chinet.MapStringNode_key_iterator(self)

    def value_iterator(self):
        return _chinet.MapStringNode_value_iterator(self)

    def __setitem__(self, *args):
        return _chinet.MapStringNode___setitem__(self, *args)

    def asdict(self):
        return _chinet.MapStringNode_asdict(self)

    def __init__(self, *args):
        _chinet.MapStringNode_swiginit(self, _chinet.new_MapStringNode(*args))

    def empty(self):
        return _chinet.MapStringNode_empty(self)

    def size(self):
        return _chinet.MapStringNode_size(self)

    def swap(self, v):
        return _chinet.MapStringNode_swap(self, v)

    def begin(self):
        return _chinet.MapStringNode_begin(self)

    def end(self):
        return _chinet.MapStringNode_end(self)

    def rbegin(self):
        return _chinet.MapStringNode_rbegin(self)

    def rend(self):
        return _chinet.MapStringNode_rend(self)

    def clear(self):
        return _chinet.MapStringNode_clear(self)

    def get_allocator(self):
        return _chinet.MapStringNode_get_allocator(self)

    def count(self, x):
        return _chinet.MapStringNode_count(self, x)

    def erase(self, *args):
        return _chinet.MapStringNode_erase(self, *args)

    def find(self, x):
        return _chinet.MapStringNode_find(self, x)

    def lower_bound(self, x):
        return _chinet.MapStringNode_lower_bound(self, x)

    def upper_bound(self, x):
        return _chinet.MapStringNode_upper_bound(self, x)
    __swig_destroy__ = _chinet.delete_MapStringNode

# Register MapStringNode in _chinet:
_chinet.MapStringNode_swigregister(MapStringNode)
class Session(object):
    r"""


    C++ includes: Session.h

    """

    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr
    nodes = property(_chinet.Session_nodes_get, _chinet.Session_nodes_set)

    def __init__(self, *args):
        r"""

        Session::Session
        """
        _chinet.Session_swiginit(self, _chinet.new_Session(*args))

    def add_node(self, name, object):
        r"""

        Session::add_node
        """
        return _chinet.Session_add_node(self, name, object)

    def get_nodes(self):
        r"""

        Session::get_nodes
        """
        return _chinet.Session_get_nodes(self)

    def write_to_db(self):
        r"""

        Session::write_to_db
        """
        return _chinet.Session_write_to_db(self)

    def read_from_db(self, oid_string):
        r"""

        Session::read_from_db
        """
        return _chinet.Session_read_from_db(self, oid_string)

    def create_port(self, *args):
        r"""

        Session::create_port
        """
        return _chinet.Session_create_port(self, *args)

    def create_node(self, *args):
        r"""

        Session::create_node
        """
        return _chinet.Session_create_node(self, *args)

    def read_session_template(self, json_string):
        r"""

        Session::read_session_template
        """
        return _chinet.Session_read_session_template(self, json_string)

    def get_session_template(self):
        r"""

        Session::get_session_template
        """
        return _chinet.Session_get_session_template(self)

    def link_nodes(self, node_name, port_name, target_node_name, target_port_name):
        r"""

        Session::link_nodes
        """
        return _chinet.Session_link_nodes(self, node_name, port_name, target_node_name, target_port_name)
    __swig_destroy__ = _chinet.delete_Session

# Register Session in _chinet:
_chinet.Session_swigregister(Session)

