class DataFormatConverter(object): """A class for converting between various data interchange formats, e.g. XML and JSON.""" #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self): """Creates a new instance of ClassTemplate.""" self._type = None self._src = None self._log = Logger('DataFormatConverter') self._path = None #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: propertyName @property def source(self): return self._src #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ load def load(self, path, fileType): if not os.path.exists(path): self._log.write('ERROR: Path does not exist [%s]. Unable to load.' % path) return False try: fh = codecs.open(path, 'r', 'utf-8') res = fh.read() fh.close() enc = res.encode('utf-8') self.loads(enc, fileType) except Exception, err: self._log.writeError('Failed to load source file [%s].' % path, err) return False self._path = path return True
class IncludeCompressor(object): #=================================================================================================== # C L A S S _REMOVE_COMMENT_RE = re.compile('/\*.+\*/', re.DOTALL) _REMOVE_COMMENT_LINE_RE = re.compile('(^|\n)[\s\t]*//.+(\n|$)') JS_TYPE = 'js' CSS_TYPE = 'css' #___________________________________________________________________________________________________ __init__ def __init__(self, compileCoffee =False): self._log = Logger('IncludeCompressor') self._compileCoffee = compileCoffee #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ compress def compress(self, rootPath): if not self._fileExists(rootPath): return False elif os.path.isfile(rootPath): return self.compressFile(rootPath) else: return self.compressPath(rootPath) #___________________________________________________________________________________________________ compressFile def compressFile(self, rootPath, directory =None): if not self._fileExists(rootPath): return False if self._compileCoffee: try: from pyaid.web.coffeescript.CoffeescriptBuilder import CoffeescriptBuilder CoffeescriptBuilder.compileAllOnPath(rootPath, os.path.dirname(rootPath), True) self._log.write('Coffeescript compiled.') except Exception, err: self._log.writeError('Failed to compile coffeescript file.', err) return False return self._compressFile(rootPath, directory)
class SocketHandler(SocketServer.StreamRequestHandler): """A class for...""" #=================================================================================================== # C L A S S SERVICE_UID = 'test' VERBOSE = False WORK_PATH = '/var/lib/' RUN_PATH = '/var/run/' LOG_PATH = '/var/log/' #___________________________________________________________________________________________________ __init__ def __init__(self, request, client_address, server): self._log = Logger(self) self._log.write('Socket handler created') SocketServer.StreamRequestHandler.__init__(self, request, client_address, server) #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: returnResponse @property def returnResponse(self): return getattr(self.__class__, 'RETURN_RESPONSE', False) #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ handle def handle(self): try: data = self.rfile.readline().strip() self._log.write('HANDLE: ' + str(data)) try: result = self._respondImpl(JSON.fromString(unquote(data))) except Exception as err: self._log.writeError('RESPOND FAILURE', err) if self.returnResponse: self.wfile.write(JSON.asString({'error':1})) return if self.returnResponse: out = {'error':0} if result: out['payload'] = result self.wfile.write(out) except Exception as err: self._log.write('HANDLE FAILURE', err) return #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _respondImpl def _respondImpl(self, data): pass
class PyGlassWindow(QtGui.QMainWindow): """A class for...""" #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self, **kwargs): """Creates a new instance of PyGlassWindow.""" parent = ArgsUtils.extract('parent', None, kwargs) self._application = ArgsUtils.extract('pyGlassApp', None, kwargs) self._qApplication = ArgsUtils.extract('qApp', None, kwargs) self._isMainWindow = ArgsUtils.extract('isMainWindow', bool(parent is None), kwargs) self._mainWindow = ArgsUtils.extract('mainWindow', None, kwargs) self._centerWidget = None self._keyboardCallback = ArgsUtils.extract('keyboardCallback', None, kwargs) if not self._mainWindow: if self._isMainWindow: self._mainWindow = self elif self._application: self._mainWindow = self._application.mainWindow self._dependentWindows = [] self._currentWidget = None QtGui.QMainWindow.__init__(self, parent, ArgsUtils.extract('flags', 0, kwargs)) if self._keyboardCallback is not None: self.setFocusPolicy(QtCore.Qt.StrongFocus) if self._isMainWindow: self._log = Logger(self, printOut=True) self._config = ApplicationConfig(self) self._commonConfig = ApplicationConfig(self, common=True) self._resourceFolderParts = PyGlassGuiUtils.getResourceFolderParts(self) icon = PyGlassGuiUtils.createIcon( ArgsUtils.get('iconsPath', self.getAppResourcePath('icons', isDir=True), kwargs) ) if icon: self.setWindowIcon(icon) elif self._mainWindow: icon = self._mainWindow.windowIcon() if icon: self.setWindowIcon(icon) # Loads the ui file if it exists hasWindowFile = ArgsUtils.get('mainWindowFile', False, kwargs) if hasWindowFile: if not self._centerWidget: self._createCentralWidget() UiFileLoader.loadWidgetFile(self, target=self._centerWidget) self._styleSheet = ArgsUtils.get('styleSheet', None, kwargs) if self._styleSheet: self.setStyleSheet(self.styleSheetPath) # Sets a non-standard central widget centralWidgetName = ArgsUtils.get('centralWidgetName', None, kwargs) if centralWidgetName and hasattr(self, centralWidgetName): self._centerWidget = getattr(self, centralWidgetName) elif not hasWindowFile: self._centerWidget = None if ArgsUtils.get('defaultCenterWidget', False, kwargs): self._createCentralWidget() self._lastWidgetID = None self._widgetParent = None self._widgets = None self._widgetFlags = None self._widgetClasses = ArgsUtils.get('widgets', None, kwargs) if self._widgetClasses: self._initializeWidgetChildren() else: self._widgetClasses = dict() self.setWindowTitle(ArgsUtils.get('title', self._createTitleFromClass(), kwargs)) self.updateStatusBar() #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: isDeployed @ClassGetter def isDeployed(cls): return PyGlassEnvironment.isDeployed #___________________________________________________________________________________________________ GS: isOnDisplay @property def isOnDisplay(self): return self.isVisible() #___________________________________________________________________________________________________ GS: appID @property def appID(self): return self.pyGlassApplication.appID #___________________________________________________________________________________________________ GS: isMainWindow @property def isMainWindow(self): return self._isMainWindow #___________________________________________________________________________________________________ GS: allowsOwnership @property def allowsOwnership(self): return True #___________________________________________________________________________________________________ GS: mainWindow @property def mainWindow(self): if self.isMainWindow: return self if self._mainWindow: return self._mainWindow self._mainWindow = PyGlassGuiUtils.getMainWindow(self) return self._mainWindow #___________________________________________________________________________________________________ GS: owner @property def owner(self): if self.isMainWindow: return self return self.mainWindow #___________________________________________________________________________________________________ GS: pyGlassApplication @property def pyGlassApplication(self): return self._application if self.isMainWindow else self.mainWindow.pyGlassApplication #___________________________________________________________________________________________________ GS: qApplication @property def qApplication(self): return self._qApplication if self.isMainWindow else self.mainWindow.qApplication #___________________________________________________________________________________________________ GS: appConfig @property def appConfig(self): return self._config if self.isMainWindow else self.mainWindow.appConfig #___________________________________________________________________________________________________ GS: commonAppConfig @property def commonAppConfig(self): return self._commonConfig if self.isMainWindow else self.mainWindow.commonAppConfig #___________________________________________________________________________________________________ GS: log @property def log(self): return self._log if self.isMainWindow else self.owner.log #___________________________________________________________________________________________________ GS: styleSheetPath @property def styleSheetPath(self): if not self._styleSheet: return None if os.path.isabs(self._styleSheet): return self._styleSheet parts = self._resourceFolderParts + self._stylesheet.split('/') return self.getResourcePath(*parts, isFile=True) #___________________________________________________________________________________________________ GS: rootResourcePath @property def rootResourcePath(self): return PyGlassEnvironment.getRootResourcePath() #___________________________________________________________________________________________________ GS: rootLocalResourcePath @property def rootLocalResourcePath(self): return PyGlassEnvironment.getRootLocalResourcePath() #___________________________________________________________________________________________________ GS: appResourcePath @property def appResourcePath(self): if not self.isMainWindow: return self.owner.appResourcePath out = self.getRootResourcePath('apps', self.appID, isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: localAppResourcePath @property def localAppResourcePath(self): if not self.isMainWindow: return self.owner.localAppResourcePath out = self.getRootLocalResourcePath('apps', self.appID, isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: sharedResourcePath @property def sharedResourcePath(self): out = self.getRootResourcePath('shared', isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: localSharedResourcePath @property def localSharedResourcePath(self): out = self.getLocalResourcePath('shared', isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: widgets @property def widgets(self): return self._widgets #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ keyPressEvent def keyPressEvent(self, event): if self._keyboardCallback is None or not self._keyboardCallback(event): super(PyGlassWindow, self).keyPressEvent(event) #___________________________________________________________________________________________________ closeEvent def closeEvent(self, *args, **kwargs): if self.isMainWindow: for depWindow in self._dependentWindows: depWindow.close() return super(PyGlassWindow, self).closeEvent(*args, **kwargs) #___________________________________________________________________________________________________ addDependentWindow def addDependentWindow(self, window): if window in self._dependentWindows: return True self._dependentWindows.append(window) return True #___________________________________________________________________________________________________ removeDependentWindow def removeDependentWindow(self, window): if window not in self._dependentWindows: return True self._dependentWindows.remove(window) return True #___________________________________________________________________________________________________ refreshWidgets def refreshWidgets(self, **kwargs): for name, widget in self._widgets.iteritems(): widget.refresh(**kwargs) self.refreshGui() #___________________________________________________________________________________________________ updateStatusBar def updateStatusBar(self, message =None, timeout =-1): if not message: self.statusBar().clearMessage() self.statusBar().setVisible(False) else: if timeout < 0: timeout = 3000 self.statusBar().showMessage(message, timeout=timeout) self.statusBar().setVisible(True) #___________________________________________________________________________________________________ getWidgetFromID def getWidgetFromID(self, widgetID): if widgetID in self._widgets: return self._widgets[widgetID] return None #___________________________________________________________________________________________________ getSharedResourcePath def getSharedResourcePath(self, *args, **kwargs): return FileUtils.createPath(self.sharedResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getLocalSharedResourcePath def getLocalSharedResourcePath(self, *args, **kwargs): return FileUtils.createPath(self.localSharedResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getAppResourcePath def getAppResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath(self.appResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getLocalAppResourcePath def getLocalAppResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath(self.localAppResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getRootResourcePath def getRootResourcePath(self, *args, **kwargs): return PyGlassEnvironment.getRootResourcePath(*args, **kwargs) #___________________________________________________________________________________________________ getRootLocalResourcePath def getRootLocalResourcePath(self, *args, **kwargs): return PyGlassEnvironment.getRootLocalResourcePath(*args, **kwargs) #___________________________________________________________________________________________________ getResourcePath def getResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath( self.rootResourcePath, 'widget', self._resourceFolderParts, *args, **kwargs) #___________________________________________________________________________________________________ getLocalResourcePath def getLocalResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath( self.rootLocalResourcePath, 'widget', self._resourceFolderParts, *args, **kwargs) #___________________________________________________________________________________________________ showLoading def showLoading(self, **kwargs): if self._currentWidget.widgetID != 'loading': self._lastWidgetID = self._currentWidget.widgetID self._showLoadingImpl(**kwargs) self.setActiveWidget('loading', force=True, args=kwargs) #___________________________________________________________________________________________________ hideLoading def hideLoading(self, **kwargs): if self._currentWidget.widgetID != 'loading': return self._hideLoadingImpl(**kwargs) if self._lastWidgetID: self.setActiveWidget(self._lastWidgetID, args=kwargs) #___________________________________________________________________________________________________ addWidget def addWidget(self, key, widgetClass, setActive =False): self._widgetClasses[key] = widgetClass if self._widgets is None: self._initializeWidgetChildren(key if setActive else None) elif setActive: return self.setActiveWidget(key) return True #___________________________________________________________________________________________________ setActiveWidget def setActiveWidget(self, widgetID, force =False, args =None, doneArgs =None): if not self._centerWidget or widgetID is None or widgetID not in self._widgetClasses: return False if not force and self._currentWidget and self._currentWidget.widgetID == widgetID: return True if widgetID not in self._widgets: self.loadWidgets(widgetID) widget = self._widgets[widgetID] # Deactivates the current widget if the widgets are being switched. However, ignored if the # same widget is being activated for a second time. if self._currentWidget and widgetID != self._currentWidget.widgetID: if self._currentWidget.widgetID == 'loading': self._hideLoadingImpl() if doneArgs is None: doneArgs = dict() self._currentWidget.deactivateWidgetDisplay(**doneArgs) self._currentWidget.setParent(self._widgetParent) self._currentWidget = widget if self._centerWidget: layout = self._centerWidget.layout() if not layout: layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._centerWidget.setLayout(layout) layout.addWidget(widget) else: self.setCentralWidget(widget) self.setContentsMargins(0, 0, 0, 0) self.refreshGui() if args is None: args = dict() widget.activateWidgetDisplay(**args) return True #___________________________________________________________________________________________________ loadWidgets def loadWidgets(self, widgetIdents =None): if not widgetIdents: widgetIdents = self._widgetClasses.keys() elif isinstance(widgetIdents, basestring): widgetIdents = [widgetIdents] for widgetID in widgetIdents: if widgetID in self._widgets: continue if widgetID not in self._widgetClasses: self._log.write( 'ERROR: Unrecognized widgetID "%s" in %s' % (str(widgetID), str(self))) widget = self._widgetClasses[widgetID]( self._widgetParent, flags=self._widgetFlags, widgetID=widgetID) self._widgets[widgetID] = widget #___________________________________________________________________________________________________ refreshGui def refreshGui(self): self.qApplication.processEvents() #___________________________________________________________________________________________________ exit def exit(self): self.qApplication.exit() #___________________________________________________________________________________________________ initialize def initialize(self, *args, **kwargs): if AlembicUtils.hasAlembic: self.pyGlassApplication.updateSplashScreen('Conforming internal data') AlembicUtils.upgradeAppDatabases(self.appID) self._initializeImpl(*args, **kwargs) #___________________________________________________________________________________________________ initializeComplete def initializeComplete(self, preDisplay =None): self.pyGlassApplication.closeSplashScreen() result = False if preDisplay: preDisplay.show() result = self.qApplication.exec_() if not result: self.preShow() self.show() result = self.qApplication.exec_() self.postShow() sys.exit(result) #___________________________________________________________________________________________________ preShow def preShow(self, **kwargs): self._preShowImpl(**kwargs) #___________________________________________________________________________________________________ postShow def postShow(self, **kwargs): self._postShowImpl(**kwargs) #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _createCentralWidget def _createCentralWidget(self): w1 = self.centralWidget() w2 = self._centerWidget if w1 and w2: return w2 elif w1 and not w2: self._centerWidget = w1 return w1 layout = self.layout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) w = QtGui.QWidget(self) layout.addWidget(w) self.setCentralWidget(w) self._centerWidget = w return w #___________________________________________________________________________________________________ _initializeWidgetChildren def _initializeWidgetChildren(self, activeWidgetID =None): if not self._widgetClasses or self._widgets: return False self._widgetParent = PyGlassBackgroundParent(proxy=self) self._widgets = dict() if 'loading' not in self._widgetClasses: self._widgetClasses['loading'] = LoadingWidget if activeWidgetID: self.setActiveWidget(activeWidgetID) #___________________________________________________________________________________________________ _preShowImpl def _preShowImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _postShowImpl def _postShowImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _showLoadingImpl def _showLoadingImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _hideLoadingImpl def _hideLoadingImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _createTitleFromClass def _createTitleFromClass(self): """Doc...""" src = self.__class__.__name__ out = src[0] wasCaps = True for c in src[1:]: if c.lower() == c: out += c wasCaps = False elif wasCaps: out += c else: out += ' ' + c wasCaps = True return out #___________________________________________________________________________________________________ _initializeImpl def _initializeImpl(self, *args, **kwargs): self.initializeComplete() #=================================================================================================== # I N T R I N S I C #___________________________________________________________________________________________________ __repr__ def __repr__(self): return self.__str__() #___________________________________________________________________________________________________ __unicode__ def __unicode__(self): return unicode(self.__str__()) #___________________________________________________________________________________________________ __str__ def __str__(self): return '<%s>' % self.__class__.__name__
class TrackLinkConnector(object): """A class for...""" #=============================================================================== # C L A S S _TRACK_NUMBER_RE = re.compile('(?P<prefix>[^0-9\-]*)(?P<number>-?[0-9]+)(?P<suffix>[^0-9]*)') #_______________________________________________________________________________ def __init__(self, logger =None): """Creates a new instance of TrackLinkConnector.""" self.logger = logger if not logger: self.logger = Logger(self, printOut=True) self.searchNext = True self.searchPrev = True self.overrideExisting = False self.operatedTracks = [] self.modifiedTracks = [] self.trackLinkages = [] #=============================================================================== # P U B L I C #_______________________________________________________________________________ def echoResult(self): out = [] for item in self.trackLinkages: out.append(item[0].name + ' -> ' + item[1].name) return u'\n'.join(out) #_______________________________________________________________________________ def runAll(self, session): model = Tracks_Track.MASTER return self.run(session.query(model).all(), session) #_______________________________________________________________________________ def run(self, tracks, session): """Doc...""" for track in tracks: if track not in self.operatedTracks: self._runTrack(track, session) #=============================================================================== # P R O T E C T E D #_______________________________________________________________________________ def _runTrack(self, source, session): """Doc...""" model = source.__class__ trackSeries = session.query(model).filter( model.site == source.site, model.sector == source.sector, model.level == source.level, model.trackwayType == source.trackwayType, model.trackwayNumber == source.trackwayNumber, model.pes == source.pes, model.left == source.left).order_by(model.number.asc()).all() if not trackSeries: return False #------------------------------------------------------------------------------------------- # TRACK ORDERING # Tracks numbers are strings to support naming conventions like 10b or 12c, where the # number is possibly followed by a non-numeric set of characters. To establish track # ordering the sequence should be sorted primarily by the numeric sequence and # secondarily by the suffix first numerically and then alphabetically respectively. trackNumbers = dict() for track in trackSeries: result = self._TRACK_NUMBER_RE.search(track.number) if not result or result.group('prefix'): self.logger.write([ u'ERROR: Unable to parse track number: ' + StringUtils.toUnicode(track.number), u'TRACK: ' + DictUtils.prettyPrint(track.toDict()) ]) continue number = result.group('number') suffix = result.group('suffix') if number not in trackNumbers: trackNumbers[number] = {'track':None, 'extras':{}, 'number':int(number)} entry = trackNumbers[number] if number == track.number and not suffix: entry['track'] = track elif not suffix: self.logger.write([ u'ERROR: Invalid track number: ' + StringUtils.toUnicode(track.number), u'TRACK: ' + DictUtils.prettyPrint(track.toDict()) ]) continue else: entry['extras'][suffix] = track if track not in self.operatedTracks: self.operatedTracks.append(track) prev = None entries = list(trackNumbers.values()) entries.sort(key=lambda x: x['number']) for entry in entries: track = entry['track'] tracks = [] if track is None else [track] for key in sorted(entry['extras']): tracks.append(entry['extras'][key]) for track in tracks: if not prev: prev = track continue # If the previous entry has an existing next that doesn't match if not self.overrideExisting and prev.next and prev.next != track.uid: continue prev.next = track.uid self.modifiedTracks.append(prev) self.trackLinkages.append((prev, track)) prev = track #=============================================================================== # I N T R I N S I C #_______________________________________________________________________________ def __repr__(self): return self.__str__() #_______________________________________________________________________________ def __str__(self): return '<%s>' % self.__class__.__name__
class CadenceDrawing(object): """ A class for writing Scalable Vector Graphics (SVG) files, tailored to create overlays for site maps. Each site map has a marker that indicates a reference point in Swiss Federal coordinates. At least one such marker appears somewhere within each site map (in cases where there were two, the more central was chosen). The maps are all oriented such that the x axis is positve to the right (towards the east) and the y axis is positive down (southward). For visualization in Cadence, a site map is projected onto the y=0 plane of a 3D scene such that the Federal Coordinate marker is placed at the origin in 3D, and the scene's positive x axis increases to the left ('west') and the scene's positive z axis increases to the 'north'. The correspondence between these two coordinate systems is handled by public functions to be found in this class, based on information derived from an instance of a Tracks_SiteMap (specifically the scale and the location of a federal coordinates marker within the siteMap). This class wraps (owns) an instance of an svgwrite.Drawing and handles the mapping from 3D scene coordinates (x, z) to SVG coordinates (x, y). Scene coordinates are in real-world cm, while the SVG coordinates used in the sitemaps is in (50:1 scaled) mm. That is, one mm in the _drawing equals 5 cm, realworld. By default, a saved CadenceDrawing can be placed in an Adobe Illustrator layer, then adjusted to be in registation with the sitemap. CadenceDrawing is built upon the svgwrite.Drawing class, which provides the basic functions to draw lines, rectangles, and other SVG objects. For further information on svgwrite, consult: https://pythonhosted.org/svgwrite A CadenceDrawing instance simplifies the functionality of svgwrite, encapsulating all the handling of all SVG fragments through function calls to create lines, polyLines, rects, circles, elipses, and text, plus transformable groups, with the resultant SVG file written by the function save. A CadenceDrawing adopts the underlying svgwrite convention of using kwargs to provide a Pythonic means to specify SVG attributes such as stroke, stroke_linecap, stroke_width, and fill. CadenceDrawing is a wrapper adaptation of svgwrite. That is, a CadenceDrawing encapsulates an instance of an svgwrite Drawing. Coordinate mapping allows trackway data (coordinates and dimensions) to be scaled appropriately for inclusion into an SVG-format tracksite file to be placed in a layer in Adobe illustrator). This scaling is provided by the kwarg scene=True, wherein scene coordinates (in cm) are converted to scaled mm. The following is an example in which all tracks for a given site are loaded and drawn: tracks = siteMap.getAllTracks(session) for track in tracks: x = track.x z = track.z # Track dimensions are in fractional meters, so multiply by 100 to convert to cm. r = 100*0.5*(track.width/2.0 + track.length/2.0) drawing.circle((x, z), r, scene=True, fill='none', stroke='blue', stroke_width=1) # compute this track's averge uncertainty in cm (also stored in fractional meters) u = 100*(track.widthUncertainty + track.lengthUncertainty)/2.0 drawing.circle((x, z), u, scene=True, fill='red', stroke='red', stroke_width=1) A more advanced usage uses groups that can be transformed (rotated, scaled, translated). A group is created and given an ID that is then passed to drawing functions (which create the shape), then the group is used (instantiated) at somePlace at a rotation of 45 degrees: drawing.createGroup('g1') drawing.rect((0, 0), width, height, groupId='g1') ...etc... drawing.use('g1', somePlace, rotation=45) The use of groups, while convenient, requires that all map coordinates be converted to px. For more detail, see the use function and grid, which produces a 10 m grid. """ # =============================================================================== # C L A S S # _______________________________________________________________________________ def __init__( self, fileName, siteMap, labelTracks=True, labelColor="black", session=None, showUncertainty=True, showCenters=True, **kwargs ): """ Creates a new instance of CadenceDrawing. Calls to the public functions line(), rect(), and others result in objects being added to the SVG canvas, with the file written by the save() method to specified fileName. The second argument, the siteMap is provided as an argument to establish the correspondence between the Maya scene and the site siteMap coordinates. """ self._logger = kwargs.get("logger") if not self._logger: self._logger = Logger(self, printOut=True) self.siteMapReady = siteMap.isReady if not self.siteMapReady: self._logger.write('[ERROR|CadenceDrawing]: Sitemap "%s-%s" not ready' % (siteMap.name, siteMap.level)) return self.fileName = fileName self.siteMap = siteMap self.siteName = siteMap.name self.siteLevel = siteMap.level # Generally units can be specified in millimeters. In a few cases, however, (e.g., # PolyLine) the coordinates must be unqualified integers (as px). The site maps, however # are in 'scaled mm'. Hence the need for a cnversion factor pxPerMm. Unfortunately, the # conversion between px and mm is OS-dependent. The conversion from px to inches is 72 for # Apple but 90 more generally). ppi = 72 if OsUtils.isMac() else 90 self.pxPerMm = ppi / 25.4 # specify the width and height explicitly in mm, and likewise for the background rect left = siteMap.left * mm top = siteMap.top * mm width = siteMap.width * mm height = siteMap.height * mm self._drawing = svgwrite.Drawing(fileName, profile="tiny", size=(width, height), stroke=svgwrite.rgb(0, 0, 0)) self._drawing.add(self._drawing.rect((left, top), (width, height), opacity="0")) self.groups = dict() if labelTracks: self.labelTracks( color=labelColor, session=session, showUncertainty=showUncertainty, showCenters=showCenters ) # =============================================================================== # G E T / S E T # _______________________________________________________________________________ @property def pixelWidth(self): return math.ceil(self.siteMap.width * self.pxPerMm) # _______________________________________________________________________________ @property def pixelHeight(self): return math.ceil(self.siteMap.height * self.pxPerMm) # =============================================================================== # P U B L I C # _______________________________________________________________________________ def circle(self, center, radius, scene=True, groupId=None, **extra): """ Adds a circle object to the SVG file. All coordinates are explicitly labled with 'mm' and passed to svgwrite. """ if not self.siteMapReady: return # convert from scene coordinates to map coordinates as necessary if scene: center = self.projectToMap(center) radius = self.scaleToMap(radius) # convert from (scaled) mm to px center = (self.pxPerMm * center[0], self.pxPerMm * center[1]) radius *= self.pxPerMm # create the object obj = self._drawing.circle(center, radius, **extra) # and add it to either a specific group or to the default _drawing if groupId: group = self.groups[groupId] if group: group.add(obj) else: print("circle: %s is not a valid group ID" % groupId) return else: self._drawing.add(obj) # _______________________________________________________________________________ def createGroup(self, id, **extra): """ Creates an SVG group, so that subsequent SVG fragments can be added to the group. When the group is subsequently used (by the use function) an instance is created, and placed at a particular location in the drawing, with a particular scale and rotation. This method only creates tghe group; to then add fragments, the group's id is passed to draw functions so that those fragments are added to the group rather than to the drawing directly. Groups are intended to be placed readily across a drawing, hence the pivot for the group should normally be centered on the user space (map) origin.""" if not self.siteMapReady: return group = self._drawing.g(id=id, **extra) # add it to defs so that it is not directly rendered self._drawing.defs.add(group) # and keep track of the id so it can be used to refer to the group self.groups[id] = group # _______________________________________________________________________________ def ellipse(self, center, radii, scene=True, groupId=None, **extra): """ Adds an ellipse object to the SVG file, based on a center point and two radii. All coordinates are explicitly labled with 'mm' and passed to svgwrite. """ if not self.siteMapReady: return # convert from scene coordinates to map coordinates as necessary if scene: center = self.projectToMap(center) radii = [self.scaleToMap(radii[0]), self.scaleToMap(radii[1])] # convert from (scaled) mm to px center = (self.pxPerMm * center[0], self.pxPerMm * center[1]) radii = (self.pxPerMm * radii[0], self.pxPerMm * radii[1]) # create the object obj = self._drawing.ellipse(center, radii, **extra) # and add it to either a specific group or to the default _drawing if groupId: group = self.groups[groupId] if group: group.add(obj) else: print("ellipse: %s is not a valid group ID" % groupId) return else: self._drawing.add(obj) # _______________________________________________________________________________ def federalCoordinates(self, deltaX=-4, deltaZ=-2.5, diskRadius=2): """ Place the coordinates as a text string at the specified offset from the fiducial marker. """ if not self.siteMapReady: return text = "%s-%s (%s, %s)" % (self.siteName, self.siteLevel, self.siteMap.federalEast, self.siteMap.federalNorth) self.text(text, (deltaX, deltaZ), scene=True, stroke_width=0.05, font_size="4") # place an unfilled green circle of specified radius atop the federal coordinate marker self.circle((0, 0), diskRadius, scene=True, fill="none", stroke="green", stroke_width=1) # _______________________________________________________________________________ def grid(self, size=2, diagonals=True, dx=200, dy=200, **extra): """ This is a group-based version of grid. It creates a rectangular grid of marks. The grid marks on a site map are separated by 10 m in the real world, or 200 units in the map in their 'scaled mm' convention. Unfortunately, the group construct in svgwrite requires px values, and will not allow the mm suffix. The default spacing is 1 m by 1 m (i.e., dx=20 and dy=20). """ if not self.siteMapReady: return x0 = self.siteMap.xFederal % dx y0 = self.siteMap.yFederal % dy xn = int(self.siteMap.width / dx) yn = int(self.siteMap.height / dy) self.createGroup("mark") self.mark(size, scene=False, groupId="mark") for i in range(xn): x = x0 + i * dy for j in range(yn): y = y0 + j * dy self.use("mark", [self.pxPerMm * x, self.pxPerMm * y], rotation=45, scene=False) p = 0 delta = 300 count = [0, 0] while p <= self.pixelWidth: # Vertical lines count[0] += 1 obj = self._drawing.line( (p, 0), (p, self.pixelHeight), stroke="black", stroke_width=1, stroke_opacity="0.1", stroke_dasharray="5,5", ) self._drawing.add(obj) if p == self.pixelWidth: break p = min(p + delta, self.pixelWidth) p = 0 while p <= self.pixelHeight: # Horizontal lines count[1] += 1 obj = self._drawing.line( (0, p), (self.pixelWidth, p), stroke="black", stroke_width=1, stroke_opacity="0.1", stroke_dasharray="5,5", ) self._drawing.add(obj) if p == self.pixelHeight: break p = min(p + delta, self.pixelHeight) for ix in range(count[0] - 1): # Text Coordinate Labels for iy in range(count[1] - 1): obj = self._drawing.text( "[%s-%s]" % (iy + 1, ix + 1), (delta * ix + 5, delta * iy + 17), font_size="12", fill="black", fill_opacity="0.15", stroke="none", ) self._drawing.add(obj) # _______________________________________________________________________________ def labelTracks( self, color="black", opacity=0.25, strokeWidth=0.5, session=None, showUncertainty=True, showCenters=True ): """ Finds all tracks for the current tracksite, then marks their centers and adds a text label for each track. """ from cadence.models.tracks.Tracks_Track import Tracks_Track model = Tracks_Track.MASTER s = session if session else model.createSession() query = s.query(model) query = query.filter(model.site == self.siteName) result = query.filter(model.level == self.siteLevel).all() # for each track in this tracksite-level, mark its center and label it (e.g., 'S18 LP3') for track in result: # Use the position value to draw values rounded to uncertainty pos = track.positionValue.toMayaTuple() if pos[0] == 0 and pos[1] == 0: continue if showCenters: self.circle(pos, 2, scene=True, fill=color, fill_opacity=opacity, stroke="none") if showUncertainty: self.circle( pos, 100.0 * min(track.width, track.length), scene=True, fill="none", stroke_width=strokeWidth, stroke=color, stroke_opacity=opacity, ) self.text( track.sitemapDisplayLabel, (pos[0] - 4, pos[1] - 2.5), scene=True, font_size="4", fill=color, fill_opacity=opacity, stroke="none", ) # all done if not session: s.close() # _______________________________________________________________________________ def lineSegment(self, line, groupId=None, **extra): """ Adds a line object to the svg file based on a LineSegment2D instance. """ self.line(line.start.toMayaTuple(), line.end.toMayaTuple(), groupId=groupId, **extra) # _______________________________________________________________________________ def line(self, p1, p2, scene=True, groupId=None, **extra): """ Adds a line object to the svg file based on two scene points. It first converts from scene to siteMap coordinates if necessary, then concatenates the units suffix 'mm' to all coordinate values. """ if not self.siteMapReady: return # convert from scene coordinates to map coordinates as necessary if scene: p1 = self.projectToMap(p1) p2 = self.projectToMap(p2) # convert from (scaled) mm to px p1 = (self.pxPerMm * p1[0], self.pxPerMm * p1[1]) p2 = (self.pxPerMm * p2[0], self.pxPerMm * p2[1]) # create the object obj = self._drawing.line(p1, p2, **extra) # and add it to either a specific group or to _drawing (the default) if groupId: group = self.groups[groupId] if group: group.add(obj) else: print("line: %s is not a valid group ID" % groupId) return else: self._drawing.add(obj) # _______________________________________________________________________________ def mark(self, size, scene=True, groupId=None, **extra): """ Adds an axis-aligned '+' mark of given size at the origin. If scene=True, the size is transformed to map coordinates, else it is presumed to already be in map coordinates. If groupId=True, the mark is added to the specified group, rather than to the drawing. This fragment is intended for use as a group (see grid). """ if not self.siteMapReady: return self.line([-size, 0], [size, 0], scene=scene, groupId=groupId, **extra) self.line([0, -size], [0, size], scene=scene, groupId=groupId, **extra) # _______________________________________________________________________________ def mm(self, p): """ Appends the units label 'mm' to each value. Too many cases where svgwrite will not allow this suffix, so not currently used. """ return (p[0] * mm, p[1] * mm) # _______________________________________________________________________________ def polyLine(self, points, scene=True, groupId=None, **extra): """ Adds a polyline object to the SVG file, based on a list of scene points. If canvas is specified, this permits adding this object to a """ if not self.siteMapReady: return # map from scene coordinates to map coordinates as necessary if scene: mappedPoints = list() for p in points: mappedPoints.append(self.projectToMap(p)) points = mappedPoints # svgwrite does not allow coordinates with the suffix 'mm', hence all values must be in px. convertedPoints = list() for p in points: x = self.pxPerMm * p[0] y = self.pxPerMm * p[1] convertedPoints.append((x, y)) # create the object obj = self._drawing.polyline(convertedPoints, **extra) # and add it to either a specific group or symbol, or the default _drawing if groupId: group = self.groups[groupId] if group: group.add(obj) else: print("polyLine: %s is not a valid group ID" % groupId) return else: self._drawing.add(obj) # _______________________________________________________________________________ def projectToScene(self, p): """ The given siteMap location p is projected to the corresponding scene point and returned. In the scene, x is positive to the left, and z is positive upwards. In the siteMap, x is positive to the right and y is positive downwards. """ if not self.siteMapReady: return xMap = p[0] yMap = p[1] xScene = -self.scaleToScene(xMap - self.siteMap.xFederal) zScene = -self.scaleToScene(yMap - self.siteMap.yFederal) return (xScene, zScene) # _______________________________________________________________________________ def projectToMap(self, p): """ The given 2D scene point p, comprised of scene cooordinates (xScene, zScene), is projected to the corresponding 2D siteMap location (xMap, yMap) and returned. xScene is positive to the left, and zScene is positive upwards; xMap is positive to the right and yMap is positive downwards. """ if not self.siteMapReady: return xScene = p[0] yScene = p[1] xMap = self.siteMap.xFederal - self.scaleToMap(xScene) yMap = self.siteMap.yFederal - self.scaleToMap(yScene) return (xMap, yMap) # _______________________________________________________________________________ def rect(self, center, width, height, scene=True, groupId=None, rx=None, ry=None, **extra): """ Adds a rect object to the SVG file, based on center and dimensions. If the boolean scene is True, the arguments are converted to 'scaled mm', otherwise they are presumed to be in mm. All coordinates are explicitly labled with 'mm' and passed to svgwrite. """ if not self.siteMapReady: return xCenter = center[0] yCenter = center[1] # convert from scene coordinates to map coordinates as necessary if scene: xCenter = self.scaleToMap(xCenter) yCenter = self.scaleToMap(yCenter) width = self.scaleToMap(width) height = self.scaleToMap(height) # now compute the insert point, i.e., the upper left corner insert = (xCenter - width / 2, yCenter - height / 2) # convert from (scaled) mm to px insert = (self.pxPerMm * insert[0], self.pxPerMm * insert[1]) size = (self.pxPerMm * width, self.pxPerMm * height) # create the object obj = self._drawing.rect(insert, size, rx, ry, **extra) # and add it to either a specific group or to the default _drawing if groupId: group = self.groups[groupId] if group: group.add(obj) else: print("rect: %s is not a valid group ID" % groupId) return else: self._drawing.add(obj) # _______________________________________________________________________________ def save(self, toPDF=True): """ Writes the current _drawing in SVG format to the file specified at initialization. If one wishes to have create a PDF file (same file name as used for the .SVG, but with suffix .PDF), then call with toPDF True). """ if not self.siteMapReady: return # Make sure the directory where the file will be saved exists before saving FileUtils.getDirectoryOf(self._drawing.filename, createIfMissing=True) self._drawing.save() # we're done if no PDF version is also required if not toPDF: return # strip any extension off of the file name basicName = self.fileName.split(".")[0] # load up the command cmd = ["/Applications/Inkscape.app/Contents/Resources/bin/inkscape", "-f", None, "-A", None] cmd[2] = basicName + ".svg" cmd[4] = basicName + ".pdf" # and execute it response = SystemUtils.executeCommand(cmd) if response["error"]: print("response[error]=%s" % response["error"]) # _______________________________________________________________________________ def scaleToMap(self, v): """ Converts from scene coordinates (in cm) to siteMap coordinates ('scaled mm'). The siteMap is usually drawn in 50:1 scale. """ if not self.siteMapReady: return return v / (0.1 * self.siteMap.scale) # _______________________________________________________________________________ def scaleToScene(self, value): """ Site maps (Adobe Illustrator .ai files) are typically in 50:1 scale, and use mm as their units. Consequently a single unit in the site map corresponds to 50 mm in the 'real world'. The 3D scene on the other hand, uses cm scale. This function converts the given value from the 'scaled mm' of the map into centimeter units of the 3D scene. For example, a value of 20 units corresponds to 100 cm in the scene, which is returned. """ if not self.siteMapReady: return return 0.1 * self.siteMap.scale * value # _______________________________________________________________________________ def text(self, textString, insert, scene=True, groupId=None, **extra): """ Adds a text of a given fill at the given insertion point. """ if not self.siteMapReady: return # convert from scene coordinates to map coordinates as necessary if scene: insert = self.projectToMap(insert) # convert from (scaled) mm to px insert = (self.pxPerMm * insert[0], self.pxPerMm * insert[1]) # create the object obj = self._drawing.text(textString, insert, **extra) # and add it to either a specific group or to the default _drawing if groupId: group = self.groups[groupId] if group: group.add(obj) else: print("text: %s is not a valid group ID" % groupId) return else: self._drawing.add(obj) # _______________________________________________________________________________ def use(self, id, center, scene=True, rotation=None, rotationCenter=None, scale=None, scaleY=None, **extra): """ Groups are given an id when created. This id is used to create instances that are added to the Cadence drawing (and hence the SVG file) by this function. The group is placed in the drawing using map coordinates. Rotation defaults to about the origin. A preferred usage would be to create a create a group relative to (i.e., centered upon) the origin, so that the rotation pivot is naturally at the group's center. The group is then placed at the specfified center location (which either in map coordinates or scene coordinates depending upon the kwarg scene). For example, for a group 'g' to be placed at some point (xScene, yScene) and rotated 45 degrees, and with 2x scale: use('g', (xScene, yScene), scene=True, rotation=45, scale=2) """ if not self.siteMapReady: return if scene: center = self.projectToMap(center) tx = self.pxPerMm * center[0] ty = self.pxPerMm * center[1] else: tx = center[0] ty = center[1] element = self.groups[id] if not element: print("CadenceDrawing.use: %s is not a valid group id" % id) return instance = self._drawing.use(element, **extra) instance.translate(tx, ty) # right-handed coordinates, hence postive counterclockwise about y axis if rotation: instance.rotate(-rotation, center=rotationCenter) # scale anisotropically only if scaleY is specified, else isotropically if scale: if not scaleY: scaleY = scale instance.scale(scale, sy=scaleY) self._drawing.add(instance)
class CoffeescriptBuilder(object): """A class for...""" CLASS_PATTERN = "^[\s\t]*class[\s\t]+(?P<class>[^\s\t\r\n]+)[\s\t]*" MISSING_CLASS_PATTERN = "[\s\t\(\[\{\!]+(?=[A-Z])(?P<class>[A-Za-z0-9_]+)(?P<next>[^A-Za-z0-9_]+)" _WARN_ID_MISSING_IMPORT = "MISSING-IMPORT" _GLOBAL_CLASSES = [ "SFLOW", "PAGE", "FB", "Math", "JSON", "String", "ActiveXObject", "Date", "DOMParser", "RegExp", "Object", "Number", "Array", "Function", "XMLHttpRequest", ] _results = None _missing = None # =================================================================================================== # C L A S S # ___________________________________________________________________________________________________ __init__ def __init__( self, targetPackageOrPath, rootPath, verbose=True, debug=False, trace=False, force=False, compress=False, buildOnly=False, ): """Creates a new instance of CoffeescriptBuilder.""" self.buildOnly = buildOnly self._imports = dict() self._requires = dict() self._includes = dict() self._report = dict() self._warnings = [] self._dependencyReport = dict() self._verbose = verbose self._log = Logger(self, printOut=True) self._trace = trace self._debug = debug self._targets = [] self._force = force self._compress = compress self._rootPath = rootPath if not isinstance(targetPackageOrPath, CoffeescriptDependency): target = CoffeescriptDependency(targetPackageOrPath, rootPath, None) else: target = targetPackageOrPath if target.exists: self._targets.append(target) else: csFiles = CoffeescriptBuilder.getScriptsInPath(target.packagePath) # Look for exec matches first for f in csFiles: testTarget = CoffeescriptDependency(f, rootPath, None) if testTarget.isExec: self._targets.append(testTarget) # Look for lib matches second. Lib matches are tested as a second pass because # constructing all exec files first potentially optimizes the import process for # the libraries. for f in csFiles: testTarget = CoffeescriptDependency(f, rootPath, None) if testTarget.isLib: self._targets.append(testTarget) if len(self._targets) == 0: print("\n\n") self._log.write("No targets exist for: %s. Compilation aborted." % targetPackageOrPath) print("\n") # =================================================================================================== # G E T / S E T # ___________________________________________________________________________________________________ GS: report @property def report(self): return self._report # ___________________________________________________________________________________________________ GS: warnings @property def warnings(self): return self._warnings # ___________________________________________________________________________________________________ GS: imports @property def imports(self): return self._imports # ___________________________________________________________________________________________________ GS: requires @property def requires(self): return self._requires # ___________________________________________________________________________________________________ GS: includes @property def includes(self): return self._includes # =================================================================================================== # P U B L I C # ___________________________________________________________________________________________________ construct def construct(self): """Doc...""" for t in self._targets: self._report[t.package] = -1 if t.isLib: self._constructLibrary(t) else: self._constructTarget(t) if self._compress: print("COMPRESSING:", t.package) from pyaid.web.coffeescript.IncludeCompressor import IncludeCompressor ic = IncludeCompressor() if not ic.compressFile(t.compiledPath): print("COMPRESSION FAILURE:", t.compiledPath) return self._targets # ___________________________________________________________________________________________________ compileAllOnPath @staticmethod def compileAllOnPath(path, rootPath=None, recursive=False, debug=False, trace=False, force=False, compress=False): CoffeescriptBuilder._results = "" CoffeescriptBuilder._missing = {} if recursive: print("RECURSIVE COMPILE AT: " + path) def walker(paths, dirName, names): out = CoffeescriptBuilder._compileAllInDirectory( os.path.join(paths[0], dirName), paths[1], debug=debug, trace=trace, force=force, compress=compress ) CoffeescriptBuilder._results += out["res"] for n, v in DictUtils.iter(out["missing"]): if n in CoffeescriptBuilder._missing: continue CoffeescriptBuilder._missing[n] = v FileUtils.walkPath(path, walker, [path, rootPath]) print("\n\nCOMPILATION RESULTS:" + CoffeescriptBuilder._results) if CoffeescriptBuilder._missing: print("\n\nMISSING IMPORTS:" + "\n\n") for n, v in DictUtils.iter(CoffeescriptBuilder._missing): print(v["class"] + " [LINE: #" + str(v["line"]) + " | " + v["package"] + "]") else: print("COMPILING DIRECTORY: " + path) CoffeescriptBuilder._compileAllInDirectory( path, rootPath, debug=debug, trace=trace, force=force, compress=compress ) # ___________________________________________________________________________________________________ getScriptsInPath @staticmethod def getScriptsInPath(path): files = [] for f in os.listdir(path): if f.lower().endswith("." + CoffeescriptDependency.EXTENSION): files.append(os.path.join(path, f)) return files # =================================================================================================== # P R O T E C T E D # ___________________________________________________________________________________________________ _constructLibrary def _constructLibrary(self, target): try: if self._verbose: print("\n\n" + ("-" * 100) + "\n") self._log.add("LIBRARY: %s\n\tsource: %s\n\troot: %s" % (target.package, target.path, target.rootPath)) # --------------------------------------------------------------------------------------- # Compile all includes using library data targets, imports, modules, includes = self._getLibraryData(target) # Process requires for all of the targets for t in targets + imports + modules: self._processRequires(t) # --------------------------------------------------------------------------------------- # IMPORTS # Compile all excludes skipping any exec or lib files that are listed in the import # statements. importExcludes = [] for t in targets: for imp in self._imports[t.package]: if not (imp.isExec or imp.isLib or imp.isInList(importExcludes)): importExcludes.append(imp) # Compile all imports needed for the library. Any excludes are added to the shared # library to be made accessible via the VIZME registry. libImports = [] sharedImports = [] for t in imports + modules: for imp in self.imports[t.package]: if not imp.isInList(libImports): if imp.isInList(importExcludes): if not imp.isInList(sharedImports): sharedImports.append(imp) else: libImports.append(imp) libImports.append(target) # --------------------------------------------------------------------------------------- # INCLUDES # Compile all includes to exclude from the library because they already exist in a # target. includeExcludes = [] for t in targets: for inc in self._includes[t.package]: if not inc.isInList(includeExcludes): includeExcludes.append(inc) # Compile all includes needed for the library. libIncludes = [] sharedIncludes = [] # Add the top-level includes directly because they are not handled implicitly like # the import case for inc in includes: if inc.isInList(includeExcludes): sharedIncludes.append(inc) else: libIncludes.append(inc) for t in imports + modules: for inc in self.includes[t.package]: if not inc.isInList(libIncludes): if inc.isInList(includeExcludes): if not inc.isInList(sharedIncludes): sharedIncludes.append(inc) else: libIncludes.append(inc) if self._verbose: print("\n") s = "IMPORTING:" for imp in libImports: s += "\n\t" + imp.package for inc in libIncludes: s += "\n\tEXTERNAL: " + inc.package self._log.add(s) print("\n") s = "EXCLUDING:" for imp in sharedImports: s += "\n\t" + imp.package for inc in sharedIncludes: s += "\n\tEXTERNAL: " + inc.package self._log.add(s) # --------------------------------------------------------------------------------------- # Construct intermediate compilation file. assembledFile = self._assembleFile(target, libImports, sharedImports, {"modules": modules}) if assembledFile is None: self._log.write("ERROR: File assembly failed.") return # --------------------------------------------------------------------------------------- # Compile to Javascript if not self.buildOnly: self._compileToJavascript(target, assembledFile, libIncludes) if self._verbose: print("\n" + ("-" * 100) + "\n") except Exception as err: print("\n\n\n") self._log.writeError( "ERROR: Compilation failure for: %s\n\tsource: %s\n\troot: %s" % (target.package, target.path, target.rootPath), err, ) # ___________________________________________________________________________________________________ _constructTarget def _constructTarget(self, target): try: if self._verbose: print("\n\n" + ("-" * 100) + "\n") self._log.write( "EXECUTABLE: %s\n\tsource: %s\n\troot: %s" % (target.package, target.path, target.rootPath) ) # --------------------------------------------------------------------------------------- # Handle imports and requires self._parseIncludes(target) self._processRequires(target) if self._verbose: s = "IMPORTING:" for imp in self._imports[target.package]: s += "\n\t" + imp.package self._log.write(s) # --------------------------------------------------------------------------------------- # Construct intermediate compilation file. assembledFile = self._assembleFile(target) if assembledFile is None: self._log.write("ERROR: File assembly failed.") return # --------------------------------------------------------------------------------------- # Compile to Javascript if not self.buildOnly: self._compileToJavascript(target, assembledFile) if self._verbose: print("\n" + ("-" * 100) + "\n") except Exception as err: print("\n\n\n") self._log.writeError( "ERROR: Compilation failure for: %s\n\tsource: %s\n\troot: %s" % (target.package, target.path, target.rootPath), err, ) # ___________________________________________________________________________________________________ _createOutputFile def _createOutputFile(self, target): """Creates the output ccs assembly file for writing.""" outFile = target.assembledPath try: return open(outFile, "w") except Exception as err: print("\n\n") self._log.write( "Unable To Open output file: " + str(outFile) + "\n" "Check to make sure you have write permissions to that directory." ) return None # ___________________________________________________________________________________________________ _writeRegistryEntry def _writeRegistryEntry(self, out, cacheOut, entry): # If there is an unconsumed registryEntry write it. if not entry: return None s = "\n" + entry + "\n" out.write(s) if cacheOut: cacheOut.write(s) return None # ___________________________________________________________________________________________________ _assembleFile def _assembleFile(self, target, importOverride=None, replacements=None, assembleData=None): # ------------------------------------------------------------------------------------------- # CREATE FILE # Creates the file to write out = self._createOutputFile(target) if not out: self._log("ERROR: Unable to create output file") return # ------------------------------------------------------------------------------------------- # DEFINE IMPORTS # Specify the files to import. For exec files the default packages are included, for # libraries these are overridden based on library target dependencies. targetImports = self._imports[target.package] if importOverride is None else importOverride replacements = replacements if isinstance(replacements, list) else [] classList = [] # ------------------------------------------------------------------------------------------- # Note the last dependency so that the glue script can be appended prior lastDep = targetImports[-1] # ------------------------------------------------------------------------------------------- # DEPENDENCY ASSEMBLY LOOP print("\n") for dep in targetImports: dep.open() if self._force or not dep.useCache: if not self._compileDependency(dep, out, replacements, targetImports, classList): return None continue self._log.write("\tFROM CACHE: " + dep.package) out.write(dep.cacheSource) dep.close() out.close() if self._verbose: print("\n") self._log.add("CONSTRUCTED: " + out.name) return out.name # ___________________________________________________________________________________________________ _compileDependency def _compileDependency(self, dep, out, replacements, targetImports, classList): classPattern = re.compile(CoffeescriptBuilder.CLASS_PATTERN) missingPattern = re.compile(CoffeescriptBuilder.MISSING_CLASS_PATTERN) # ------------------------------------------------------------------------------------------- # MISSING DEPENDENCIES # Handle missing dependencies if not os.path.exists(dep.path): print("\n\n") self._log.write("ERROR: " + dep.package + " package does not exist at: " + dep.path) return False lastWhitespace = "" openParens = 0 openBrackets = 0 openBraces = 0 skipNextLine = False methodName = "" className = "" registryEntry = None raw = dep.source dep.close() s = "\n\n\t#" + ("%" * 100) + "\n\t#" + ("%" * 100) + "\n#\t\t" + dep.package + "\n" out.write(s) if dep.allowCaching: cacheOut = open(dep.cachePath, "w") cacheOut.write(s) else: try: if os.path.exists(dep.cachePath): os.remove(dep.cachePath) except Exception as err: pass cacheOut = None self._log.write("\tCOMPILING: " + dep.package) analyzer = CoffeescriptAnalyzer(raw, debug=self._debug) analyzer.analyze() # --------------------------------------------------------------------------------------- # COMPILE # Line by line compile to ccs output file for l in analyzer: # ----------------------------------------------------------------------------------- # RETARGET CLASS ACCESSORS TO VIZME registry # All classes (except internal class references) are made to # VIZME registry ClassName to prevent class conflicts. for rep in replacements + targetImports: if rep != dep: offset = 0 res = rep.searchPattern.finditer(l.redacted) for r in res: start = r.start() + offset end = r.end() + offset if self._trace: self._log.write("RETARGET: " + l.source[start:end] + " | " + str(r.groupdict())) # Make the replacement and adjust offsets for additional replacements l.insert(start, end, rep.registryName) offset += len(rep.registryName) - end + start # ----------------------------------------------------------------------------------- # IDENTIFY CLASS DEFINITIONS # Find class definitions so they can be added to the VIZME registry. res = classPattern.search(l.redacted) if res: registryEntry = self._writeRegistryEntry(out, cacheOut, registryEntry) className = res.group("class").strip() registryEntry = "\n%s.%s ?= %s" % (CoffeescriptDependency.REGISTRY, className, className) classList.append(className) # ----------------------------------------------------------------------------------- # CHECK FOR MISSING CLASSES # Search and find any missing class imports. If a possible missing import is found # flag it in the response. res = missingPattern.finditer(l.redacted) if res: for r in res: cn = r.group("class").strip() start = r.start() if cn == className: continue # Ignore anything in all CAPS! if cn.upper() == cn: continue # Ignore globally defined objects and classes if cn in CoffeescriptBuilder._GLOBAL_CLASSES + analyzer.globalObjects: continue self._warnings.append( { "id": CoffeescriptBuilder._WARN_ID_MISSING_IMPORT, "class": cn, "line": l.lineNumber, "package": dep.package, } ) print("\n") self._log.write( "WARNING: Possible missing import\n\tmissing: %s\n\tfrom: %s [line #%s]" % (cn, dep.package, str(l.lineNumber)) ) # ----------------------------------------------------------------------------------- # LINE DEBUGGER ANALYSIS c = l.redacted.strip() skip = skipNextLine or not l.isSignificant skipNextLine = False if not skip: skips = ["class", "try", "catch", "else", "when", ".", "+", "-", "/", "=", "*", ",", "and", "or"] for s in skips: if c.startswith(s): skip = True break if not skip: skips = ["->", "=>"] methodPattern = re.compile("^(?P<method>[^:]+)") for s in skips: if c.endswith(s): skip = True res = methodPattern.search(c) if res and res.group("method"): methodName = res.group("method") elif c.startswith("$"): methodName = "$" break # Check for line continuations if l.isSignificant: skips = [".", "+", "-", "/", "=", "*", ",", "and", "or"] for s in skips: if c.endswith(s): skipNextLine = True break if self._trace: self._log.write( c.replace("\n", "") + ( "\n\t@@@@ skip: " + str(skip) + "\n\t@@@@ parens: " + str(openParens) + "\n\t@@@@ braces: " + str(openBraces) + "\n\t@@@@ brackets: " + str(openBraces) + "\n\t@@@@ skipNext: " + str(skipNextLine) ) ) if self._debug and not skip and openParens == 0 and openBraces == 0 and openBrackets == 0: debugLine = "window.___vmiDebug('%s', '%s', '%s', %s)\n" % ( dep.package, className, methodName, str(l.lineNumber), ) indent = len(l.indent) > len(lastWhitespace) dedent = len(l.indent) < len(lastWhitespace) skips = [")", "]", "}"] skip = False for s in skips: if c.startswith(s): skip = True break if dedent and skip: lastWhitespace = lastWhitespace else: lastWhitespace = l.indent codePattern = re.compile("(?P<code>[^\s\t\n]+)") res = codePattern.search(c) if not res or len(res.groupdict()["code"]) == 0: if self._trace: self._log.write('EMPTY: "' + c + '"') debugLine = "" l.insert(0, 0, l.indent + debugLine) if l.isSignificant: openParens += l.redacted.count("(") - l.redacted.count(")") openBrackets += l.redacted.count("[") - l.redacted.count("]") openBraces += l.redacted.count("{") - l.redacted.count("}") # --------------------------------------------------------------------------------------- # WRITE MODIFIED OUTPUT out.write(l.source) if cacheOut: cacheOut.write(l.source) self._writeRegistryEntry(out, cacheOut, registryEntry) if cacheOut: cacheOut.close() return True # ___________________________________________________________________________________________________ _compileToJavascript def _compileToJavascript(self, target, assembledFile, jsIncludeOverrides=None): # Use the Coffeescript compiler to create a JS compilation of the assembled CS file result = SystemUtils.executeCommand(["coffee", "-c", "--bare", assembledFile]) status = result["code"] output = result["out"] errors = 0 forceVerbose = False # ------------------------------------------------------------------------------------------- # ERROR HANDLING # Check the error status of the compilation process and if a failure occurred parse the # error results for display and logging. if status: outputLines = str(output).replace("\r", "").split("\n") for line in outputLines: if line.startswith("Error:") or line.startswith("SyntaxError:"): errors += 1 result = CoffeescriptBuilder._parseError(line) if result: self._log.add(result) else: forceVerbose = True if forceVerbose: self._log.add(output) self._report[target.package] = errors if self._verbose: print("\n\n") if errors == 0 and status == 0: self._log.write("Compilation complete: " + target.compiledPath) else: self._log.write("Compilation FAILED: " + target.package) f = open(target.compiledPath, "r") res = f.read() f.close() # ___________________________________________________________________________________________________ _parseIncludes def _parseIncludes(self, target, rootTarget=None): """Doc...""" if rootTarget is None: rootTarget = target if not rootTarget.package in self._imports: self._imports[rootTarget.package] = [] if not rootTarget.package in self._requires: self._requires[rootTarget.package] = [] if not rootTarget.package in self._includes: self._includes[rootTarget.package] = [] if not os.path.exists(target.path): print("\n") self._log.add("WARNING: Missing import.\n\tPACKAGE: " + target.package + "\n\tFILE: " + target.path) print("\n") return f = open(target.path) for line in f: # import parse dependency = CoffeescriptDependency.createImport(line, self._rootPath) if dependency and not dependency.isInList(self._imports[rootTarget.package]): self._parseIncludes(dependency, rootTarget) self._imports[rootTarget.package].append(dependency) continue # require parse dependency = CoffeescriptDependency.createRequire(line, self._rootPath) if dependency and not dependency.isInList(self._imports[rootTarget.package]): self._requires[rootTarget.package].append(dependency) continue # include parse dependency = CoffeescriptDependency.createInclude(line, self._rootPath) if dependency and not dependency.isInList(self._includes[rootTarget.package]): self._includes[rootTarget.package].append(dependency) continue f.close() self._imports[rootTarget.package].append(target) # ___________________________________________________________________________________________________ _processRequires def _processRequires(self, target): currentTarget = self._imports[target.package].pop() while len(self._requires[target.package]) > 0: self._parseIncludes(self._requires[target.package].pop(0), target) outlist = [] for item in self._imports[target.package]: if not item.isInList(outlist) and not item.compare(currentTarget): outlist.append(item) self._imports[target.package] = outlist self._imports[target.package].append(currentTarget) # ___________________________________________________________________________________________________ _getLibraryData def _getLibraryData(self, target): targets = [] modules = [] imports = [] includes = [] src = open(target.path, "r") for line in src: # target parse d = CoffeescriptDependency.create(line, self._rootPath) if not d: continue if d.dependencyType == CoffeescriptDependency.TARGET_TYPE: targets.append(d) elif d.dependencyType == CoffeescriptDependency.IMPORT_TYPE: imports.append(d) elif d.dependencyType == CoffeescriptDependency.REQUIRE_TYPE: imports.append(d) elif d.dependencyType == CoffeescriptDependency.INCLUDE_TYPE: includes.append(d) elif d.dependencyType == CoffeescriptDependency.MODULE_TYPE: modules.append(d) else: continue self._parseIncludes(d) src.close() return targets, imports, modules, includes # ___________________________________________________________________________________________________ _compileAllInDirectory @staticmethod def _compileAllInDirectory(path, rootPath=None, debug=False, trace=False, force=False, compress=False): results = "" missing = {} count = 0 for f in CoffeescriptBuilder.getScriptsInPath(path): target = CoffeescriptDependency(f, rootPath) if not (target.exists and (target.isExec or target.isLib)): continue c = CoffeescriptBuilder(target, rootPath, debug=debug, trace=trace, force=force, compress=compress) c.construct() count += 1 for n, v in DictUtils.iter(c.report): num = max(0, 60 - len(n)) results += "\n" + n + ":" + ("." * num) if v == 0: results += "SUCCESS" elif v > 0: results += "COMPILATION FAILED" else: results += "ASSEMBLY FAILED" if len(c.warnings) > 0: results += "[" + str(len(c.warnings)) + " WARNINGS]" for v in c.warnings: if not v["id"] == CoffeescriptBuilder._WARN_ID_MISSING_IMPORT: continue key = v["package"] + "-" + v["class"] + "-" + str(v["line"]) if key in missing: continue missing[key] = v if len(results) > 0: print("\nDIRECTORY " + path + " COMPILE RESULTS [" + str(count) + "]:" + results) return {"res": results, "missing": missing} # ___________________________________________________________________________________________________ _parseError @staticmethod def _parseError(error): """ Parses errors of the format: "Error: In /vizme2/website/js/vmi/blog/author/exec.ccs, Parse error on line 181: Unexpected 'INDENT'" """ ccsFile = None prefixReplacements = ["SyntaxError: In ", "Error: In "] for p in prefixReplacements: error = error.replace(p, "") out = "\n-----------------------------------------------\nERROR: " try: sep = error.index(",") ccsFile = error[:sep] except Exception: pass try: sep2 = error.index(":") out += error[sep2 + 1 :].strip() + "\n" except Exception: if error and sep: out += error[sep + 1 :].strip() + "\n" pattern = re.compile("line[\s\t]+(?P<linenumber>[0-9]+)") res = pattern.search(error) if res and len(res.groups()) > 0: lineNumber = int(res.groups()[0]) - 1 else: out += " Unspecified location" return if ccsFile: padSize = len(str(lineNumber + 3)) jQueryName = "Exec Function (JQUERY Document ready)" functionName = None className = None trace = "" f = open(ccsFile, "r") for i, line in enumerate(f): if i > lineNumber + 4: break if i <= lineNumber: pattern = re.compile("^class[\s\t]+(?P<classname>[a-zA-Z0-9_]+)") res = pattern.search(line) if res and len(res.groups()) > 0: className = res.groups()[0] functionName = None pattern = re.compile("^\$[\s\t]*[-=]+>") res = pattern.search(line) if res: className = jQueryName functionName = None pattern = re.compile("[\s\t]*(?P<name>[a-zA-Z0-9_]+)[\s\t]*:[^-=>]*[-=]+>") res = pattern.search(line) if res and len(res.groups()) > 0: functionName = res.groups()[0] if i > lineNumber - 4: marker = ">>" if i == lineNumber else " " trace += marker + str(i).rjust(padSize) + "| " + line f.close() if functionName: out += " " + ("METHOD" if className else "FUNCTION") + ": " + functionName + "\n" if className: out += " " + ("CLASS" if className != jQueryName else "EXEC") + ": " + className + "\n" out += " TRACE:\n" + trace return out + "\n"
class CoffeescriptBuilder(object): """A class for...""" CLASS_PATTERN = '^[\s\t]*class[\s\t]+(?P<class>[^\s\t\r\n]+)[\s\t]*' MISSING_CLASS_PATTERN = '[\s\t\(\[\{\!]+(?=[A-Z])(?P<class>[A-Za-z0-9_]+)(?P<next>[^A-Za-z0-9_]+)' _WARN_ID_MISSING_IMPORT = 'MISSING-IMPORT' _GLOBAL_CLASSES = [ 'SFLOW', 'PAGE', 'FB', 'Math', 'JSON', 'String', 'ActiveXObject', 'Date', 'DOMParser', 'RegExp', 'Object', 'Number', 'Array', 'Function', 'XMLHttpRequest'] _results = None _missing = None #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__( self, targetPackageOrPath, rootPath, verbose =True, debug =False, trace = False, force =False, compress =False, buildOnly =False ): """Creates a new instance of CoffeescriptBuilder.""" self.buildOnly = buildOnly self._imports = dict() self._requires = dict() self._includes = dict() self._report = dict() self._warnings = [] self._dependencyReport = dict() self._verbose = verbose self._log = Logger(self, printOut=True) self._trace = trace self._debug = debug self._targets = [] self._force = force self._compress = compress self._rootPath = rootPath if not isinstance(targetPackageOrPath, CoffeescriptDependency): target = CoffeescriptDependency(targetPackageOrPath, rootPath, None) else: target = targetPackageOrPath if target.exists: self._targets.append(target) else: csFiles = CoffeescriptBuilder.getScriptsInPath(target.packagePath) # Look for exec matches first for f in csFiles: testTarget = CoffeescriptDependency(f, rootPath, None) if testTarget.isExec: self._targets.append(testTarget) # Look for lib matches second. Lib matches are tested as a second pass because # constructing all exec files first potentially optimizes the import process for # the libraries. for f in csFiles: testTarget = CoffeescriptDependency(f, rootPath, None) if testTarget.isLib: self._targets.append(testTarget) if len(self._targets) == 0: print '\n\n' self._log.write('No targets exist for: %s. Compilation aborted.' % targetPackageOrPath) print '\n' #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: report @property def report(self): return self._report #___________________________________________________________________________________________________ GS: warnings @property def warnings(self): return self._warnings #___________________________________________________________________________________________________ GS: imports @property def imports(self): return self._imports #___________________________________________________________________________________________________ GS: requires @property def requires(self): return self._requires #___________________________________________________________________________________________________ GS: includes @property def includes(self): return self._includes #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ construct def construct(self): """Doc...""" for t in self._targets: self._report[t.package] = -1 if t.isLib: self._constructLibrary(t) else: self._constructTarget(t) if self._compress: print 'COMPRESSING:',t.package from pyaid.web.coffeescript.IncludeCompressor import IncludeCompressor ic = IncludeCompressor() if not ic.compressFile(t.compiledPath): print 'COMPRESSION FAILURE:',t.compiledPath return self._targets #___________________________________________________________________________________________________ compileAllOnPath @staticmethod def compileAllOnPath(path, rootPath =None, recursive =False, debug =False, trace =False, force =False, compress=False): CoffeescriptBuilder._results = '' CoffeescriptBuilder._missing = {} if recursive: print 'RECURSIVE COMPILE AT: ' + path def walker(paths, dirName, names): out = CoffeescriptBuilder._compileAllInDirectory( os.path.join(paths[0], dirName), paths[1], debug=debug, trace=trace, force=force, compress=compress ) CoffeescriptBuilder._results += out['res'] for n,v in out['missing'].iteritems(): if n in CoffeescriptBuilder._missing: continue CoffeescriptBuilder._missing[n] = v os.path.walk(path, walker, [path, rootPath]) print '\n\nCOMPILATION RESULTS:' + CoffeescriptBuilder._results if CoffeescriptBuilder._missing: print '\n\nMISSING IMPORTS:' + '\n\n' for n,v in CoffeescriptBuilder._missing.iteritems(): print v['class'] + ' [LINE: #' + str(v['line']) + ' | ' + v['package'] + ']' else: print 'COMPILING DIRECTORY: ' + path CoffeescriptBuilder._compileAllInDirectory( path, rootPath, debug=debug, trace=trace, force=force, compress=compress) #___________________________________________________________________________________________________ getScriptsInPath @staticmethod def getScriptsInPath(path): files = [] for f in os.listdir(path): if f.lower().endswith('.' + CoffeescriptDependency.EXTENSION): files.append(os.path.join(path, f)) return files #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _constructLibrary def _constructLibrary(self, target): try: if self._verbose: print "\n\n" + ('-'*100) + '\n' self._log.add( 'LIBRARY: %s\n\tsource: %s\n\troot: %s' % ( target.package, target.path, target.rootPath)) #--------------------------------------------------------------------------------------- # Compile all includes using library data targets, imports, modules, includes = self._getLibraryData(target) # Process requires for all of the targets for t in (targets + imports + modules): self._processRequires(t) #--------------------------------------------------------------------------------------- # IMPORTS # Compile all excludes skipping any exec or lib files that are listed in the import # statements. importExcludes = [] for t in targets: for imp in self._imports[t.package]: if not (imp.isExec or imp.isLib or imp.isInList(importExcludes)): importExcludes.append(imp) # Compile all imports needed for the library. Any excludes are added to the shared # library to be made accessible via the VIZME registry. libImports = [] sharedImports = [] for t in (imports + modules): for imp in self.imports[t.package]: if not imp.isInList(libImports): if imp.isInList(importExcludes): if not imp.isInList(sharedImports): sharedImports.append(imp) else: libImports.append(imp) libImports.append(target) #--------------------------------------------------------------------------------------- # INCLUDES # Compile all includes to exclude from the library because they already exist in a # target. includeExcludes = [] for t in targets: for inc in self._includes[t.package]: if not inc.isInList(includeExcludes): includeExcludes.append(inc) # Compile all includes needed for the library. libIncludes = [] sharedIncludes = [] # Add the top-level includes directly because they are not handled implicitly like # the import case for inc in includes: if inc.isInList(includeExcludes): sharedIncludes.append(inc) else: libIncludes.append(inc) for t in (imports + modules): for inc in self.includes[t.package]: if not inc.isInList(libIncludes): if inc.isInList(includeExcludes): if not inc.isInList(sharedIncludes): sharedIncludes.append(inc) else: libIncludes.append(inc) if self._verbose: print '\n' s = 'IMPORTING:' for imp in libImports: s += '\n\t' + imp.package for inc in libIncludes: s += '\n\tEXTERNAL: ' + inc.package self._log.add(s) print '\n' s = 'EXCLUDING:' for imp in sharedImports: s += '\n\t' + imp.package for inc in sharedIncludes: s += '\n\tEXTERNAL: ' + inc.package self._log.add(s) #--------------------------------------------------------------------------------------- # Construct intermediate compilation file. assembledFile = self._assembleFile( target, libImports, sharedImports, {'modules':modules} ) if assembledFile is None: self._log.write('ERROR: File assembly failed.') return #--------------------------------------------------------------------------------------- # Compile to Javascript if not self.buildOnly: self._compileToJavascript(target, assembledFile, libIncludes) if self._verbose: print "\n" + ('-'*100) + '\n' except Exception, err: print "\n\n\n" self._log.writeError( 'ERROR: Compilation failure for: %s\n\tsource: %s\n\troot: %s' % (target.package, target.path, target.rootPath), err)
class TrackCsvImporter(object): """ Imports track data from CSV formatted spreadsheets into the local Cadence database. """ #=============================================================================== # C L A S S # Used to break trackway specifier into separate type and number entries _TRACKWAY_PATTERN = re.compile('(?P<type>[^0-9\s\t]+)[\s\t]*(?P<number>[^\(\s\t]+)') _UNDERPRINT_IGNORE_TRACKWAY_STR = ':UTW' _OVERPRINT_IGNORE_TRACKWAY_STR = ':OTW' #_______________________________________________________________________________ def __init__(self, path =None, logger =None): """Creates a new instance of TrackCsvImporter.""" self._path = path self.created = [] self.modified = [] self.fingerprints = dict() self.remainingTracks = dict() self._logger = logger if not logger: self._logger = Logger(self, printOut=True) #=============================================================================== # P U B L I C #_______________________________________________________________________________ def read(self, session, analysisSession, path =None, compressed =False): """ Reads from the spreadsheet located at the absolute path argument and adds each row to the tracks in the database. """ if path is not None: self._path = path if self._path is None: return False model = Tracks_Track.MASTER for existingTrack in session.query(model).all(): self.remainingTracks[existingTrack.uid] = existingTrack.fingerprint try: data = pd.read_csv(self._path) except Exception as err: self._writeError({ 'message':'ERROR: Unable to read CSV file "%s"' % self._path, 'error':err }) return if data is None: self._writeError({ 'message':'ERROR: Failed to create CSV reader for file "%s"' % self._path }) return for index, row in data.iterrows(): # Skip any rows that don't start with the proper numeric index value, which # includes the header row (if it exists) with the column names try: index = int(row[0]) except Exception: continue rowDict = dict() for column in Reflection.getReflectionList(TrackCsvColumnEnum): value = row[column.index] if value and StringUtils.isStringType(value) and not StringUtils.isTextType(value): # Try to decode the value into a unicode string using common codecs for codec in ['utf8', 'MacRoman', 'utf16']: try: decodedValue = value.decode(codec) if decodedValue: value = decodedValue break except Exception: continue try: # Check to see if the value is NaN, and if it is replace it with an empty # string to be ignored during import value = '' if np.isnan(value) else value except Exception: pass if value != '' or value is None: rowDict[column.name] = value self.fromSpreadsheetEntry(rowDict, session) for uid, fingerprint in DictUtils.iter(self.remainingTracks): # Iterate through the list of remaining tracks, which are tracks not found by the # importer. If the track is marked as custom (meaning it is not managed by the importer) # it is ignored. Otherwise, the track is deleted from the database as a track that no # longer exists. track = Tracks_Track.MASTER.getByUid(uid, session) if track.custom: continue Tracks_Track.removeTrack(track, analysisSession) self._logger.write('[REMOVED]: No longer exists "%s" (%s)' % ( track.fingerprint, track.uid)) session.flush() for track in self.created: self._logger.write('[CREATED]: "%s" (%s)' % (track.fingerprint, track.uid)) return True #_______________________________________________________________________________ def fromSpreadsheetEntry(self, csvRowData, session): """ From the spreadsheet data dictionary representing raw track data, this method creates a track entry in the database. """ #------------------------------------------------------------------------------------------- # MISSING # Try to determine if the missing value has been set for this row data. If so and it # has been marked missing, skip the track during import to prevent importing tracks # with no data. try: missingValue = csvRowData[TrackCsvColumnEnum.MISSING.name].strip() if missingValue: return False except Exception: pass try: csvIndex = int(csvRowData[TrackCsvColumnEnum.INDEX.name]) except Exception: self._writeError({ 'message':'Missing spreadsheet index', 'data':csvRowData }) return False model = Tracks_Track.MASTER t = model() t.importFlags = 0 t.index = csvIndex #------------------------------------------------------------------------------------------- # SITE try: t.site = csvRowData.get(TrackCsvColumnEnum.TRACKSITE.name).strip().upper() except Exception: self._writeError({ 'message':'Missing track site', 'data':csvRowData, 'index':csvIndex }) return False #------------------------------------------------------------------------------------------- # SECTOR try: t.sector = csvRowData.get(TrackCsvColumnEnum.SECTOR.name).strip().upper() except Exception: self._writeError({ 'message':'Missing sector', 'data':csvRowData, 'index':csvIndex }) return False #------------------------------------------------------------------------------------------- # LEVEL try: t.level = csvRowData.get(TrackCsvColumnEnum.LEVEL.name) except Exception: self._writeError({ 'message':'Missing level', 'data':csvRowData, 'index':csvIndex }) return False #------------------------------------------------------------------------------------------- # TRACKWAY # Parse the trackway entry into type and number values. In the process illegal # characters are removed to keep the format something that can be handled correctly # within the database. try: test = csvRowData.get(TrackCsvColumnEnum.TRACKWAY.name).strip().upper() except Exception: self._writeError({ 'message':'Missing trackway', 'data':csvRowData, 'index':csvIndex }) return False # If the trackway contains an ignore pattern then return without creating the track. # This is used for tracks in the record that are actually under-prints from a higher # level recorded in the spreadsheet only for catalog reference. testIndexes = [ test.find(self._UNDERPRINT_IGNORE_TRACKWAY_STR), test.find(self._OVERPRINT_IGNORE_TRACKWAY_STR) ] testParensIndex = test.find('(') for testIndex in testIndexes: if testIndex != -1 and (testParensIndex == -1 or testParensIndex > testIndex): return False result = self._TRACKWAY_PATTERN.search(test) try: t.trackwayType = result.groupdict()['type'].upper().strip() t.trackwayNumber = result.groupdict()['number'].upper().strip() except Exception: self._writeError({ 'message':'Invalid trackway value: %s' % test, 'data':csvRowData, 'result':result, 'match':result.groupdict() if result else 'N/A', 'index':csvIndex }) return False #------------------------------------------------------------------------------------------- # NAME # Parse the name value into left, pes, and number attributes try: t.name = csvRowData.get(TrackCsvColumnEnum.TRACK_NAME.name).strip() except Exception: self._writeError({ 'message':'Missing track name', 'data':csvRowData, 'index':csvIndex }) return False #------------------------------------------------------------------------------------------- # YEAR try: year = csvRowData.get(TrackCsvColumnEnum.MEASURED_DATE.name) if not year: year = '2014' else: try: y = StringUtils.toText(year).split(';')[-1].strip().replace( '/', '_').replace( ' ', '').replace( '-', '_').split('_')[-1] year = int(re.compile('[^0-9]+').sub('', y)) except Exception: year = 2014 if year > 2999: # When multiple year entries combine into a single large number year = int(StringUtils.toUnicode(year)[-4:]) elif year < 2000: # When two digit years (e.g. 09) are used instead of four digit years year += 2000 year = StringUtils.toUnicode(year) t.year = year except Exception: self._writeError({ 'message':'Missing cast date', 'data':csvRowData, 'index':csvIndex }) return False #------------------------------------------------------------------------------------------- # FIND EXISTING # Use data set above to attempt to load the track database entry fingerprint = t.fingerprint for uid, fp in DictUtils.iter(self.remainingTracks): # Remove the fingerprint from the list of fingerprints found in the database, which at # the end will leave only those fingerprints that exist in the database but were not # touched by the importer. These values can be used to identify tracks that should # have been "touched" but were not. if fp == fingerprint: del self.remainingTracks[uid] break existing = t.findExistingTracks(session) if existing and not isinstance(existing, Tracks_Track): existing = existing[0] if fingerprint in self.fingerprints: if not existing: existing = self.fingerprints[fingerprint] self._writeError({ 'message':'Ambiguous track entry "%s" [%s -> %s]' % ( fingerprint, csvIndex, existing.index), 'data':csvRowData, 'existing':existing, 'index':csvIndex }) return False self.fingerprints[fingerprint] = t if existing: t = existing else: session.add(t) session.flush() TCCE = TrackCsvColumnEnum IFE = ImportFlagsEnum #------------------------------------------------------------------------------------------- # CSV PROPERTY CLEANUP # Cleanup and format additional CSV values before saving the csv data to the track's # snapshot. removeNonColumns = [ TrackCsvColumnEnum.PRESERVED.name, TrackCsvColumnEnum.CAST.name, TrackCsvColumnEnum.OUTLINE_DRAWING.name] for columnName in removeNonColumns: if columnName in csvRowData: testValue = StringUtils.toText(csvRowData[columnName]).strip().upper() if testValue.startswith('NON'): del csvRowData[columnName] # Create a snapshot that only includes a subset of properties that are flagged to be # included in the database snapshot entry snapshot = dict() for column in Reflection.getReflectionList(TrackCsvColumnEnum): # Include only values that are marked in the enumeration as to be included if not column.snapshot or column.name not in csvRowData: continue value = csvRowData.get(column.name) if value is None: continue elif not value is StringUtils.isStringType(value): value = StringUtils.toText(value) value = StringUtils.toText(value).strip() if value in ['-', b'\xd0'.decode(b'MacRoman')]: continue snapshot[column.name] = value #------------------------------------------------------------------------------------------- # WIDTH # Parse the width into a numerical value and assign appropriate default uncertainty try: t.widthMeasured = 0.01*float(self._collapseManusPesProperty( t, csvRowData, TCCE.PES_WIDTH, TCCE.PES_WIDTH_GUESS, TCCE.MANUS_WIDTH, TCCE.MANUS_WIDTH_GUESS, '0', IFE.HIGH_WIDTH_UNCERTAINTY, IFE.NO_WIDTH )) t.widthMeasured = t.widthMeasured if not existing or t.widthUncertainty == 0: t.widthUncertainty = 0.05 if (t.importFlags & IFE.HIGH_WIDTH_UNCERTAINTY) else 0.03 except Exception as err: print(Logger().echoError('WIDTH PARSE ERROR:', err)) self._writeError({ 'message':'Width parse error', 'data':csvRowData, 'error':err, 'index':csvIndex }) t.widthMeasured = 0.0 if not existing: t.widthUncertainty = 0.05 #------------------------------------------------------------------------------------------- # LENGTH # Parse the length into a numerical value and assign appropriate default uncertainty try: t.lengthMeasured = 0.01*float(self._collapseManusPesProperty( t, csvRowData, TCCE.PES_LENGTH, TCCE.PES_LENGTH_GUESS, TCCE.MANUS_LENGTH, TCCE.MANUS_LENGTH_GUESS, '0', IFE.HIGH_LENGTH_UNCERTAINTY, IFE.NO_LENGTH )) t.lengthMeasured = t.lengthMeasured if not existing or t.lengthUncertainty == 0: t.lengthUncertainty = 0.05 if (t.importFlags & IFE.HIGH_LENGTH_UNCERTAINTY) else 0.03 except Exception as err: print(Logger().echoError('LENGTH PARSE ERROR:', err)) self._writeError({ 'message':'Length parse error', 'data':csvRowData, 'error':err, 'index':csvIndex }) t.lengthMeasured = 0.0 if not existing: t.lengthUncertainty = 0.05 #------------------------------------------------------------------------------------------- # DEPTH # Parse the depth into a numerical value and assign appropriate default uncertainty try: t.depthMeasured = 0.01*float(self._collapseManusPesProperty( t, csvRowData, TCCE.PES_DEPTH, TCCE.PES_DEPTH_GUESS, TCCE.MANUS_DEPTH, TCCE.MANUS_DEPTH_GUESS, '0', IFE.HIGH_DEPTH_UNCERTAINTY, 0 )) if not existing or t.depthUncertainty == 0: t.depthUncertainty = 0.05 if (t.importFlags & IFE.HIGH_DEPTH_UNCERTAINTY) else 0.03 except Exception as err: print(Logger().echoError('DEPTH PARSE ERROR:', err)) t.depthMeasured = 0.0 if not existing: t.depthUncertainty = 0.05 #------------------------------------------------------------------------------------------- # ROTATION # Parse the rotation into a numerical value and assign appropriate default uncertainty try: t.rotationMeasured = float(self._collapseLimbProperty( t, csvRowData, TCCE.LEFT_PES_ROTATION, TCCE.LEFT_PES_ROTATION_GUESS, TCCE.RIGHT_PES_ROTATION, TCCE.RIGHT_PES_ROTATION_GUESS, TCCE.LEFT_MANUS_ROTATION, TCCE.LEFT_MANUS_ROTATION_GUESS, TCCE.RIGHT_MANUS_ROTATION, TCCE.RIGHT_MANUS_ROTATION_GUESS, '0', IFE.HIGH_ROTATION_UNCERTAINTY, 0 )) if not existing or t.rotationUncertainty == 0: t.rotationUncertainty = \ 10.0 if (t.importFlags & IFE.HIGH_ROTATION_UNCERTAINTY) else 45.0 except Exception as err: print(Logger().echoError('ROTATION PARSE ERROR:', err)) self._writeError({ 'message':'Rotation parse error', 'error':err, 'data':csvRowData, 'index':csvIndex }) t.rotationMeasured = 0.0 if not existing: t.rotationUncertainty = 45.0 #------------------------------------------------------------------------------------------- # STRIDE try: strideLength = self._collapseManusPesProperty( t, csvRowData, TCCE.PES_STRIDE, TCCE.PES_STRIDE_GUESS, TCCE.MANUS_STRIDE, TCCE.MANUS_STRIDE_GUESS, None, IFE.HIGH_STRIDE_UNCERTAINTY ) strideFactor = self._collapseManusPesProperty( t, csvRowData, TCCE.PES_STRIDE_FACTOR, None, TCCE.MANUS_STRIDE_FACTOR, None, 1.0) if strideLength: snapshot[SnapshotDataEnum.STRIDE_LENGTH] = 0.01*float(strideLength)*float(strideFactor) except Exception as err: print(Logger().echoError('STRIDE PARSE ERROR:', err)) #------------------------------------------------------------------------------------------- # WIDTH ANGULATION PATTERN try: widthAngulation = self._collapseManusPesProperty( t, csvRowData, TCCE.WIDTH_PES_ANGULATION_PATTERN, TCCE.WIDTH_PES_ANGULATION_PATTERN_GUESS, TCCE.WIDTH_MANUS_ANGULATION_PATTERN, TCCE.WIDTH_MANUS_ANGULATION_PATTERN_GUESS, None, IFE.HIGH_WIDTH_ANGULATION_UNCERTAINTY ) if widthAngulation: snapshot[SnapshotDataEnum.WIDTH_ANGULATION_PATTERN] = 0.01*float(widthAngulation) except Exception as err: print(Logger().echoError('WIDTH ANGULATION PARSE ERROR:', err)) #------------------------------------------------------------------------------------------- # PACE try: pace = self._collapseLimbProperty( t, csvRowData, TCCE.LEFT_PES_PACE, TCCE.LEFT_PES_PACE_GUESS, TCCE.RIGHT_PES_PACE, TCCE.RIGHT_PES_PACE_GUESS, TCCE.LEFT_MANUS_PACE, TCCE.LEFT_MANUS_PACE_GUESS, TCCE.RIGHT_MANUS_PACE, TCCE.RIGHT_MANUS_PACE_GUESS, None, IFE.HIGH_PACE_UNCERTAINTY ) if pace: snapshot[SnapshotDataEnum.PACE] = 0.01*float(pace) except Exception as err: print(Logger().echoError('PACE PARSE ERROR:', err)) #------------------------------------------------------------------------------------------- # PACE ANGULATION PATTERN try: paceAngulation = self._collapseManusPesProperty( t, csvRowData, TCCE.PES_PACE_ANGULATION, TCCE.PES_PACE_ANGULATION_GUESS, TCCE.MANUS_PACE_ANGULATION, TCCE.MANUS_PACE_ANGULATION_GUESS, None, IFE.HIGH_WIDTH_ANGULATION_UNCERTAINTY ) if paceAngulation: snapshot[SnapshotDataEnum.PACE_ANGULATION_PATTERN] = float(paceAngulation) except Exception as err: print(Logger().echoError('PACE ANGULATION PARSE ERROR:', err)) #------------------------------------------------------------------------------------------- # PROGRESSION try: progression = self._collapseLimbProperty( t, csvRowData, TCCE.LEFT_PES_PROGRESSION, TCCE.LEFT_PES_PROGRESSION_GUESS, TCCE.RIGHT_PES_PROGRESSION, TCCE.RIGHT_PES_PROGRESSION_GUESS, TCCE.LEFT_MANUS_PROGRESSION, TCCE.LEFT_MANUS_PROGRESSION_GUESS, TCCE.RIGHT_MANUS_PROGRESSION, TCCE.RIGHT_MANUS_PROGRESSION_GUESS, None, IFE.HIGH_PROGRESSION_UNCERTAINTY ) if progression: snapshot[SnapshotDataEnum.PROGRESSION] = 0.01*float(progression) except Exception as err: print(Logger().echoError('PROGRESSION PARSE ERROR:', err)) #------------------------------------------------------------------------------------------- # GLENO-ACETABULAR DISTANCE try: gad = self._collapseGuessProperty( t, csvRowData, TCCE.GLENO_ACETABULAR_DISTANCE, TCCE.GLENO_ACETABULAR_DISTANCE_GUESS, None, IFE.HIGH_GLENO_ACETABULAR_UNCERTAINTY ) if gad: snapshot[SnapshotDataEnum.GLENO_ACETABULAR_LENGTH] = 0.01*float(gad) except Exception as err: print(Logger().echoError('GLENO-ACETABULAR DISTANCE PARSE ERROR:', err)) # Save the snapshot try: t.snapshot = JSON.asString(snapshot) except Exception: raise if TrackCsvColumnEnum.MEASURED_BY.name not in snapshot: # Mark entries that have no field measurements with a flag for future reference t.importFlags |= ImportFlagsEnum.NO_FIELD_MEASUREMENTS if existing: self.modified.append(t) else: self.created.append(t) return t #_______________________________________________________________________________ def _writeError(self, data): """ Writes import error data to the logger, formatting it for human readable display. """ source = {} if 'data' in data: for n,v in DictUtils.iter(data['data']): source[' '.join(n.split('_')).title()] = v indexPrefix = '' if 'index' in data: indexPrefix = ' [INDEX: %s]:' % data.get('index', 'Unknown') result = [ 'IMPORT ERROR%s: %s' % (indexPrefix, data['message']), 'DATA: ' + DictUtils.prettyPrint(source)] if 'existing' in data: source = {} snapshot = data['existing'].snapshot if snapshot: snapshot = JSON.fromString(snapshot) if snapshot: for n,v in DictUtils.iter(snapshot): source[' '.join(n.split('_')).title()] = v result.append('CONFLICT: ' + DictUtils.prettyPrint(source)) if 'error' in data: self._logger.writeError(result, data['error']) else: self._logger.write(result) #_______________________________________________________________________________ @classmethod def _getStrippedValue(cls, value): try: return value.strip() except Exception: return value #_______________________________________________________________________________ @classmethod def _getStrippedRowData(cls, source, trackCsvEnum): out = source.get(trackCsvEnum.name) try: return out.strip() except Exception: return out #_______________________________________________________________________________ @classmethod def _collapseManusPesProperty( cls, track, csvRowData, pesEnum, pesGuessEnum, manusEnum, manusGuessEnum, defaultValue, guessFlag =0, missingFlag =0 ): if track.pes: return cls._collapseGuessProperty( track=track, csvRowData=csvRowData, regularPropertyEnum=pesEnum, guessPropertyEnum=pesGuessEnum, defaultValue=defaultValue, guessFlag=guessFlag, missingFlag=missingFlag) else: return cls._collapseGuessProperty( track=track, csvRowData=csvRowData, regularPropertyEnum=manusEnum, guessPropertyEnum=manusGuessEnum, defaultValue=defaultValue, guessFlag=guessFlag, missingFlag=missingFlag) #_______________________________________________________________________________ @classmethod def _collapseLimbProperty( cls, track, csvRowData, lpEnum, lpGuessEnum, rpEnum, rpGuessEnum, lmEnum, lmGuessEnum, rmEnum, rmGuessEnum, defaultValue, guessFlag =0, missingFlag =0 ): if track.pes and track.left: return cls._collapseGuessProperty( track, csvRowData, lpEnum, lpGuessEnum, defaultValue, guessFlag, missingFlag) elif track.pes and not track.left: return cls._collapseGuessProperty( track, csvRowData, rpEnum, rpGuessEnum, defaultValue, guessFlag, missingFlag) elif not track.pes and track.left: return cls._collapseGuessProperty( track, csvRowData, lmEnum, lmGuessEnum, defaultValue, guessFlag, missingFlag) elif not track.pes and not track.left: return cls._collapseGuessProperty( track, csvRowData, rmEnum, rmGuessEnum, defaultValue, guessFlag, missingFlag) else: return None #_______________________________________________________________________________ @classmethod def _collapseGuessProperty( cls, track, csvRowData, regularPropertyEnum, guessPropertyEnum, defaultValue, guessFlag =0, missingFlag =0 ): value = cls._getStrippedRowData(csvRowData, regularPropertyEnum) if guessPropertyEnum: valueGuess = cls._getStrippedRowData(csvRowData, guessPropertyEnum) else: valueGuess = None if not value: if not valueGuess: track.importFlags |= (missingFlag & guessFlag) return defaultValue track.importFlags |= guessFlag return valueGuess return value #=============================================================================== # I N T R I N S I C #_______________________________________________________________________________ def __repr__(self): return self.__str__() #_______________________________________________________________________________ def __unicode__(self): return StringUtils.toUnicode(self.__str__()) #_______________________________________________________________________________ def __str__(self): return '<%s>' % self.__class__.__name__
class WidgetUiCompiler(object): """A class for...""" #=================================================================================================== # C L A S S _CLASS_NAME_RE = re.compile('(?<=class )(?P<classname>[a-zA-z0-9_]+)(?=\()') _SETUP_UI_RE = re.compile('(?<=def setupUi\(self, )(?P<parentName>[a-zA-z0-9_\-]+)(?=\):)') _RETRANSLATE_RE = re.compile( '(?<=def retranslateUi\(self, )(?P<parentName>[a-zA-z0-9_\-]+)(?=\):)' ) _SELF_RE = re.compile('(?P<self>self\.)(?!retranslateUi\()') #___________________________________________________________________________________________________ __init__ def __init__(self, rootPath =None, recursive =True, **kwargs): """Creates a new instance of WidgetUiCompiler.""" self._log = Logger(self) self._verbose = ArgsUtils.get('verbose', False, kwargs) self._recursive = recursive self._pythonPath = os.path.normpath(sys.exec_prefix) if rootPath and os.path.isabs(rootPath): self._rootPath = FileUtils.cleanupPath(rootPath, isDir=True) elif rootPath: parts = rootPath.split(os.sep if rootPath.find(os.sep) != -1 else '/') self._rootPath = PyGlassEnvironment.getRootResourcePath(*parts, isDir=True) else: self._rootPath = PyGlassEnvironment.getRootResourcePath() #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ run def run(self): """Doc...""" arg = dict() if self._recursive: os.path.walk(self._rootPath, self._compileInFolder, arg) else: self._compileInFolder(arg, self._rootPath, os.listdir(self._rootPath)) #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _compileInFolder def _compileInFolder(self, arg, dirname, names): for name in names: if not name.endswith('.ui'): continue self._compileUiFile(dirname, name) #___________________________________________________________________________________________________ _compileUiFile def _compileUiFile(self, path, filename): """Doc...""" source = FileUtils.createPath(path, filename, isFile=True) if self._verbose: self._log.write('COMPILING: ' + source) if PyGlassEnvironment.isWindows: uicCommand = FileUtils.createPath(self._pythonPath, 'Scripts', 'pyside-uic.exe') else: uicCommand = 'pyside-uic' cmd = '%s %s' % (uicCommand, source) pipe = subprocess.Popen( cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, error = pipe.communicate() if pipe.returncode or error: self._log.write('ERROR: Failed to compile %s widget: %s' % (str(source), str(error))) return False res = WidgetUiCompiler._CLASS_NAME_RE.search(out) if not res: self._log.write('ERROR: Failed to find widget class name for ' + str(source)) return False out = WidgetUiCompiler._CLASS_NAME_RE.sub('PySideUiFileSetup', out, 1) res = WidgetUiCompiler._SETUP_UI_RE.search(out) if not res: self._log.write('ERROR: Failed to find widget setupUi method for ' + str(source)) return False targetName = res.groupdict().get('parentName') out = WidgetUiCompiler._SETUP_UI_RE.sub('\g<parentName>', out, 1) res = WidgetUiCompiler._RETRANSLATE_RE.search(out) if not res: self._log.write('ERROR: Failed to find widget retranslateUi method for ' + str(source)) return False out = WidgetUiCompiler._RETRANSLATE_RE.sub('\g<parentName>', out, 1) if isinstance(out, unicode): out = out.encode('utf8', 'ignore') out = WidgetUiCompiler._SELF_RE.sub(targetName + '.', out) dest = FileUtils.createPath(path, filename[:-3] + '.py', isFile=True) if os.path.exists(dest): os.remove(dest) f = open(dest, 'w+') f.write(out) f.close() py_compile.compile(dest) return True #=================================================================================================== # I N T R I N S I C #___________________________________________________________________________________________________ __repr__ def __repr__(self): return self.__str__() #___________________________________________________________________________________________________ __unicode__ def __unicode__(self): return unicode(self.__str__()) #___________________________________________________________________________________________________ __str__ def __str__(self): return '<%s>' % self.__class__.__name__
class DataFormatConverter(object): """A class for converting between various data interchange formats, e.g. XML and JSON.""" #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self): """Creates a new instance of ClassTemplate.""" self._type = None self._src = None self._log = Logger('DataFormatConverter') self._path = None #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: propertyName @property def source(self): return self._src #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ load def load(self, path, fileType): if not os.path.exists(path): self._log.write('ERROR: Path does not exist [%s]. Unable to load.' % path) return False try: fh = codecs.open(path, 'r', 'utf-8') res = fh.read() fh.close() enc = res.encode('utf-8') self.loads(enc, fileType) except Exception as err: self._log.writeError('Failed to load source file [%s].' % path, err) return False self._path = path return True #___________________________________________________________________________________________________ load def loads(self, srcString, srcType): if srcString is None: self._log.write('ERROR: Source string is empty or invalid.') return False srcString = StringUtils.toStr2(srcString) self._path = None self._src = srcString self._type = srcType return True #___________________________________________________________________________________________________ convertDirectory def convertDirectory(self, path, srcType, targetType, recursive =False): if srcType is None or targetType is None: self._log.write('ERROR: Source and/or target types are invalid. Operation aborted.') return False if not os.path.exists(path): self._log.write('ERROR: The specified path [%s] does not exist. Operation aborted.' \ % str(path)) return False if recursive: FileUtils.walkPath(path, self._convertInDirectory, [srcType, targetType]) else: self._convertInDirectory([srcType, targetType], path, os.listdir(path)) return True #___________________________________________________________________________________________________ writeToFile def writeToFile(self, targetType, path =None): if path is None and self._path is None: self._log.write('ERROR: Unable to write to file, no path was specified.') return False # Assign the reader based on source type reader = self._getParserFromType() if reader is None: self._log.write('ERROR: Unrecognized source type [%s]. Unable to convert.' % self._type) return False # Assign writer based on target type writer = self._getParserFromType(targetType) if writer is None: self._log.write('ERROR: Unrecognized conversion target type [%s]. Unable to convert.' \ % targetType) return False path = path if path else self._path d = os.path.dirname(path) f = os.path.basename(path).split('.')[0] f += '.' + writer.TYPE_ID if not os.path.exists(d): os.makedirs(d) try: print(len(self._src)) src = reader.parse(self._src, None, True) except Exception as err: self._log.writeError('ERROR: Failed to parse source. Conversion aborted.', err) return False try: res = writer.serialize(src) except Exception as err: self._log.writeError('ERROR: Failed to serialized data. Conversion aborted.', err) return False out = os.path.join(d, f) try: fh = codecs.open(out, 'wb', 'utf-8') fh.write(res) fh.close() except Exception as err: self._log.writeError('ERROR: Failed to write file [%s]. Conversion aborted.' \ % str(out), err) return False self._log.write('Converted: [%s] => [%s].' % (self._path, out)) return True #___________________________________________________________________________________________________ getAsXML def getAsXML(self): """Doc...""" if self._type == XMLConfigParser.TYPE_ID: return self._src else: return self._convert(XMLConfigParser.TYPE_ID) #___________________________________________________________________________________________________ getAsJSON def getAsJSON(self): """Doc...""" if self._type == JSONConfigParser.TYPE_ID: return self._src else: return self._convert(JSONConfigParser.TYPE_ID) #___________________________________________________________________________________________________ getAsDictionary def getAsDictionary(self, asInterchangeFormat =False): reader = self._getParserFromType() reader.parse(self._src, None, asInterchangeFormat) #___________________________________________________________________________________________________ executeConversion @staticmethod def executeConversion(source =None, srcType =None, targetType =None, target =None, recursive =False): types = ['xml', 'json'] if source is None: source = queryGeneralValue('Enter the source file (or path) to convert:') if srcType is None and os.path.isfile(source): fileType = source.split('.')[-1].lower() if fileType in types: srcType = fileType if srcType is None: srcType = queryFromList('Specify source file(s) type:', types) if targetType is None: targetType = queryFromList('Specify target file(s) type:', types) d = DataFormatConverter() if os.path.isfile(source): d.load(source, srcType) d.writeToFile(targetType, target) else: d.convertDirectory(source, srcType, targetType, recursive) #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _convert def _convert(self, targetType): reader = self._getParserFromType() data = reader.parse(self._src, None, True) if data is None: self._log.write('ERROR: Failed to parse input from. Skipping conversion.') return None writer = self._getParserFromType(targetType) return writer.serialize(data) #___________________________________________________________________________________________________ _getParserFromType def _getParserFromType(self, typeID =None): if typeID is None: typeID = self._type if typeID == XMLConfigParser.TYPE_ID: return XMLConfigParser elif typeID == JSONConfigParser.TYPE_ID: return JSONConfigParser else: self._log.write('ERROR: _getParserFromType() failed for type: ' + str(typeID)) return None #___________________________________________________________________________________________________ _convertInDirectory def _convertInDirectory(self, types, dirname, names): if dirname.find('.svn') != -1: return reader = self._getParserFromType(types[0]) writer = self._getParserFromType(types[1]) for n in names: if not n.endswith(reader.TYPE_ID): continue src = os.path.join(dirname, n) self.load(src, reader.TYPE_ID) self.writeToFile(writer.TYPE_ID)
def populateTrackwaysTable(cls, session =None, logger =None): """ Populate the trackways table by removing all existing rows and attempting to calculate trackways from the implicit track series defined by the linkages of tracks. This operation should only be carried out for initial population purposes as it will dispose of all existing data and changes made by users. """ from cadence.models.tracks.Tracks_Track import Tracks_Track from cadence.models.tracks.Tracks_SiteMap import Tracks_SiteMap missingSitemaps = [] sitemapModel = Tracks_SiteMap.MASTER trackModel = Tracks_Track.MASTER model = cls.MASTER if not logger: logger = Logger(cls, printOut=True) newSession = False if not session: newSession = True session = model.createSession() # Get all tracks that have no next (end of a track series) endTracks = session.query(trackModel).filter( trackModel.next == '').all() index = 0 trackways = dict() tested = [] for track in endTracks: if track in tested or track.hidden: # Skip tracks that have already been tested or are hidden continue prev = track while prev: tested.append(prev) t = prev.getPreviousTrack() if not t: break prev = t if not prev: continue name = prev.trackwayFingerprint sitemapStamp = '%s-%s' % (prev.site, prev.level) if sitemapStamp in missingSitemaps: # Ignore the trackway if there's no sitemap to support it continue if name in trackways: tw = trackways[name] else: # If the trackway name isn't in the list of existing trackways, # create a new trackway model instance for that trackway tw = Tracks_Trackway() tw.index = index tw.name = name sitemap = session.query(sitemapModel).filter( sitemapModel.name == prev.site).filter( sitemapModel.level == prev.level).first() if not sitemap: missingSitemaps.append(sitemapStamp) logger.write( '[WARNING]: No site map found for "%s" level "%s"' % ( prev.site, prev.level)) else: tw.siteMapIndex = sitemap.index index += 1 trackways[tw.name] = tw if prev.left and prev.pes: existing = tw.firstLeftPes tw.firstLeftPes = prev.uid elif prev.left: existing = tw.firstLeftManus tw.firstLeftManus = prev.uid elif prev.pes: existing = tw.firstRightPes tw.firstRightPes = prev.uid else: existing = tw.firstRightManus tw.firstRightManus = prev.uid if existing and existing != prev.uid: logger.write([ '[WARNING]: Duplicate tracks found for the same series', 'TRACKS: "%s" AND "%s"' % (existing, prev.uid), 'TRACKWAY: %s' % tw.name]) # Delete all existing rows if any exist rowCount = session.query(model).count() if rowCount > 0: session.query(model).delete() # Add the new trackways entries to the session for fingerprint, trackway in trackways.items(): session.add(trackway) if newSession: session.commit() session.close()
class IncludeCompressor(object): #=================================================================================================== # C L A S S _REMOVE_COMMENT_RE = re.compile('/\*.+\*/', re.DOTALL) _REMOVE_COMMENT_LINE_RE = re.compile('(^|\n)[\s\t]*//.+(\n|$)') JS_TYPE = 'js' CSS_TYPE = 'css' #___________________________________________________________________________________________________ __init__ def __init__(self, compileCoffee =False): self._log = Logger('IncludeCompressor') self._compileCoffee = compileCoffee #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ compress def compress(self, rootPath): if not self._fileExists(rootPath): return False elif os.path.isfile(rootPath): return self.compressFile(rootPath) else: return self.compressPath(rootPath) #___________________________________________________________________________________________________ compressFile def compressFile(self, rootPath, directory =None): if not self._fileExists(rootPath): return False if self._compileCoffee: try: from pyaid.web.coffeescript.CoffeescriptBuilder import CoffeescriptBuilder CoffeescriptBuilder.compileAllOnPath(rootPath, os.path.dirname(rootPath), True) self._log.write('Coffeescript compiled.') except Exception as err: self._log.writeError('Failed to compile coffeescript file.', err) return False return self._compressFile(rootPath, directory) #___________________________________________________________________________________________________ compressPath def compressPath(self, rootPath): # First compile any coffee scripts to js files if self._compileCoffee: try: from pyaid.web.coffeescript.CoffeescriptBuilder import CoffeescriptBuilder CoffeescriptBuilder.compileAllOnPath(rootPath, rootPath, True) self._log.write('Coffee scripts compiled.') except Exception as err: self._log.writeError('Failed to compile coffeescript files.', err) return False FileUtils.walkPath(rootPath, self._compressInFolder, None) self._log.write('Compression operation complete.') return True #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _fileExists def _fileExists(self, rootPath): if not os.path.exists(rootPath): self._log.write('ERROR: [%s] does not exist. Operation aborted.' % rootPath) return False return True #___________________________________________________________________________________________________ _compressFile def _compressFile(self, target, directory): # Skip compiled files. if target.endswith('comp.js') or target.endswith('comp.css'): return False if target.endswith('.js'): fileType = IncludeCompressor.JS_TYPE elif target.endswith('.css'): fileType = IncludeCompressor.CSS_TYPE else: return False if not directory: directory = '' if not directory.endswith(os.sep) and not target.startswith(os.sep): directory += os.sep inFile = directory + target tempFile = directory + target + '.temp' try: fh = open(inFile, 'r') fileString = fh.read() fh.close() except Exception as err: self._log.writeError('FAILED: Unable to read ' + str(inFile), err) return False if fileType == IncludeCompressor.CSS_TYPE: fileString = fileString.replace('@charset "utf-8";', '') ofn = (target[0:-3] + 'comp.css') else: ofn = (target[0:-2] + 'comp.js') try: fh = open(tempFile, 'w') fh.write(fileString) fh.close() except Exception as err: self._log.writeError('FAILED: Unable to write temp file ' + str(tempFile), err) return False outFile = directory + '/' + ofn cmd = ['minify', '"%s"' % tempFile, '"%s"' % outFile] result = SystemUtils.executeCommand(cmd) if result['code']: self._log.write('FAILED: Unable to compress ' + str(inFile)) if os.path.exists(tempFile): os.remove(tempFile) if not os.path.exists(outFile): self._log.write('FAILED: ' + target + ' -> ' + ofn) return False elif fileType == IncludeCompressor.JS_TYPE: f = open(outFile, 'r') compressed = f.read() f.close() compressed = IncludeCompressor._REMOVE_COMMENT_RE.sub('', compressed) compressed = IncludeCompressor._REMOVE_COMMENT_LINE_RE.sub('', compressed) f = open(outFile, 'w') f.write(compressed.strip()) f.close() inSize = SizeUnits.SizeConversion.bytesToKilobytes(inFile, 2) outSize = SizeUnits.SizeConversion.bytesToKilobytes(outFile, 2) saved = SizeUnits.SizeConversion.convertDelta( inSize, outSize, SizeUnits.SIZES.KILOBYTES, 2) self._log.write( 'Compressed[%s]: %s -> %s [%sKB -> %sKB | Saved: %sKB]' % ( fileType, target, ofn, inSize, outSize, saved)) return True #___________________________________________________________________________________________________ _compressInFolder def _compressInFolder(self, dumb, directory, names): if directory.find('.svn') != -1: return for fn in names: self._compressFile(fn, directory)
class CoffeescriptBuilder(object): """A class for...""" CLASS_PATTERN = '^[\s\t]*class[\s\t]+(?P<class>[^\s\t\r\n]+)[\s\t]*' MISSING_CLASS_PATTERN = '[\s\t\(\[\{\!]+(?=[A-Z])(?P<class>[A-Za-z0-9_]+)(?P<next>[^A-Za-z0-9_]+)' _WARN_ID_MISSING_IMPORT = 'MISSING-IMPORT' _GLOBAL_CLASSES = [ 'SFLOW', 'PAGE', 'FB', 'Math', 'JSON', 'String', 'ActiveXObject', 'Date', 'DOMParser', 'RegExp', 'Object', 'Number', 'Array', 'Function', 'XMLHttpRequest' ] _results = None _missing = None #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self, targetPackageOrPath, rootPath, verbose=True, debug=False, trace=False, force=False, compress=False, buildOnly=False): """Creates a new instance of CoffeescriptBuilder.""" self.buildOnly = buildOnly self._imports = dict() self._requires = dict() self._includes = dict() self._report = dict() self._warnings = [] self._dependencyReport = dict() self._verbose = verbose self._log = Logger(self, printOut=True) self._trace = trace self._debug = debug self._targets = [] self._force = force self._compress = compress self._rootPath = rootPath if not isinstance(targetPackageOrPath, CoffeescriptDependency): target = CoffeescriptDependency(targetPackageOrPath, rootPath, None) else: target = targetPackageOrPath if target.exists: self._targets.append(target) else: csFiles = CoffeescriptBuilder.getScriptsInPath(target.packagePath) # Look for exec matches first for f in csFiles: testTarget = CoffeescriptDependency(f, rootPath, None) if testTarget.isExec: self._targets.append(testTarget) # Look for lib matches second. Lib matches are tested as a second pass because # constructing all exec files first potentially optimizes the import process for # the libraries. for f in csFiles: testTarget = CoffeescriptDependency(f, rootPath, None) if testTarget.isLib: self._targets.append(testTarget) if len(self._targets) == 0: print('\n\n') self._log.write('No targets exist for: %s. Compilation aborted.' % targetPackageOrPath) print('\n') #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: report @property def report(self): return self._report #___________________________________________________________________________________________________ GS: warnings @property def warnings(self): return self._warnings #___________________________________________________________________________________________________ GS: imports @property def imports(self): return self._imports #___________________________________________________________________________________________________ GS: requires @property def requires(self): return self._requires #___________________________________________________________________________________________________ GS: includes @property def includes(self): return self._includes #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ construct def construct(self): """Doc...""" for t in self._targets: self._report[t.package] = -1 if t.isLib: self._constructLibrary(t) else: self._constructTarget(t) if self._compress: print('COMPRESSING:', t.package) from pyaid.web.coffeescript.IncludeCompressor import IncludeCompressor ic = IncludeCompressor() if not ic.compressFile(t.compiledPath): print('COMPRESSION FAILURE:', t.compiledPath) return self._targets #___________________________________________________________________________________________________ compileAllOnPath @staticmethod def compileAllOnPath(path, rootPath=None, recursive=False, debug=False, trace=False, force=False, compress=False): CoffeescriptBuilder._results = '' CoffeescriptBuilder._missing = {} if recursive: print('RECURSIVE COMPILE AT: ' + path) def walker(paths, dirName, names): out = CoffeescriptBuilder._compileAllInDirectory( os.path.join(paths[0], dirName), paths[1], debug=debug, trace=trace, force=force, compress=compress) CoffeescriptBuilder._results += out['res'] for n, v in DictUtils.iter(out['missing']): if n in CoffeescriptBuilder._missing: continue CoffeescriptBuilder._missing[n] = v FileUtils.walkPath(path, walker, [path, rootPath]) print('\n\nCOMPILATION RESULTS:' + CoffeescriptBuilder._results) if CoffeescriptBuilder._missing: print('\n\nMISSING IMPORTS:' + '\n\n') for n, v in DictUtils.iter(CoffeescriptBuilder._missing): print(v['class'] + ' [LINE: #' + str(v['line']) + ' | ' + v['package'] + ']') else: print('COMPILING DIRECTORY: ' + path) CoffeescriptBuilder._compileAllInDirectory(path, rootPath, debug=debug, trace=trace, force=force, compress=compress) #___________________________________________________________________________________________________ getScriptsInPath @staticmethod def getScriptsInPath(path): files = [] for f in os.listdir(path): if f.lower().endswith('.' + CoffeescriptDependency.EXTENSION): files.append(os.path.join(path, f)) return files #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _constructLibrary def _constructLibrary(self, target): try: if self._verbose: print("\n\n" + ('-' * 100) + '\n') self._log.add('LIBRARY: %s\n\tsource: %s\n\troot: %s' % (target.package, target.path, target.rootPath)) #--------------------------------------------------------------------------------------- # Compile all includes using library data targets, imports, modules, includes = self._getLibraryData(target) # Process requires for all of the targets for t in (targets + imports + modules): self._processRequires(t) #--------------------------------------------------------------------------------------- # IMPORTS # Compile all excludes skipping any exec or lib files that are listed in the import # statements. importExcludes = [] for t in targets: for imp in self._imports[t.package]: if not (imp.isExec or imp.isLib or imp.isInList(importExcludes)): importExcludes.append(imp) # Compile all imports needed for the library. Any excludes are added to the shared # library to be made accessible via the VIZME registry. libImports = [] sharedImports = [] for t in (imports + modules): for imp in self.imports[t.package]: if not imp.isInList(libImports): if imp.isInList(importExcludes): if not imp.isInList(sharedImports): sharedImports.append(imp) else: libImports.append(imp) libImports.append(target) #--------------------------------------------------------------------------------------- # INCLUDES # Compile all includes to exclude from the library because they already exist in a # target. includeExcludes = [] for t in targets: for inc in self._includes[t.package]: if not inc.isInList(includeExcludes): includeExcludes.append(inc) # Compile all includes needed for the library. libIncludes = [] sharedIncludes = [] # Add the top-level includes directly because they are not handled implicitly like # the import case for inc in includes: if inc.isInList(includeExcludes): sharedIncludes.append(inc) else: libIncludes.append(inc) for t in (imports + modules): for inc in self.includes[t.package]: if not inc.isInList(libIncludes): if inc.isInList(includeExcludes): if not inc.isInList(sharedIncludes): sharedIncludes.append(inc) else: libIncludes.append(inc) if self._verbose: print('\n') s = 'IMPORTING:' for imp in libImports: s += '\n\t' + imp.package for inc in libIncludes: s += '\n\tEXTERNAL: ' + inc.package self._log.add(s) print('\n') s = 'EXCLUDING:' for imp in sharedImports: s += '\n\t' + imp.package for inc in sharedIncludes: s += '\n\tEXTERNAL: ' + inc.package self._log.add(s) #--------------------------------------------------------------------------------------- # Construct intermediate compilation file. assembledFile = self._assembleFile(target, libImports, sharedImports, {'modules': modules}) if assembledFile is None: self._log.write('ERROR: File assembly failed.') return #--------------------------------------------------------------------------------------- # Compile to Javascript if not self.buildOnly: self._compileToJavascript(target, assembledFile, libIncludes) if self._verbose: print("\n" + ('-' * 100) + '\n') except Exception as err: print("\n\n\n") self._log.writeError( 'ERROR: Compilation failure for: %s\n\tsource: %s\n\troot: %s' % (target.package, target.path, target.rootPath), err) #___________________________________________________________________________________________________ _constructTarget def _constructTarget(self, target): try: if self._verbose: print("\n\n" + ('-' * 100) + '\n') self._log.write('EXECUTABLE: %s\n\tsource: %s\n\troot: %s' % (target.package, target.path, target.rootPath)) #--------------------------------------------------------------------------------------- # Handle imports and requires self._parseIncludes(target) self._processRequires(target) if self._verbose: s = 'IMPORTING:' for imp in self._imports[target.package]: s += '\n\t' + imp.package self._log.write(s) #--------------------------------------------------------------------------------------- # Construct intermediate compilation file. assembledFile = self._assembleFile(target) if assembledFile is None: self._log.write('ERROR: File assembly failed.') return #--------------------------------------------------------------------------------------- # Compile to Javascript if not self.buildOnly: self._compileToJavascript(target, assembledFile) if self._verbose: print("\n" + ('-' * 100) + '\n') except Exception as err: print("\n\n\n") self._log.writeError( 'ERROR: Compilation failure for: %s\n\tsource: %s\n\troot: %s' % (target.package, target.path, target.rootPath), err) #___________________________________________________________________________________________________ _createOutputFile def _createOutputFile(self, target): """Creates the output ccs assembly file for writing.""" outFile = target.assembledPath try: return open(outFile, 'w') except Exception as err: print("\n\n") self._log.write('Unable To Open output file: ' + str(outFile) + '\n' \ 'Check to make sure you have write permissions to that directory.') return None #___________________________________________________________________________________________________ _writeRegistryEntry def _writeRegistryEntry(self, out, cacheOut, entry): # If there is an unconsumed registryEntry write it. if not entry: return None s = '\n' + entry + '\n' out.write(s) if cacheOut: cacheOut.write(s) return None #___________________________________________________________________________________________________ _assembleFile def _assembleFile(self, target, importOverride=None, replacements=None, assembleData=None): #------------------------------------------------------------------------------------------- # CREATE FILE # Creates the file to write out = self._createOutputFile(target) if not out: self._log('ERROR: Unable to create output file') return #------------------------------------------------------------------------------------------- # DEFINE IMPORTS # Specify the files to import. For exec files the default packages are included, for # libraries these are overridden based on library target dependencies. targetImports = self._imports[ target.package] if importOverride is None else importOverride replacements = replacements if isinstance(replacements, list) else [] classList = [] #------------------------------------------------------------------------------------------- # Note the last dependency so that the glue script can be appended prior lastDep = targetImports[-1] #------------------------------------------------------------------------------------------- # DEPENDENCY ASSEMBLY LOOP print('\n') for dep in targetImports: dep.open() if self._force or not dep.useCache: if not self._compileDependency(dep, out, replacements, targetImports, classList): return None continue self._log.write('\tFROM CACHE: ' + dep.package) out.write(dep.cacheSource) dep.close() out.close() if self._verbose: print('\n') self._log.add('CONSTRUCTED: ' + out.name) return out.name #___________________________________________________________________________________________________ _compileDependency def _compileDependency(self, dep, out, replacements, targetImports, classList): classPattern = re.compile(CoffeescriptBuilder.CLASS_PATTERN) missingPattern = re.compile(CoffeescriptBuilder.MISSING_CLASS_PATTERN) #------------------------------------------------------------------------------------------- # MISSING DEPENDENCIES # Handle missing dependencies if not os.path.exists(dep.path): print("\n\n") self._log.write('ERROR: ' + dep.package + ' package does not exist at: ' + dep.path) return False lastWhitespace = '' openParens = 0 openBrackets = 0 openBraces = 0 skipNextLine = False methodName = '' className = '' registryEntry = None raw = dep.source dep.close() s = '\n\n\t#' + ('%' * 100) + '\n\t#' + ( '%' * 100) + '\n#\t\t' + dep.package + '\n' out.write(s) if dep.allowCaching: cacheOut = open(dep.cachePath, 'w') cacheOut.write(s) else: try: if os.path.exists(dep.cachePath): os.remove(dep.cachePath) except Exception as err: pass cacheOut = None self._log.write('\tCOMPILING: ' + dep.package) analyzer = CoffeescriptAnalyzer(raw, debug=self._debug) analyzer.analyze() #--------------------------------------------------------------------------------------- # COMPILE # Line by line compile to ccs output file for l in analyzer: #----------------------------------------------------------------------------------- # RETARGET CLASS ACCESSORS TO VIZME registry # All classes (except internal class references) are made to # VIZME registry ClassName to prevent class conflicts. for rep in replacements + targetImports: if rep != dep: offset = 0 res = rep.searchPattern.finditer(l.redacted) for r in res: start = r.start() + offset end = r.end() + offset if self._trace: self._log.write('RETARGET: ' + l.source[start:end] + ' | ' + str(r.groupdict())) # Make the replacement and adjust offsets for additional replacements l.insert(start, end, rep.registryName) offset += len(rep.registryName) - end + start #----------------------------------------------------------------------------------- # IDENTIFY CLASS DEFINITIONS # Find class definitions so they can be added to the VIZME registry. res = classPattern.search(l.redacted) if res: registryEntry = self._writeRegistryEntry( out, cacheOut, registryEntry) className = res.group('class').strip() registryEntry = '\n%s.%s ?= %s' % ( CoffeescriptDependency.REGISTRY, className, className) classList.append(className) #----------------------------------------------------------------------------------- # CHECK FOR MISSING CLASSES # Search and find any missing class imports. If a possible missing import is found # flag it in the response. res = missingPattern.finditer(l.redacted) if res: for r in res: cn = r.group('class').strip() start = r.start() if cn == className: continue # Ignore anything in all CAPS! if cn.upper() == cn: continue # Ignore globally defined objects and classes if cn in CoffeescriptBuilder._GLOBAL_CLASSES + analyzer.globalObjects: continue self._warnings.append({ 'id': CoffeescriptBuilder._WARN_ID_MISSING_IMPORT, 'class': cn, 'line': l.lineNumber, 'package': dep.package }) print('\n') self._log.write( 'WARNING: Possible missing import\n\tmissing: %s\n\tfrom: %s [line #%s]' % (cn, dep.package, str(l.lineNumber))) #----------------------------------------------------------------------------------- # LINE DEBUGGER ANALYSIS c = l.redacted.strip() skip = skipNextLine or not l.isSignificant skipNextLine = False if not skip: skips = [ 'class', 'try', 'catch', 'else', 'when', '.', '+', '-', '/', '=', '*', ',', 'and', 'or' ] for s in skips: if c.startswith(s): skip = True break if not skip: skips = ['->', '=>'] methodPattern = re.compile('^(?P<method>[^:]+)') for s in skips: if c.endswith(s): skip = True res = methodPattern.search(c) if res and res.group('method'): methodName = res.group('method') elif c.startswith('$'): methodName = '$' break # Check for line continuations if l.isSignificant: skips = ['.', '+', '-', '/', '=', '*', ',', 'and', 'or'] for s in skips: if c.endswith(s): skipNextLine = True break if self._trace: self._log.write( c.replace('\n', '') + ('\n\t@@@@ skip: ' + str(skip) + '\n\t@@@@ parens: ' + str(openParens) + '\n\t@@@@ braces: ' + str(openBraces) + '\n\t@@@@ brackets: ' + str(openBraces) + '\n\t@@@@ skipNext: ' + str(skipNextLine))) if self._debug and not skip and openParens == 0 and openBraces == 0 and openBrackets == 0: debugLine = 'window.___vmiDebug(\'%s\', \'%s\', \'%s\', %s)\n' % \ (dep.package, className, methodName, str(l.lineNumber)) indent = len(l.indent) > len(lastWhitespace) dedent = len(l.indent) < len(lastWhitespace) skips = [')', ']', '}'] skip = False for s in skips: if c.startswith(s): skip = True break if dedent and skip: lastWhitespace = lastWhitespace else: lastWhitespace = l.indent codePattern = re.compile('(?P<code>[^\s\t\n]+)') res = codePattern.search(c) if not res or len(res.groupdict()['code']) == 0: if self._trace: self._log.write('EMPTY: "' + c + '"') debugLine = '' l.insert(0, 0, l.indent + debugLine) if l.isSignificant: openParens += l.redacted.count('(') - l.redacted.count(')') openBrackets += l.redacted.count('[') - l.redacted.count(']') openBraces += l.redacted.count('{') - l.redacted.count('}') #--------------------------------------------------------------------------------------- # WRITE MODIFIED OUTPUT out.write(l.source) if cacheOut: cacheOut.write(l.source) self._writeRegistryEntry(out, cacheOut, registryEntry) if cacheOut: cacheOut.close() return True #___________________________________________________________________________________________________ _compileToJavascript def _compileToJavascript(self, target, assembledFile, jsIncludeOverrides=None): # Use the Coffeescript compiler to create a JS compilation of the assembled CS file result = SystemUtils.executeCommand( ['coffee', '-c', '--bare', assembledFile]) status = result['code'] output = result['out'] errors = 0 forceVerbose = False #------------------------------------------------------------------------------------------- # ERROR HANDLING # Check the error status of the compilation process and if a failure occurred parse the # error results for display and logging. if status: outputLines = str(output).replace('\r', '').split('\n') for line in outputLines: if line.startswith('Error:') or line.startswith( 'SyntaxError:'): errors += 1 result = CoffeescriptBuilder._parseError(line) if result: self._log.add(result) else: forceVerbose = True if forceVerbose: self._log.add(output) self._report[target.package] = errors if self._verbose: print("\n\n") if errors == 0 and status == 0: self._log.write('Compilation complete: ' + target.compiledPath) else: self._log.write('Compilation FAILED: ' + target.package) f = open(target.compiledPath, 'r') res = f.read() f.close() #___________________________________________________________________________________________________ _parseIncludes def _parseIncludes(self, target, rootTarget=None): """Doc...""" if rootTarget is None: rootTarget = target if not rootTarget.package in self._imports: self._imports[rootTarget.package] = [] if not rootTarget.package in self._requires: self._requires[rootTarget.package] = [] if not rootTarget.package in self._includes: self._includes[rootTarget.package] = [] if not os.path.exists(target.path): print("\n") self._log.add('WARNING: Missing import.\n\tPACKAGE: ' + target.package + '\n\tFILE: ' \ + target.path) print("\n") return f = open(target.path) for line in f: # import parse dependency = CoffeescriptDependency.createImport( line, self._rootPath) if dependency and not dependency.isInList( self._imports[rootTarget.package]): self._parseIncludes(dependency, rootTarget) self._imports[rootTarget.package].append(dependency) continue # require parse dependency = CoffeescriptDependency.createRequire( line, self._rootPath) if dependency and not dependency.isInList( self._imports[rootTarget.package]): self._requires[rootTarget.package].append(dependency) continue # include parse dependency = CoffeescriptDependency.createInclude( line, self._rootPath) if dependency and not dependency.isInList( self._includes[rootTarget.package]): self._includes[rootTarget.package].append(dependency) continue f.close() self._imports[rootTarget.package].append(target) #___________________________________________________________________________________________________ _processRequires def _processRequires(self, target): currentTarget = self._imports[target.package].pop() while len(self._requires[target.package]) > 0: self._parseIncludes(self._requires[target.package].pop(0), target) outlist = [] for item in self._imports[target.package]: if not item.isInList(outlist) and not item.compare(currentTarget): outlist.append(item) self._imports[target.package] = outlist self._imports[target.package].append(currentTarget) #___________________________________________________________________________________________________ _getLibraryData def _getLibraryData(self, target): targets = [] modules = [] imports = [] includes = [] src = open(target.path, 'r') for line in src: # target parse d = CoffeescriptDependency.create(line, self._rootPath) if not d: continue if d.dependencyType == CoffeescriptDependency.TARGET_TYPE: targets.append(d) elif d.dependencyType == CoffeescriptDependency.IMPORT_TYPE: imports.append(d) elif d.dependencyType == CoffeescriptDependency.REQUIRE_TYPE: imports.append(d) elif d.dependencyType == CoffeescriptDependency.INCLUDE_TYPE: includes.append(d) elif d.dependencyType == CoffeescriptDependency.MODULE_TYPE: modules.append(d) else: continue self._parseIncludes(d) src.close() return targets, imports, modules, includes #___________________________________________________________________________________________________ _compileAllInDirectory @staticmethod def _compileAllInDirectory(path, rootPath=None, debug=False, trace=False, force=False, compress=False): results = '' missing = {} count = 0 for f in CoffeescriptBuilder.getScriptsInPath(path): target = CoffeescriptDependency(f, rootPath) if not (target.exists and (target.isExec or target.isLib)): continue c = CoffeescriptBuilder(target, rootPath, debug=debug, trace=trace, force=force, compress=compress) c.construct() count += 1 for n, v in DictUtils.iter(c.report): num = max(0, 60 - len(n)) results += '\n' + n + ':' + ('.' * num) if v == 0: results += 'SUCCESS' elif v > 0: results += 'COMPILATION FAILED' else: results += 'ASSEMBLY FAILED' if len(c.warnings) > 0: results += '[' + str(len(c.warnings)) + ' WARNINGS]' for v in c.warnings: if not v[ 'id'] == CoffeescriptBuilder._WARN_ID_MISSING_IMPORT: continue key = v['package'] + '-' + v['class'] + '-' + str( v['line']) if key in missing: continue missing[key] = v if len(results) > 0: print('\nDIRECTORY ' + path + ' COMPILE RESULTS [' + str(count) + ']:' + results) return {'res': results, 'missing': missing} #___________________________________________________________________________________________________ _parseError @staticmethod def _parseError(error): """ Parses errors of the format: "Error: In /vizme2/website/js/vmi/blog/author/exec.ccs, Parse error on line 181: Unexpected 'INDENT'" """ ccsFile = None prefixReplacements = ['SyntaxError: In ', 'Error: In '] for p in prefixReplacements: error = error.replace(p, '') out = '\n-----------------------------------------------\nERROR: ' try: sep = error.index(',') ccsFile = error[:sep] except Exception: pass try: sep2 = error.index(':') out += error[sep2 + 1:].strip() + '\n' except Exception: if error and sep: out += error[sep + 1:].strip() + '\n' pattern = re.compile('line[\s\t]+(?P<linenumber>[0-9]+)') res = pattern.search(error) if res and len(res.groups()) > 0: lineNumber = int(res.groups()[0]) - 1 else: out += ' Unspecified location' return if ccsFile: padSize = len(str(lineNumber + 3)) jQueryName = 'Exec Function (JQUERY Document ready)' functionName = None className = None trace = '' f = open(ccsFile, 'r') for i, line in enumerate(f): if i > lineNumber + 4: break if i <= lineNumber: pattern = re.compile( '^class[\s\t]+(?P<classname>[a-zA-Z0-9_]+)') res = pattern.search(line) if res and len(res.groups()) > 0: className = res.groups()[0] functionName = None pattern = re.compile('^\$[\s\t]*[-=]+>') res = pattern.search(line) if res: className = jQueryName functionName = None pattern = re.compile( '[\s\t]*(?P<name>[a-zA-Z0-9_]+)[\s\t]*:[^-=>]*[-=]+>') res = pattern.search(line) if res and len(res.groups()) > 0: functionName = res.groups()[0] if i > lineNumber - 4: marker = ">>" if i == lineNumber else " " trace += marker + str(i).rjust(padSize) + '| ' + line f.close() if functionName: out += " " + ("METHOD" if className else "FUNCTION") + ": " + functionName + "\n" if className: out += " " + ("CLASS" if className != jQueryName else "EXEC") + ": " + className + "\n" out += " TRACE:\n" + trace return out + "\n"
class PyGlassWindow(QtGui.QMainWindow): """A class for...""" #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self, **kwargs): """Creates a new instance of PyGlassWindow.""" parent = ArgsUtils.extract('parent', None, kwargs) self._application = ArgsUtils.extract('pyGlassApp', None, kwargs) self._qApplication = ArgsUtils.extract('qApp', None, kwargs) self._isMainWindow = ArgsUtils.extract('isMainWindow', bool(parent is None), kwargs) self._mainWindow = ArgsUtils.extract('mainWindow', None, kwargs) self._appWrappingWidget = None self._centerWidget = None self._hasShown = False self._isHighDpi = OsUtils.isHighDpiScaledScreen() self._settings = ConfigsDict() self._appLevelWidgets = dict() self._appLevelWidgetDisplayHistory = [] self._keyboardCallback = ArgsUtils.extract('keyboardCallback', None, kwargs) if not self._mainWindow: if self._isMainWindow: self._mainWindow = self elif self._application: self._mainWindow = self._application.mainWindow self._dependentWindows = [] self._currentWidget = None QtGui.QMainWindow.__init__(self, parent, ArgsUtils.extract('flags', 0, kwargs)) self._instanceUid = TimeUtils.getUidTimecode( prefix=self.__class__.__name__, suffix=StringUtils.getRandomString(8)) self._styleSheet = kwargs.get('styleSheet', None) if self._styleSheet: self.setStyleSheet(self.styleSheetPath) if self._keyboardCallback is not None: self.setFocusPolicy(QtCore.Qt.StrongFocus) if self._isMainWindow: self._log = Logger(self, printOut=True) self._config = ApplicationConfig(self) self._commonConfig = ApplicationConfig(self, common=True) self._resourceFolderParts = PyGlassGuiUtils.getResourceFolderParts(self) icon = PyGlassGuiUtils.createIcon( kwargs.get('iconsPath', self.getAppResourcePath('icons', isDir=True)) ) if icon: self.setWindowIcon(icon) elif self._mainWindow: icon = self._mainWindow.windowIcon() if icon: self.setWindowIcon(icon) self._appWrappingWidget = VisibilityElement(self) layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self._appWrappingWidget.setLayout(layout) self._contentWrappingWidget = self.addApplicationLevelWidget('main') layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self._contentWrappingWidget.setLayout(layout) # Loads the ui file if it exists externalCentralParent = None hasWindowFile = kwargs.get('mainWindowFile', False) if hasWindowFile == self: UiFileLoader.loadWidgetFile(self) externalCentralParent = getattr(self, 'windowContainer') if externalCentralParent: externalLayout = externalCentralParent.layout() if not externalLayout: externalLayout = QtGui.QVBoxLayout() externalLayout.setContentsMargins(0, 0, 0, 0) externalLayout.setSpacing(0) externalCentralParent.setLayout(externalLayout) if externalCentralParent: self._appWrappingWidget.setParent(externalCentralParent) externalLayout.addWidget(self._appWrappingWidget) else: self.setCentralWidget(self._appWrappingWidget) # Sets a non-standard central widget centralWidgetName = kwargs.get('centralWidgetName') if centralWidgetName and hasattr(self, centralWidgetName): self._centerWidget = getattr(self, centralWidgetName) elif hasWindowFile and not hasWindowFile == self: if not self._centerWidget: self._createCentralWidget() UiFileLoader.loadWidgetFile(self, target=self._centerWidget) elif not hasWindowFile: self._centerWidget = None if not self._centerWidget and kwargs.get('defaultCenterWidget', True): self._createCentralWidget() self._lastChildWidgetID = None self._widgetParent = None self._widgets = None self._widgetFlags = None self._widgetClasses = kwargs.get('widgets', dict()) if self._widgetClasses: self._initializeWidgetChildren() self.setWindowTitle(kwargs.get('title', self._createTitleFromClass())) self.updateStatusBar() #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: settings @property def settings(self): return self._settings #___________________________________________________________________________________________________ GS: isHighDpi @property def isHighDpi(self): return self._isHighDpi #___________________________________________________________________________________________________ GS: instanceUid @property def instanceUid(self): return self._instanceUid #___________________________________________________________________________________________________ GS: isDeployed @ClassGetter def isDeployed(cls): return PyGlassEnvironment.isDeployed #___________________________________________________________________________________________________ GS: isOnDisplay @property def isOnDisplay(self): return self.isVisible() #___________________________________________________________________________________________________ GS: appID @property def appID(self): return self.pyGlassApplication.appID #___________________________________________________________________________________________________ GS: isMainWindow @property def isMainWindow(self): return self._isMainWindow #___________________________________________________________________________________________________ GS: allowsOwnership @property def allowsOwnership(self): return True #___________________________________________________________________________________________________ GS: mainWindow @property def mainWindow(self): if self.isMainWindow: return self if self._mainWindow: return self._mainWindow self._mainWindow = PyGlassGuiUtils.getMainWindow(self) # Handle case where main window turns out to this window if self._mainWindow == self: self._isMainWindow = True self._mainWindow = None return self return self._mainWindow #___________________________________________________________________________________________________ GS: owner @property def owner(self): if self.isMainWindow: return self return self.mainWindow #___________________________________________________________________________________________________ GS: pyGlassApplication @property def pyGlassApplication(self): return self._application if self.isMainWindow else self.mainWindow.pyGlassApplication #___________________________________________________________________________________________________ GS: application @property def application(self): if self._application is not None: return self._application return self._application if self.isMainWindow else self.mainWindow.application #___________________________________________________________________________________________________ GS: qApplication @property def qApplication(self): if self._qApplication is not None: return self._qApplication return self._qApplication if self.isMainWindow else self.mainWindow.qApplication #___________________________________________________________________________________________________ GS: appConfig @property def appConfig(self): return self._config if self.isMainWindow else self.mainWindow.appConfig #___________________________________________________________________________________________________ GS: commonAppConfig @property def commonAppConfig(self): return self._commonConfig if self.isMainWindow else self.mainWindow.commonAppConfig #___________________________________________________________________________________________________ GS: logger @property def logger(self): return self._log if self.isMainWindow else self.owner.log #___________________________________________________________________________________________________ GS: log @property def log(self): return self.logger #___________________________________________________________________________________________________ GS: styleSheetPath @property def styleSheetPath(self): if not self._styleSheet: return None if os.path.isabs(self._styleSheet): return self._styleSheet parts = self._resourceFolderParts + self._stylesheet.split('/') return self.getResourcePath(*parts, isFile=True) #___________________________________________________________________________________________________ GS: rootResourcePath @property def rootResourcePath(self): return PyGlassEnvironment.getRootResourcePath() #___________________________________________________________________________________________________ GS: rootLocalResourcePath @property def rootLocalResourcePath(self): return PyGlassEnvironment.getRootLocalResourcePath() #___________________________________________________________________________________________________ GS: appResourcePath @property def appResourcePath(self): if not self.isMainWindow: return self.owner.appResourcePath out = self.pyGlassApplication.getAppResourcePath(isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: localAppResourcePath @property def localAppResourcePath(self): if not self.isMainWindow: return self.owner.localAppResourcePath out = self.pyGlassApplication.getLocalAppResourcePath(isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: sharedResourcePath @property def sharedResourcePath(self): out = self.getRootResourcePath('shared', isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: localSharedResourcePath @property def localSharedResourcePath(self): out = self.getLocalResourcePath('shared', isDir=True) if not os.path.exists(out): os.makedirs(out) return out #___________________________________________________________________________________________________ GS: widgets @property def widgets(self): return self._widgets #___________________________________________________________________________________________________ GS: screenWidth @property def screenWidth(self): rect = self._qApplication.desktop().screenGeometry() return rect.width() #___________________________________________________________________________________________________ GS: screenHeight @property def screenHeight(self): rect = self._qApplication.desktop().screenGeometry() return rect.height() #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ scaleByDpi def scaleByDpi(self, value, rounded =False, asInt =False): if self._isHighDpi: value *= 2 if rounded or asInt: value = round(value) if asInt: return int(value) return value #___________________________________________________________________________________________________ keyPressEvent def keyPressEvent(self, event): if self._keyboardCallback is None or not self._keyboardCallback(event): super(PyGlassWindow, self).keyPressEvent(event) #___________________________________________________________________________________________________ showEvent def showEvent(self, *args, **kwargs): if not self._hasShown: self._firstShowImpl() self._hasShown = True #___________________________________________________________________________________________________ closeEvent def closeEvent(self, *args, **kwargs): if self.isMainWindow: for depWindow in self._dependentWindows: depWindow.close() return super(PyGlassWindow, self).closeEvent(*args, **kwargs) #___________________________________________________________________________________________________ addDependentWindow def addDependentWindow(self, window): if window in self._dependentWindows: return True self._dependentWindows.append(window) return True #___________________________________________________________________________________________________ removeDependentWindow def removeDependentWindow(self, window): if window not in self._dependentWindows: return True self._dependentWindows.remove(window) return True #___________________________________________________________________________________________________ refreshWidgets def refreshWidgets(self, **kwargs): for name, widget in DictUtils.iter(self._widgets): widget.refresh(**kwargs) self.refreshGui() #___________________________________________________________________________________________________ updateStatusBar def updateStatusBar(self, message =None, timeout =-1): if not message: self.statusBar().clearMessage() self.statusBar().setVisible(False) else: if timeout < 0: timeout = 3000 self.statusBar().showMessage(message, timeout=timeout) self.statusBar().setVisible(True) #___________________________________________________________________________________________________ getWidgetFromID def getWidgetFromID(self, widgetID, createIfMissing =True): if widgetID not in self._widgets and createIfMissing: self.loadWidgets(widgetID) return self._widgets.get(widgetID, None) #___________________________________________________________________________________________________ getSharedResourcePath def getSharedResourcePath(self, *args, **kwargs): return FileUtils.createPath(self.sharedResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getLocalSharedResourcePath def getLocalSharedResourcePath(self, *args, **kwargs): return FileUtils.createPath(self.localSharedResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getAppResourcePath def getAppResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath(self.appResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getLocalAppResourcePath def getLocalAppResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath(self.localAppResourcePath, *args, **kwargs) #___________________________________________________________________________________________________ getRootResourcePath def getRootResourcePath(self, *args, **kwargs): return PyGlassEnvironment.getRootResourcePath(*args, **kwargs) #___________________________________________________________________________________________________ getRootLocalResourcePath def getRootLocalResourcePath(self, *args, **kwargs): return PyGlassEnvironment.getRootLocalResourcePath(*args, **kwargs) #___________________________________________________________________________________________________ getResourcePath def getResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath( self.rootResourcePath, 'widget', self._resourceFolderParts, *args, **kwargs) #___________________________________________________________________________________________________ getLocalResourcePath def getLocalResourcePath(self, *args, **kwargs): """Doc...""" return FileUtils.createPath( self.rootLocalResourcePath, 'widget', self._resourceFolderParts, *args, **kwargs) #___________________________________________________________________________________________________ showApplicationLevelWidget def showApplicationLevelWidget(self, widgetID, **kwargs): w = self.getApplicationLevelWidget(widgetID) if not w: return for wid, widget in DictUtils.iter(self._appLevelWidgets): if wid == widgetID: widget.setVisible(True) widget.activateWidgetDisplay(**kwargs) else: widget.visibility.addMuteRequest(w) self.refreshGui() #___________________________________________________________________________________________________ hideApplicationLevelWidget def hideApplicationLevelWidget(self, widgetID, **kwargs): w = self.getApplicationLevelWidget(widgetID) if not w: return for wid, widget in DictUtils.iter(self._appLevelWidgets): if wid == widgetID: widget.setVisible(False) widget.deactivateWidgetDisplay(**kwargs) else: widget.visibility.removeMuteRequest(w) if widget.visibility.isVisible: widget.refreshWidgetDisplay() self.refreshGui() #___________________________________________________________________________________________________ showLoading def showLoading(self, target, **kwargs): w = self.getApplicationLevelWidget('loading') if not w: return self.showApplicationLevelWidget('loading', target=target, **kwargs) self._showLoadingImpl(target=target, **kwargs) #___________________________________________________________________________________________________ hideLoading def hideLoading(self, target, **kwargs): w = self.getApplicationLevelWidget('loading') if not w or not w.target == target: return self.hideApplicationLevelWidget('loading', target=target, **kwargs) self._hideLoadingImpl(target=target, **kwargs) #___________________________________________________________________________________________________ addWidget def addWidget(self, key, widgetClass, setActive =False): self._widgetClasses[key] = widgetClass if self._widgets is None: self._initializeWidgetChildren(key if setActive else None) elif setActive: return self.setActiveWidget(key) return True #___________________________________________________________________________________________________ setActiveWidget def setActiveWidget(self, widgetID, force =False, args =None, doneArgs =None): if not self._centerWidget or widgetID is None or widgetID not in self._widgetClasses: return False if not force and self._currentWidget and self._currentWidget.widgetID == widgetID: return True if widgetID not in self._widgets: self.loadWidgets(widgetID) widget = self._widgets[widgetID] # Deactivates the current widget if the widgets are being switched. However, ignored if the # same widget is being activated for a second time. if self._currentWidget and widgetID != self._currentWidget.widgetID: if doneArgs is None: doneArgs = dict() self._currentWidget.deactivateWidgetDisplay(**doneArgs) self._currentWidget.setParent(self._widgetParent) self._lastChildWidgetID = self._currentWidget.widgetID self._currentWidget = widget if self._centerWidget: layout = self._centerWidget.layout() if not layout: layout = QtGui.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self._centerWidget.setLayout(layout) layout.addWidget(widget) else: self._contentWrappingWidget.layout().addWidget(widget) self.setContentsMargins(0, 0, 0, 0) self.refreshGui() if args is None: args = dict() widget.activateWidgetDisplay(lastPeerWidgetID=self._lastChildWidgetID, **args) return True #___________________________________________________________________________________________________ loadWidgets def loadWidgets(self, widgetIdents =None): if not widgetIdents: widgetIdents = self._widgetClasses.keys() elif StringUtils.isStringType(widgetIdents): widgetIdents = [widgetIdents] for widgetID in widgetIdents: if widgetID in self._widgets: continue if widgetID not in self._widgetClasses: self._log.write( 'ERROR: Unrecognized widgetID "%s" in %s' % (str(widgetID), str(self))) try: widget = self._widgetClasses[widgetID]( parent=self._widgetParent, flags=self._widgetFlags, widgetID=widgetID) self._widgets[widgetID] = widget except Exception as err: self._log.write('ERROR: Failed to load widget with id: "%s" ->' % widgetID) raise #___________________________________________________________________________________________________ refreshGui def refreshGui(self): self.qApplication.processEvents() #___________________________________________________________________________________________________ exit def exit(self): self.qApplication.exit() #___________________________________________________________________________________________________ initialize def initialize(self, *args, **kwargs): self._initializeImpl(*args, **kwargs) #___________________________________________________________________________________________________ initializeComplete def initializeComplete(self, preDisplay =None): self.pyGlassApplication.closeSplashScreen() result = False if preDisplay: preDisplay.show() result = self.qApplication.exec_() if result: sys.exit(result) self._application.runMainLoop() #___________________________________________________________________________________________________ preShow def preShow(self, **kwargs): self._preShowImpl(**kwargs) #___________________________________________________________________________________________________ postShow def postShow(self, **kwargs): self._postShowImpl(**kwargs) #___________________________________________________________________________________________________ addApplicationLevelWidget def addApplicationLevelWidget(self, widgetID, widgetClass =None, **kwargs): if widgetClass is None: widgetClass = ApplicationLevelWidget ArgsUtils.addIfMissing('widgetFile', False, kwargs) widget = widgetClass(parent=self._appWrappingWidget, **kwargs) self._appWrappingWidget.layout().addWidget(widget) self._appLevelWidgets[widgetID] = widget return widget #___________________________________________________________________________________________________ getApplicationLevelWidget def getApplicationLevelWidget(self, widgetID): if widgetID in self._appLevelWidgets: return self._appLevelWidgets[widgetID] return None #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _createCentralWidget def _createCentralWidget(self): widget = self._centerWidget if widget: return widget w = QtGui.QWidget(self._contentWrappingWidget) self._contentWrappingWidget.layout().addWidget(w) self._centerWidget = w return w #___________________________________________________________________________________________________ _initializeWidgetChildren def _initializeWidgetChildren(self, activeWidgetID =None): if not self._widgetClasses or self._widgets: return False self._widgetParent = PyGlassBackgroundParent(proxy=self) self._widgets = dict() if activeWidgetID: self.setActiveWidget(activeWidgetID) #___________________________________________________________________________________________________ _preShowImpl def _preShowImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _firstShowImpl def _firstShowImpl(self): pass #___________________________________________________________________________________________________ _postShowImpl def _postShowImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _showLoadingImpl def _showLoadingImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _hideLoadingImpl def _hideLoadingImpl(self, **kwargs): pass #___________________________________________________________________________________________________ _createTitleFromClass def _createTitleFromClass(self): """Doc...""" src = self.__class__.__name__ out = src[0] wasCaps = True for c in src[1:]: if c.lower() == c: out += c wasCaps = False elif wasCaps: out += c else: out += ' ' + c wasCaps = True return out #___________________________________________________________________________________________________ _initializeImpl def _initializeImpl(self, *args, **kwargs): self.initializeComplete() #=================================================================================================== # I N T R I N S I C #___________________________________________________________________________________________________ __repr__ def __repr__(self): return self.__str__() #___________________________________________________________________________________________________ __unicode__ def __unicode__(self): return StringUtils.toUnicode(self.__str__()) #___________________________________________________________________________________________________ __str__ def __str__(self): return '<%s>' % self.__class__.__name__
class IncludeCompressor(object): #=================================================================================================== # C L A S S _REMOVE_COMMENT_RE = re.compile('/\*.+\*/', re.DOTALL) _REMOVE_COMMENT_LINE_RE = re.compile('(^|\n)[\s\t]*//.+(\n|$)') JS_TYPE = 'js' CSS_TYPE = 'css' #___________________________________________________________________________________________________ __init__ def __init__(self, compileCoffee=False): self._log = Logger('IncludeCompressor') self._compileCoffee = compileCoffee #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ compress def compress(self, rootPath): if not self._fileExists(rootPath): return False elif os.path.isfile(rootPath): return self.compressFile(rootPath) else: return self.compressPath(rootPath) #___________________________________________________________________________________________________ compressFile def compressFile(self, rootPath, directory=None): if not self._fileExists(rootPath): return False if self._compileCoffee: try: from pyaid.web.coffeescript.CoffeescriptBuilder import CoffeescriptBuilder CoffeescriptBuilder.compileAllOnPath(rootPath, os.path.dirname(rootPath), True) self._log.write('Coffeescript compiled.') except Exception as err: self._log.writeError('Failed to compile coffeescript file.', err) return False return self._compressFile(rootPath, directory) #___________________________________________________________________________________________________ compressPath def compressPath(self, rootPath): # First compile any coffee scripts to js files if self._compileCoffee: try: from pyaid.web.coffeescript.CoffeescriptBuilder import CoffeescriptBuilder CoffeescriptBuilder.compileAllOnPath(rootPath, rootPath, True) self._log.write('Coffee scripts compiled.') except Exception as err: self._log.writeError('Failed to compile coffeescript files.', err) return False FileUtils.walkPath(rootPath, self._compressInFolder, None) self._log.write('Compression operation complete.') return True #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _fileExists def _fileExists(self, rootPath): if not os.path.exists(rootPath): self._log.write('ERROR: [%s] does not exist. Operation aborted.' % rootPath) return False return True #___________________________________________________________________________________________________ _compressFile def _compressFile(self, target, directory): # Skip compiled files. if target.endswith('comp.js') or target.endswith('comp.css'): return False if target.endswith('.js'): fileType = IncludeCompressor.JS_TYPE elif target.endswith('.css'): fileType = IncludeCompressor.CSS_TYPE else: return False if not directory: directory = '' if not directory.endswith(os.sep) and not target.startswith(os.sep): directory += os.sep inFile = directory + target tempFile = directory + target + '.temp' try: fh = open(inFile, 'r') fileString = fh.read() fh.close() except Exception as err: self._log.writeError('FAILED: Unable to read ' + str(inFile), err) return False if fileType == IncludeCompressor.CSS_TYPE: fileString = fileString.replace('@charset "utf-8";', '') ofn = (target[0:-3] + 'comp.css') else: ofn = (target[0:-2] + 'comp.js') try: fh = open(tempFile, 'w') fh.write(fileString) fh.close() except Exception as err: self._log.writeError( 'FAILED: Unable to write temp file ' + str(tempFile), err) return False outFile = directory + '/' + ofn cmd = ['minify', '"%s"' % tempFile, '"%s"' % outFile] result = SystemUtils.executeCommand(cmd) if result['code']: self._log.write('FAILED: Unable to compress ' + str(inFile)) if os.path.exists(tempFile): os.remove(tempFile) if not os.path.exists(outFile): self._log.write('FAILED: ' + target + ' -> ' + ofn) return False elif fileType == IncludeCompressor.JS_TYPE: f = open(outFile, 'r') compressed = f.read() f.close() compressed = IncludeCompressor._REMOVE_COMMENT_RE.sub( '', compressed) compressed = IncludeCompressor._REMOVE_COMMENT_LINE_RE.sub( '', compressed) f = open(outFile, 'w') f.write(compressed.strip()) f.close() inSize = SizeUnits.SizeConversion.bytesToKilobytes(inFile, 2) outSize = SizeUnits.SizeConversion.bytesToKilobytes(outFile, 2) saved = SizeUnits.SizeConversion.convertDelta( inSize, outSize, SizeUnits.SIZES.KILOBYTES, 2) self._log.write( 'Compressed[%s]: %s -> %s [%sKB -> %sKB | Saved: %sKB]' % (fileType, target, ofn, inSize, outSize, saved)) return True #___________________________________________________________________________________________________ _compressInFolder def _compressInFolder(self, dumb, directory, names): if directory.find('.svn') != -1: return for fn in names: self._compressFile(fn, directory)
class TrackExporter(object): """A class for...""" #=============================================================================== # C L A S S DELETED_IDENTIFIER = u'##DEL##' #_______________________________________________________________________________ def __init__(self, logger =None): """Creates a new instance of TrackExporter.""" self.results = None self.logger = logger self.modifications = 0 if not logger: self.logger = Logger(self, printOut=True) #=============================================================================== # P U B L I C #_______________________________________________________________________________ def process(self, session, difference =True): """Doc...""" if self.results is not None: return True results = [] model = Tracks_Track.MASTER if session is None: session = model.createSession() trackStores = session.query(model).all() index = 0 indices = NumericUtils.linearSpace(0, len(trackStores), roundToIntegers=True)[1:] for trackStore in trackStores: track = trackStore.getMatchingTrack(session) if track is None: self.modifications += 1 results.append({'uid':trackStore.uid, 'action':self.DELETED_IDENTIFIER}) self.logger.write( u'<div>DELETED: %s</div>' % DictUtils.prettyPrint( trackStore.toDict(uniqueOnly=True))) else: if difference: diff = trackStore.toDiffDict(track.toDict()) if diff is not None: self.modifications += 1 results.append(diff) self.logger.write( u'<div>MODIFIED: %s</div>' % trackStore.fingerprint) else: results.append(track.toDict()) index += 1 if index in indices: self.logger.write( u'<div style="color:#33CC33">%s%% Complete</div>' % StringUtils.toUnicode( 10*(indices.index(index) + 1))) self.logger.write(u'<div style="color:#33CC33">100% Complete</div>') self.results = results return True #_______________________________________________________________________________ def write(self, session, path, pretty =False, gzipped =True, difference =True): if self.results is None and not self.process(session, difference): return False try: JSON.toFile(path, self.results, pretty=pretty, gzipped=gzipped, throwError=True) return True except Exception as err: self.logger.writeError([ u'ERROR: Unable to write export file', u'PATH: ' + StringUtils.toUnicode(path)], err) return False #=============================================================================== # I N T R I N S I C #_______________________________________________________________________________ def __repr__(self): return self.__str__() #_______________________________________________________________________________ def __unicode__(self): return StringUtils.toUnicode(self.__str__()) #_______________________________________________________________________________ def __str__(self): return '<%s>' % self.__class__.__name__
class SocketHandler(SocketServer.StreamRequestHandler): """A class for...""" #=================================================================================================== # C L A S S SERVICE_UID = 'test' VERBOSE = False WORK_PATH = '/var/lib/' RUN_PATH = '/var/run/' LOG_PATH = '/var/log/' #___________________________________________________________________________________________________ __init__ def __init__(self, request, client_address, server): self._log = Logger(self) self._log.write('Socket handler created') SocketServer.StreamRequestHandler.__init__(self, request, client_address, server) #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: returnResponse @property def returnResponse(self): return getattr(self.__class__, 'RETURN_RESPONSE', False) #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ handle def handle(self): try: data = self.rfile.readline().strip() self._log.write('HANDLE: ' + str(data)) try: result = self._respondImpl(JSON.fromString(unquote(data))) except Exception as err: self._log.writeError('RESPOND FAILURE', err) if self.returnResponse: self.wfile.write(JSON.asString({'error': 1})) return if self.returnResponse: out = {'error': 0} if result: out['payload'] = result self.wfile.write(out) except Exception as err: self._log.write('HANDLE FAILURE', err) return #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _respondImpl def _respondImpl(self, data): pass
class ResourceCollector(object): """A class for...""" #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self, compiler, **kwargs): """Creates a new instance of ResourceCollector.""" self._log = Logger(self) self._verbose = ArgsUtils.get('verbose', False, kwargs) self._compiler = compiler if OsUtils.isWindows(): self._targetPath = self._compiler.getBinPath('resources', isDir=True) elif OsUtils.isMac(): self._targetPath = self._compiler.getBinPath('resources', 'resources', isDir=True) if os.path.exists(self._targetPath): shutil.rmtree(self._targetPath) if not os.path.exists(self._targetPath): os.makedirs(self._targetPath) #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ run def run(self): """Doc...""" resources = self._compiler.resources #------------------------------------------------------------------------------------------- # APP RESOURCES # If no resource folders were specified copy the entire contents of the resources # folder. Make sure to skip the local resources path in the process. if not resources: for item in os.listdir(PyGlassEnvironment.getRootResourcePath(isDir=True)): itemPath = PyGlassEnvironment.getRootResourcePath(item) if os.path.isdir(itemPath) and not item == 'local': resources.append(item) for container in resources: parts = container.replace('\\', '/').split('/') self._copyResourceFolder( PyGlassEnvironment.getRootResourcePath(*parts, isDir=True), parts ) #------------------------------------------------------------------------------------------- # PYGLASS RESOURCES # Copy the resources from the PyGlass resources = [] for item in os.listdir(PyGlassEnvironment.getPyGlassResourcePath('..', isDir=True)): itemPath = PyGlassEnvironment.getPyGlassResourcePath('..', item) if os.path.isdir(itemPath): resources.append(item) for container in resources: self._copyResourceFolder( PyGlassEnvironment.getPyGlassResourcePath('..', container), [container] ) #------------------------------------------------------------------------------------------- # CLEANUP if self._verbose: self._log.write('CLEANUP: Removing unwanted destination files.') self._cleanupFiles(self._targetPath) self._copyPythonStaticResources() if self._verbose: self._log.write('COMPLETE: Resource Collection') return True #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _copyResourceFolder def _copyResourceFolder(self, sourcePath, parts): targetPath = FileUtils.createPath(self._targetPath, *parts, isDir=True) WidgetUiCompiler(sourcePath).run() if self._verbose: self._log.write('COPYING: %s -> %s' % (sourcePath, targetPath)) results = FileUtils.mergeCopy(sourcePath, targetPath) #___________________________________________________________________________________________________ _copyPythonStaticResources def _copyPythonStaticResources(self): sourcePath = requests.utils.DEFAULT_CA_BUNDLE_PATH parts = sourcePath[len(sys.exec_prefix):].strip(os.sep).split(os.sep) destPath = FileUtils.createPath(self._targetPath, 'pythonRoot', *parts, isFile=True) folder = os.path.dirname(destPath) if not os.path.exists(folder): os.makedirs(folder) shutil.copy(sourcePath, destPath) #___________________________________________________________________________________________________ _compilePythonFiles def _compilePythonFiles(self, rootPath): os.path.walk(rootPath, self._compileInFolder, dict()) #___________________________________________________________________________________________________ _compileInFolder def _compileInFolder(self, arg, dirname, names): for name in names: if name.endswith('.py'): py_compile.compile(FileUtils.createPath(dirname, name, isFile=True)) #___________________________________________________________________________________________________ _cleanupFiles def _cleanupFiles(self, targetPath): os.path.walk(targetPath, self._cleanupInFolder, dict()) #___________________________________________________________________________________________________ _cleanupInFolder def _cleanupInFolder(self, arg, dirname, names): for name in names: if StringUtils.ends(name, self._compiler.ignoreExtensions): os.remove(FileUtils.createPath(dirname, name, isFile=True)) # Deletes python (.py) files associated with ui files so only .pyc files remain. if name.endswith('.ui'): pyName = name.rsplit('.', 1)[0] + '.py' pyNamePath = FileUtils.createPath(dirname, pyName, isFile=True) if os.path.exists(pyNamePath): os.remove(pyNamePath) #=================================================================================================== # I N T R I N S I C #___________________________________________________________________________________________________ __repr__ def __repr__(self): return self.__str__() #___________________________________________________________________________________________________ __unicode__ def __unicode__(self): return unicode(self.__str__()) #___________________________________________________________________________________________________ __str__ def __str__(self): return '<%s>' % self.__class__.__name__
class ResourceCollector(object): """A class for...""" #=================================================================================================== # C L A S S #___________________________________________________________________________________________________ __init__ def __init__(self, compiler, **kwargs): """Creates a new instance of ResourceCollector.""" self._log = Logger(self, printOut=True) self._verbose = ArgsUtils.get('verbose', False, kwargs) self._compiler = compiler if OsUtils.isWindows(): self._targetPath = self._compiler.getBinPath('resources', isDir=True) elif OsUtils.isMac(): # Resource folder resides inside another resource folder so that the copying retains # the original directory structure self._targetPath = self._compiler.getBinPath('resources', 'resources', isDir=True) #self._targetPath = self._compiler.getBinPath('resources', isDir=True) if os.path.exists(self._targetPath): shutil.rmtree(self._targetPath) if not os.path.exists(self._targetPath): os.makedirs(self._targetPath) #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ run def run(self): """Doc...""" resources = self._compiler.resources #------------------------------------------------------------------------------------------- # RESOURCES # If no resource folders were specified copy the entire contents of the resources # folder. Make sure to skip the local resources path in the process. if not resources: for item in os.listdir(PyGlassEnvironment.getRootResourcePath(isDir=True)): itemPath = PyGlassEnvironment.getRootResourcePath(item) if os.path.isdir(itemPath) and not item in ['local', 'apps']: resources.append(item) for container in resources: parts = container.replace('\\', '/').split('/') self._copyResourceFolder( PyGlassEnvironment.getRootResourcePath(*parts, isDir=True), parts) #------------------------------------------------------------------------------------------- # APP RESOURCES appResources = self._compiler.resourceAppIds if not appResources: appResources = [] for appResource in appResources: itemPath = PyGlassEnvironment.getRootResourcePath('apps', appResource, isDir=True) if not os.path.exists(itemPath): self._log.write('[WARNING]: No such app resource path found: %s' % appResource) continue self._copyResourceFolder(itemPath, ['apps', appResource]) #------------------------------------------------------------------------------------------- # PYGLASS RESOURCES # Copy the resources from the PyGlass resources = [] for item in os.listdir(PyGlassEnvironment.getPyGlassResourcePath('..', isDir=True)): itemPath = PyGlassEnvironment.getPyGlassResourcePath('..', item) if os.path.isdir(itemPath): resources.append(item) for container in resources: self._copyResourceFolder( PyGlassEnvironment.getPyGlassResourcePath('..', container), [container]) # Create a stamp file in resources for comparing on future installations creationStampFile = FileUtils.makeFilePath(self._targetPath, 'install.stamp') JSON.toFile(creationStampFile, {'CTS':TimeUtils.toZuluPreciseTimestamp()}) #------------------------------------------------------------------------------------------- # CLEANUP if self._verbose: self._log.write('CLEANUP: Removing unwanted destination files.') self._cleanupFiles(self._targetPath) self._copyPythonStaticResources() if self._verbose: self._log.write('COMPLETE: Resource Collection') return True #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _copyResourceFolder def _copyResourceFolder(self, sourcePath, parts): targetPath = FileUtils.createPath(self._targetPath, *parts, isDir=True) WidgetUiCompiler(sourcePath).run() if self._verbose: self._log.write('COPYING: %s -> %s' % (sourcePath, targetPath)) return FileUtils.mergeCopy(sourcePath, targetPath) #___________________________________________________________________________________________________ _copyPythonStaticResources def _copyPythonStaticResources(self): sourcePath = requests.utils.DEFAULT_CA_BUNDLE_PATH parts = sourcePath.strip(os.sep).split(os.sep) index = parts.index('site-packages') parts = parts[index:] destPath = FileUtils.createPath(self._targetPath, 'pythonRoot', *parts, isFile=True) folder = os.path.dirname(destPath) if not os.path.exists(folder): os.makedirs(folder) shutil.copy(sourcePath, destPath) #___________________________________________________________________________________________________ _compilePythonFiles def _compilePythonFiles(self, rootPath): FileUtils.walkPath(rootPath, self._compileInFolder, dict()) #___________________________________________________________________________________________________ _compileInFolder def _compileInFolder(self, arg, dirname, names): for name in names: if name.endswith('.py'): py_compile.compile(FileUtils.createPath(dirname, name, isFile=True)) #___________________________________________________________________________________________________ _cleanupFiles def _cleanupFiles(self, targetPath): FileUtils.walkPath(targetPath, self._cleanupInFolder, dict()) #___________________________________________________________________________________________________ _cleanupInFolder def _cleanupInFolder(self, data): dirname = data.folder for name in data.names: if StringUtils.ends(name, self._compiler.ignoreExtensions): os.remove(FileUtils.createPath(dirname, name, isFile=True)) # Deletes python (.py) files associated with ui files so only .pyc files remain. if name.endswith('.ui'): pyName = name.rsplit('.', 1)[0] + '.py' pyNamePath = FileUtils.createPath(dirname, pyName, isFile=True) if os.path.exists(pyNamePath): os.remove(pyNamePath) #=================================================================================================== # I N T R I N S I C #___________________________________________________________________________________________________ __repr__ def __repr__(self): return self.__str__() #___________________________________________________________________________________________________ __unicode__ def __unicode__(self): return StringUtils.toUnicode(self.__str__()) #___________________________________________________________________________________________________ __str__ def __str__(self): return '<%s>' % self.__class__.__name__
class RemoteExecutionThread(QtCore.QThread): """ Threaded external processor execution""" #=================================================================================================== # C L A S S _ACTIVE_THREAD_STORAGE = [] completeSignal = QtCore.Signal(object) eventSignal = QtCore.Signal(object) logSignal = QtCore.Signal(object) progressSignal = QtCore.Signal(object) #___________________________________________________________________________________________________ __init__ def __init__(self, parent, **kwargs): QtCore.QThread.__init__(self, parent) self.userData = ArgsUtils.get('userData', None, kwargs) self._events = dict() self._log = Logger(self) self._log.trace = True self._log.addPrintCallback(self._handleLogWritten) self._logger = self._log self._maxLogBufferSize = 0 self._logBuffer = [] self._returnCode = None self._output = None self._error = None self._explicitComplete = ArgsUtils.get('explicitComplete', False, kwargs) # Add the thread to the static active thread storage so that it won't be garbage collected # until the thread completes. self.__class__._ACTIVE_THREAD_STORAGE.append(self) self._connectSignals(**kwargs) #=================================================================================================== # G E T / S E T #___________________________________________________________________________________________________ GS: success @property def success(self): return self.returnCode == 0 #___________________________________________________________________________________________________ GS: log @property def log(self): return self._log #___________________________________________________________________________________________________ GS: logger @property def logger(self): return self._log #___________________________________________________________________________________________________ GS: response @property def response(self): warnings.warn( 'RemoteExceutionThread.response is deprecated in favor of .returnCode', DeprecationWarning) self._log.write('[DEPRECATION WARNING]: Use returnCode instead of response', traceStack=True) return self._returnCode #___________________________________________________________________________________________________ GS: returnCode @property def returnCode(self): return self._returnCode #___________________________________________________________________________________________________ GS: output @property def output(self): return self._output #___________________________________________________________________________________________________ GS: error @property def error(self): return self._error #=================================================================================================== # P U B L I C #___________________________________________________________________________________________________ dispatchEvent def dispatchEvent(self, signal, identifier =None, data =None): signal.emit(RemoteThreadEvent( identifier=identifier, target=self, data=data)) #___________________________________________________________________________________________________ execute def execute( self, callback =None, logCallback =None, progressCallback =None, eventCallback =None, **kwargs ): self._connectSignals( callback=callback, logCallback=logCallback, progressCallback=progressCallback, eventCallback=eventCallback, **kwargs) self.start() #___________________________________________________________________________________________________ run def run(self): """ Thread run method.""" response = self._runImpl() if self._explicitComplete: return self._runComplete(response) #___________________________________________________________________________________________________ connectSignals def connectSignals(self, onComplete =None, onLog =None, onProgress =None, onEvent =None): """ Quick access method to connect callbacks to the various remote thread signals. """ return self._connectSignals( callback=onComplete, logCallback=onLog, progressCallback=onProgress, eventCallback=onEvent) #___________________________________________________________________________________________________ enableLogBuffer def enableLogBuffer(self, maxLength = 0): self._maxLogBufferSize = maxLength #___________________________________________________________________________________________________ disableLogBuffer def disableLogBuffer(self): self.flushLogBuffer(disable=True) #___________________________________________________________________________________________________ flushLogBuffer def flushLogBuffer(self, disable =False): if disable: self._maxLogBufferSize = 0 if self._logBuffer: b = self._logBuffer self._logBuffer = [] self.dispatchEvent(self.logSignal, 'log', {'message':'\n'.join(b)}) #=================================================================================================== # P R O T E C T E D #___________________________________________________________________________________________________ _connectSignals def _connectSignals(self, **kwargs): logCallback = ArgsUtils.get('logCallback', None, kwargs) if logCallback: self.logSignal.connect(logCallback) completeCallback = ArgsUtils.get('callback', None, kwargs) if completeCallback: self.completeSignal.connect(completeCallback) progressCallback = ArgsUtils.get('progressCallback', None, kwargs) if progressCallback: self.progressSignal.connect(progressCallback) eventCallback = ArgsUtils.get('eventCallback', None, kwargs) if eventCallback: self.eventSignal.connect(eventCallback) #___________________________________________________________________________________________________ _runComplete def _runComplete(self, response): self._returnCode = response if self._returnCode is None: self._returnCode = 0 self.dispatchEvent(self.completeSignal, 'complete', { 'response':self._returnCode, 'error':self._error, 'output':self._output, 'thread':self, 'userData':self.userData }) # Remove the thread from the active thread storage so that it can be garbage collected. self.__class__._ACTIVE_THREAD_STORAGE.remove(self) #___________________________________________________________________________________________________ _runImpl def _runImpl(self): return 0 #=================================================================================================== # H A N D L E R S #___________________________________________________________________________________________________ _handleLogWritten def _handleLogWritten(self, logger, value): if self._maxLogBufferSize > 0: self._logBuffer.append(value) if len(self._logBuffer) > self._maxLogBufferSize: self.flushLogBuffer() else: self.dispatchEvent(self.logSignal, 'log', {'message':value})