[cmislib-alfresco-extension] 3 new revisions pushed by pcollar...@gmail.com on 2011-07-21 08:15 GMT

12 views
Skip to first unread message

cmislib-alfre...@googlecode.com

unread,
Jul 21, 2011, 4:15:25 AM7/21/11
to cmislib-alfresco-...@googlegroups.com
3 new revisions:

Revision: bf2ef9837aa5
Author: Patrice Collardez
Date: Fri Jun 24 03:04:59 2011
Log: Added tag 0.1 for changeset f48aadb0c03a
http://code.google.com/p/cmislib-alfresco-extension/source/detail?r=bf2ef9837aa5

Revision: dd1a87255a71
Author: Patrice Collardez
Date: Fri Jun 24 04:10:22 2011
Log: Added license...
http://code.google.com/p/cmislib-alfresco-extension/source/detail?r=dd1a87255a71

Revision: a8a2ba870ee4
Author: Patrice Collardez
Date: Wed Jul 20 02:14:19 2011
Log: Added non-Alfresco repository tests...
http://code.google.com/p/cmislib-alfresco-extension/source/detail?r=a8a2ba870ee4

==============================================================================
Revision: bf2ef9837aa5
Author: Patrice Collardez
Date: Fri Jun 24 03:04:59 2011
Log: Added tag 0.1 for changeset f48aadb0c03a
http://code.google.com/p/cmislib-alfresco-extension/source/detail?r=bf2ef9837aa5

Added:
/.hgtags

=======================================
--- /dev/null
+++ /.hgtags Fri Jun 24 03:04:59 2011
@@ -0,0 +1,1 @@
+f48aadb0c03a99ab3c49a38e6f1a26c78eb37ad7 0.1

==============================================================================
Revision: dd1a87255a71
Author: Patrice Collardez
Date: Fri Jun 24 04:10:22 2011
Log: Added license
Moved utility methods into a module (no API change)
http://code.google.com/p/cmislib-alfresco-extension/source/detail?r=dd1a87255a71

Added:
/LICENSE.txt
/src/cmislibalf/extension.py
Modified:
/.hgignore
/setup.cfg
/setup.py
/src/cmislibalf/__init__.py
/src/tests/__init__.py
/src/tests/cmislibalftest.py

=======================================
--- /dev/null
+++ /LICENSE.txt Fri Jun 24 04:10:22 2011
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other
modifications
+ represent, as a whole, an original work of authorship. For the
purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces
of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright
owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control
systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this
License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
=======================================
--- /dev/null
+++ /src/cmislibalf/extension.py Fri Jun 24 04:10:22 2011
@@ -0,0 +1,287 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+from cmislib import model
+from cmislib.exceptions import InvalidArgumentException
+import datetime
+
+ALFRESCO_NS = 'http://www.alfresco.org'
+ALFRESCO_NSALIAS = 'alf'
+ALFRESCO_NSALIAS_DECL = 'xmlns:' + ALFRESCO_NSALIAS
+ALFRESCO_NSPREFIX = ALFRESCO_NSALIAS + ':'
+
+LOCALNAME_ASPECTS = 'aspects'
+LOCALNAME_PROPERTIES = 'properties'
+LOCALNAME_APPLIED_ASPECTS = 'appliedAspects'
+LOCALNAME_SET_ASPECTS = 'setAspects'
+LOCALNAME_ASPECTS_TO_ADD = 'aspectsToAdd'
+LOCALNAME_ASPECTS_TO_REMOVE = 'aspectsToRemove'
+
+TAGNAME_ALFRESCO_PROPERTIES = ALFRESCO_NSPREFIX + LOCALNAME_PROPERTIES
+TAGNAME_SET_ASPECTS = ALFRESCO_NSPREFIX + LOCALNAME_SET_ASPECTS
+TAGNAME_ASPECTS_TO_ADD = ALFRESCO_NSPREFIX + LOCALNAME_ASPECTS_TO_ADD
+TAGNAME_ASPECTS_TO_REMOVE = ALFRESCO_NSPREFIX + LOCALNAME_ASPECTS_TO_REMOVE
+
+OBJECT_TYPE_ID = 'cmis:objectTypeId'
+
+def addSetAspectsToXMLDocument(xmldoc):
+ entryElements = xmldoc.getElementsByTagNameNS(model.ATOM_NS, 'entry')
+ entryElements[0].setAttribute(ALFRESCO_NSALIAS_DECL, ALFRESCO_NS)
+
+ propertiesElements = xmldoc.getElementsByTagNameNS(model.CMIS_NS,
LOCALNAME_PROPERTIES)
+ if len(propertiesElements) == 0:
+ objectElement =
xmldoc.getElementsByTagNameNS(model.CMISRA_NS, 'object')
+ propertiesElement =
xmldoc.createElementNS(model.CMIS_NS, 'cmis:properties')
+ objectElement[0].appendChild(propertiesElement)
+ else:
+ propertiesElement = propertiesElements[0]
+
+ aspectsElement = xmldoc.createElementNS(ALFRESCO_NS,
TAGNAME_SET_ASPECTS)
+ propertiesElement.appendChild(aspectsElement)
+
+ return aspectsElement
+
+def addPropertiesToXMLElement(xmldoc, element, properties):
+ for propName, propValue in properties.items():
+ """
+ the name of the element here is significant: it includes the
+ data type. I should be able to figure out the right type based
+ on the actual type of the object passed in.
+
+ I could do a lookup to the type definition, but that doesn't
+ seem worth the performance hit
+ """
+ propType = type(propValue)
+ isList = False
+ if (propType == list):
+ propType = type(propValue[0])
+ isList = True
+
+ if (propType == model.CmisId):
+ propElementName = 'cmis:propertyId'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(val)
+ else:
+ propValueStrList = [propValue]
+ elif (propType == str):
+ propElementName = 'cmis:propertyString'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(val)
+ else:
+ propValueStrList = [propValue]
+ elif (propType == datetime.datetime):
+ propElementName = 'cmis:propertyDateTime'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(val.isoformat())
+ else:
+ propValueStrList = [propValue.isoformat()]
+ elif (propType == bool):
+ propElementName = 'cmis:propertyBoolean'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(unicode(val).lower())
+ else:
+ propValueStrList = [unicode(propValue).lower()]
+ elif (propType == int):
+ propElementName = 'cmis:propertyInteger'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(unicode(val))
+ else:
+ propValueStrList = [unicode(propValue)]
+ elif (propType == float):
+ propElementName = 'cmis:propertyDecimal'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(unicode(val))
+ else:
+ propValueStrList = [unicode(propValue)]
+ else:
+ propElementName = 'cmis:propertyString'
+ if isList:
+ propValueStrList = []
+ for val in propValue:
+ propValueStrList.append(unicode(val))
+ else:
+ propValueStrList = [unicode(propValue)]
+
+ propElement = xmldoc.createElementNS(model.CMIS_NS,
propElementName)
+ propElement.setAttribute('propertyDefinitionId', propName)
+ for val in propValueStrList:
+ valElement =
xmldoc.createElementNS(model.CMIS_NS, 'cmis:value')
+ valText = xmldoc.createTextNode(val)
+ valElement.appendChild(valText)
+ propElement.appendChild(valElement)
+ element.appendChild(propElement)
+
+def initData(self):
+ model.CmisObject._initData(self)
+ self._aspects = {}
+ self._alfproperties = {}
+
+def findAlfrescoExtensions(self):
+ if not hasattr(self, '_aspects'):
+ self._aspects = {}
+ if self._aspects == {}:
+ if self.xmlDoc == None:
+ self.reload()
+ appliedAspects = self.xmlDoc.getElementsByTagNameNS(ALFRESCO_NS,
LOCALNAME_APPLIED_ASPECTS)
+ for node in appliedAspects:
+ aspectType =
self._repository.getTypeDefinition(node.childNodes[0].data)
+ self._aspects[node.childNodes[0].data] = aspectType
+
+def hasAspect(self, arg):
+ result = False
+ if arg is not None:
+ self._findAlfrescoExtensions()
+ if isinstance(arg, model.ObjectType):
+ result = arg.getTypeId() in self._aspects
+ else:
+ result = arg in self._aspects
+ return result
+
+def getAspects(self):
+ self._findAlfrescoExtensions()
+ return self._aspects.values()
+
+def findAspect(self, propertyId):
+ self._findAlfrescoExtensions()
+ if (propertyId is not None) and (len(self._aspects) > 0):
+ for id, aspect in self._aspects.iteritems():
+ props = aspect.getProperties()
+ if propertyId in props:
+ return aspect
+ return None
+
+def updateAspects(self, addAspects=None, removeAspects=None):
+ if addAspects or removeAspects:
+ selfUrl = self._getSelfLink()
+ xmlEntryDoc = model.getEntryXmlDoc()
+ # Patch xmlEntryDoc
+ setAspectsElement = addSetAspectsToXMLDocument(xmlEntryDoc)
+
+ if addAspects:
+ addAspectElement = xmlEntryDoc.createElementNS(ALFRESCO_NS,
TAGNAME_ASPECTS_TO_ADD)
+ valText = xmlEntryDoc.createTextNode(addAspects)
+ addAspectElement.appendChild(valText)
+ setAspectsElement.appendChild(addAspectElement)
+
+ if removeAspects:
+ removeAspectElement = xmlEntryDoc.createElementNS(ALFRESCO_NS,
TAGNAME_ASPECTS_TO_REMOVE)
+ valText = xmlEntryDoc.createTextNode(removeAspects)
+ removeAspectElement.appendChild(valText)
+ setAspectsElement.appendChild(removeAspectElement)
+
+ updatedXmlDoc = self._cmisClient.put(selfUrl.encode('utf-8'),
+
xmlEntryDoc.toxml(encoding='utf-8'),
+ model.ATOM_XML_TYPE)
+
+ self.xmlDoc = updatedXmlDoc
+ self._initData()
+
+def getProperties(self):
+ result = model.CmisObject.getProperties(self)
+ if not hasattr(self, '_alfproperties'):
+ self._alfproperties = {}
+ if self._alfproperties == {}:
+ alfpropertiesElement =
self.xmlDoc.getElementsByTagNameNS(ALFRESCO_NS, LOCALNAME_PROPERTIES)[0]
+ for node in [e for e in alfpropertiesElement.childNodes if
e.nodeType == e.ELEMENT_NODE and e.namespaceURI == model.CMIS_NS]:
+ #propertyId, propertyString, propertyDateTime
+ #propertyType = cpattern.search(node.localName).groups()[0]
+ propertyName = node.attributes['propertyDefinitionId'].value
+ if node.childNodes and \
+ node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0] and \
+
node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0].childNodes:
+ valNodeList =
node.getElementsByTagNameNS(model.CMIS_NS, 'value')
+ if (len(valNodeList) == 1):
+ propertyValue = model.parsePropValue(valNodeList[0].
+ childNodes[0].data,
+ node.localName)
+ else:
+ propertyValue = []
+ for valNode in valNodeList:
+ propertyValue.append(model.parsePropValue(valNode.
+ childNodes[0].data,
+ node.localName))
+ else:
+ propertyValue = None
+ self._alfproperties[propertyName] = propertyValue
+ result.update(self._alfproperties)
+ return result
+
+def updateProperties(self, properties):
+ selfUrl = self._getSelfLink()
+ cmisproperties = {}
+ alfproperties = {}
+
+ objectTypeId = properties.get(OBJECT_TYPE_ID)
+ if (objectTypeId is None):
+ objectTypeId = self.properties.get(OBJECT_TYPE_ID)
+ objectType = self._repository.getTypeDefinition(objectTypeId)
+ objectTypePropsDef = objectType.getProperties()
+
+ for propertyName, propertyValue in properties.items():
+ if (propertyName == OBJECT_TYPE_ID) or (propertyName in
objectTypePropsDef.keys()):
+ cmisproperties[propertyName] = propertyValue
+ else:
+ if self.findAspect(propertyName) is None:
+ raise InvalidArgumentException
+ else:
+ alfproperties[propertyName] = propertyValue
+
+ xmlEntryDoc = model.getEntryXmlDoc(cmisproperties)
+
+ # Patch xmlEntryDoc
+ # add alfresco properties
+ if len(alfproperties) > 0:
+ aspectsElement = addSetAspectsToXMLDocument(xmlEntryDoc)
+
+ alfpropertiesElement = xmlEntryDoc.createElementNS(ALFRESCO_NS,
TAGNAME_ALFRESCO_PROPERTIES)
+ aspectsElement.appendChild(alfpropertiesElement)
+ # Like regular properties
+ addPropertiesToXMLElement(xmlEntryDoc, alfpropertiesElement,
alfproperties)
+
+ updatedXmlDoc = self._cmisClient.put(selfUrl.encode('utf-8'),
+
xmlEntryDoc.toxml(encoding='utf-8'),
+ model.ATOM_XML_TYPE)
+ self.xmlDoc = updatedXmlDoc
+ self._initData()
+ return self
+
+def addAspect(self, arg):
+ if arg is not None:
+ aspect_id = arg
+ if isinstance(arg, model.ObjectType):
+ aspect_id = arg.getTypeId()
+ self._updateAspects(addAspects=aspect_id)
+
+def removeAspect(self, arg):
+ if arg is not None:
+ aspect_id = arg
+ if isinstance(arg, model.ObjectType):
+ aspect_id = arg.getTypeId()
+ self._updateAspects(removeAspects=aspect_id)
=======================================
--- /.hgignore Mon May 30 07:39:10 2011
+++ /.hgignore Fri Jun 24 04:10:22 2011
@@ -0,0 +1,5 @@
+syntax: glob
+build/*
+dist/*
+*.pyc
+*.egg-info
=======================================
--- /setup.cfg Mon May 30 07:39:10 2011
+++ /setup.cfg Fri Jun 24 04:10:22 2011
@@ -1,2 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
[egg_info]
tag_build =
=======================================
--- /setup.py Mon May 30 07:39:10 2011
+++ /setup.py Fri Jun 24 04:10:22 2011
@@ -1,7 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
import os
from setuptools import setup, find_packages

-version = '0.1'
+version = '0.2'

def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
@@ -11,15 +30,15 @@
description = 'Apache Chemistry CMIS client library Alfresco extension
for Python',
version = version,
author = 'Patrice Collardez',
- author_email = 'pcoll...@acxio.fr',
+ author_email = 'pcoll...@gmail.com',
license = 'Apache License (2.0)',
- url = 'http://www.acxio.fr/',
+ url = 'http://code.google.com/p/cmislib-alfresco-extension/',
package_dir = {'':'src'},
packages = find_packages('src', exclude=['tests']),
#include_package_data = True,
exclude_package_data = {'':['tests']},
zip_safe = False,
- install_requires = ('cmislib'),
+ install_requires = ('cmislib>=0.4'),
long_description = read('README.txt'),
classifiers = [
"Development Status :: 3 - Alpha",
=======================================
--- /src/cmislibalf/__init__.py Wed Jun 1 07:21:13 2011
+++ /src/cmislibalf/__init__.py Fri Jun 24 04:10:22 2011
@@ -1,291 +1,41 @@
-from cmislib import model
-from cmislib.exceptions import InvalidArgumentException
-import datetime
-
-ALFRESCO_NS = 'http://www.alfresco.org'
-ALFRESCO_NSALIAS = 'alf'
-ALFRESCO_NSALIAS_DECL = 'xmlns:' + ALFRESCO_NSALIAS
-ALFRESCO_NSPREFIX = ALFRESCO_NSALIAS + ':'
-
-LOCALNAME_ASPECTS = 'aspects'
-LOCALNAME_PROPERTIES = 'properties'
-LOCALNAME_APPLIED_ASPECTS = 'appliedAspects'
-LOCALNAME_SET_ASPECTS = 'setAspects'
-LOCALNAME_ASPECTS_TO_ADD = 'aspectsToAdd'
-LOCALNAME_ASPECTS_TO_REMOVE = 'aspectsToRemove'
-
-TAGNAME_ALFRESCO_PROPERTIES = ALFRESCO_NSPREFIX + LOCALNAME_PROPERTIES
-TAGNAME_SET_ASPECTS = ALFRESCO_NSPREFIX + LOCALNAME_SET_ASPECTS
-TAGNAME_ASPECTS_TO_ADD = ALFRESCO_NSPREFIX + LOCALNAME_ASPECTS_TO_ADD
-TAGNAME_ASPECTS_TO_REMOVE = ALFRESCO_NSPREFIX + LOCALNAME_ASPECTS_TO_REMOVE
-
-OBJECT_TYPE_ID = 'cmis:objectTypeId'
-
-def addSetAspectsToXMLDocument(xmldoc):
- entryElements = xmldoc.getElementsByTagNameNS(model.ATOM_NS, 'entry')
- entryElements[0].setAttribute(ALFRESCO_NSALIAS_DECL, ALFRESCO_NS)
-
- propertiesElements = xmldoc.getElementsByTagNameNS(model.CMIS_NS,
LOCALNAME_PROPERTIES)
- if len(propertiesElements) == 0:
- objectElement =
xmldoc.getElementsByTagNameNS(model.CMISRA_NS, 'object')
- propertiesElement =
xmldoc.createElementNS(model.CMIS_NS, 'cmis:properties')
- objectElement[0].appendChild(propertiesElement)
- else:
- propertiesElement = propertiesElements[0]
-
- aspectsElement = xmldoc.createElementNS(ALFRESCO_NS,
TAGNAME_SET_ASPECTS)
- propertiesElement.appendChild(aspectsElement)
-
- return aspectsElement
-
-def addPropertiesToXMLElement(xmldoc, element, properties):
- for propName, propValue in properties.items():
- """
- the name of the element here is significant: it includes the
- data type. I should be able to figure out the right type based
- on the actual type of the object passed in.
-
- I could do a lookup to the type definition, but that doesn't
- seem worth the performance hit
- """
- propType = type(propValue)
- isList = False
- if (propType == list):
- propType = type(propValue[0])
- isList = True
-
- if (propType == model.CmisId):
- propElementName = 'cmis:propertyId'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(val)
- else:
- propValueStrList = [propValue]
- elif (propType == str):
- propElementName = 'cmis:propertyString'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(val)
- else:
- propValueStrList = [propValue]
- elif (propType == datetime.datetime):
- propElementName = 'cmis:propertyDateTime'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(val.isoformat())
- else:
- propValueStrList = [propValue.isoformat()]
- elif (propType == bool):
- propElementName = 'cmis:propertyBoolean'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(unicode(val).lower())
- else:
- propValueStrList = [unicode(propValue).lower()]
- elif (propType == int):
- propElementName = 'cmis:propertyInteger'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(unicode(val))
- else:
- propValueStrList = [unicode(propValue)]
- elif (propType == float):
- propElementName = 'cmis:propertyDecimal'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(unicode(val))
- else:
- propValueStrList = [unicode(propValue)]
- else:
- propElementName = 'cmis:propertyString'
- if isList:
- propValueStrList = []
- for val in propValue:
- propValueStrList.append(unicode(val))
- else:
- propValueStrList = [unicode(propValue)]
-
- propElement = xmldoc.createElementNS(model.CMIS_NS,
propElementName)
- propElement.setAttribute('propertyDefinitionId', propName)
- for val in propValueStrList:
- valElement =
xmldoc.createElementNS(model.CMIS_NS, 'cmis:value')
- valText = xmldoc.createTextNode(val)
- valElement.appendChild(valText)
- propElement.appendChild(valElement)
- element.appendChild(propElement)
-
-def _initData(self):
- model.CmisObject._initData(self)
- self._aspects = {}
- self._alfproperties = {}
-
-def _findAlfrescoExtensions(self):
- if not hasattr(self, '_aspects'):
- self._aspects = {}
- if self._aspects == {}:
- if self.xmlDoc == None:
- self.reload()
- appliedAspects = self.xmlDoc.getElementsByTagNameNS(ALFRESCO_NS,
LOCALNAME_APPLIED_ASPECTS)
- for node in appliedAspects:
- aspectType =
self._repository.getTypeDefinition(node.childNodes[0].data)
- self._aspects[node.childNodes[0].data] = aspectType
-
-def hasAspect(self, arg):
- result = False
- if arg is not None:
- self._findAlfrescoExtensions()
- if isinstance(arg, model.ObjectType):
- result = arg.getTypeId() in self._aspects
- else:
- result = arg in self._aspects
- return result
-
-def getAspects(self):
- self._findAlfrescoExtensions()
- return self._aspects.values()
-
-def findAspect(self, propertyId):
- self._findAlfrescoExtensions()
- if (propertyId is not None) and (len(self._aspects) > 0):
- for id, aspect in self._aspects.iteritems():
- props = aspect.getProperties()
- if propertyId in props:
- return aspect
- return None
-
-def _updateAspects(self, addAspects=None, removeAspects=None):
- if addAspects or removeAspects:
- selfUrl = self._getSelfLink()
- xmlEntryDoc = model.getEntryXmlDoc()
- # Patch xmlEntryDoc
- setAspectsElement = addSetAspectsToXMLDocument(xmlEntryDoc)
-
- if addAspects:
- addAspectElement = xmlEntryDoc.createElementNS(ALFRESCO_NS,
TAGNAME_ASPECTS_TO_ADD)
- valText = xmlEntryDoc.createTextNode(addAspects)
- addAspectElement.appendChild(valText)
- setAspectsElement.appendChild(addAspectElement)
-
- if removeAspects:
- removeAspectElement = xmlEntryDoc.createElementNS(ALFRESCO_NS,
TAGNAME_ASPECTS_TO_REMOVE)
- valText = xmlEntryDoc.createTextNode(removeAspects)
- removeAspectElement.appendChild(valText)
- setAspectsElement.appendChild(removeAspectElement)
-
- updatedXmlDoc = self._cmisClient.put(selfUrl.encode('utf-8'),
-
xmlEntryDoc.toxml(encoding='utf-8'),
- model.ATOM_XML_TYPE)
-
- self.xmlDoc = updatedXmlDoc
- self._initData()
-
-def getProperties(self):
- result = model.CmisObject.getProperties(self)
- if not hasattr(self, '_alfproperties'):
- self._alfproperties = {}
- if self._alfproperties == {}:
- alfpropertiesElement =
self.xmlDoc.getElementsByTagNameNS(ALFRESCO_NS, LOCALNAME_PROPERTIES)[0]
- for node in [e for e in alfpropertiesElement.childNodes if
e.nodeType == e.ELEMENT_NODE and e.namespaceURI == model.CMIS_NS]:
- #propertyId, propertyString, propertyDateTime
- #propertyType = cpattern.search(node.localName).groups()[0]
- propertyName = node.attributes['propertyDefinitionId'].value
- if node.childNodes and \
- node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0] and \
-
node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0].childNodes:
- valNodeList =
node.getElementsByTagNameNS(model.CMIS_NS, 'value')
- if (len(valNodeList) == 1):
- propertyValue = model.parsePropValue(valNodeList[0].
- childNodes[0].data,
- node.localName)
- else:
- propertyValue = []
- for valNode in valNodeList:
- propertyValue.append(model.parsePropValue(valNode.
- childNodes[0].data,
- node.localName))
- else:
- propertyValue = None
- self._alfproperties[propertyName] = propertyValue
- result.update(self._alfproperties)
- return result
-
-def updateProperties(self, properties):
- selfUrl = self._getSelfLink()
- cmisproperties = {}
- alfproperties = {}
-
- objectTypeId = properties.get(OBJECT_TYPE_ID)
- if (objectTypeId is None):
- objectTypeId = self.properties.get(OBJECT_TYPE_ID)
- objectType = self._repository.getTypeDefinition(objectTypeId)
- objectTypePropsDef = objectType.getProperties()
-
- for propertyName, propertyValue in properties.items():
- if (propertyName == OBJECT_TYPE_ID) or (propertyName in
objectTypePropsDef.keys()):
- cmisproperties[propertyName] = propertyValue
- else:
- if self.findAspect(propertyName) is None:
- raise InvalidArgumentException
- else:
- alfproperties[propertyName] = propertyValue
-
- xmlEntryDoc = model.getEntryXmlDoc(cmisproperties)
-
- # Patch xmlEntryDoc
- # add alfresco properties
- if len(alfproperties) > 0:
- aspectsElement = addSetAspectsToXMLDocument(xmlEntryDoc)
-
- alfpropertiesElement = xmlEntryDoc.createElementNS(ALFRESCO_NS,
TAGNAME_ALFRESCO_PROPERTIES)
- aspectsElement.appendChild(alfpropertiesElement)
- # Like regular properties
- addPropertiesToXMLElement(xmlEntryDoc, alfpropertiesElement,
alfproperties)
-
- updatedXmlDoc = self._cmisClient.put(selfUrl.encode('utf-8'),
-
xmlEntryDoc.toxml(encoding='utf-8'),
- model.ATOM_XML_TYPE)
- self.xmlDoc = updatedXmlDoc
- self._initData()
- return self
-
-def addAspect(self, arg):
- if arg is not None:
- aspect_id = arg
- if isinstance(arg, model.ObjectType):
- aspect_id = arg.getTypeId()
- self._updateAspects(addAspects=aspect_id)
-
-def removeAspect(self, arg):
- if arg is not None:
- aspect_id = arg
- if isinstance(arg, model.ObjectType):
- aspect_id = arg.getTypeId()
- self._updateAspects(removeAspects=aspect_id)
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+from extension import *

# Types' hooks
-model.Document._initData = _initData
-model.Document._findAlfrescoExtensions = _findAlfrescoExtensions
+model.Document._initData = initData
+model.Document._findAlfrescoExtensions = findAlfrescoExtensions
model.Document.hasAspect = hasAspect
model.Document.getAspects = getAspects
model.Document.findAspect = findAspect
-model.Document._updateAspects = _updateAspects
+model.Document._updateAspects = updateAspects
model.Document.getProperties = getProperties
model.Document.updateProperties = updateProperties
model.Document.addAspect = addAspect
model.Document.removeAspect = removeAspect

-model.Folder._initData = _initData
-model.Folder._findAlfrescoExtensions = _findAlfrescoExtensions
+model.Folder._initData = initData
+model.Folder._findAlfrescoExtensions = findAlfrescoExtensions
model.Folder.hasAspect = hasAspect
model.Folder.getAspects = getAspects
model.Folder.findAspect = findAspect
-model.Folder._updateAspects = _updateAspects
+model.Folder._updateAspects = updateAspects
model.Folder.getProperties = getProperties
model.Folder.updateProperties = updateProperties
model.Folder.addAspect = addAspect
=======================================
--- /src/tests/__init__.py Mon May 30 07:39:10 2011
+++ /src/tests/__init__.py Fri Jun 24 04:10:22 2011
@@ -0,0 +1,18 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
=======================================
--- /src/tests/cmislibalftest.py Wed Jun 1 07:21:13 2011
+++ /src/tests/cmislibalftest.py Fri Jun 24 04:10:22 2011
@@ -1,8 +1,22 @@
-'''
-Created on 27 mai 2011
-
-@author: pcollardez
-'''
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
import unittest
from unittest import TestSuite, TestLoader
import cmislibalf
@@ -46,7 +60,7 @@
titledAspectObjectType =
self._repo.getTypeDefinition('P:sys:temporary')
self.assertFalse(otherDoc.hasAspect(titledAspectObjectType))

- self.assertEqual(3, len(otherDoc.getAspects()))
+ self.assertEqual(4, len(otherDoc.getAspects()))

aspect = otherDoc.findAspect('cm:title')
self.assertEqual('P:cm:titled', aspect.getTypeId())

==============================================================================
Revision: a8a2ba870ee4
Author: Patrice Collardez
Date: Wed Jul 20 02:14:19 2011
Log: Added non-Alfresco repository tests
Updated to work with non-Alfresco repositories (raise exceptions or return
nothing)
http://code.google.com/p/cmislib-alfresco-extension/source/detail?r=a8a2ba870ee4

Added:
/src/tests/cmislibnuxtest.py
Modified:
/src/cmislibalf/extension.py

=======================================
--- /dev/null
+++ /src/tests/cmislibnuxtest.py Wed Jul 20 02:14:19 2011
@@ -0,0 +1,86 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+import unittest
+from unittest import TestSuite, TestLoader
+import cmislibalf
+from cmislib import CmisClient
+from cmislib.exceptions import *
+from time import time
+
+REPOSITORY_URL = 'http://localhost:8080/nuxeo/atom/cmis'
+USERNAME = 'Administrator'
+PASSWORD = 'Administrator'
+EXT_ARGS = {}
+TEST_ROOT_PATH = '/default-domain/workspaces/cmislibnux'
+
+
+class CmisAlfTestBase(unittest.TestCase):
+
+ """ Common ancestor class for most cmislib unit test classes. """
+
+ def setUp(self):
+ """ Create a root test folder for the test. """
+ self._cmisClient = CmisClient(REPOSITORY_URL, USERNAME, PASSWORD,
**EXT_ARGS)
+ self._repo = self._cmisClient.getDefaultRepository()
+ self._rootFolder = self._repo.getObjectByPath(TEST_ROOT_PATH)
+ self._folderName = " ".join(['cmislibnux',
self.__class__.__name__, str(time())])
+ self._testFolder = self._rootFolder.createFolder(self._folderName)
+
+ def tearDown(self):
+ """ Clean up after the test. """
+ self._testFolder.deleteTree()
+
+class HookTest(CmisAlfTestBase):
+
+ def testHook(self):
+ documentName = 'testDocument'
+ newDoc = self._repo.createDocument(documentName,
parentFolder=self._testFolder)
+ self.assertEquals(documentName, newDoc.getName())
+ self.assertFalse(newDoc.hasAspect('P:cm:summarizable'))
+
+ otherDoc = self._repo.getObjectByPath(TEST_ROOT_PATH
+ '/testAspects')
+ self.assertEqual(0, len(otherDoc.getAspects()))
+
+ aspect = otherDoc.findAspect('cm:title')
+ self.assertEqual(None, aspect)
+
+ self.assertRaises(InvalidArgumentException,
newDoc.addAspect, 'P:cm:summarizable')
+ self.assertFalse(newDoc.hasAspect('P:cm:summarizable'))
+ props = {'cm:summary': 'bla bla bla'}
+ self.assertRaises(InvalidArgumentException,
newDoc.updateProperties, props)
+ self.assertEqual(None, newDoc.getProperties().get('cm:summary'))
+
+ self.assertEqual(newDoc.properties, newDoc.getProperties())
+
+ self.assertRaises(InvalidArgumentException,
newDoc.removeAspect, 'P:cm:summarizable')
+ self.assertFalse(newDoc.hasAspect('P:cm:summarizable'))
+ self.assertTrue(newDoc.getProperties().get('cm:summary') is None)
+
+ self.assertRaises(InvalidArgumentException,
newDoc.addAspect, 'P:no:aspect')
+ self.assertRaises(InvalidArgumentException,
newDoc.updateProperties, props)
+
+ self.assertTrue(newDoc.getProperties().get('cm:summary') is None)
+
+
+if __name__ == "__main__":
+ #import sys;sys.argv = ['', 'Test.testName']
+ tts = TestSuite()
+ tts.addTests(TestLoader().loadTestsFromTestCase(HookTest))
+ unittest.TextTestRunner().run(tts)
=======================================
--- /src/cmislibalf/extension.py Fri Jun 24 04:10:22 2011
+++ /src/cmislibalf/extension.py Wed Jul 20 02:14:19 2011
@@ -208,28 +208,30 @@
if not hasattr(self, '_alfproperties'):
self._alfproperties = {}
if self._alfproperties == {}:
- alfpropertiesElement =
self.xmlDoc.getElementsByTagNameNS(ALFRESCO_NS, LOCALNAME_PROPERTIES)[0]
- for node in [e for e in alfpropertiesElement.childNodes if
e.nodeType == e.ELEMENT_NODE and e.namespaceURI == model.CMIS_NS]:
- #propertyId, propertyString, propertyDateTime
- #propertyType = cpattern.search(node.localName).groups()[0]
- propertyName = node.attributes['propertyDefinitionId'].value
- if node.childNodes and \
- node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0] and \
-
node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0].childNodes:
- valNodeList =
node.getElementsByTagNameNS(model.CMIS_NS, 'value')
- if (len(valNodeList) == 1):
- propertyValue = model.parsePropValue(valNodeList[0].
- childNodes[0].data,
- node.localName)
+ alfpropertiesElements =
self.xmlDoc.getElementsByTagNameNS(ALFRESCO_NS, LOCALNAME_PROPERTIES)
+ if len(alfpropertiesElements) > 0:
+ alfpropertiesElement = alfpropertiesElements[0]
+ for node in [e for e in alfpropertiesElement.childNodes if
e.nodeType == e.ELEMENT_NODE and e.namespaceURI == model.CMIS_NS]:
+ #propertyId, propertyString, propertyDateTime
+ #propertyType = cpattern.search(node.localName).groups()[0]
+ propertyName =
node.attributes['propertyDefinitionId'].value
+ if node.childNodes and \
+ node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0]
and \
+
node.getElementsByTagNameNS(model.CMIS_NS, 'value')[0].childNodes:
+ valNodeList =
node.getElementsByTagNameNS(model.CMIS_NS, 'value')
+ if (len(valNodeList) == 1):
+ propertyValue =
model.parsePropValue(valNodeList[0].
+ childNodes[0].data,
+ node.localName)
+ else:
+ propertyValue = []
+ for valNode in valNodeList:
+
propertyValue.append(model.parsePropValue(valNode.
+ childNodes[0].data,
+ node.localName))
else:
- propertyValue = []
- for valNode in valNodeList:
- propertyValue.append(model.parsePropValue(valNode.
- childNodes[0].data,
- node.localName))
- else:
- propertyValue = None
- self._alfproperties[propertyName] = propertyValue
+ propertyValue = None
+ self._alfproperties[propertyName] = propertyValue
result.update(self._alfproperties)
return result

@@ -277,6 +279,8 @@
aspect_id = arg
if isinstance(arg, model.ObjectType):
aspect_id = arg.getTypeId()
+ if self._repository.getTypeDefinition(aspect_id) is None:
+ raise InvalidArgumentException
self._updateAspects(addAspects=aspect_id)

def removeAspect(self, arg):
@@ -284,4 +288,6 @@
aspect_id = arg
if isinstance(arg, model.ObjectType):
aspect_id = arg.getTypeId()
+ if self._repository.getTypeDefinition(aspect_id) is None:
+ raise InvalidArgumentException
self._updateAspects(removeAspects=aspect_id)

Reply all
Reply to author
Forward
0 new messages