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,44 @@
"""
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.
"""
# -------------------------------------------------------------------------
# The __init__.py files help guide import statements without automatically
# importing all of the modules
"""azpy.shared.ui.__init__"""
import os
import logging
import logging.config
# global space debug flag
_G_DEBUG = os.getenv('DCCSI_GDEBUG', False)
# global space debug flag
_DCCSI_DEV_MODE = os.getenv('DCCSI_DEV_MODE', False)
if _DCCSI_DEV_MODE:
_PACKAGENAME = __name__
if _PACKAGENAME is '__main__':
_PACKAGENAME = 'noodely'
_PKG_PARENT_PATH = str('azpy.shared')
_PKG_PATH = str('{0}.{1}'.format(_PKG_PARENT_PATH, _PACKAGENAME))
_LOGGER = logging.getLogger(_PACKAGENAME)
_LOGGER.debug('Invoking __init__.py for {0}.'.format({_PKG_PATH}))
# -------------------------------------------------------------------------
#
__all__ = ['config', 'find_arg', 'master', 'node', 'synth',
'synth_arg_kwarg', 'test_foo']
#
# -------------------------------------------------------------------------
del _LOGGER
@@ -0,0 +1,123 @@
"""
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.
"""
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# find_arg.py
# A simple function for arg, kwarg retrieval
# version: 0.1
# maintenance: Gallowj
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
"""Module docstring: A simple function for retrieval of arg, kwarg"""
__author__ = 'HogJonny'
# -------------------------------------------------------------------------
def find_arg(argPosIndex=None, argTag=None, removeKwarg=None,
inArgs=None, inKwargs=None, defaultValue=None):
"""
# finds and returns an arg...
# if a positional index is given argPosIndex=0, it checks args first
# if a argTag is given, it checks kwargs
# If removeKwarg=True, it will remove the found arg from kwargs
# * I actually want/need to do this often
#
# a set kwarg will ALWAYS take precident over
# positional arg!!!
#
# return outArg, args, kwargs <-- get back modified kwargs!
#
# proper usage:
#
# foundArg, args, kwargs = find_arg(0, 'name',)
"""
if argPosIndex != None:
if not isinstance(argPosIndex, int):
raise TypeError('argPosIndex: accepts a index integer!\r'
'got: {0}'.format(argPosIndex))
# positional args ... check the position
if len(inArgs) > 0:
try:
foundArg = inArgs[argPosIndex]
except:
pass
# check kwargs ... a set kwarg will ALWAYS take precident over
# positional arg!!!
try:
foundArg
except:
foundArg = inKwargs.get(argTag, defaultValue) # defaults to None
if removeKwarg:
if argTag in inKwargs:
del inKwargs[argTag]
# if we didn't find the arg/kwarg, the defualt return will be None
return foundArg, inKwargs
# -------------------------------------------------------------------------
###########################################################################
# --call block-------------------------------------------------------------
if __name__ == "__main__":
print ("# ----------------------------------------------------------------------- #\r")
print ('~ find_arg.py ... Running script as __main__')
print ("# ----------------------------------------------------------------------- #\r")
_G_DEBUG = True
from test_foo import Foo
#######################################################################
# Node Class
# ---------------------------------------------------------------------
class TestNode(Foo):
def __init__(self, *args, **kwargs):
super().__init__()
self._name, kwargs = find_arg(argTag='foo', removeKwarg=True,
inArgs=args, inKwargs=kwargs)
self._name, kwargs = find_arg(argPosIndex=0, argTag='name',
removeKwarg=True,
inArgs=args, inKwargs=kwargs) # <-- first positional OR kwarg
self._parent, kwargs = find_arg(argPosIndex=1, argTag='parent',
removeKwarg=True,
inArgs=args, inKwargs=kwargs) # <-- second positional OR kwarg
self._kwargsDict = {}
# arbitrary argument properties
# checking **kwargs, any kwargs left
# will be used to synthesize a property
for key, value in kwargs.items():
self._kwargsDict[key] = value
# synthesize(self, '{0}'.format(key), value) <-- I have a method,
# which synthesizes properties... with gettr, settr, etc.
if _G_DEBUG:
print("{0}:{1}".format(key, value))
# representation
def __repr__(self):
return '{0}({1})\r'.format(self.__class__.__name__, self.__dict__)
# ---------------------------------------------------------------------
# -------------------------------------------------------------------------
testNode = TestNode('foo')
testNode2 = TestNode(name='fooey', parent=testNode)
testNode3 = TestNode('kablooey', testNode2, goober='dufus')
print ('testNode2, name: {0}, parent: {1}'.format(testNode2._name, testNode2._parent))
print (testNode3)
@@ -0,0 +1,46 @@
"""
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.
"""
# -------------------------------------------------------------------------
###########################################################################
# HELPER method functions
# -------------------------------------------------------------------------
def istext(filename):
"""
A guess if a file is text or binary
"""
s = open(filename).read(512)
text_characters = "".join(map(chr, range(32, 127)) + list("\n\r\t\b"))
_null_trans = string.maketrans("", "")
if not s:
# Empty files are considered text
return True
if "\0" in s:
# Files with null bytes are likely binary
return False
# Get the non-text characters (maps a character to itself then
# use the 'remove' option to get rid of the text characters.)
t = s.translate(_null_trans, text_characters)
# If more than 30% non-text characters, then
# this is considered a binary file
if float(len(t)) / float(len(s)) > 0.30:
return False
return True
def display_cached_value(cache, cache_key):
try:
cached_value = cache[cache_key]
print("{0}={1}".format(cache_key, cached_value))
except KeyError:
print("{0}=Not in cache".format(cache_key))
@@ -0,0 +1,90 @@
"""
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.
"""
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# master.py
# Allows for project based setup to be used with noodly
# version: 0.1
# author: Gallowj
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
import os
from unipath import Path
_G_DEFAULT_PROJECT_DIR = os.getcwd()
_G_MASTER_ROOT_NODE = None
@property
def _G_DEFAULT_PROJECT_DIR(value):
_G_DEFAULT_PROJECT_DIR = value
return _G_DEFAULT_PROJECT_DIR
def set_PROJECT_DIR(value):
"""Sets and returns _G_DEFAULT_PROJECT_DIR"""
global _G_DEFAULT_PROJECT_DIR
_G_DEFAULT_PROJECT_DIR = Path(value).expand()
return Path(_G_DEFAULT_PROJECT_DIR)
@property
def _G_MASTER_ROOT_NODE(value):
_G_MASTER_ROOT_NODE = value
return _G_MASTER_ROOT_NODE
def set_MASTER_ROOT_NODE(value):
"""Sets and returns _G_MASTER_ROOT_NODE"""
global _G_MASTER_ROOT_NODE
if not isinstance(inNode, ProjectRootNode):
raise TypeError('self._projectRootNode is: {0}\r'
'A _projectRootNode, needs to be properly set\r'
'So that we can acces:\r'
'\tself._projectRootNode._sourceRoot\r'
'\tself._projectRootNode._overrideRoot\r'
'Use self.assignProjectRootNode(<projectRootNode>)\r'
''.format(type(inNode)))
_G_MASTER_ROOT_NODE = inNode
return _G_MASTER_ROOT_NODE
###########################################################################
# tests(), code block for testing module
# -------------------------------------------------------------------------
def tests():
set_PROJECT_DIR(os.getcwd())
print(_G_DEFAULT_PROJECT_DIR)
print(_G_DEFAULT_PROJECT_DIR.parent)
print(_G_DEFAULT_PROJECT_DIR.components())
# NOT implemented yet
# set_PROJECT_DIR
return
###########################################################################
# --call block-------------------------------------------------------------
if __name__ == "__main__":
print ("# ----------------------------------------------------------------------- #")
print ('~ noodly.master ... Running script as __main__')
print ("# ----------------------------------------------------------------------- #\r")
# run simple tests
tests()
#_G_DEFAULT_PROJECT_DIR = Path(os.getcwd())
print(_G_DEFAULT_PROJECT_DIR.components())
@@ -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()
@@ -0,0 +1,407 @@
"""
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
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# pathnode.py
# simple path objecy based Node Class, for tool creation.
# version: 0.1
# author: Gallowj
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
"""
Module docstring:
A simple path objecy based Node Class, for creating path hierarchies.
"""
__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
# -------------------------------------------------------------------------
# built-ins
import os
import copy
import subprocess
import traceback
import string
import logging
from unipath import Path, AbstractPath
# local ly imports
from LyPy.si_shared.noodly.helpers import istext
from LyPy.si_shared.noodly.find_arg import find_arg
from LyPy.si_shared.noodly.synth import synthesize
from LyPy.si_shared.noodly.node import Node
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# 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
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# set up logger
_G_LOGGER = logging.getLogger(__name__)
# -------------------------------------------------------------------------
class PathNode(Node):
"""doc string"""
# share the debug state
_DEBUG = _G_DEBUG
# logger
_LOGGER = _G_LOGGER
# class header
_message_header = 'noodly, PathNode(): Message'
# App Launcher paths...
try:
_maya_exe_path = Path(os.environ['MAYAPY'])
except:
_maya_exe_path = Path(r"C:\Program Files\Autodesk\Maya2019\bin\maya.exe")
try:
_notepad_exe_path = Path(os.environ['DEFAULT_TXT_EXE'])
except:
_notepad_exe_path = Path(r"C:\Program Files (x86)\Notepad++\notepad++.exe")
# --BASE-METHODS-------------------------------------------------------
def __new__(cls, path="", root_path=None, *args, **kwargs):
'''docstring'''
# if not isinstance(path, str) and not isinstance(path, Path):
# raise TypeError("{0}, {1}: Accepts paths as str or Path() types!\r"
# "Input data is:{2}\r"
# "".format('noodly, PathNode',
# 'PathNode(filename)', type(path)))
#
self = super(PathNode, cls).__new__(cls)
return self
# --constructor--------------------------------------------------------
def __init__(self, path="", root_path=None, parent_is_root=None,
name_is_path=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 = {}
# -- 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.k_wargs_dict['temp_node'] = self._temp_node
# -- Node class args/kwargs ---------------------------------------
node_name, kwargs = find_arg(argPosIndex=2, argTag='node_name',
removeKwarg=True, inArgs=args,
inKwargs=kwargs) # <-- third arg, kwarg
parent_node, kwargs = find_arg(argPosIndex=3, argTag='parent_node',
removeKwarg=True, inArgs=args,
inKwargs=kwargs) # <-- fourth arg, kwarg
self._root_path = root_path
self._parent_is_root = parent_is_root
if self._parent_is_root != None:
self._kwargs_dict['parent_is_root'] = self.parent_is_root
if parent_is_root: # <-- do it
self._root_path = parent_node
# make sure the path is a Path
self._path = path
if not isinstance(self._path, Path):
try:
self._path = Path(path)
except:
self._path = Path() # empty path object fallback
self._name_is_path = name_is_path
if self._name_is_path:
self._kwargs_dict['name_is_path'] = self._name_is_path
# this might only work if the file actually exists
self._node_name = node_name
if self._name_is_path:
if self._path.name != None or self._path.name != '':
self._node_name = str(self._path.name)
# Path.__init__(self)
super(PathNode, self).__init__(self._node_name, parent_node,
temp_node=temp_node,
*args, **kwargs)
# -- properties -------------------------------------------------------
@property
def path(self):
return self._path
@path.setter
def path(self, path):
self._path = path
return self._path
@path.getter
def path(self):
return self._path
@property
def root_path(self):
return self._root_path
@root_path.setter
def root_path(self, root_path):
self._root_path = root_path
return self._root_path
@root_path.getter
def root_path(self):
return self._root_path
@property
def parent_is_root(self):
return self._parent_is_root
@parent_is_root.setter
def parent_is_root(self, parent_is_root):
self._parent_is_root = parent_is_root
return self._parent_is_root
@parent_is_root.getter
def parent_is_root(self):
return self._parent_is_root
@property
def name_is_path(self):
return self._name_is_path
# @name_is_path.setter
# def name_is_path(self, name_is_path):
# self._name_is_path = name_is_path
# return self._name_is_path
@name_is_path.getter
def name_is_path(self):
return self._name_is_path
# --method-------------------------------------------------------------
def set_file_path(self, path):
if not isinstance(path, Path):
try:
path = Path(path)
except:
raise TypeError("must be Path compatible")
# retreive a copy of the old _kwargs dict
_kwargs_dict_copy = copy.copy(self._kwargs_dict)
_name_is_uni_hashid = copy.copy(self.name_is_uni_hashid)
# create a new me (self), with new value
# attempt to keep existing attrs/settings
self = PathNode(path=path,
root_path=self.root_path,
parent_is_root=self.parent_is_root,
name_is_path=self.name_is_path,
temp_node=self.temp_node,
node_name=self.node_name,
parent_node=self.parent_node,
name_is_uni_hashid=self.name_is_uni_hashid)
# now we need to restore any custom properties on the replacement object
for key, value in _kwargs_dict_copy.items():
self._kwargs_dict[key] = value
try:
synthesize(self, '{0}'.format(key), value)
except:
code = compile('self._{0} = {1}'.format(key, value), 'synthProp', 'exec')
if Node._DEBUG:
self.logger.error('can not set: self._{0} = {1}'.format(key, value))
# replace myself in the class nodeDict, based on my unihashid
self.cls_node_dict[self.uni_hashid] = self
# return the new version of myself
return self.cls_node_dict[self.uni_hashid]
# ---------------------------------------------------------------------
# --method-------------------------------------------------------------
def start_file(self, filepath=None):
'''opens the file in the prefered os editor for the filetype'''
if filepath == None:
filepath = self.path
if not isinstance(filepath, Path): # <-any subclass of Path works?
filepath = Path(filepath)
self.logger.debug('starting file: {0}'.format(filepath))
try:
os.startfile(filepath)
except IOError as e:
self.logger.error(e)
return filepath
# ---------------------------------------------------------------------
# --method-------------------------------------------------------------
def explore_file(self, filepath=None):
if filepath == None:
filepath = self.path
if not isinstance(filepath, Path):
filepath = Path(filepath)
self.logger.debug('exploring file: {0}'.format(filepath))
if filepath.exists():
try:
subprocess.Popen(r'explorer /select,"{0}"'.format(filepath))
except IOError as e:
self.logger.error(e)
else:
self.logger.error('file does not exist: {0}'.format(filepath))
return filepath
# ---------------------------------------------------------------------
# --method-------------------------------------------------------------
def hierarchy(self, tabLevel=-1):
output = ''
if isinstance(self, RootNode):
if gDebug:
func = inspect.currentframe().f_back.f_code
output += ('{0}Called from:\n'
'{0}{1}\n'.format('\t' * (tabLevel + 1), func))
tabLevel += 1
for i in range(tabLevel):
output += '\t'
output += ('{tab}/------ nodeName:: "{0}"\n'
'{1} |typeInfo:: {2}\n'
'{1} |_uniHashid:: "{3}"\r'
'{1} |path:: "{4}"\n'
'{1} |get_root():: "{5}"\n'
'{1} |getPathFromRoot():: "{6}"\n'
''.format(self.getNodeName(),
'\t' * tabLevel,
self.get_typeInfo(),
self.get_uniHashid(),
self,
self.get_root(),
self.getPathFromRoot(),
tab=tabLevel))
for child in self._children:
output += child.hierarchy(tabLevel)
tabLevel -= 1
return output
# ---------------------------------------------------------------------
# --Class End--------------------------------------------------------------
###########################################################################
# tests(), code block for testing module
# -------------------------------------------------------------------------
def tests():
from node import Node
default_node = Node() # result: Node(node_name='MASTER')
print(default_node)
first_child = PathNode(path=None, node_name='first_child', parent_node=default_node)
print(first_child)
# result: PathNode(temp_node=True, parent_node=Node(node_name='MASTER')).siblingNodeFromHashid('WNPZoKBVpXV16QLz')
# first_child.nodeType
# first_child.parent_node
# first_child.node_name
try:
# PathNode requires a arg 'path' input (should be a path str)
fubar_path_node = PathNode() # <-- this should fail
print (fubar_path_node)
except Exception as err:
print ('\r{0}'.format(err))
print (traceback.format_exc())
foo = PathNode(r'\foo\fooey\kablooey', node_name='foo',
parent_node=default_node)
print(foo)
testes = Path(r'/foo/fooey/kablooey')
print(foo.path.exists())
print(foo.path.parent)
print(foo.path.norm_case())
print(foo.path.absolute())
fooey = PathNode(None, parent_node=foo)
print(fooey)
kablooey = PathNode(r'\foo\fooey\kablooey',
parent_node=default_node,
name_is_path=True)
print(kablooey)
kablooey = kablooey.set_file_path(r'c:\mytemp\fubar.txt')
print(kablooey)
kablooey.start_file()
kablooey.explore_file()
return
# - END, tests() ----------------------------------------------------------
def main():
pass
return
# - END, main() -----------------------------------------------------------
###########################################################################
# --call block-------------------------------------------------------------
if __name__ == "__main__":
print ("# ----------------------------------------------------------------------- #")
print ('~ noodly.PathNode ... Running script as __main__')
print ("# ----------------------------------------------------------------------- #\r")
# run simple tests
tests()
@@ -0,0 +1,116 @@
"""
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.
"""
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# synth.py
# Convenience module for a standardized attr interface for classes/objects.
# version: 0.1
# date: 11/14/2013
# author: jGalloway
# -------------------------------------------------------------------------
__author__ = 'HogJonny'
# -------------------------------------------------------------------------
"""
This module contains the function
.synthesize(inst, name, value, readonly=False)
It is useful in object oriented class attributes, providing a stardard
interface for creating properties of classes.
Can be called within an objects Class, or an instance of an object can be
passed into the function to have the properties added. The property will
be added and set/get/del attr interface will be created.
"""
# --------------------------------------------------------------------------
def synthesize(inst, name, value, readonly=False):
"""
Convenience method to create getters, setters and a property for the
instance. Should the instance already have the getters or setters
defined this won't add them and the property will reference the already
defined getters and setters Should be called from within __init__.
Creates [name], _[name], get[Name], set[Name], del[Name], and on inst.
:param inst: An instance of the class to add the methods to.
:param name: Base name to build function names and storage variable.
:param value: Initial state of the created variable.
"""
cls = type(inst)
storageName = '_{0}'.format(name)
getterName = 'get{0}{1}'.format(name[0].capitalize(), name[1:])
setterName = 'set{0}{1}'.format(name[0].capitalize(), name[1:])
deleterName = 'del{0}{1}'.format(name[0].capitalize(), name[1:])
setattr(inst, storageName, value)
# We always define the getter
def buildCustomGetter(self):
return getattr(self, storageName)
# Add the Getter
if not hasattr(inst, getterName):
setattr(cls, getterName, buildCustomGetter)
# Handle Read Only
if readonly:
if not hasattr(inst, name):
setattr(cls, name,
property(fget=getattr(cls, getterName, None) or buildCustomGetter,
fdel=getattr(cls, getterName, None)))
else:
# We only define the setter if we arn't read only
def buildCustomSetter(self, state):
setattr(self, storageName, state)
if not hasattr(inst, setterName):
setattr(cls, setterName, buildCustomSetter)
member = None
if hasattr(cls, name):
# we need to try to update the property fget, fset, fdel
# incase the class has defined its own custom functions
member = getattr(cls, name)
if not isinstance(member, property):
raise ValueError('Member "{0}" for class "{1}" exists and is not a property.'
''.format(name, cls.__name__))
# If the class has the property or not we still try to set it
setattr(cls, name,
property(fget=getattr(member, 'fget', None)
or getattr(cls, getterName, None)
or buildCustomGetter,
fset=getattr(member, 'fset', None)
or getattr(cls, setterName, None)
or buildCustomSetter,
fdel=getattr(member, 'fdel', None)
or getattr(cls, getterName, None)))
return getattr(inst, name)
# --------------------------------------------------------------------------
###########################################################################
# Main Code Block, will run the tool
# -------------------------------------------------------------------------
if __name__ == '__main__':
"""Self Testing"""
from test_foo import Foo
# create an object from Foo Class
myFoo = Foo()
pass
@@ -0,0 +1,158 @@
"""
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.
"""
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# synth_arg_kwarg.py
# Convenience module for a standardized attr interface for classes/objects.
# -------------------------------------------------------------------------
__author__ = 'HogJonny'
# -------------------------------------------------------------------------
from find_arg import find_arg
from synth import synthesize
# -------------------------------------------------------------------------
def setSynthArgKwarg(inst, argPosIndex=None, argTag=None, defaultValue=None,
inArgs=None, inKwargs=None, removeKwarg=True,
setAnyway=True):
"""
Uses find_arg and sets a property on a object.
Special args:
setAnyway <-- if the object has the property already, set it
If the arg/property doesn't exist we synthesize it
"""
foundArg = None
argValueDict = {}
# find the argument, or set to default value
foundArg, inKwargs = find_arg(argPosIndex, argTag, removeKwarg,
inArgs, inKwargs,
defaultValue)
if foundArg:
argTag = foundArg
# single arg first
# make sure the object doesn't arealdy have this property
try:
hasattr(inst, argTag) # check if property exists
if setAnyway:
try:
setattr(inst, argTag, defaultValue) # try to set
except Exception as e:
raise e
except:
pass
# make it a synthetic property
if argTag:
try:
argValue = synthesize(inst, argTag, defaultValue)
argValueDict[argTag] = argValue
except Exception as e:
raise e
# multiple and/or remaining kwards next
if inKwargs:
if len(inKwargs) > 0:
for k, v in inKwargs.items():
try:
hasattr(inst, k) # check if property exists
if setAnyway:
try:
setattr(inst, k, v) # try to set
except Exception as e:
raise e
except:
pass
if k:
try:
argValue = synthesize(inst, k, v)
argValueDict[k] = argValue
except Exception as e:
raise e
return argValueDict
# --------------------------------------------------------------------------
###########################################################################
# Main Code Block, will run the tool
# -------------------------------------------------------------------------
if __name__ == '__main__':
from test_foo import Foo
# define a arg/property tag we know doesn't exist
synthArgTag = 'syntheticArg'
# create a test object
print('~ creating the test foo object...')
myFoo = Foo()
print('~ Starting - single synthetic arg test...')
# find and set existing, or create and set
argValueDict = setSynthArgKwarg(myFoo,
argTag=synthArgTag,
defaultValue='kablooey')
# what was returned
print('~ single value returned...')
for k, v in argValueDict.items():
print("Arg '{0}':'{1}'".format(k, v))
# attempt to access the new synthetic property directly
print('~ direct property access test...')
try:
myFoo.syntheticArg
print('myFoo.{0}: {1}'.format(synthArgTag, myFoo.syntheticArg))
except Exception as e:
raise e
# can we create a bunch of kwargs?
print('~ Starting - multiple synthetic kwarg test...')
newKwargs = {'fooey': 'chop suey', 'success': True}
# find and set existing, or create and set
argValueDict = setSynthArgKwarg(myFoo,
inKwargs=newKwargs,
defaultValue='kablooey')
# what was returned
print('~ multiple values returned...')
for k, v in argValueDict.items():
print("Arg '{0}':'{1}'".format(k, v))
print('~ multiple direct property access test...')
try:
myFoo.fooey
print('myFoo.{0}: {1}'.format('fooey', myFoo.fooey))
except Exception as e:
raise e
try:
myFoo.success
print('myFoo.{0}: {1}'.format('success', myFoo.success))
except Exception as e:
raise e
print('~ Starting - known failure test...')
try:
myFoo.knownBad
except Exception as e:
print(e)
print('Test failed as expected!!!')
@@ -0,0 +1,62 @@
"""
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.
"""
# -------------------------------------------------------------------------
# -------------------------------------------------------------------------
# test_foo.py
# just a dumb test object
# -------------------------------------------------------------------------
__author__ = 'HogJonny'
# -------------------------------------------------------------------------
from synth import synthesize
class Foo(object):
"""
This is a Class, it creates a Foo object... which does nothing really
"""
__propertyTag = 'fooProperty'
# ------------------------------------------------------------------
def __init__(self, name='Foo', value='defaultValue', *args, **kwargs):
'''Class __init__'''
synthesize(self, 'name', name)
synthesize(self, Foo.__propertyTag, value)
synthesize(self, 'test', 'testValue')
self.testDump = object.__getattribute__(self, 'test')
# This calls a class method
self.methodA()
# ------------------------------------------------------------------
def methodA(self):
'''Class synthesized property methods self-tests'''
"""test getters"""
print ('{0}.fooProperty is: {1}'
''.format(self.getName(), self.getFooProperty()))
"""test property retreival"""
print ('{0}.testDump is: {1}'
''.format(self.name, self.testDump))
# ----------------------------------------------------------------------
###########################################################################
# Main Code Block, will run the tool
# -------------------------------------------------------------------------
if __name__ == '__main__':
# create an object from Foo Class
myFoo = Foo()