Commit 97a13e65 authored by Hanno Schlichting's avatar Hanno Schlichting

flake8

parent 41c8944d
...@@ -35,7 +35,7 @@ from AccessControl.Permissions import ftp_access ...@@ -35,7 +35,7 @@ from AccessControl.Permissions import ftp_access
from AccessControl.Permissions import import_export_objects from AccessControl.Permissions import import_export_objects
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
from AccessControl.ZopeSecurityPolicy import getRoles from AccessControl.ZopeSecurityPolicy import getRoles
from Acquisition import aq_base from Acquisition import aq_base, aq_parent
from Acquisition import Implicit from Acquisition import Implicit
from App.Common import is_acquired from App.Common import is_acquired
from App.config import getConfiguration from App.config import getConfiguration
...@@ -71,6 +71,10 @@ if bbb.HAS_ZSERVER: ...@@ -71,6 +71,10 @@ if bbb.HAS_ZSERVER:
else: else:
Collection = bbb.Collection Collection = bbb.Collection
if sys.version_info >= (3, ):
basestring = str
unicode = str
# Constants: __replaceable__ flags: # Constants: __replaceable__ flags:
NOT_REPLACEABLE = 0 NOT_REPLACEABLE = 0
REPLACEABLE = 1 REPLACEABLE = 1
...@@ -95,18 +99,24 @@ def checkValidId(self, id, allow_dup=0): ...@@ -95,18 +99,24 @@ def checkValidId(self, id, allow_dup=0):
if not id or not isinstance(id, str): if not id or not isinstance(id, str):
if isinstance(id, unicode): if isinstance(id, unicode):
id = escape(id) id = escape(id)
raise BadRequest, ('Empty or invalid id specified', id) raise BadRequest('Empty or invalid id specified', id)
if bad_id(id) is not None: if bad_id(id) is not None:
raise BadRequest, ( raise BadRequest(
'The id "%s" contains characters illegal in URLs.' % escape(id)) 'The id "%s" contains characters illegal in URLs.' % escape(id))
if id in ('.', '..'): raise BadRequest, ( if id in ('.', '..'):
raise BadRequest(
'The id "%s" is invalid because it is not traversable.' % id) 'The id "%s" is invalid because it is not traversable.' % id)
if id.startswith('_'): raise BadRequest, ( if id.startswith('_'):
'The id "%s" is invalid because it begins with an underscore.' % id) raise BadRequest(
if id.startswith('aq_'): raise BadRequest, ( 'The id "%s" is invalid because it '
'begins with an underscore.' % id)
if id.startswith('aq_'):
raise BadRequest(
'The id "%s" is invalid because it begins with "aq_".' % id) 'The id "%s" is invalid because it begins with "aq_".' % id)
if id.endswith('__'): raise BadRequest, ( if id.endswith('__'):
'The id "%s" is invalid because it ends with two underscores.' % id) raise BadRequest(
'The id "%s" is invalid because it '
'ends with two underscores.' % id)
if not allow_dup: if not allow_dup:
obj = getattr(self, id, None) obj = getattr(self, id, None)
if obj is not None: if obj is not None:
...@@ -116,30 +126,28 @@ def checkValidId(self, id, allow_dup=0): ...@@ -116,30 +126,28 @@ def checkValidId(self, id, allow_dup=0):
if hasattr(aq_base(self), id): if hasattr(aq_base(self), id):
# The object is located in this ObjectManager. # The object is located in this ObjectManager.
if not flags & REPLACEABLE: if not flags & REPLACEABLE:
raise BadRequest, ( raise BadRequest(
'The id "%s" is invalid - it is already in use.' % id) 'The id "%s" is invalid - it is already in use.' % id)
# else the object is replaceable even if the UNIQUE # else the object is replaceable even if the UNIQUE
# flag is set. # flag is set.
elif flags & UNIQUE: elif flags & UNIQUE:
raise BadRequest, ('The id "%s" is reserved.' % id) raise BadRequest('The id "%s" is reserved.' % id)
if id == 'REQUEST': if id == 'REQUEST':
raise BadRequest, 'REQUEST is a reserved name.' raise BadRequest('REQUEST is a reserved name.')
if '/' in id: if '/' in id:
raise BadRequest, ( raise BadRequest(
'The id "%s" contains characters illegal in URLs.' % id) 'The id "%s" contains characters illegal in URLs.' % id)
class BeforeDeleteException(Exception): class BeforeDeleteException(Exception):
pass # raise to veto deletion pass # raise to veto deletion
class BreakoutException(Exception): class BreakoutException(Exception):
pass # raised to break out of loops pass # raised to break out of loops
_marker=[] _marker = []
class ObjectManager(CopyContainer, class ObjectManager(CopyContainer,
...@@ -149,8 +157,7 @@ class ObjectManager(CopyContainer, ...@@ -149,8 +157,7 @@ class ObjectManager(CopyContainer,
Persistent, Persistent,
Collection, Collection,
LockableItem, LockableItem,
Traversable, Traversable):
):
"""Generic object manager """Generic object manager
...@@ -166,27 +173,24 @@ class ObjectManager(CopyContainer, ...@@ -166,27 +173,24 @@ class ObjectManager(CopyContainer,
meta_type = 'Object Manager' meta_type = 'Object Manager'
meta_types=() # Sub-object types that are specific to this object meta_types = () # Sub-object types that are specific to this object
_objects = () _objects = ()
security.declareProtected(view_management_screens, 'manage_main') security.declareProtected(view_management_screens, 'manage_main')
manage_main=DTMLFile('dtml/main', globals()) manage_main = DTMLFile('dtml/main', globals())
manage_index_main=DTMLFile('dtml/index_main', globals()) manage_index_main = DTMLFile('dtml/index_main', globals())
manage_options=( manage_options = (
{'label':'Contents', 'action':'manage_main'}, {'label': 'Contents', 'action': 'manage_main'},
) )
isAnObjectManager=1 isAnObjectManager = 1
isPrincipiaFolderish = 1
isPrincipiaFolderish=1
has_order_support = 0 # See OrderSupport.py has_order_support = 0 # See OrderSupport.py
# IPossibleSite API # IPossibleSite API
_components = None _components = None
security.declarePublic('getSiteManager') security.declarePublic('getSiteManager')
...@@ -199,19 +203,22 @@ class ObjectManager(CopyContainer, ...@@ -199,19 +203,22 @@ class ObjectManager(CopyContainer,
def setSiteManager(self, components): def setSiteManager(self, components):
self._components = components self._components = components
def __class_init__(self): def __class_init__(self):
try: mt=list(self.meta_types) try:
except: mt=[] mt = list(self.meta_types)
except Exception:
mt = []
for b in self.__bases__: for b in self.__bases__:
try: try:
for t in b.meta_types: for t in b.meta_types:
if t not in mt: mt.append(t) if t not in mt:
except: pass mt.append(t)
except Exception:
pass
mt.sort() mt.sort()
self.meta_types=tuple(mt) self.meta_types = tuple(mt)
InitializeClass(self) # default__class_init__ InitializeClass(self)
def all_meta_types(self, interfaces=None): def all_meta_types(self, interfaces=None):
# A list of products registered elsewhere # A list of products registered elsewhere
...@@ -221,7 +228,7 @@ class ObjectManager(CopyContainer, ...@@ -221,7 +228,7 @@ class ObjectManager(CopyContainer,
# Look at all globally visible meta types. # Look at all globally visible meta types.
for entry in getattr(Products, 'meta_types', ()): for entry in getattr(Products, 'meta_types', ()):
if ((interfaces is not None) or if ((interfaces is not None) or
(entry.get("visibility", None)=="Global")): (entry.get("visibility", None) == "Global")):
external_candidates.append(entry) external_candidates.append(entry)
# Filter the list of external candidates based on the # Filter the list of external candidates based on the
...@@ -232,7 +239,7 @@ class ObjectManager(CopyContainer, ...@@ -232,7 +239,7 @@ class ObjectManager(CopyContainer,
interface_constrained_meta_types = icmt = [] interface_constrained_meta_types = icmt = []
for entry in external_candidates: for entry in external_candidates:
try: try:
eil = entry.get('interfaces',None) eil = entry.get('interfaces', None)
if eil is not None: if eil is not None:
for ei in eil: for ei in eil:
for i in interfaces: for i in interfaces:
...@@ -250,7 +257,7 @@ class ObjectManager(CopyContainer, ...@@ -250,7 +257,7 @@ class ObjectManager(CopyContainer,
# Filter the list based on each meta-types's container_filter # Filter the list based on each meta-types's container_filter
meta_types = [] meta_types = []
for entry in interface_constrained_meta_types: for entry in interface_constrained_meta_types:
container_filter = entry.get('container_filter',None) container_filter = entry.get('container_filter', None)
if container_filter is None: if container_filter is None:
meta_types.append(entry) meta_types.append(entry)
else: else:
...@@ -295,7 +302,7 @@ class ObjectManager(CopyContainer, ...@@ -295,7 +302,7 @@ class ObjectManager(CopyContainer,
if id[:1] != '_' and hasattr(aq_base(self), id): if id[:1] != '_' and hasattr(aq_base(self), id):
return getattr(self, id) return getattr(self, id)
if default is _marker: if default is _marker:
raise AttributeError, id raise AttributeError(id)
return default return default
security.declareProtected(access_contents_information, 'hasObject') security.declareProtected(access_contents_information, 'hasObject')
...@@ -410,28 +417,28 @@ class ObjectManager(CopyContainer, ...@@ -410,28 +417,28 @@ class ObjectManager(CopyContainer,
# If 'spec' is specified, returns objects whose meta_type # If 'spec' is specified, returns objects whose meta_type
# matches 'spec'. # matches 'spec'.
if spec is not None: if spec is not None:
if type(spec)==type('s'): if isinstance(spec, str):
spec=[spec] spec = [spec]
set=[] set = []
for ob in self._objects: for ob in self._objects:
if ob['meta_type'] in spec: if ob['meta_type'] in spec:
set.append(ob['id']) set.append(ob['id'])
return set return set
return [ o['id'] for o in self._objects ] return [o['id'] for o in self._objects]
security.declareProtected(access_contents_information, 'objectValues') security.declareProtected(access_contents_information, 'objectValues')
def objectValues(self, spec=None): def objectValues(self, spec=None):
# Returns a list of actual subobjects of the current object. # Returns a list of actual subobjects of the current object.
# If 'spec' is specified, returns only objects whose meta_type # If 'spec' is specified, returns only objects whose meta_type
# match 'spec'. # match 'spec'.
return [ self._getOb(id) for id in self.objectIds(spec) ] return [self._getOb(id) for id in self.objectIds(spec)]
security.declareProtected(access_contents_information, 'objectItems') security.declareProtected(access_contents_information, 'objectItems')
def objectItems(self, spec=None): def objectItems(self, spec=None):
# Returns a list of (id, subobject) tuples of the current object. # Returns a list of (id, subobject) tuples of the current object.
# If 'spec' is specified, returns only objects whose meta_type match # If 'spec' is specified, returns only objects whose meta_type match
# 'spec' # 'spec'
return [ (id, self._getOb(id)) for id in self.objectIds(spec) ] return [(id, self._getOb(id)) for id in self.objectIds(spec)]
def objectMap(self): def objectMap(self):
# Return a tuple of mappings containing subobject meta-data # Return a tuple of mappings containing subobject meta-data
...@@ -439,13 +446,16 @@ class ObjectManager(CopyContainer, ...@@ -439,13 +446,16 @@ class ObjectManager(CopyContainer,
security.declareProtected(access_contents_information, 'objectIds_d') security.declareProtected(access_contents_information, 'objectIds_d')
def objectIds_d(self, t=None): def objectIds_d(self, t=None):
if hasattr(self, '_reserved_names'): n=self._reserved_names if hasattr(self, '_reserved_names'):
else: n=() n = self._reserved_names
if not n: return self.objectIds(t) else:
r=[] n = ()
a=r.append if not n:
return self.objectIds(t)
r = []
for id in self.objectIds(t): for id in self.objectIds(t):
if id not in n: a(id) if id not in n:
r.append(id)
return r return r
security.declareProtected(access_contents_information, 'objectValues_d') security.declareProtected(access_contents_information, 'objectValues_d')
...@@ -454,55 +464,60 @@ class ObjectManager(CopyContainer, ...@@ -454,55 +464,60 @@ class ObjectManager(CopyContainer,
security.declareProtected(access_contents_information, 'objectItems_d') security.declareProtected(access_contents_information, 'objectItems_d')
def objectItems_d(self, t=None): def objectItems_d(self, t=None):
r=[] r = []
a=r.append for id in self.objectIds_d(t):
g=self._getOb r.append((id, self._getOb(id)))
for id in self.objectIds_d(t): a((id, g(id)))
return r return r
security.declareProtected(access_contents_information, 'objectMap_d') security.declareProtected(access_contents_information, 'objectMap_d')
def objectMap_d(self, t=None): def objectMap_d(self, t=None):
if hasattr(self, '_reserved_names'): n=self._reserved_names if hasattr(self, '_reserved_names'):
else: n=() n = self._reserved_names
if not n: return self._objects else:
r=[] n = ()
a=r.append if not n:
return self._objects
r = []
for d in self._objects: for d in self._objects:
if d['id'] not in n: a(d.copy()) if d['id'] not in n:
r.append(d.copy())
return r return r
security.declareProtected(access_contents_information, 'superValues') security.declareProtected(access_contents_information, 'superValues')
def superValues(self, t): def superValues(self, t):
# Return all of the objects of a given type located in # Return all of the objects of a given type located in
# this object and containing objects. # this object and containing objects.
if type(t)==type('s'): t=(t,) if isinstance(t, str):
obj=self t = (t,)
seen={} obj = self
vals=[] seen = {}
vals = []
relativePhysicalPath = () relativePhysicalPath = ()
x=0 x = 0
while x < 100: while x < 100:
if not hasattr(obj,'_getOb'): break if not hasattr(obj, '_getOb'):
get=obj._getOb break
if hasattr(obj,'_objects'): get = obj._getOb
if hasattr(obj, '_objects'):
for i in obj._objects: for i in obj._objects:
try: try:
id=i['id'] id = i['id']
physicalPath = relativePhysicalPath + (id,) physicalPath = relativePhysicalPath + (id,)
if (physicalPath not in seen) and (i['meta_type'] in t): if ((physicalPath not in seen) and
(i['meta_type'] in t)):
vals.append(get(id)) vals.append(get(id))
seen[physicalPath]=1 seen[physicalPath] = 1
except: pass except Exception:
pass
if hasattr(obj,'aq_parent'): if hasattr(obj, '__parent__'):
obj=obj.aq_parent obj = aq_parent(obj)
relativePhysicalPath = ('..',) + relativePhysicalPath relativePhysicalPath = ('..',) + relativePhysicalPath
else: else:
return vals return vals
x=x+1 x = x + 1
return vals return vals
manage_addProduct = ProductDispatcher() manage_addProduct = ProductDispatcher()
security.declareProtected(delete_objects, 'manage_delObjects') security.declareProtected(delete_objects, 'manage_delObjects')
...@@ -514,7 +529,8 @@ class ObjectManager(CopyContainer, ...@@ -514,7 +529,8 @@ class ObjectManager(CopyContainer,
if isinstance(ids, basestring): if isinstance(ids, basestring):
ids = [ids] ids = [ids]
if not ids: if not ids:
return MessageDialog(title='No items specified', return MessageDialog(
title='No items specified',
message='No items were specified!', message='No items were specified!',
action='./manage_main',) action='./manage_main',)
try: try:
...@@ -523,7 +539,8 @@ class ObjectManager(CopyContainer, ...@@ -523,7 +539,8 @@ class ObjectManager(CopyContainer,
p = () p = ()
for n in ids: for n in ids:
if n in p: if n in p:
return MessageDialog(title='Not Deletable', return MessageDialog(
title='Not Deletable',
message='<EM>%s</EM> cannot be deleted.' % escape(n), message='<EM>%s</EM> cannot be deleted.' % escape(n),
action='./manage_main',) action='./manage_main',)
while ids: while ids:
...@@ -544,10 +561,11 @@ class ObjectManager(CopyContainer, ...@@ -544,10 +561,11 @@ class ObjectManager(CopyContainer,
security.declareProtected(access_contents_information, 'tpValues') security.declareProtected(access_contents_information, 'tpValues')
def tpValues(self): def tpValues(self):
# Return a list of subobjects, used by tree tag. # Return a list of subobjects, used by tree tag.
r=[] r = []
if hasattr(aq_base(self), 'tree_ids'): if hasattr(aq_base(self), 'tree_ids'):
tree_ids=self.tree_ids tree_ids = self.tree_ids
try: tree_ids=list(tree_ids) try:
tree_ids = list(tree_ids)
except TypeError: except TypeError:
pass pass
if hasattr(tree_ids, 'sort'): if hasattr(tree_ids, 'sort'):
...@@ -556,10 +574,10 @@ class ObjectManager(CopyContainer, ...@@ -556,10 +574,10 @@ class ObjectManager(CopyContainer,
if hasattr(self, id): if hasattr(self, id):
r.append(self._getOb(id)) r.append(self._getOb(id))
else: else:
obj_ids=self.objectIds() obj_ids = self.objectIds()
obj_ids.sort() obj_ids.sort()
for id in obj_ids: for id in obj_ids:
o=self._getOb(id) o = self._getOb(id)
if hasattr(aq_base(o), 'isPrincipiaFolderish') and \ if hasattr(aq_base(o), 'isPrincipiaFolderish') and \
o.isPrincipiaFolderish: o.isPrincipiaFolderish:
r.append(o) r.append(o)
...@@ -654,9 +672,9 @@ class ObjectManager(CopyContainer, ...@@ -654,9 +672,9 @@ class ObjectManager(CopyContainer,
def _getImportPaths(self): def _getImportPaths(self):
cfg = getConfiguration() cfg = getConfiguration()
paths = [] paths = []
if not cfg.instancehome in paths: if cfg.instancehome not in paths:
paths.append(cfg.instancehome) paths.append(cfg.instancehome)
if not cfg.clienthome in paths: if cfg.clienthome not in paths:
paths.append(cfg.clienthome) paths.append(cfg.clienthome)
return paths return paths
...@@ -677,23 +695,22 @@ class ObjectManager(CopyContainer, ...@@ -677,23 +695,22 @@ class ObjectManager(CopyContainer,
def manage_FTPlist(self, REQUEST): def manage_FTPlist(self, REQUEST):
"""Directory listing for FTP. """Directory listing for FTP.
""" """
out=() out = ()
# check to see if we are being acquiring or not # check to see if we are being acquiring or not
ob=self ob = self
while 1: while 1:
if is_acquired(ob): if is_acquired(ob):
raise ValueError('FTP List not supported on acquired objects') raise ValueError('FTP List not supported on acquired objects')
if not hasattr(ob,'aq_parent'): if not hasattr(ob, '__parent__'):
break break
ob=ob.aq_parent ob = aq_parent(ob)
files = list(self.objectItems()) files = list(self.objectItems())
# recursive ride through all subfolders (ls -R) (ajung) # recursive ride through all subfolders (ls -R) (ajung)
if REQUEST.environ.get('FTP_RECURSIVE',0) == 1: if REQUEST.environ.get('FTP_RECURSIVE', 0) == 1:
all_files = copy.copy(files) all_files = copy.copy(files)
for f in files: for f in files:
if (hasattr(aq_base(f[1]), 'isPrincipiaFolderish') and if (hasattr(aq_base(f[1]), 'isPrincipiaFolderish') and
...@@ -703,29 +720,29 @@ class ObjectManager(CopyContainer, ...@@ -703,29 +720,29 @@ class ObjectManager(CopyContainer,
# Perform globbing on list of files (ajung) # Perform globbing on list of files (ajung)
globbing = REQUEST.environ.get('GLOBBING','') globbing = REQUEST.environ.get('GLOBBING', '')
if globbing : if globbing:
files = [x for x in files if fnmatch.fnmatch(x[0],globbing)] files = [x for x in files if fnmatch.fnmatch(x[0], globbing)]
files.sort() files.sort()
if not (hasattr(self,'isTopLevelPrincipiaApplicationObject') and if not (hasattr(self, 'isTopLevelPrincipiaApplicationObject') and
self.isTopLevelPrincipiaApplicationObject): self.isTopLevelPrincipiaApplicationObject):
files.insert(0,('..',self.aq_parent)) files.insert(0, ('..', aq_parent(self)))
files.insert(0, ('.', self)) files.insert(0, ('.', self))
for k,v in files: for k, v in files:
# Note that we have to tolerate failure here, because # Note that we have to tolerate failure here, because
# Broken objects won't stat correctly. If an object fails # Broken objects won't stat correctly. If an object fails
# to be able to stat itself, we will ignore it, but log # to be able to stat itself, we will ignore it, but log
# the error. # the error.
try: try:
stat=marshal.loads(v.manage_FTPstat(REQUEST)) stat = marshal.loads(v.manage_FTPstat(REQUEST))
except: except:
LOG.error("Failed to stat file '%s'" % k, LOG.error("Failed to stat file '%s'" % k,
exc_info=sys.exc_info()) exc_info=sys.exc_info())
stat=None stat = None
if stat is not None: if stat is not None:
out=out+((k,stat),) out = out + ((k, stat),)
return marshal.dumps(out) return marshal.dumps(out)
security.declareProtected(ftp_access, 'manage_hasId') security.declareProtected(ftp_access, 'manage_hasId')
...@@ -736,36 +753,36 @@ class ObjectManager(CopyContainer, ...@@ -736,36 +753,36 @@ class ObjectManager(CopyContainer,
raise KeyError(REQUEST['id']) raise KeyError(REQUEST['id'])
security.declareProtected(ftp_access, 'manage_FTPstat') security.declareProtected(ftp_access, 'manage_FTPstat')
def manage_FTPstat(self,REQUEST): def manage_FTPstat(self, REQUEST):
"""Psuedo stat, used by FTP for directory listings. """Psuedo stat, used by FTP for directory listings.
""" """
mode=0040000 mode = 0o0040000
from AccessControl.User import nobody from AccessControl.User import nobody
# check to see if we are acquiring our objectValues or not # check to see if we are acquiring our objectValues or not
if not (len(REQUEST.PARENTS) > 1 and if not (len(REQUEST.PARENTS) > 1 and
self.objectValues() == REQUEST.PARENTS[1].objectValues()): self.objectValues() == REQUEST.PARENTS[1].objectValues()):
try: try:
if getSecurityManager().validate( if getSecurityManager().validate(
None, self, 'manage_FTPlist', self.manage_FTPlist None, self, 'manage_FTPlist', self.manage_FTPlist):
): mode = mode | 0o0770
mode=mode | 0770 except Exception:
except: pass pass
if nobody.allowed( if nobody.allowed(self, getRoles(
self, self, 'manage_FTPlist', self.manage_FTPlist, ())):
getRoles(self, 'manage_FTPlist', self.manage_FTPlist, ())): mode = mode | 0o0007
mode=mode | 0007
if hasattr(aq_base(self), '_p_mtime'): if hasattr(aq_base(self), '_p_mtime'):
mtime = DateTime(self._p_mtime).timeTime() mtime = DateTime(self._p_mtime).timeTime()
else: else:
mtime = time.time() mtime = time.time()
# get owner and group # get owner and group
owner=group='Zope' owner = group = 'Zope'
for user, roles in self.get_local_roles(): for user, roles in self.get_local_roles():
if 'Owner' in roles: if 'Owner' in roles:
owner=user owner = user
break break
return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime)) return marshal.dumps(
(mode, 0, 0, 1, owner, group, 0, mtime, mtime, mtime))
def __delitem__(self, name): def __delitem__(self, name):
return self.manage_delObjects(ids=[name]) return self.manage_delObjects(ids=[name])
...@@ -827,7 +844,7 @@ class ObjectManager(CopyContainer, ...@@ -827,7 +844,7 @@ class ObjectManager(CopyContainer,
# InitializeClass(ObjectManager) # InitializeClass(ObjectManager)
def findChildren(obj,dirname=''): def findChildren(obj, dirname=''):
""" recursive walk through the object hierarchy to """ recursive walk through the object hierarchy to
find all children of an object (ajung) find all children of an object (ajung)
""" """
...@@ -849,9 +866,11 @@ class IFAwareObjectManager: ...@@ -849,9 +866,11 @@ class IFAwareObjectManager:
if interfaces is None: if interfaces is None:
if hasattr(self, '_product_interfaces'): if hasattr(self, '_product_interfaces'):
interfaces=self._product_interfaces interfaces = self._product_interfaces
elif hasattr(self, 'aq_acquire'): elif hasattr(self, 'aq_acquire'):
try: interfaces=self.aq_acquire('_product_interfaces') try:
except: pass # Bleah generic pass is bad interfaces = self.aq_acquire('_product_interfaces')
except Exception:
pass
return ObjectManager.all_meta_types(self, interfaces) return ObjectManager.all_meta_types(self, interfaces)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment