Integrating up through commit 90f050496

This commit is contained in:
alexpete
2021-04-07 14:03:29 -07:00
parent 8f2ed080a9
commit c2cbd430fe
2694 changed files with 285622 additions and 176874 deletions
@@ -0,0 +1,623 @@
"""
All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
its licensors.
For complete copyright and license terms please see the LICENSE at the root of this
distribution (the "License"). All use of this software is governed by the License,
or, if provided, by the license below or the license accompanying this file. Do not
remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
"""
# -------------------------------------------------------------------------
# this has to be at the beginning
from __future__ import division
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# node.py
# simple base Node Class, for tool creation.
# version: 0.1
# author: Gallowj
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
"""
Module docstring:
A Simple Node Base Class Module, for creating basic nodes within a hierarchy.
"""
__author__ = 'HogJonny'
_G_DEBUG = True # global state for debugging
_G_SETTINGS = None # global Settings storage
_G_LOG = None # global LOGger storage
_G_MASTER_NODE = None # We intend to init a master node, unless provided
# -------------------------------------------------------------------------
# built-ins
import os
import copy
import traceback
import string
import logging
# using hashids to generate unique name identifiers for nodes
import hashids
import cachetools
from sched import scheduler
# local imports
from LyPy.si_shared.noodly.helpers import display_cached_value
from LyPy.si_shared.noodly.find_arg import find_arg
from LyPy.si_shared.noodly.synth import synthesize
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# quick test code (remove later)
from hashids import Hashids
hashids = Hashids(min_length=16, salt='DCCsi')
if _G_DEBUG:
print (hashids.encrypt(193487)) # test hash
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# set up logger
_G_LOGGER = logging.getLogger(__name__)
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# Use unicode strings
_base = str # Python 3 str (=unicode), or Python 2 bytes.
if os.path.supports_unicode_filenames:
try:
_base = unicode # Python 2 unicode.
except NameError:
pass
# -------------------------------------------------------------------------
###########################################################################
# HELPER method functions
# -------------------------------------------------------------------------
def return_node_from_hashid(hashid):
if not isinstance(hashid, str):
raise TypeError("{0},{1}: Accepts hashids as str types!\r"
"Input hashid:{2}\r"
"".format('noodly',
'return_node_from_hashid(hashid)',
type(hashid)))
temp_node = Node(temp_node=True).get_sibling_node_from_hashid('{0}'.format(hashid))
return temp_node
# -------------------------------------------------------------------------
class Node(object):
"""Class constructor: makes a node."""
# share the debug state
_DEBUG = _G_DEBUG
# logger
_LOGGER = _G_LOGGER
# class header
message_header = 'noodly, Node(): Message'
# class variable
_cls_node_count = 0
_cls_node_list = []
_cls_node_dict = {}
# --BASE-METHODS-------------------------------------------------------
# --constructor-
def __init__(self, node_name=None, parent_node=None, *args, **kwargs):
self._logger = Node._LOGGER
self._node_type = self.__class__.__name__
# a dict to store properties/attrs
# in the event an object is re-built / re-init
# it is important to store anything here that needs retention
self._kwargs_dict = {}
self._children = []
# private local access to the cls_node_list
self._cls_node_list = Node._cls_node_list
# -- secret keyword -----------------------------------------------
self._temp_node = False
temp_node, kwargs = find_arg(argPosIndex=None, argTag='temp_node',
removeKwarg=True, inArgs=args,
inKwargs=kwargs) # <-- kwarg only
self._temp_node = temp_node
if self._temp_node:
self._kwargs_dict['temp_node'] = self._temp_node
# -----------------------------------------------------------------
# -- store message header -----------------------------------------
# setup the .message_header <-- kwarg only
message_header, kwargs = find_arg(argPosIndex=None, argTag='message_header',
removeKwarg=True, inArgs=args, inKwargs=kwargs,
defaultValue=('{0}(), Message'
.format(self._node_type)))
self._message_header = message_header
# -----------------------------------------------------------------
# -- hashid -------------------------------------------------------
self._name_is_uni_hashid = False
self._node_class_index = len(Node._cls_node_list)
if Node._DEBUG:
print ('__init__.node_class_index: {0}'.format(self._node_class_index))
self._uni_hashid = hashids.encrypt(self._node_class_index)
if Node._DEBUG:
print ('__init__.uni_hashid: {0}'.format(self._uni_hashid))
# update class dict
if not self._temp_node:
Node._cls_node_dict[self._uni_hashid] = self
# -----------------------------------------------------------------
# -- store the node name ------------------------------------------
self._node_name = node_name
if (self._node_class_index == 0 and self._node_name == None):
self._node_name = 'MASTER'
elif (self._node_class_index > 0 and self._node_name == None):
# set a default node_name if none, based on the unihashid
if not self._name_is_uni_hashid:
self._node_name = self._uni_hashid
self._name_is_uni_hashid = True
if Node._DEBUG:
print ('__init__.node_name: {0}'.format(self._node_name))
# -----------------------------------------------------------------
# -- node parent_node --------------------------------------------------
# set up the parent_node property
self._parent_node = parent_node
if self._parent_node != None:
# add this node, to the parent_nodes list of children
try:
self._parent_node.add_child(self)
except:
pass # <-- parent_node object passed is NOT a noodly.node?
# Update class variables
Node.cls_node_count_up(self)
Node.cls_node_list_append(self)
# -----------------------------------------------------------------
# -----------------------------------------------------------------
# arbitrary argument properties
# check postions *args and **kwargs
# any kwargs left will be used to synthesize a property
try:
# checking import due to the way the code is structured
# the code was passing even if module was not imported
synthesize
synthExists = True
except Exception as e:
print(e)
raise e
for key, value in kwargs.items():
self._kwargs_dict[key] = value
try:
synthesize(self, key, value)
except Exception as e: # <-- maybe it can't synthesize?
# in which case fall back to setting the property
print(e)
code = compile(r'self._{0}={1}'.format(key, value), 'synthProp', 'exec')
pass
if Node._DEBUG:
print("{0}:{1}".format(key, value))
# -----------------------------------------------------------------
# if temp node, adjust the class counter
if temp_node:
self.cls_node_count_down()
self.cls_node_list_remove()
# -- properties ------------------------------------------------------------
@property
def logger(self):
return self._logger
@logger.setter
def logger(self, logger):
self._logger = logger
return self._logger
@logger.getter
def logger(self):
return self._logger
@property
def kwargs_dict(self):
return self._kwargs_dict
@kwargs_dict.getter
def kwargs_dict(self):
return self._kwargs_dict
@property
def message_header(self):
return self._message_header
@message_header.setter
def message_header(self, message_header):
self._message_header = message_header
return self._message_header
@property
def node_type(self):
return self._node_type
@node_type.setter
def node_type(self, node_type):
self._node_type = node_type
return self._node_type
@node_type.getter
def node_type(self):
return self._node_type
@property
def temp_node(self):
return self._temp_node
@temp_node.setter
def temp_node(self, temp_node):
self._temp_node = temp_node
return self._temp_node
@temp_node.getter
def temp_node(self):
return self._temp_node
@property
def node_name(self):
return self._node_name
@node_name.setter
def node_name(self, nameStr):
if nameStr != None:
if not isinstance(nameStr, str):
raise TypeError("{0}, {1}: Accepts str types!"
"".format(self.__class__.__name__,
self._node_name.__name__))
try:
self._node_name = nameStr
except:
synthesize(self, '_node_name', None)
return self._node_name
@node_name.getter
def node_name(self):
return self._node_name
@property
def name_is_uni_hashid(self):
return self._name_is_uni_hashid
@node_type.setter
def name_is_uni_hashid(self, value):
self._name_is_uni_hashid = value
return self._name_is_uni_hashid
@node_type.getter
def name_is_uni_hashid(self):
return self._name_is_uni_hashid
@property
def node_class_index(self):
return self._node_class_index
@property
def uni_hashid(self):
return self._uni_hashid
@property
def cls_node_dict(self):
return Node._cls_node_dict
# ----------------------------------------------------------------------
# --method-set---------------------------------------------------------
def cls_node_count_up(self):
Node._cls_node_count += 1
return Node._cls_node_count
def cls_node_count_down(self):
Node._cls_node_count -= 1
return Node._cls_node_count
def cls_node_list_append(self):
Node._cls_node_list.append(self)
return Node._cls_node_list
def cls_node_list_remove(self):
Node._cls_node_list.remove(self)
return Node._cls_node_list
# ---------------------------------------------------------------------
# --method-set---------------------------------------------------------
@property
def parent_node(self):
return self._parent_node
@parent_node.setter
def parent_node(self, parent_node):
self._parent_node = parent_node
return self._parent_node
@parent_node.getter
def parent_node(self):
return self._parent_node
def add_child(self, child):
self._children.append(child)
# --method--
def remove_child(self, child):
self._children.remove(child)
@property
def children(self):
return self._children
def child(self, row):
return self._children[row]
def child_count(self):
return len(self._children)
def row(self):
if self._parent_node != None:
return self._parent_node._children.index(self)
# ---------------------------------------------------------------------
# --method-------------------------------------------------------------
def get_sibling_node_from_hashid(self, hashid):
if not isinstance(hashid, str):
raise TypeError("{0}.{1}: Accepts hashids as str types!"
"".format(self.__class__.__name__,
'get_sibling_node_from_hashid(hashid)'))
if hashid in self.cls_node_dict.keys():
return self.cls_node_dict[hashid]
else:
return None
# --method-------------------------------------------------------------
def clear_node_dep(self):
self.clear_children
self.clear_node_list()
self.clear_node_count()
return self
def clear_node_list(self):
Node._cls_node_list = []
return Node._cls_node_list
def clear_node_count(self):
Node._cls_node_count = 0
return Node._cls_node_count
def clear_children(self):
self._children = []
return self._children
# ---------------------------------------------------------------------
# ---------------------------------------------------------------------
@cachetools.cached(cachetools.LFUCache(maxsize=2048))
def cache_node(self):
return self
# ---------------------------------------------------------------------
# --method-------------------------------------------------------------
def hierarchy(self, tab_level=-1):
output = ''
tab_level += 1
for i in range(tab_level):
output += '\t'
output += ('{tab}/------node_name:: "{0}"\n'
'{1} |type:: {2}\n'
'{1} |_uni_hashid:: "{3}"\r'
''.format(self._node_name,
'\t' * tab_level,
self._node_type,
self._uni_hashid,
tab=tab_level))
# TO DO:: object hierarchy "'hips'|'rightLeg'|'etc'"
for child in self._children:
output += child.hierarchy(tab_level)
tab_level -= 1
# output += '\n'
return output
def log_hierarchy(self):
# Not implemented
self._logger.autolog(self.hierarchy(),
"return_node_from_hashid('{0}').log_hierarchy()"
"".format(self._uni_hashid()))
return
# ---------------------------------------------------------------------
# --method-------------------------------------------------------------
# representation
def __str__(self):
'''Returns a nice string representation of the object.'''
# TO DO: need to improve this
if self.node_name == None or self.name_is_uni_hashid == True:
# open parenthesis only
output = ("{0}(node_name='{1}'"
"".format(self.__class__.__name__,
self.uni_hashid))
else:
output = ("{0}(node_name='{1}'"
"".format(self.__class__.__name__,
self.node_name))
if self.parent_node != None:
output += (", parent_node=return_node_from_hashid('{0}')"
"".format(self.parent_node.uni_hashid))
if len(self.kwargs_dict) > 0:
for key, value in self.kwargs_dict.items():
if not isinstance(value, str):
output += (", {0}={1}".format(key, value))
else: # if a str add the extra quotes
output += (", {0}='{1}'".format(key, value))
# add the close parenthesis
output += ')'
if self.name_is_uni_hashid == True or self.temp_node:
output = ("return_node_from_hashid('{0}')"
"".format(self.node_name))
# Node(self, node_name, parent_node=None, path='')
return output
# representation
def __repr__(self):
return '{0}({1})\r'.format(self.__class__.__name__, self.__dict__)
# --Class End--------------------------------------------------------------
class ClassProperty(property):
"""Decorator"""
def __get__(self, cls, owner):
return self.fget.__get__(None, owner)()
# --Class End--------------------------------------------------------------
###########################################################################
# tests(), code block for testing module
# -------------------------------------------------------------------------
def tests():
default_node = Node()
print(str(default_node))
print(repr(default_node))
print(default_node.uni_hashid)
print(default_node.kwargs_dict)
print(default_node.message_header)
print(default_node.node_name)
print(default_node.parent_node)
print(default_node.node_class_index)
# print(default_node.cls_node_dict)
# temp_node = Node()
temp_node = Node(temp_node=True)
print(temp_node)
test_default_node = Node(temp_node=True).get_sibling_node_from_hashid('kxYLm0XQeXJ7jWaP')
print(test_default_node)
another_test = return_node_from_hashid('kxYLm0XQeXJ7jWaP')
print(another_test)
second_node = Node(node_name='foo', parent_node=default_node)
print(str(second_node))
print(second_node.uni_hashid)
print(second_node.kwargs_dict)
print(second_node.message_header)
print(second_node.node_name)
print(second_node.parent_node.node_name)
print(second_node.node_class_index)
# print(second_node.cls_node_dict)
second_child = Node(node_name='fooey', parent_node=another_test)
print(str(second_child))
print(second_child.uni_hashid)
print(second_child.kwargs_dict)
print(second_child.message_header)
print(second_child.node_name)
print(second_child.parent_node.node_name)
print(second_child.node_class_index)
# print(second_child.cls_node_dict)
third_node = Node(node_name='kablooey', parent_node=second_node,
message_header='Node(): CUSTOM Message')
print(str(third_node))
print(third_node.uni_hashid)
print(third_node.kwargs_dict)
print(third_node.message_header)
print(third_node.node_name)
print(third_node.parent_node.node_name)
print(third_node.node_class_index)
fourth_node = Node(parent_node=second_node,
message_header='Node(): CUSTOM Message')
print(str(fourth_node))
print(fourth_node.uni_hashid)
print(fourth_node.kwargs_dict)
print(fourth_node.message_header)
print(fourth_node.node_name)
print(fourth_node.parent_node.node_name)
print(fourth_node.node_class_index)
kwarg_test_child = Node(node_name='kwargChild', parent_node=default_node, garble=1001001) # custom kwarg
print(str(kwarg_test_child))
print(kwarg_test_child.uni_hashid)
print(kwarg_test_child.node_name)
print(kwarg_test_child.parent_node.node_name)
print(kwarg_test_child.kwargs_dict)
# check the custom arg/property garble
print(kwarg_test_child.garble)
# check the node hierarchy
print(default_node.hierarchy())
# retreive a node from it's known hashid
master_node = return_node_from_hashid('kxYLm0XQeXJ7jWaP')
print(master_node.uni_hashid) # verify hasid
# should return the same node as default_node
print(master_node.node_name) # should be 'MASTER'
return
# -------------------------------------------------------------------------
def cache_tests():
cache = cachetools.LFUCache(maxsize=128)
runner = scheduler()
cache["HogJonny"] = 1001001
runner.enter(2, 1, display_cached_value,
kwargs={'cache': cache, 'cache_key': 'HogJonny'})
runner.enter(6, 1, display_cached_value,
kwargs={'cache': cache, 'cache_key': 'HogJonny'})
runner.run()
return
# -------------------------------------------------------------------------
def main():
return
# - END, main() --
###########################################################################
# --call block-------------------------------------------------------------
if __name__ == "__main__":
print ("# ----------------------------------------------------------------------- #")
print ('~ noodly.Node ... Running script as __main__')
print ("# ----------------------------------------------------------------------- #\r")
# run simple tests
tests()
cache_tests()