Hi,
@indexofrefraction said in Debug Python related CRASH:
I'd need to store an info globally which doesn't stay alive when saving / reopening the file.
- To store stuff 'globally' the common approach is to inject your objects into the Python interpreter. There are many places you can choose from and they are all equally bad. It's a hack. I like to use Python's module dictionary, because it has the benefit of a nice syntax (you can import your stuff). Just make sure not to overwrite any modules.
import sys
if "my_stuff" not in sys.modules.keys():
sys.modules["my_stuff"] = "bob is your uncle!"
# Somewhere else in the same interpreter instance.
import my_stuff
print my_stuff
- The life time of objects depends on their document being loaded. So if you want to 'cache' nodes beyond the life time of their hosting document, you have to do that manually. Below you will find a rough sketch on how you can approach that. There are many other ways to approach that. The UUIDs for a document will work beyond save boundaries, so you can cache something with that approach, save the document, even relocate it, and then load it again and feed the document into the cache interface query and will spit out the clones of the cached nodes.
Cheers,
zipit
"""A simple interface to cache nodes.
This is an example, not finished code.
Run in the script manager, read the comments. The *meat* is in
CacheInterface.add() and CacheInterface.query(), start reading in main().
"""
import c4d
class CacheInterface (object):
"""A simple interface to cache nodes.
"""
def __init__(self):
"""Init.
"""
self._cache = {}
def _get_cache(self, uuid):
"""Returns the cache for a cache document identifier.
Args:
uuid (c4d.storage.ByteSequence): The document identifier for the
cache.
Returns:
dict["doc": c4d.documents.BaseDocument,
"nodes": list[c4d.GeListNode]]: The cache for the given
identifier.
"""
if not uuid in self._cache.keys():
doc = c4d.documents.BaseDocument()
self._cache[uuid] = {"doc": doc, "nodes": []}
return self._cache[uuid]
def _get_tag_index(self, node, tag):
"""Returns the index of a tag.
Args:
node (c4d.BaseObject): The object the tag is attached to.
tag (c4d.BaseTag): The tag.
Returns:
int or None: The index or None when the tag is not attached to
the object.
"""
current = node.GetFirstTag()
index = 0
while current:
if current == tag:
return index
current = current.GetNext()
return None
def add(self, node):
"""Adds a node to the cache.
Args:
node (c4d-GeListNode): The node to cache. Currently only
BaseObjects and BaseTags have been implemented.
Returns:
c4d-storage.ByteSeqeunce: The identifier for the cache the node
has been inserted in.
Raises:
NotImplementedError: When an unimplemented node type has been
passed.
ValueError: When the passed node is not attached to a document.
"""
doc = node.GetDocument()
if doc is None:
raise ValueError("Can only cache nodes attached to a document.")
uuid = doc.FindUniqueID(c4d.MAXON_CREATOR_ID)
cache = self._get_cache(uuid)
# BaseObjects
if isinstance(node, c4d.BaseObject):
# Pretty easy, clone and inject
clone = node.GetClone(0)
cache["doc"].InsertObject(clone)
cache["nodes"].append(clone)
# BaseTags
elif isinstance(node, c4d.BaseTag):
# For tags things are a bit more complicated.
# First we get the index of the tag.
index = self._get_tag_index(node.GetObject(), node)
if index is None:
msg = "Could not find tag on source object."
raise AttributeError(msg)
# Then we clone the host of object of the tag and the tag.
clone_object = node.GetObject().GetClone(0)
clone_tag = clone_object.GetTag(node.GetType(), index)
# Insert the host object into our cache document.
cache["doc"].InsertObject(clone_object)
# And append the tag of the same type at the given index
# to our cache list. A bit dicey, you might wanna add some
# checks to ensure that we actually got the right tag.
cache["nodes"].append(clone_tag)
# Other node types go here ...
else:
msg = "The node type {} has not been implemented for caching."
raise NotImplementedError(msg.format(type(node)))
return uuid
def query(self, identifier):
"""
Args:
identifier (c4d.storage.ByteSeqence |
c4d.documents.BaseDocument): The identifier for the cache to
query or the document that has been the source for the cache.
Returns:
list[c4d.GeListNode]: The cached nodes.
Raises:
KeyError: When the provided identifier does not resolve.
TypeError: When the identifier is neither a document nor an uuid.
"""
if isinstance(identifier, c4d.documents.BaseDocument):
identifier = identifier.FindUniqueID(c4d.MAXON_CREATOR_ID)
if not isinstance(identifier, c4d.storage.ByteSeq):
msg = "Illegal identifier type: {}"
raise TypeError(msg.format(type(uuid)))
uuid = identifier
if uuid not in self._cache.keys():
msg = "Provided uuid is not a key in the cache."
raise KeyError(msg)
return self._cache[uuid]["nodes"]
def main():
"""Entry point.
"""
if op is None:
raise ValueError("Please select an object to cache.")
# The cache
interface = CacheInterface()
# Some stuff to cache
obj, tag = op, op.GetFirstTag()
# Inject the nodes into the cache.
uuid = interface.add(obj)
# We do not need to store the uuid here, since both nodes come from
# the same document.
interface.add(tag)
print "Original nodes:", obj, tag
print "Their cache:", interface.query(uuid)
if __name__ == "__main__":
main()