[dataimport] Correctly serialize datetime objects in _create_copyfrom_buffer, closes #3712885
# copyright 2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr -- mailto:contact@logilab.fr## This program is free software: you can redistribute it and/or modify it under# the terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## This program is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with this program. If not, see <http://www.gnu.org/licenses/>."""Instrumentation utilities"""importostry:importpygraphvizexceptImportError:pygraphviz=Nonefromcubicweb.cwvregimportCWRegistryStorefromcubicweb.devtools.devctlimportDevConfigurationALL_COLORS=["00FF00","0000FF","FFFF00","FF00FF","00FFFF","000000","800000","008000","000080","808000","800080","008080","808080","C00000","00C000","0000C0","C0C000","C000C0","00C0C0","C0C0C0","400000","004000","000040","404000","400040","004040","404040","200000","002000","000020","202000","200020","002020","202020","600000","006000","000060","606000","600060","006060","606060","A00000","00A000","0000A0","A0A000","A000A0","00A0A0","A0A0A0","E00000","00E000","0000E0","E0E000","E000E0","00E0E0","E0E0E0",]_COLORS={}defget_color(key):try:return_COLORS[key]exceptKeyError:_COLORS[key]='#'+ALL_COLORS[len(_COLORS)%len(ALL_COLORS)]return_COLORS[key]defwarn(msg,*args):print'WARNING: %s'%(msg%args)definfo(msg):print'INFO: '+msgclassPropagationAnalyzer(object):"""Abstract propagation analyzer, providing utility function to extract entities involved in propagation from a schema, as well as propagation rules from hooks (provided they use intrumentalized sets, see :class:`CubeTracerSet`). Concrete classes should at least define `prop_rel` class attribute and implements the `is_root` method. See `localperms` or `nosylist` cubes for example usage (`ccplugin` module). """prop_rel=None# name of the propagation relationdefinit(self,cube):"""Initialize analyze for the given cube, returning the (already loaded) vregistry and a set of entities which we're interested in. """config=DevConfiguration(cube)schema=config.load_schema()vreg=CWRegistryStore(config)vreg.set_schema(schema)# set_schema triggers objects registrationseschemas=set(eschemaforeschemainschema.entities()ifself.should_include(eschema))returnvreg,eschemasdefis_root(self,eschema):"""Return `True` if given entity schema is a root of the graph"""raiseNotImplementedError()defshould_include(self,eschema):"""Return `True` if given entity schema should be included by the graph. """ifself.prop_relineschema.subjrelsorself.is_root(eschema):returnTruereturnFalsedefprop_edges(self,s_rels,o_rels,eschemas):"""Return a set of edges where propagation has been detected. Each edge is defined by a 4-uple (from node, to node, rtype, package) where `rtype` is the relation type bringing from <from node> to <to node> and `package` is the cube adding the rule to the propagation control set (see see :class:`CubeTracerSet`). """schema=iter(eschemas).next().schemaprop_edges=set()forrtypeins_rels:found=Falseforsubj,objinschema.rschema(rtype).rdefs:ifsubjineschemasandobjineschemas:found=Trueprop_edges.add((subj,obj,rtype,s_rels.value_cube[rtype]))ifnotfound:warn('no rdef match for %s',rtype)forrtypeino_rels:found=Falseforsubj,objinschema.rschema(rtype).rdefs:ifsubjineschemasandobjineschemas:found=Trueprop_edges.add((obj,subj,rtype,o_rels.value_cube[rtype]))ifnotfound:warn('no rdef match for %s',rtype)returnprop_edgesdefdetect_problems(self,eschemas,edges):"""Given the set of analyzed entity schemas and edges between them, return a set of entity schemas where a problem has been detected. """problematic=set()foreschemaineschemas:ifself.has_problem(eschema,edges):problematic.add(eschema)not_problematic=set(eschemas).difference(problematic)ifnot_problematic:info('nothing problematic in: %s'%', '.join(e.typeforeinnot_problematic))returnproblematicdefhas_problem(self,eschema,edges):"""Return `True` if the given schema is considered problematic, considering base propagation rules. """root=self.is_root(eschema)has_prop_rel=self.prop_relineschema.subjrels# root but no propagation relationifrootandnothas_prop_rel:warn('%s is root but miss %s',eschema,self.prop_rel)returnTrue# propagated but without propagation relation / not propagated but# with propagation relationifnothas_prop_reland \any(edgeforedgeinedgesifedge[1]==eschema):warn("%s miss %s but is reached by propagation",eschema,self.prop_rel)returnTrueelifhas_prop_relandnotroot:rdef=eschema.rdef(self.prop_rel,takefirst=True)edges=[edgeforedgeinedgesifedge[1]==eschema]ifnotedges:warn("%s has %s but isn't reached by ""propagation",eschema,self.prop_rel)returnTrue# require_permission relation / propagation rule not added by# the same cubeelifnotany(edgeforedgeinedgesifedge[-1]==rdef.package):warn('%s has %s relation / propagation rule'' not added by the same cube (%s / %s)',eschema,self.prop_rel,rdef.package,edges[0][-1])returnTruereturnFalsedefinit_graph(self,eschemas,edges,problematic):"""Initialize and return graph, adding given nodes (entity schemas) and edges between them. Require pygraphviz installed. """ifpygraphvizisNone:raiseRuntimeError('pygraphviz is not installed')graph=pygraphviz.AGraph(strict=False,directed=True)foreschemaineschemas:ifeschemainproblematic:params={'color':'#ff0000','fontcolor':'#ff0000'}else:params={}#'color': get_color(eschema.package)}graph.add_node(eschema.type,**params)forsubj,obj,rtype,packageinedges:graph.add_edge(str(subj),str(obj),label=rtype,color=get_color(package))returngraphdefadd_colors_legend(self,graph):"""Add a legend of used colors to the graph."""forpackage,colorinsorted(_COLORS.iteritems()):graph.add_node(package,color=color,fontcolor=color,shape='record')classCubeTracerSet(object):"""Dumb set implementation whose purpose is to keep track of which cube is being loaded when something is added to the set. Results will be found in the `value_cube` attribute dictionary. See `localperms` or `nosylist` cubes for example usage (`hooks` module). """def__init__(self,vreg,wrapped):self.vreg=vregself.wrapped=wrappedself.value_cube={}defadd(self,value):self.wrapped.add(value)cube=self.vreg.currently_loading_cubeifvalueinself.value_cube:warn('%s is propagated by cube %s and cube %s',value,self.value_cube[value],cube)else:self.value_cube[value]=cubedef__iter__(self):returniter(self.wrapped)def__ior__(self,other):forvalueinother:self.add(value)returnselfdef__ror__(self,other):other|=self.wrappedreturnother