0% found this document useful (0 votes)
13 views36 pages

Dirty

Uploaded by

LE Thuc Trinh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
13 views36 pages

Dirty

Uploaded by

LE Thuc Trinh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 36

#

# Copyright (c) 2013-Present Arteris and its applicable affiliates, subject to


license from Qualcomm Technologies. All rights reserved.
#
import inspect

from tools.utils.override import Override

import loc.strongBox as sb
import sw.ns.bootstrap.application as app
import threading
import time
import sys
import random
import os
import re
import collections

from tools.utils.lru_backport import lru_cache


from tools.utils.licenser import theLicenser

unstableEvent = threading.Event()

_nothing_ = object()
class _Track(dict):
"Utility class, should not be instantiated manually. " \
"A _Track instance is return by Spooler.subscribe(). " \
"Behaves like a {element:value} dictionary. " \
"The view is notified whenever elements in self are updated or destroyed, " \
"as well as children cretead in those. "
def __init__(self,view):
dict.__init__(self)
self.view = view
self._thread = None
self._living = True
self._soft = False
self._suspended = False
def __setitem__(self,element,val):
if element not in self:
assert self._living
element._trackCount += 1
track,dirty,root,renames,changed_sb_items =
app.theSpooler._subscriptions[self.view]
assert track is self
assert isinstance(element,Element)
assert element.descendsOf(root)
if self.view.receiveNotification :
for sub in element :
dirty.setdefault(sub,app.theSpooler.CREATED)
dirty[element]=app.theSpooler.UPDATED
dict.__setitem__(self,element,val)
def update(self,dic):
print("update")
assert self._living
for key,val in dic.iteritems():
self[key] = val # So that it calls __setitem__
def __delitem__(self,element):
x = dict.pop(self,element,_nothing_)
if x is _nothing_ : raise KeyError
elif self._living : element._trackCount -= 1
def pop(self,element,default=_nothing_):
x = dict.pop(self,element,_nothing_)
if x is _nothing_ :
if default is _nothing_ : raise KeyError
else : return default
else :
if self._living : element._trackCount -= 1
return x
def _kill(self):
self._living = False
for element in self :
element._trackCount -= 1
def running(self): return self._thread is not None
def setSoft(self,soft):
self._soft = soft

def setSuspended(self,suspended):
self._suspended = suspended
if not suspended and self._thread is None :
app.theSpooler.startStabilizingThread(self.view)

def isSuspended( self ) :


return self._suspended

class PoisonException(Exception): pass


class StabilizeException(Exception): pass
class ToxicException(Exception): pass

class View(object):
receiveNotification = True
skip_network_requests = False

def notifyUnstableRoot( self ) : pass


def notifyBegin ( self, ) : return False
#indicate that the view need all subscribtion
def notifyStableRoot ( self ) : pass
def notifyElement
( self,deletions,updates,creations,renames,changed_sb_items ) : pass
def notifyCompletion ( self ) : pass
def notifyDeletedRoot ( self ) : pass

class Spooler(object):
DELETED = 0
UPDATED = 1
CREATED = 2
def __init__(self):
self._lock = threading.RLock()
self._subscriptions = {}
self._all_update_subscriptions = set()
self._gatherer = None
self._viewLevel = 0
self._revision = 0
self._need_to_notify_reload = False

app.controller.subscribe(self,self.closeTransaction,self.openTransaction)

def subscribe(self,view,root=None):
"Registers a new subscription. " \
"A view can only register once. " \
"Returns an empty Track instance. "
with self._lock :
assert isinstance(view,View) , "only Views can subscribe to the
Spooler."
assert view not in self._subscriptions , "View %s has already
subscribed."
if root is None : root = self.root()
track = _Track(view)
track._viewLevel = self._viewLevel
# Track, dirty, root, renames, sbItems changed
self._subscriptions[view] = ( track , {} , root, {}, set())
if getattr(view, 'ALL_UPDATES', False):
self._all_update_subscriptions.add(view)

# Only stabilize elements which are enabled.


if not root.disabled():
self.startStabilizingThread(view)
return track

def unsubscribe(self,view):
"Unregisters a subscription. "
with self._lock :
if view in self._all_update_subscriptions:
self._all_update_subscriptions.remove(view)
track,dirty,root,renames,changed_sb_items =
self._subscriptions.pop(view)
track._kill()
thread = track._thread
if thread is not None : thread._poison = True
track._thread = None

def setDirty(self,view, val = 1):


"Set dirty for a subscription"
with self._lock :
if view in self._subscriptions:
values = list(self._subscriptions[view])
if isinstance(values[1], dict):
values[1][view] = val
self._subscriptions[view] = tuple(values)

def __enter__(self):
self._viewLevel += 1
def __exit__(self,excType,excValue,excTb):
if theLicenser.haveLicense("LaunchDevelopper") and excValue is not
None:
raise excValue
self._viewLevel -=1
self.kick()

def announceCreation(self,element):
if element._parent is None : return
if element._parent._trackCount :
with self._lock :
hit = False
for view,(track,dirty,root,renames,changed_sb_items) in
self._subscriptions.iteritems() :
if (element._parent in track and element not in
track) or view in self._all_update_subscriptions:
hit = True
dirty[element] = self.CREATED
assert hit or LogBook.warning('%s pretends to be tracked
but is not [C] !' % element._parent) or True
else:
with self._lock :
for view in self._all_update_subscriptions:
track, dirty, root, renames, changed_sb_items =
self._subscriptions[view]
dirty[element] = self.CREATED

def announceDeletion(self,element):
assert not element._stable
# Cancels a furtive creation
if element._parent is not None and element._parent._trackCount :
with self._lock :
hit = False
for view,(track,dirty,root,renames,changed_sb_items) in
self._subscriptions.iteritems() :
if element._parent in track or view in
self._all_update_subscriptions:
hit = True
if dirty.get(element,None) is self.CREATED :
del dirty[element]
assert hit or LogBook.warning('%s pretends to be tracked
but is not [D1] !' % element._parent) or True
if element._trackCount :
with self._lock :
hit = False
for view,(track,dirty,root,renames,changed_sb_items) in
self._subscriptions.iteritems() :
if element in track or view in
self._all_update_subscriptions:
hit = True
dirty[element] = self.DELETED
assert hit or LogBook.warning('%s pretends to be tracked
but is not [D2] !' % element) or True
else:
with self._lock :
for view in self._all_update_subscriptions:
track, dirty, root, renames, changed_sb_items =
self._subscriptions[view]
dirty[element] = self.CREATED

def announceUpdate(self,element):
if element._trackCount :
with self._lock :
hit = False
for view,(track,dirty,root,renames,changed_sb_items) in
self._subscriptions.iteritems() :
if element in track or view in
self._all_update_subscriptions:
hit = True
if element not in dirty:
dirty[element] = self.UPDATED
assert hit or LogBook.warning('%s pretends to be tracked
but is not [U] !' % element) or True
else:
with self._lock :
for view in self._all_update_subscriptions:
track, dirty, root, renames, changed_sb_items =
self._subscriptions[view]
dirty[element] = self.CREATED

def announceTreeUpdate(self,element):
"Announces an update on all elements rooted at 'element'."
self.announceUpdate(element)
for subElement in element :
self.announceTreeUpdate(subElement)
for dependency in element._fwdDependencies :
self.announceUpdate(dependency)

def registerGatherer(self,gatherer):
self._gatherer = gatherer
def unregisterGatherer(self,gatherer):
assert self._gatherer==gatherer,"Unregistering wrong gatherer"
self._gatherer = None
def root(self):
return app.root.getElement()

def exitCleanUp(self):
threads = [ thread for thread in threading.enumerate() if
isinstance(thread, StabilizingThread) ]
for thread in threads : thread._poison = True
for thread in threads : thread.join()

def clearProject(self):
with self._lock :
for view, (track, dirty, root, renames, changed_sb_items) in
self._subscriptions.iteritems():
if hasattr(view, 'handleClearProject'):
view.handleClearProject()

def reloadProject(self):
with self._lock:
self._need_to_notify_reload = True

def openTransaction(self):
"Called back before any change to the strong box." \
"Poisons any running stablizing thread ."
threads = set()
with self._lock :
self._revision += 1
for view,(track,dirty,root,renames,changed_sb_items) in
self._subscriptions.iteritems() :
thread = track._thread
if thread is not None :
thread._poison = True
threads.add(thread)
for thread in threads : thread.join()

def closeTransaction(self,sbItems, skip_stabilize=False,


network_request=False):
"Called back after a transaction on the strong box." \
"Updates object elements, and starts stabilizing threads."
if skip_stabilize:
self.kick(skip_stabilize, network_request)
return

for sbItem in sbItems :


if sbItem.out() :
for element in list(sbItem.getElements()):
for dep in element._fwdDieDependencies:
dep.unstabilize()
element._fwdDieDependencies.clear()
element.itemDestroyed()
elif sbItem.getKernelItem() is not app.root.getKernelItem():
element = sbItem.getElement()
# Destroy elements whose item has been reparented.
if element is not Ellipsis :
if element.parent()._item is not sbItem.getParent() :
for element in list(sbItem.getElements()):
for dep in element._fwdDieDependencies:
dep.unstabilize()
element._fwdDieDependencies.clear()
element.itemDestroyed()

## Unstabilize all element for which the new sbItems will be associated
# This requires multiple iteration as a full hierarchy can be created
at once
# but can only be handled one level at a time.
itemToElt = { i : i.getElement() for i in sbItems }
todoStack = [ i for i in sbItems if itemToElt[i] is Ellipsis ]
prevSize = 0
while 1:
if len(todoStack) == prevSize:
break
stack = todoStack
todoStack = []
prevSize = len(stack)
for sbItem in stack:
pElement =
itemToElt.get(sbItem.getParent(),sbItem.getParent().getElement())
if pElement is not Ellipsis :
if not sbItem.out() :
e = pElement.itemCreated(sbItem)
if e is not None: itemToElt[sbItem] = e
for dep in set(pElement._fwdChildDependencies) :
dep.unstabilize()
pElement._fwdChildDependencies.clear()
pElement.unstabilize()
else:
todoStack.append(sbItem)

for sbItem in sbItems :


element = sbItem.getElement()
if element is not Ellipsis :
element.unstabilize()

for view, (track, dirty, root, renames, changed_sb_items) in


self._subscriptions.items():
changed_sb_items.add(sbItem)

self.kick(skip_stabilize, network_request)

def kick(self, skip_stabilize, network_request):


views = set()
for view , (track,dirty,root,renames,changed_sb_items) in
self._subscriptions.iteritems() :
if track._viewLevel == self._viewLevel :
if not root.stable() and not root.disabled():
views.add(view)

for view in views:


self.startStabilizingThread(view, skip_stabilize,
network_request)

def startStabilizingThread(self, view, skip_stabilize=False,


network_request=False):
thread = None
with self._lock :
track,dirty,root,renames,changed_sb_items =
self._subscriptions[view]
if track._thread is None and not track.isSuspended():
try : view.notifyUnstableRoot()
except : sys.excepthook(*sys.exc_info())
track._thread = thread = StabilizingThread(view,root,
skip_stabilize, network_request)
if thread is not None : thread.start() # must be done outside the
lock !

def threadCount(self):
i = 0
for track,view,root,renames,changed_sb_items in
self._subscriptions.itervalues():
if track._thread is not None : i += 1
return i

def trigger(self,view):
"Called back on the death of a stabilizing thread." \
"Arms the gatherer, to call self.flush(), in the main thread."
if view not in self._subscriptions : return
if self._gatherer is not None :
self._gatherer.arm(view)

def notifyView(self, view):


"""
Notify the view of any changes in its subscription.

:param view: The view to notify.


:type view: Actor
"""
(track, dirty, root, renames, changed_sb_items) =
self._subscriptions[view]
if track._suspended:
return

# No need to process any further if the view is not dirty.


if not dirty:
return

if getattr(track._thread, 'network_request', False) and


view.skip_network_requests:
self._subscriptions[view] = (track, {}, root, {}, set())
return
# Keep processing
# The views can call stabilize on elements, and if the element raises a
stablization
# exception and becomes toxic, then we can end up in an infinite loop
where the
# element goes into the dirty dict every iteration.
# Keep track of what the current dirty items are and at the end of the
loop, check
# if nothing has changed and if that is the case, just break.
old_dirty = set()

while dirty:
old_dirty = set(dirty.items())
deletions = set()
updates = set()
creations = set()
d = (deletions, updates, creations)

# Categorize the changes into the three states of deleted,


updated, and created.
for element, state in list(dirty.iteritems()):
d[state].add(element)

# Clear the dirty "flag" of the subscription.


self._subscriptions[view] = (track, {}, root, {}, set())

# Notify the view of any changes.


try:
# print("dirty", dirty)
view.notifyElement(deletions, updates, creations, renames,
changed_sb_items)

# If there were any errors, notify the user.


except:
sys.excepthook(*sys.exc_info())

# ! The view may very well have unsubscribed during the


notification :
if view in self._subscriptions:
assert not any(element in track for element in
deletions), \
"View %s did not delete all the notified items : %s"
% (view,' , '.join([str(element) for element in deletions if element in track]))
dirty = self._subscriptions[view][1]

# print("dirty", dirty)
# print("dirty.type", type(dirty))
# import ipdb; ipdb.set_trace()
else:
dirty = False

if set(dirty.items()) == old_dirty:
break

# Inform the view that the notifications are finished.


view.notifyCompletion()

def flush(self,view):
"Called in the main thread by the gatherer at the end of the stabiling
thread." \
"Summarizes the changes and calls the view. "

with self._lock :
if self._need_to_notify_reload:
self._need_to_notify_reload = False
for view_ in self._subscriptions.keys():
if hasattr(view_, 'handleReloadProject'):
view_.handleReloadProject()

thread = None
with self._lock :
self._revision += 1

# The view may have unsubscribed in the meanwhile !


if view not in self._subscriptions:
return

(track, dirty, root, renames, changed_sb_items) =


self._subscriptions[view]

# The view changed its root!


if track._thread is None:
return

if root.isDead() :
try:
view.notifyDeletedRoot()
except:
sys.excepthook(*sys.exc_info())

assert view not in self._subscriptions or


self._subscriptions[view][2] is not root, (
"View %s did not unsubscribe in response to the
deletion of its root"
% view
)

elif root.status() is None:


track._thread = thread = StabilizingThread(view,root,
network_request=getattr(track._thread, 'network_request', False))

# The root is alive and well.


else:
try:
view.notifyBegin()
except:
sys.excepthook(*sys.exc_info())

self.notifyView(view)

try:
view.notifyStableRoot()
except:
sys.excepthook(*sys.exc_info())

track._thread = None
# Start the thread if we created one. This must be done outside of the
lock!
if thread is not None:
thread.start()

def pollSoft(self):
with self._lock :
for view , (track,dirty,root,renames,changed_sb_items) in
self._subscriptions.items() :
if track._soft and not root.isDead() : # and track._thread
if dirty :
# import ipdb; ipdb.set_trace()
self.notifyView(view)

def transaction(self,text, skip_stabilize=False):


return app.controller.transaction(text, skip_stabilize=skip_stabilize)

class StabilizingThread(threading.Thread):
def __init__(self,view,element, skip_stabilize=False, network_request=False):
self.view = view
self.skip_stabilize = skip_stabilize
self.element = element
self.stack = []
self.stack_set = set()
self._poison = False
self.network_request = network_request
self.__logStack__ = [ LogBook.rootLogger() ]
self.start_time = time.time()
super(StabilizingThread,self).__init__()
self.setName("%s for %s" % (element,view))

def start(self):
super(StabilizingThread,self).start()
unstableEvent.set()
if __options__.noThread : self.join()
def run(self):
os.nice(10)
if __options__.profile :
import cProfile
cProfile.runctx('self.run0()',globals(),locals(),"%s_%x.pyProf"%
(__options__.profile,threading.currentThread().ident))
else :
self.run0()
def run0(self):
# XXX ! We can only start a thread from an ObjectElement !
# Otherwise it may die _while_ we are stabilizing it !
try :
if not self.skip_stabilize:
self.element.parentObject().stabilize()

except PoisonException:
pass

finally :
# When quitting while thread are active strange things, add
protections
try:
app.theSpooler.trigger(self.view)
except:
pass

def sortKey(element): return element.sortKey()

def sortedElementList(l):
""" Sort the element by pathname."""
convert = lambda text: int(text) if text.isdigit() else text
alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)',
key.pathname(key.projectAncestor())) ]
return sorted(l, key = alphanum_key)

@lru_cache
def lru_methods(class_):
return [
obj for (name, obj) in inspect.getmembers(class_)
if inspect.ismethod(obj) and hasattr(obj, 'cache_clear')
]

cnt = 0
class Element(object):
_uLock = threading.RLock()
displayName = 'UNSET DISPLAY NAME'
_dead = False
_parent = None
_item = None
_selfWeak = False
isObject = False
isProjectAncestor = False
isParameter = False
isIssue = False
isCompiled = False
canBeDisabled = False
createDisabled = False
twtTopic = None
publishableAttributes = ()
_frozen = None
def __init__(self,parent,key):
# TODO: remove sb.Item when C conversion progressed
assert isinstance(key,(str,sb.Item,Element)) , "Key be %s (%s)" %
(key,type(key))
if type(key) is str :
sKey = True
rKey = key
else:
if isinstance(key,Element):
key = key._item
sKey = False
rKey = key.objectOrigin()

self.toxic = False
self._parent = parent
self._children = collections.OrderedDict()
self._lock = threading.Lock()
self._status = False
self._trackCount = 0
self._key = key
self._fullSortKey = None
# TODO When we have a C++ implementation of weakref, use. This will
avoid a memory leak
self._fwdDependencies = set()
self._fwdChildDependencies = set()
self._fwdDieDependencies = set()
self._stable = False
self._path = None
self._cachedAbstractionIn = {}
if parent is not None :
assert rKey not in parent._children, "Key %s already present in
%s" % (rKey,dict([(k,str(v)) for k,v in parent._children.iteritems()]))
parent._children[rKey] = self
parent.unstabilize()
if not sKey:
key.addElement(self)
app.theSpooler.announceCreation(self)

# Find all functions which are tagged with lru_cache.


self._lru_methods = [obj.__get__(self) for obj in
lru_methods(self.__class__)]

def __copy__(self):
return self

def __deepcopy__(self, memo):


memo[id(self)] = self
return self

def _resetPathCache(self):
for function in self._lru_methods:
function.cache_clear()

for child in self:


child._resetPathCache()

def recursiveChildren(self):
"""
:returns: All of the recursive children of this element.
:rtype: Set[Element]
"""
children = set()
for child in self:
children.add(child)
children |= child.recursiveChildren()
return children

def destroy(self):
"Interal the wheel of fortune, do not call."
if self._dead : return
with self._uLock :
if self._dead : return
self._dead = True
self.unstabilize()
for child in self._children.values():
if not child._dead: child.destroy()
app.theSpooler.announceDeletion(self)
key = self._key
if type(key) is str :
self._parent._children.pop(key,None) #Sometimes seems to be
already removed Bug#18429
else :
key.removeElement(self)
if key.getElement() is self :
key.setObjectElement(Ellipsis)
assert self._parent is not None
self._parent._children.pop(key.objectOrigin(),None)
#Sometimes seems to be already removed Bug#18429
self.resetAttrs()
# del self._parent

@lru_cache(maxsize=None)
def path(self):
if self._path is None:
path = []
scan = self
while scan : path.append(scan) ; scan = scan._parent
path.reverse()
self._path = path
return self._path

def disabled(self): return False

def resetAttrs(self): pass

@lru_cache(maxsize=None)
def __str__(self):
return '<%s:%s>' % (type(self).__name__,self.pathname())

def __getitem__(self, key):


"""
:param key: The key of the child element.
:type key: Union[Tuple[Element, ...], List[Element, ...], str,
Element]

:returns: The child element under the given key.


:rtype: Element
"""
# Since this is called so much, we use a direct type check instead of
# isinstance, since it is faster.
if type(key) in (tuple, list):
c = self
for k in key:
c = c[k]
return c

# If the key is a string, we check our children.


if type(key) is str :
return self._children[key]

# Any other item is assumed to be an Element.


else:
key = getattr(key,'_item',key) # Faster than if
isinstance(key,Element):
return self._children[key.objectOrigin()]

def get(self, key, default=None):


""" Mimic dict.get, but using self.__getitem__ """
try:
return self[key]
except KeyError:
return default

def hasKey(self,key):
if type(key) is str : return key in self._children
if isinstance(key,Element):
key = key._item
return key.objectOrigin() in self._children

def __contains__( self , key ) :


#used in code: if key in self
return self.hasKey( key )

def __iter__(self):
"Iterates over self's children. "
#used in code: for key in self
return self._children.itervalues()
def iterObjects(self):
for x in self :
if x.isObject : yield x
def childCount(self):
"Returns the number of self's children."
return len(self._children)

def isDead(self): return self._dead

def __eq__ (self,other): return self is other


def __ne__ (self,other): return self is not other
def __cmp__(self,other):
"Compares self's and Other. " \
"If 'a' is self's and other's last common ancestor. " \
"'s' is the child of 'a', ancestor of self. " \
"'o' is the child of 'a', ancestor of other. " \
"Actually compares s.sortKey() and o.sortKey(). " \
"[And this is what you expect !] "

if not isinstance(other,Element): return cmp(super(Element,self),other)


if self is other : return 0
return cmp(self.fullSortKey(),other.fullSortKey())

def __enter__(self):
thread = threading.currentThread()
thread.stack.append(self)
thread.stack_set.add(self)

def __exit__(self,excType,excValue,excTraceback):
try:
thread = threading.currentThread()
elt = thread.stack.pop()
thread.stack_set.remove(elt)
assert elt is self
if excValue :
if type(excValue) in (PoisonException,SystemExit) :
self._status = None ; return False
self._status = False
sys.excepthook(excType,excValue,excTraceback)
self._stable = True
finally:
if self._lock.locked():
self._lock.release()
app.theSpooler.announceUpdate(self)
return True

def orderedChildren(self):
"Iterates over self's children, using a deterministic order. "
return sorted(self,key=sortKey)

def _resetFullSortKey(self):
if self._fullSortKey is not None:
self._fullSortKey = None
for c in self:
c._resetFullSortKey()

def fullSortKey(self):
if self._fullSortKey is None:
if self._parent:
self._fullSortKey = self._parent.fullSortKey() +
(self.sortKey(),)
else:
self._fullSortKey = (self.sortKey(),)
return self._fullSortKey

@lru_cache(maxsize=None)
def sortKey(self):
return str(self._key)

@lru_cache(maxsize=None)
def descendsOf(self,element):
"Returns True is element is an ancestor of self."
scan = self
while scan :
if scan is element : return True
scan = scan._parent
return False

def parent(self):
"returns self's parent."
return self._parent
def origin(self):
"returns self's origin. [ Only for ObjectElements. ]"
return None
def key (self):
"Returns self's key in parent. " \
"Result is either a string or an Item instance. "
return self._key

@lru_cache(maxsize=None)
def name(self):
"Returns a reasonable name for self in self's parent. " \
"Result is a string, but cannot be used as a key. "
return str(self._key)

def color( self , in_ = None , saturation = 1 , alpha = 1 , stringStart = 0 ,


child = None ) :
import PyQt4.Qt as qt
c = qt.QColor()
r = random.Random(self.pathname(in_)[ stringStart : ] + '' if child is
None else child.pathname( in_ ) )
c.setHsvF(r.random(),saturation , 1 - .4*saturation*r.random(),alpha)
return c

def niceName(self,in_ = None):


if in_ is None : return self.pathname()
elif in_ is not self : return self.pathname(in_)[1:]
else : return "[%s]" % self.displayName

def reprName(self,in_ = None):


return self.pathname(in_)
# should actually never be called
# overloaded in sub classes
def __repr__(self):
return self.reprName()

@lru_cache(maxsize=None)
def pathname(self,in_ = None,watch=None):
"Returns self's pathname. Result is a string. "
parentObject = self.parentObject()
parentObjectItem = parentObject._item

# XXX Must be un-re-cursed


key = self._key
n = key if type(key)==str else key.pathFor(parentObjectItem)
if watch:
self.watch(watch)
if self._parent is in_ : return n
else : return self._parent.pathname(in_,watch)+'..'+n

@classmethod
def fromPath(cls,pathname):
"Retrieves an element, out of its pathname. "
path = pathname.split('..')
rootItem = app.root.getitem_str(path[0][1:])
scan = rootItem.getElement()
for z in path[1:] :
if z[0] == '(':
ref = rootItem.getReferenceByName(z)
if ref not in scan and not scan.stable():
try:
scan.stabilize()
except StabilizeException:
pass
scan = scan[ref]
else:
if z not in scan and not scan.stable():
try:
scan.stabilize()
except StabilizeException:
pass
scan = scan[z]
return scan

@lru_cache(maxsize=None)
def exportName(self,in_=None):
if isinstance(in_,type): in_ = self.ancestor(in_)
pathname = self.pathname(in_)
if pathname.startswith('/'): pathname = pathname[1:]
# @.. is for clockGaters
return
pathname.replace('..@..','_').replace('@..','').replace('/','_').replace('..','_').
replace('.','_')

@lru_cache(maxsize=None)
def nameListIn(self,ancestor):
current = self
nameList = []
while current is not ancestor and current is not None:
nameList.insert(0,current.name())
current = current.parent()
assert current is ancestor, "Ancestor is not a parent of self"
return nameList
def abstractionIn(self,scope):
if scope.isProjectAncestor:
if scope not in self._cachedAbstractionIn or
self._cachedAbstractionIn[scope].isDead():
selfPath = []
scan = self
while scan is not None and not scan.isProjectAncestor:
selfPath.insert(0,scan._key)
scan = scan._parent
if scan is None: return None
if not scan._item.shareOriginLineWith(scope._item): return
None
scan = scope
for key in selfPath:
try:
scan = scan._children[key] if type(key) is str
else scan._children[key.objectOrigin()]
except KeyError:
return None
self._cachedAbstractionIn[scope] = scan
assert not self._cachedAbstractionIn[scope].isDead()
return self._cachedAbstractionIn[scope]
else:
selfPath = []
scopePath = []
scan = self
while scan is not None : selfPath.append(scan._key) ;
scan=scan._parent
scan = scope
while scan is not None : scopePath.append(scan._key) ;
scan=scan._parent
if len(scopePath)>len(selfPath) :
return None
while scopePath :
selfKey = selfPath.pop()
scopeKey = scopePath.pop()
if selfKey == scopeKey : continue
if (
not isinstance(selfKey,sb.CoreItem)
or not isinstance(scopeKey,sb.CoreItem)
or not selfKey.shareOriginLineWith(scopeKey)
):
return None
scan = scope
try :
while selfPath :
scan = scan[selfPath.pop()]
except KeyError :
return None
return scan

def asObjects(self):
return set()

def asParameters(self):
return set()

def stable(self):
return self._stable
def status(self):
if not self._stable : return None
return self._status

def watch(self,for_):
self._fwdDependencies.add(for_)
return True
def watchChildren(self,for_):
self._fwdChildDependencies.add(for_)
return True
def watchDie(self,for_):
self._fwdDieDependencies.add(for_)
return True

def walkObjects(self,cls,sort=True):
stack = collections.deque([self])
while stack :
x = stack.popleft()
if isinstance(x,cls):
yield x
if sort:
stack.extend(sorted([child for child in x if
isinstance(child,cls)],reverse=True,key=lambda c:c.sortKey()))
else:
stack.extend(child for child in x if isinstance(child,cls))
def walkKinds(self,kinds,sort):
assert sort in (True,False)
assert type(kinds) is not str
stack = collections.deque([self])
kinds = {k for k in kinds}
while stack :
current = stack.popleft()
if current.isObject and current.kind in kinds:
yield current
if sort:
stack.extend(sorted((child for child in current if
child.isObject and child.kind in kinds),key=lambda c:c.sortKey()))
else:
stack.extend(child for child in current if child.isObject
and child.kind in kinds)
def walkKind(self,kind,sort):
assert sort in (True,False)
stack = collections.deque([self])
while stack :
current = stack.popleft()
if current.isObject and (kind is None or current.kind == kind):
yield current
if sort:
stack.extend(sorted((child for child in current if
child.isObject and (kind is None or child.kind == kind)),key=lambda c:c.sortKey()))
else:
stack.extend(child for child in current if child.isObject
and (kind is None or child.kind == kind))

def childrenOfKinds(self, kinds, sort):


assert sort in (True,False)
assert type(kinds) is not str
stack = collections.deque([self])
kinds = {k for k in kinds}

# Dict-casting here is to make the access of itervalues faster. This


means that we lose the reproducible
# iteration of OrderedDict.
children = (child for child in dict(self._children).itervalues() if
child.isObject and child.kind in kinds)
if sort:
children = sorted(children, key=lambda c: c.sortKey())

for current in children:


yield current

def recursiveChildren(self):
"""
:returns: All of the recursive children of this element.
:rtype: Set[Element]
"""
children = set()
for child in self:
children.add(child)
children |= child.recursiveChildren()

return children

def stabilize(self,weak=False,block_on_acquire_lock=True):
thread = threading.currentThread()
if thread.stack: self._fwdDependencies.add(thread.stack[-1])
if self._stable and self._status is not None and not self.toxic:
return self._status
assert self not in thread.stack_set, "Dependency loop : %s"%
([x.pathname() for x in thread.stack+[self]],)

if not self._lock.acquire(block_on_acquire_lock):
raise StabilizeException

if self._stable and self._status is not None : # May have been


stabilized during the lock acquisition !
self._lock.release()
return self._status

if self._dead:
self._lock.release()
return False

# Lock is released in self.__exit__!!!


with self:
if thread._poison:
raise PoisonException

if weak and self.disabled():


self._status = None

else:
self._selfWeak = weak
if self.isParameter:
self.toxic = False

try:
self._status = self.stabilizeJob()

# If we stabilized successfully, go through the


issues and check if there are
# any which were created from a previous thread which
might have been running
# at the same time as this one.
if self._status is True and '!' in self and
hasattr(thread, 'start_time'):
for issue in self['!']:
if issue.thread_creation_time is not None
and issue.thread_creation_time < thread.start_time:
issue.destroy()
except StabilizeException:
self._status = None
except ToxicException:
assert self.isParameter, "ToxicException can only by
used inside the stabilizeJob of a ParameterElement"
self._status = False
self.toxic = True

return self._status

def unstabilize(self):
with self._uLock :
if self._stable :
app.theSpooler.announceUpdate(self)
#global cnt
#cnt += 1
self._stable = False
self._status = None
self._resetFullSortKey()
for element in list(self._fwdDependencies) :
element.unstabilize()
self.unstabilizeJob()
self._fwdDependencies.clear()

def stabilizeJob(self): return False


def unstabilizeJob(self): pass
def userStr(self): return ''

@lru_cache(maxsize=None)
def parentObject(self):
scan = self
while scan and not scan.isObject : scan=scan._parent
return scan
@lru_cache(maxsize=None)
def projectAncestor(self):
scan = self
while scan and not scan.isProjectAncestor : scan=scan._parent
return scan

@lru_cache(maxsize=None)
def ancestor(self,cls):
"""
Return the first parent of self that is of type 'cls'.
Can return None if there is no such parent
"""
scan = self
while scan is not None and not isinstance(scan,cls): scan =
scan._parent
return scan
@lru_cache(maxsize=None)
def ancestorOfKind(self,kind):
"""
Return the first parent of self that is of type 'cls'.
Can return None if there is no such parent
"""
scan = self
while scan is not None and not (scan.isObject and scan.kind == kind):
scan = scan._parent
return scan

def htmlRef(self,for_=None):
return '<a href="%s"> %s </a>' % (self.url(),self.reprName(for_ if for_
is not self else for_.projectAncestor()))

def url(self):
return "ans:%s" % self.pathname()

def htmlDescription(self):
return (
"<b>%s</b>"% self.reprName()
)

class CompiledElement(Element):
isCompiled = True
def __init__(self,parent,key):
self._dynamically_compiled_children = []
super(CompiledElement, self).__init__(parent, key)

def itemDestroyed(self):
self.destroy()
def reprName(self,in_=None):
if self._key is '@' : return 'Synthesis of %s' %
self.parent().reprName(in_)
p = self.parentObject()
if (in_ is None or in_.isObject) and '@' in p:
return 'Synthesized %s of %s' % ( self.pathname(p['@']) ,
p.reprName(in_) )
else :
return self.pathname(in_)
def niceName( self , in_ = None ) :
if in_ is None : return self.pathname()
elif in_ is not self : return self.pathname(in_)
else : return "[%s]" % self.displayName
return self.pathName

def stabilizeJob(self):
self.buildCompiledChildren()

try :
return all([child.stabilize() for child in self])
except None:
raise

def unstabilizeJob(self):
for child in self._dynamically_compiled_children:
child.destroy()
self._dynamically_compiled_children = []
super(CompiledElement, self).unstabilizeJob()

def _buildCompiledChildren(self):
return []

def buildCompiledChildren(self):
if self._dynamically_compiled_children:
return

self._dynamically_compiled_children = self._buildCompiledChildren()

class CompiledWithOriginElement(CompiledElement):
_origin = None
_conversions = {}
def stabilizeJob(self):
self._origin = origin = self.parent().origin()[self._key]
origin.stabilize()
for child in list(self) : child.destroy() # Is this massive destruction
too violent ?
for child in origin :
newType = self._conversions.get(type(child),None)
if newType is not None :
if isinstance(child._key, sb.Item):
key =
child._key.getElement().abstractionIn(self.projectAncestor())._item
else:
key = child._key
newType(self,key)
return super(CompiledWithOriginElement,self).stabilizeJob()

def origin(self):
return self._origin

class SortedCompiledElement(CompiledElement):
def __init__(self,parent,key):
super(SortedCompiledElement,self).__init__(parent,key)
self.order = self.buildChildren()

def stabilizeJob(self):
try :
return all([self[key].stabilize() for key in self.order])
except None:
raise

class ObjectElement(Element):
isObject = True
# Maintained as a (parentElementClass,kind) -> elementClass
# XXX As it is, only leaf classes can be used
_objectKinds = {}
_shadowKinds = {}
_hasLicenseRight = False
kind = "????"
allowedParents = tuple()
allowedOrigins = tuple()
defaultNewName = "Object"
displayName = "Object"
icon = "eltUnknown"
shadow = False
creationByUserIsAllowed = True
deletionByUserIsAllowed = True

def __init__(self, parent, item):


super(ObjectElement, self).__init__(parent, item)
self._item = item.getKernelItem()
self._itemName = item.getName()
self._itemOrigin = item.origin()
item.setObjectElement(self)
self.propertiesElement()(self, "$")
self.compiledElement()(self, "@")
self.issueElement()(self, "!")
for subitem in item:
ObjectElement.createElementFromItem(self, subitem)

# Some elements can be created disabled. If the disabled property is


None, then
# we check the element class if it should be created disabled.
if self.canBeDisabled :
if __options__.disableAutomaticUpdate:
self._item._disabled = True
elif self._item._disabled is None:
self._item._disabled = self.createDisabled

if __options__.webSocket and self._item._kind in


['switchBasedArchitecture', 'outline']:
self._item._disabled = False

self._frozen = item._frozen

@lru_cache(maxsize=None)
def name(self):
return str(self._key.getName())

def sortKey(self):
return str(self._key.getName())

def origin(self):
return None if self._itemOrigin is None else
self._itemOrigin.getElement()

def occurrenceIn(self, other):


return self._item.occurrenceIn(other._item).getElement()

def disabled(self):
return self.canBeDisabled and self._item.disabled()

def setDisabled(self, disabled):


app.controller.setDisabled(self._item, disabled)

def delete(self):
"""
Deletes self's strong box item, leading to self's destruction.
"""
# We need to make sure that switch pipes are preserved when their
neighbors are deleted.
if (
not isinstance(self, ForbiddenObjectElement) and
self.projectAncestor().kind == 'switchBasedArchitecture'
and
hasattr(self, 'network') and
'info' in self['@'][self.network]
):
arch = self.projectAncestor()._item

# Get a mapping of all items after the one we are deleting in the
routes to
# the items that come before the one we are deleting.
# We need to use the items because this can happen between
stabilizations
# and the items are always up to date.
after_befores = defaultdict(set)

if '$' in arch and self.network + 'Route' in arch['$']:


for init in arch['$'][self.network + 'Route']:
for target in init:
for direction in ['requestPath',
'responsePath']:
# Not all networks have both e.g.
observation.
if direction not in target:
continue

route = list(sorted(target[direction],
key=lambda x: int(x.name())))
for index, entry in enumerate(route):
if entry.value() is self._item:
if index == 0:
if direction ==
'requestPath':
before = init._key
else:
before =
target._key
else:
before = route[index -
1].value()

if index + 1 == len(route):
if direction ==
'requestPath':
after =
target._key
else:
after = init._key
else:
after = route[index +
1].value()

# The pipe references are


always to sockets and not the flows.
if before.kind() == 'flow':
before = before._parent
if after.kind() == 'flow':
after = after._parent

after_befores[after].add(before)
route_element =
target[direction].getElement()
if route_element and route_element is not
Ellipsis:
route_element.unstabilize()

# Iterate through all of the neighbors and make sure that their
new pipes will be the same
# as before.
for after, befores in after_befores.items():
# If the item is unrecoverably unstable, we skip trying to
update it.
if '$' not in after:
continue

for before in befores:


# If the item is unrecoverably unstable, we skip
trying to update it.
if '$' not in before:
continue

if self.network in before['$']:
if 'outputPipes' in before['$'][self.network]
and self._item in before['$'][self.network]['outputPipes']:
if after not in before['$'][self.network]
['outputPipes']:
new_before_entry =
sb.EntryItem(before['$'][self.network]['outputPipes'], after)
else:
new_before_entry = before['$']
[self.network]['outputPipes'][after]

if self._item in before['$']
[self.network]['outputPipes']:
for i in before['$'][self.network]
['outputPipes'][self._item] or []:

i._duplicateEntries(new_before_entry, {})

if 'domainCrossings' in before['$']
[self.network] and self._item in before['$'][self.network]['domainCrossings']:
if after not in before['$'][self.network]
['domainCrossings']:
new_before_entry =
sb.EntryItem(before['$'][self.network]['domainCrossings'], after)
else:
new_before_entry = before['$']
[self.network]['domainCrossings'][after]

if self._item in before['$']
[self.network]['domainCrossings']:
for i in before['$'][self.network]
['domainCrossings'][self._item] or []:

i._duplicateEntries(new_before_entry, {})

if self.network in after['$']:
if 'inputPipes' in after['$'][self.network] and
self._item in after['$'][self.network]['inputPipes']:
if before not in after['$'][self.network]
['inputPipes']:
new_after_entry =
sb.EntryItem(after['$'][self.network]['inputPipes'], before)
else:
new_after_entry = after['$']
[self.network]['inputPipes'][before]

if self._item in after['$'][self.network]
['inputPipes']:
for i in after['$'][self.network]
['inputPipes'][self._item] or []:

i._duplicateEntries(new_after_entry, {})

if 'domainCrossings' in after['$']
[self.network] and self._item in after['$'][self.network]['domainCrossings']:
if before not in after['$'][self.network]
['domainCrossings']:
new_after_entry =
sb.EntryItem(after['$'][self.network]['domainCrossings'], before)
else:
new_after_entry = after['$']
[self.network]['domainCrossings'][before]

if self._item in after['$'][self.network]
['domainCrossings']:
for i in after['$'][self.network]
['domainCrossings'][self._item] or []:

i._duplicateEntries(new_after_entry, {})

app.controller.destroy(self._item)

def duplicate(self):
item = self._item
return app.controller.duplicate(
item, item.getParent().proposeChildName(item.name())
)

def duplicateWithOccurrences(
self, folderName, commonFolderNumber, newName=None, newOrigin=None
):
item = self._item
folderList = self.name().split(".")
simpleName = folderList[-1]
createFolder = folderList[commonFolderNumber:-1]
baseName = folderName
project = app.theSpooler.root()
fromPath = project.fromPath
for name in createFolder:
if baseName == "":
baseName = name
else:
baseName = ".".join((baseName, name))
try:
fromPath("/%s" % baseName)
except:
sb.ObjectItem(project._item, baseName, "folder", None)
if baseName == "":
if newName is None:
name = simpleName
else:
name = newName
else:
if newName is None:
name = ".".join((baseName, simpleName))
else:
name = ".".join((baseName, newName))
name = item.getParent().proposeChildName(name)
LogBook.info("From %s create %s." % (self.name(), name))
newOrigin = app.controller.duplicate(item, name, newOrigin=newOrigin)
for occurrence in list(item.getOccurrences()):
if occurrence.kind() not in (
"architectureResult",
"scenarioResult",
"structureArea",
"structureFloorplan",
):
occurrenceFolderList = occurrence.name().split(".")[:-1]
if occurrenceFolderList ==
occurrence.origin().name().split(".") or (
newOrigin.origin() is not None
and newOrigin.origin().name().split(".")
== newOrigin.name().split(".")[:-1]
):
if folderName == "":
newFolderName = name.split(".")[-1]
else:
newFolderName = ".".join((folderName,
name.split(".")[-1]))
if len(createFolder) > 0:
newFolderName = ".".join(createFolder +
[newFolderName])
newCommonFolderNumber = commonFolderNumber + 1 +
len(createFolder)
else:
newFolderName = folderName
newCommonFolderNumber = commonFolderNumber
occurrence.getElement().duplicateWithOccurrences(
newFolderName, newCommonFolderNumber,
newOrigin=newOrigin
)

def replicate(self, newName, number):


item = self._item
proposeChildName = item.getParent().proposeChildName
return [
app.controller.duplicate(item, proposeChildName(newName))
for i in xrange(number)
]

def signature(self):
return self._item.signature()

def reparent(self, newParent):


self._resetPathCache()
if not isinstance(newParent, sb.ObjectItem):
newParent = newParent._item
app.controller.reparent(self._item, newParent)

def rename(self, newName):


self._resetPathCache()
self.stabilize()
app.controller.rename(self._item, newName)

def itemDestroyed(self):
self.destroy()

def itemCreated(self, item):


assert (
self._item is not None
and self._item.getKernelItem() is
item.getParent().getKernelItem()
), str(
self._item
) # +" " + str(item.getParent())
ObjectElement.createElementFromItem(self, item)
self.unstabilize()

def checkKindError(self, reference, errorReport):


def getArticle(name):
return "an" if name[0] in "aeiouyAEIOUY" else "a"

if not isinstance(reference, (list, tuple)):


reference = [reference]
kinds = [ref.kind for ref in reference]
error = self.kind not in kinds
errorMsg = ["%s %s" % (getArticle(kind), kind) for kind in kinds]
if len(kinds) == 1:
msg = errorMsg[0]
else:
msg = " or ".join([", ".join(errorMsg[:-1]), errorMsg[-1]])
if error:
errorReport.append(
TWT(
"%s is %s %s but not %s."
% (self.name(), getArticle(self.kind), self.kind,
msg)
)
)
return error

@classmethod
def createElementFromItem(cls, parent, item):
# type: (ObjectElement, sw.ns.kernel.strongBox.ObjectItem) ->
ObjectElement
""" Get XML item from a pdd and return the matching Object Element

Args:
parent: The element to attach the newly created element to
item: The xml node representing the element we want to
create
"""

if item.getClass() == "ObjectItem":
types = (type(parent), item.kind())

# Get the element class matching this element


types = (type(parent), item.kind())
# (don't refactory types ouside of the if, not all items
have .kind)
cls = ObjectElement._objectKinds.get(types, None) # type:
Type[ObjectElement]

# Check we have the right to use this class


if cls is None:
cls = UnknownObjectElement

elif not cls._hasLicenseRight:


cls = ForbiddenObjectElement

else:
origin = item.origin()

if origin is None:
hasBadOrigins = cls.allowedOrigins
else:
allowedOrigins = (allowed.kind for allowed in
cls.allowedOrigins)
hasBadOrigins = origin.kind() not in allowedOrigins

if hasBadOrigins:
cls = BadOriginObjectElement

# Intanciate the class


return cls(parent, item)

elif item.getClass() == "ShadowItem":


types = (type(parent), item.kind())
cls = ObjectElement._shadowKinds.get(types, None)
if cls is None:
cls = UnknownObjectElement
elif not cls._hasLicenseRight:
cls = ForbiddenObjectElement
return cls(parent, item)

def stabilizeJob(self):
origin = self.origin()
a = origin.stabilize() if origin is not None else True
b = all([child.stabilize() for child in self])
if (
self.parent() is not None
and self.parent().kind != "project"
and "." in self.name()
):
DotInNameIssue(self)
return False
return a and b

def unstabilizeJob(self):
newName = self._item.name()
if self._itemName != newName:
app.theSpooler.announceTreeUpdate(self)
self._itemName = newName
super(ObjectElement, self).unstabilizeJob()

def asObjects(self):
return {self}

def asParameters(self):
if theLicenser.haveLicense("WaiverFullObjectHandling"):
return {self["$"]}
else:
return set()

@lru_cache(maxsize=None)
def pathname(self, in_=None, watch=None):
if in_ is not None:
assert in_.isObject
assert self.descendsOf(in_)
in_ = in_._key
if watch:
parent = self
while parent.parent() is not None or (
in_ and parent is not None and parent._item is not in_
):
parent.watch(watch)
parent = parent.parent()

return self._item.path(in_)

def reprName(self, in_=None):


return "%s:%s" % (self.displayName, self.pathname(in_))

@classmethod
def _buildFolderNames(cls, parentItem, name):
"""
return newName,folderNames
"""
folderNames = set()
if parentItem.getElement() is app.theSpooler.root():
splitNames = name.split(".")
folderName = None
i = 0
while i < len(splitNames) - 1:
splitName = splitNames[i]
newFolderName = (
"%s.%s" % (folderName, splitName)
if folderName is not None
else splitName
)
try:
folder = parentItem[newFolderName]
if folder.kind() != "folder":
splitNames[i] =
parentItem.proposeChildName(newFolderName)
continue
except KeyError:
folderNames.add(newFolderName)
folderName = newFolderName
i += 1
newName = ".".join(splitNames)
else:
newName = name
return newName, folderNames

@classmethod
def createIn(cls, parent, name=None, copies=1, overWrite=False):
if name is None:
name = cls.defaultNewName
if isinstance(parent, ObjectElement):
assert isinstance(parent, cls.allowedParents)
parentItem = parent._item
else:
parentItem = parent
newName, folderNames = cls._buildFolderNames(parentItem, name)
if copies > 1:
copieMsg = "%i copies of " % (copies)
else:
copieMsg = ""
with app.controller.transaction(
"Create %s%s %s in %s" % (copieMsg, cls.displayName, name,
parentItem)
):
for folderName in folderNames:
sb.ObjectItem(parentItem, folderName, "folder", None)
item = sb.ObjectItem(
parentItem, newName, cls.kind, None, overWrite=overWrite
)
if copies != 1:
items = [item]
for i in xrange(copies - 1):
items.append(
app.controller.duplicate(
item, item.getParent().proposeChildName(name)
)
)
if copies != 1:
return items
else:
return item

@classmethod
def createFromOrigin(cls, origin, name=None):
if name is None:
name = cls.defaultNewName
if isinstance(origin, ObjectElement):
assert isinstance(origin, cls.allowedOrigins)
originItem = origin._item
else:
originItem = origin
parentItem = originItem.getParent()
if originItem.name() == ".".join(name.split(".")[:-1]):
folderNames = []
newName = name
else:
newName, folderNames = cls._buildFolderNames(parentItem, name)
with app.controller.transaction(
"Create %s of %s '%s' in %s"
% (cls.displayName, originItem.path(), name, parentItem)
):
for folderName in folderNames:
sb.ObjectItem(parentItem, folderName, "folder", None)
return sb.ObjectItem(parentItem, newName, cls.kind, originItem)

@classmethod
def getCreators(cls):
withOrigin = bool(cls.allowedOrigins)
return (
(
cls.displayName,
withOrigin,
cls.createFromOrigin if withOrigin else cls.createIn,
cls.allowedOrigins if withOrigin else cls.allowedParents,
),
)

def propertiesElement(self):
return parameterElement.StructPElt

def compiledElement(self):
return CompiledElement

def issueElement(self):
return issueElement.IssueRecord
# Is this really the good place ... probably not.
def _stringifyThis(x,scope=None):
if isinstance(x,str) and x.startswith('@html@'): return x[6:]
if isinstance(x,Element ): return str(x.niceName(scope))
if isinstance(x,(list,tuple)): return ', '.join([_stringifyThis(y,scope) for
y in x])
return str(x)

def stringifyInfos(d,scope):
return { k:_stringifyThis(v,scope) for k,v in d.iteritems() }

def _htmlifyThis(x,scope=None):
if isinstance(x,basestring ):
if x.startswith('@html@'): return x[6:]
else: return
x.replace('<','&lt;').replace('>','&gt;')
if isinstance(x,Element ): return str(x.htmlRef(scope))
if isinstance(x,(list,tuple)): return ', '.join([_htmlifyThis(y,scope) for y
in x])
return str(x)

def htmlifyInfos(d,scope):
return { k:_htmlifyThis(v,scope) for k,v in d.iteritems() }

# A bit of comment :
# The Context class represents the 'active content' to be passed from an engine to
another,
# It consists in 3 topics :
# - the selection :
# a set of Elements, representing the selection
# - the root :
# a single Element, root of any element in the selection,
# representing the context where the selection was produced.
# - the possible creations :
# a set of Element subClasses, representing the objects meaningfull to create
'now'.
#
# A new context object is produced at each 'Grab' action
# context.abstractionIn( element ) returns a new Context object, caching the result
#

def or_(l):
s = set()
for i in l : s|=i
return frozenset(s)

class Context(object):
isContext = True # For bootstrap to detect
def __init__(self, selection , root = None , creations = None ) :
self._revision = -1
self._cachedStable = False
selection = {s for s in selection}
selection.discard(None)
self._selection = selection
assert not any( element for element in self._selection if element is
Ellipsis ) , 'Ellipsis element in context'
if root is None : root = app.root.getElement()
self._root = root
if creations is not None : creations = tuple(creations)
self._creations = creations
self.isStable()

def __iter__ (self): return iter(self._selection)


def __nonzero__(self): return bool(self._selection)
def __len__ (self): return len (self._selection)
def __repr__ (self): return 'Context(%s)' % self._selection

def selection (self): return self._selection


def root (self): return self._root
def possibleCreations(self): return self._creations

def abstractionIn(self,scope):
r = self._abstractionCache.get(scope,None)
if r is None :
self._abstractionCache[scope] = r = Context(
{ element.abstractionIn(scope) for element in
self._selection } - {None}
, self._root.abstractionIn(scope)
, self._creations
)
return r

def filterBy(self,func):
r = self._preprocessCache.get(func,None)
if r is None :
self._preprocessCache[func] = r = func(self)
return r

def needsReassess(self):
return self._revision != app.theSpooler._revision

def isStable( self ):


if self._revision == app.theSpooler._revision : return
self._cachedStable
self._revision = app.theSpooler._revision
self._selection = { element for element in self._selection if
not element.isDead() }
self._abstractionCache = {}
self._preprocessCache = {}
self._cachedStable = all( element.stable() for element in
self._selection )
return self._cachedStable

@staticmethod
def objectsFilter(context):
return or_( element.asObjects() for element in context )

@staticmethod
def objectFilter(context):
objs = context.filterBy(context.objectsFilter)
return iter(objs).next() if len(objs) == 1 else None

@staticmethod
def parameterFilter(context):
# Remove issues to be allowed to provide an 'asParameter' more all
issueElement to be seen as parameters in customizer
return or_( element.asParameters() for element in context if not
isinstance(element,issueElement.IssueElement) )

import loc.parameterElement
import loc.issueElement

class UnknownObjectIssue(issueElement.IssueElement):
_messageTemplate = TWT("PDD object $object belongs to an unknown class,
$kind.")
_descriptionTemplate = TWT(
"This class of PDD object cannot be identified by the program, "
"and will be ignored."
)
_code = "UOBJ"
_reason = "Unknown Object"
_severity = issueElement.IssueElement.Severity.WARNING

class ForbiddenObjectIssue(issueElement.IssueElement):
_messageTemplate = TWT("Object $object ($kind) requires a license. ")
_descriptionTemplate = TWT(
"Object $object ($kind) requires a specific license feature '$feature'
that is currently lacking or out-of-date in your license configuration. The object
will be ignored."
)
_code = "RLIC"
_reason = "License Required"
_severity = issueElement.IssueElement.Severity.WARNING

class BadOriginIssue(issueElement.IssueElement):
_messageTemplate = TWT("Object $object ($kind) violates PDD internal
formatting rules. ")
_descriptionTemplate = TWT(
"Object $object ($kind) is incorrectly formatted within the PDD, thus
disrupting the object hierarchy of the XML-based file."
)
_code = "PFRV"
_reason = "PDD Formatting Rules Violation"
class DotInNameIssue(issueElement.IssueElement):
_messageTemplate = TWT("$element contains a '.' in its name. ")
_descriptionTemplate = TWT("$element contains a '.' in its name. ")
_code = "NAMI"
_reason = "Naming Rules Violation"

class BrokenObjectElement(ObjectElement):
displayName = 'Broken'
defaultNewName = 'Broken'
_allowedParents = (ObjectElement,)
icon = 'eltBroken'
def __init__(self,parent,key):
super(BrokenObjectElement,self).__init__(parent,key)
self.issue=None
def htmlDescription(self):
if self.issue is not None:
return self.issue.htmlDescription()
return super(BrokenObjectElement,self).htmlDescription()
def stabilizeJob(self):
return False

class UnknownObjectElement(BrokenObjectElement):
displayName = 'Unknown'
defaultNewName = 'Unknown'
def __init__(self,parent,key):
super(UnknownObjectElement,self).__init__(parent,key)
self.shadow = key.objectOrigin() is not key
if not self.shadow and not isinstance(parent,BrokenObjectElement) :
self.issue=UnknownObjectIssue(self,kind=key.kind())

class ForbiddenObjectElement(BrokenObjectElement):
displayName = 'Forbidden'
defaultNewName = 'Forbidden'
def __init__(self,parent,key):
super(ForbiddenObjectElement,self).__init__(parent,key)
self.shadow = key.objectOrigin() is not key
if not self.shadow and not isinstance(parent,BrokenObjectElement) :
kind = key.kind()
licName = ""
if theLicenser.haveLicense("LaunchDevelopper") :
licName =
theLicenser.getFeatureName('Object'+kind[0].upper()+kind[1:])
self.issue=ForbiddenObjectIssue(self,kind=kind,feature=licName)
class BadOriginObjectElement(BrokenObjectElement):
displayName = 'BadOrigin'
defaultNewName = 'BadOrigin'
def __init__(self,parent,key):
super(BadOriginObjectElement,self).__init__(parent,key)
self.shadow = key.objectOrigin() is not key
if not isinstance(parent,BrokenObjectElement):
kind = key.kind()
self.issue=BadOriginIssue(self,kind=kind)

threading.currentThread().stack = []
threading.currentThread().stack_set = set()
threading.currentThread()._poison = False

You might also like