You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by lm...@apache.org on 2018/07/29 16:55:46 UTC

svn commit: r1836994 [1/2] - in /chemistry/cmislib/branches/py3_compat: ./ src/cmislib/ src/cmislib/atompub/ src/cmislib/browser/ src/tests/

Author: lmignon
Date: Sun Jul 29 16:55:46 2018
New Revision: 1836994

URL: http://svn.apache.org/viewvc?rev=1836994&view=rev
Log:
py3compat: replace httplib2 by requests and fix StringIO->BytesIO 

Removed:
    chemistry/cmislib/branches/py3_compat/src/cmislib/net.py
Modified:
    chemistry/cmislib/branches/py3_compat/.travis.yml
    chemistry/cmislib/branches/py3_compat/setup.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/atompub/binding.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/browser/binding.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/cmis_services.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/domain.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/exceptions.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/model.py
    chemistry/cmislib/branches/py3_compat/src/cmislib/util.py
    chemistry/cmislib/branches/py3_compat/src/tests/test_document.py
    chemistry/cmislib/branches/py3_compat/src/tests/test_query.py
    chemistry/cmislib/branches/py3_compat/src/tests/test_repository.py
    chemistry/cmislib/branches/py3_compat/tox.ini

Modified: chemistry/cmislib/branches/py3_compat/.travis.yml
URL: http://svn.apache.org/viewvc/chemistry/cmislib/branches/py3_compat/.travis.yml?rev=1836994&r1=1836993&r2=1836994&view=diff
==============================================================================
--- chemistry/cmislib/branches/py3_compat/.travis.yml (original)
+++ chemistry/cmislib/branches/py3_compat/.travis.yml Sun Jul 29 16:55:46 2018
@@ -7,6 +7,9 @@ language: python
 
 python:
   - "2.7"
+  - "3.4"
+  - "3.5"
+  - "3.6"
 
 services:
   - docker

Modified: chemistry/cmislib/branches/py3_compat/setup.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/branches/py3_compat/setup.py?rev=1836994&r1=1836993&r2=1836994&view=diff
==============================================================================
--- chemistry/cmislib/branches/py3_compat/setup.py (original)
+++ chemistry/cmislib/branches/py3_compat/setup.py Sun Jul 29 16:55:46 2018
@@ -19,7 +19,7 @@
 import os
 from setuptools import setup, find_packages
 
-version = '0.6.0'
+version = '0.7.0.dev1'
 
 def read(fname):
     return open(os.path.join(os.path.dirname(__file__), fname)).read()
@@ -30,7 +30,8 @@ setup(
     version = version,
     install_requires = [
         'iso8601',
-        'httplib2'
+        'requests',
+        'requests-toolbelt',
         ],
     author = 'Apache Chemistry Project',
     author_email = 'dev@chemistry.apache.org',
@@ -39,14 +40,17 @@ setup(
     package_dir = {'':'src'},
     packages = find_packages('src', exclude=['tests']),
     #include_package_data = True,
-    exclude_package_data = {'':['tests']},
+    exclude_package_data = {'': ['tests']},
     long_description = read('README.txt'),
     classifiers = [
         "Development Status :: 4 - Beta",
         "Intended Audience :: Developers",
         "License :: OSI Approved :: Apache Software License",
         "Operating System :: OS Independent",
-        "Programming Language :: Python",
+        'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.5',
+        'Programming Language :: Python :: 3.6',
         "Topic :: Software Development :: Libraries",
         ],
 )

Modified: chemistry/cmislib/branches/py3_compat/src/cmislib/atompub/binding.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/branches/py3_compat/src/cmislib/atompub/binding.py?rev=1836994&r1=1836993&r2=1836994&view=diff
==============================================================================
--- chemistry/cmislib/branches/py3_compat/src/cmislib/atompub/binding.py (original)
+++ chemistry/cmislib/branches/py3_compat/src/cmislib/atompub/binding.py Sun Jul 29 16:55:46 2018
@@ -21,11 +21,13 @@
 Module containing the Atom Pub binding-specific objects used to work with a CMIS
 provider.
 """
-import sys
+import base64
 import datetime
 import logging
 import mimetypes
 import re
+import sys
+from io import BytesIO
 from xml.dom import minidom
 from xml.parsers.expat import ExpatError
 
@@ -36,16 +38,14 @@ from cmislib.domain import CmisId, CmisO
 from cmislib.exceptions import CmisException, \
     ObjectNotFoundException, InvalidArgumentException, \
     NotSupportedException
-from cmislib.net import RESTService as Rest
 from cmislib.util import multiple_replace, parsePropValue, parseBoolValue, \
-    toCMISValue, parseDateTimeValue, safe_quote
+    toCMISValue, parseDateTimeValue, safe_quote, to_native
 
 if sys.version_info >= (3,):
     from urllib.parse import urlparse, urlunparse
-    import io as StringIO
+    unicode = str
 else:
     from urlparse import urlparse, urlunparse
-    import StringIO
 
 moduleLogger = logging.getLogger('cmislib.atompub.binding')
 
@@ -109,11 +109,21 @@ class AtomPubBinding(Binding):
 
     def __init__(self, **kwargs):
         self.extArgs = kwargs
+        self.user_agent = 'cmislib/atompub +http://chemistry.apache.org/'
 
     def getRepositoryService(self):
         return RepositoryService()
 
-    def get(self, url, username, password, **kwargs):
+    def _get_http_headers(self, **kwargs):
+        headers = {}
+        if kwargs:
+            if 'headers' in kwargs:
+                headers = kwargs['headers']
+                del kwargs['headers']
+        headers['User-Agent'] = self.user_agent
+        return headers
+
+    def get(self, url, session, **kwargs):
 
         """
         Does a get against the CMIS service. More than likely, you will not
@@ -130,20 +140,16 @@ class AtomPubBinding(Binding):
         if len(self.extArgs) > 0:
             kwargs.update(self.extArgs)
 
-        resp, content = Rest().get(url,
-                                   username=username,
-                                   password=password,
-                                   **kwargs)
-        if resp['status'] != '200':
-            self._processCommonErrors(resp, url)
-            return content
-        else:
+        headers = self._get_http_headers(**kwargs)
+        response = session.get(url, params=kwargs, headers=headers)
+        if '+xml' in response.headers.get('content-type'):
             try:
-                return minidom.parseString(content)
+                return minidom.parse(BytesIO(response.content))
             except ExpatError:
                 raise CmisException('Could not parse server response', url)
+        return response
 
-    def delete(self, url, username, password, **kwargs):
+    def delete(self, url, session, **kwargs):
 
         """
         Does a delete against the CMIS service. More than likely, you will not
@@ -157,17 +163,11 @@ class AtomPubBinding(Binding):
         if len(self.extArgs) > 0:
             kwargs.update(self.extArgs)
 
-        resp, content = Rest().delete(url,
-                                      username=username,
-                                      password=password,
-                                      **kwargs)
-        if resp['status'] != '200' and resp['status'] != '204':
-            self._processCommonErrors(resp, url)
-            return content
-        else:
-            pass
+        headers = self._get_http_headers(**kwargs)
+        response = session.delete(url, params=kwargs, headers=headers)
+        return response
 
-    def post(self, url, username, password, payload, contentType, **kwargs):
+    def post(self, url, session, payload, contentType, **kwargs):
 
         """
         Does a post against the CMIS service. More than likely, you will not
@@ -181,28 +181,18 @@ class AtomPubBinding(Binding):
         # merge the cmis client extended args with the ones that got passed in
         if len(self.extArgs) > 0:
             kwargs.update(self.extArgs)
-
-        resp, content = Rest().post(url,
-                                    payload,
-                                    contentType,
-                                    username=username,
-                                    password=password,
-                                    **kwargs)
-        if resp['status'] == '200':
-            try:
-                return minidom.parseString(content)
-            except ExpatError:
-                raise CmisException('Could not parse server response', url)
-        elif resp['status'] == '201':
+        headers = self._get_http_headers(**kwargs)
+        headers['Content-Type'] = contentType
+        result = session.post(
+            url, params=kwargs, data=payload, headers=headers)
+        if result.text:
             try:
-                return minidom.parseString(content)
+                return minidom.parse(BytesIO(result.content))
             except ExpatError:
                 raise CmisException('Could not parse server response', url)
-        else:
-            self._processCommonErrors(resp, url)
-            return resp
+        return None
 
-    def put(self, url, username, password, payload, contentType, **kwargs):
+    def put(self, url, session, payload, contentType, **kwargs):
 
         """
         Does a put against the CMIS service. More than likely, you will not
@@ -217,21 +207,16 @@ class AtomPubBinding(Binding):
         if len(self.extArgs) > 0:
             kwargs.update(self.extArgs)
 
-        resp, content = Rest().put(url,
-                                   payload,
-                                   contentType,
-                                   username=username,
-                                   password=password,
-                                   **kwargs)
-        if resp['status'] != '200' and resp['status'] != '201':
-            self._processCommonErrors(resp, url)
-            return content
-        else:
+        headers = self._get_http_headers(**kwargs)
+        headers['Content-Type'] = contentType
+        response = session.put(url, data=payload, params=kwargs, headers=headers)
+        if response.text:
             try:
-                return minidom.parseString(content)
+                return minidom.parseString(response.text)
             except ExpatError:
                 # This may happen and is normal
                 return None
+        return None
 
 
 class RepositoryService(RepositoryServiceIfc):
@@ -249,9 +234,8 @@ class RepositoryService(RepositoryServic
         """ Reloads the state of the repository object."""
 
         self.logger.debug('Reload called on object')
-        obj.xmlDoc = obj._cmisClient.binding.get(obj._cmisClient.repositoryUrl.encode('utf-8'),
-                                                 obj._cmisClient.username,
-                                                 obj._cmisClient.password)
+        obj.xmlDoc = obj._cmisClient.binding.get(obj._cmisClient.repositoryUrl,
+                                                 obj._cmisClient.session)
         obj._initData()
 
     def getRepository(self, client, repositoryId):
@@ -260,7 +244,7 @@ class RepositoryService(RepositoryServic
         Get the repository for the specified repositoryId.
         """
 
-        doc = client.binding.get(client.repositoryUrl, client.username, client.password, **client.extArgs)
+        doc = client.binding.get(client.repositoryUrl, client.session, **client.extArgs)
         workspaceElements = doc.getElementsByTagNameNS(APP_NS, 'workspace')
 
         for workspaceElement in workspaceElements:
@@ -276,7 +260,7 @@ class RepositoryService(RepositoryServic
         Get all of the repositories provided by the server.
         """
 
-        result = client.binding.get(client.repositoryUrl, client.username, client.password, **client.extArgs)
+        result = client.binding.get(client.repositoryUrl, client.session, **client.extArgs)
 
         workspaceElements = result.getElementsByTagNameNS(APP_NS, 'workspace')
         # instantiate a Repository object using every workspace element
@@ -296,7 +280,7 @@ class RepositoryService(RepositoryServic
         Returns the default repository for the server via the AtomPub binding.
         """
 
-        doc = client.binding.get(client.repositoryUrl, client.username, client.password, **client.extArgs)
+        doc = client.binding.get(client.repositoryUrl, client.session, **client.extArgs)
         workspaceElements = doc.getElementsByTagNameNS(APP_NS, 'workspace')
         # instantiate a Repository object with the first workspace
         # element we find
@@ -396,9 +380,8 @@ class AtomPubCmisObject(CmisObject):
         # fill in the template
         byObjectIdUrl = multiple_replace(params, template)
 
-        self.xmlDoc = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                                   self._cmisClient.username,
-                                                   self._cmisClient.password,
+        self.xmlDoc = self._cmisClient.binding.get(byObjectIdUrl,
+                                                   self._cmisClient.session,
                                                    **addOptions)
         self._initData()
 
@@ -456,9 +439,8 @@ class AtomPubCmisObject(CmisObject):
             raise NotSupportedException('Root folder does not support getObjectParents')
 
         # invoke the URL
-        result = self._cmisClient.binding.get(parentUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(parentUrl,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -668,9 +650,8 @@ class AtomPubCmisObject(CmisObject):
         self.logger.debug('xmlEntryDoc:' + xmlEntryDoc.toxml())
 
         # do a PUT of the entry
-        updatedXmlDoc = self._cmisClient.binding.put(selfUrl.encode('utf-8'),
-                                                     self._cmisClient.username,
-                                                     self._cmisClient.password,
+        updatedXmlDoc = self._cmisClient.binding.put(selfUrl,
+                                                     self._cmisClient.session,
                                                      xmlEntryDoc.toxml(encoding='utf-8'),
                                                      ATOM_XML_TYPE,
                                                      **args)
@@ -699,9 +680,8 @@ class AtomPubCmisObject(CmisObject):
         args = {"sourceFolderId": sourceFolder.id}
 
         # post the Atom entry
-        self._cmisClient.binding.post(postUrl.encode('utf-8'),
-                                      self._cmisClient.username,
-                                      self._cmisClient.password,
+        self._cmisClient.binding.post(postUrl,
+                                      self._cmisClient.session,
                                       self.xmlDoc.toxml(encoding='utf-8'),
                                       ATOM_XML_ENTRY_TYPE,
                                       **args)
@@ -721,9 +701,8 @@ class AtomPubCmisObject(CmisObject):
         """
 
         url = self._getSelfLink()
-        self._cmisClient.binding.delete(url.encode('utf-8'),
-                                        self._cmisClient.username,
-                                        self._cmisClient.password,
+        self._cmisClient.binding.delete(url,
+                                        self._cmisClient.session,
                                         **kwargs)
 
     def applyPolicy(self, policyId):
@@ -763,9 +742,8 @@ class AtomPubCmisObject(CmisObject):
         url = self._getLink(RELATIONSHIPS_REL)
         assert url is not None, 'Could not determine relationships URL'
 
-        result = self._cmisClient.binding.post(url.encode('utf-8'),
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
                                                xmlDoc.toxml(encoding='utf-8'),
                                                ATOM_XML_TYPE)
 
@@ -800,9 +778,8 @@ class AtomPubCmisObject(CmisObject):
         url = self._getLink(RELATIONSHIPS_REL)
         assert url is not None, 'Could not determine relationships URL'
 
-        result = self._cmisClient.binding.get(url.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -848,9 +825,8 @@ class AtomPubCmisObject(CmisObject):
             # if the ACL capability is discover or manage, this must be
             # supported
             aclUrl = self._getLink(ACL_REL)
-            result = self._cmisClient.binding.get(aclUrl.encode('utf-8'),
-                                                  self._cmisClient.username,
-                                                  self._cmisClient.password)
+            result = self._cmisClient.binding.get(aclUrl,
+                                                  self._cmisClient.session)
             return AtomPubACL(xmlDoc=result)
         else:
             raise NotSupportedException
@@ -877,9 +853,8 @@ class AtomPubCmisObject(CmisObject):
                 raise CmisException('The ACL to apply must be an instance of the ACL class.')
             aclUrl = self._getLink(ACL_REL)
             assert aclUrl, "Could not determine the object's ACL URL."
-            result = self._cmisClient.binding.put(aclUrl.encode('utf-8'),
-                                                  self._cmisClient.username,
-                                                  self._cmisClient.password,
+            result = self._cmisClient.binding.put(aclUrl,
+                                                  self._cmisClient.session,
                                                   acl.getXmlDoc().toxml(encoding='utf-8'),
                                                   CMIS_ACL_TYPE)
             return AtomPubACL(xmlDoc=result)
@@ -980,9 +955,8 @@ class AtomPubRepository(object):
         repository.
         """
         self.logger.debug('Reload called on object')
-        self.xmlDoc = self._cmisClient.binding.get(self._cmisClient.repositoryUrl.encode('utf-8'),
-                                                   self._cmisClient.username,
-                                                   self._cmisClient.password)
+        self.xmlDoc = self._cmisClient.binding.get(self._cmisClient.repositoryUrl,
+                                                   self._cmisClient.session)
         self._initData()
 
     def _initData(self):
@@ -1322,9 +1296,8 @@ class AtomPubRepository(object):
         if typeId:
             targetType = self.getTypeDefinition(typeId)
             childrenUrl = targetType.getLink(DOWN_REL, ATOM_XML_FEED_TYPE_P)
-            typesXmlDoc = self._cmisClient.binding.get(childrenUrl.encode('utf-8'),
-                                                       self._cmisClient.username,
-                                                       self._cmisClient.password)
+            typesXmlDoc = self._cmisClient.binding.get(childrenUrl,
+                                                       self._cmisClient.session)
             entryElements = typesXmlDoc.getElementsByTagNameNS(ATOM_NS, 'entry')
             types = []
             for entryElement in entryElements:
@@ -1393,9 +1366,8 @@ class AtomPubRepository(object):
         if not descendUrl:
             raise NotSupportedException("Could not determine the type descendants URL")
 
-        typesXmlDoc = self._cmisClient.binding.get(descendUrl.encode('utf-8'),
-                                                   self._cmisClient.username,
-                                                   self._cmisClient.password,
+        typesXmlDoc = self._cmisClient.binding.get(descendUrl,
+                                                   self._cmisClient.session,
                                                    **kwargs)
         entryElements = typesXmlDoc.getElementsByTagNameNS(ATOM_NS, 'entry')
         types = []
@@ -1424,8 +1396,7 @@ class AtomPubRepository(object):
 
         typesUrl = self.getCollectionLink(TYPES_COLL)
         typesXmlDoc = self._cmisClient.binding.get(typesUrl,
-                                                   self._cmisClient.username,
-                                                   self._cmisClient.password,
+                                                   self._cmisClient.session,
                                                    **kwargs)
         entryElements = typesXmlDoc.getElementsByTagNameNS(ATOM_NS, 'entry')
         types = []
@@ -1587,9 +1558,8 @@ class AtomPubRepository(object):
         byObjectPathUrl = multiple_replace(params, template)
 
         # do a GET against the URL
-        result = self._cmisClient.binding.get(byObjectPathUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(byObjectPathUrl,
+                                              self._cmisClient.session,
                                               **addOptions)
 
         # instantiate CmisObject objects with the results and return the list
@@ -1651,9 +1621,8 @@ class AtomPubRepository(object):
 
         # do the POST
         # print 'posting:%s' % xmlDoc.toxml(encoding='utf-8')
-        result = self._cmisClient.binding.post(queryUrl.encode('utf-8'),
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(queryUrl,
+                                               self._cmisClient.session,
                                                xmlDoc.toxml(encoding='utf-8'),
                                                CMIS_QUERY_TYPE)
 
@@ -1710,9 +1679,8 @@ class AtomPubRepository(object):
             raise NotSupportedException(messages.NO_CHANGE_LOG_SUPPORT)
 
         changesUrl = self.getLink(CHANGE_LOG_REL)
-        result = self._cmisClient.binding.get(changesUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(changesUrl,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -1748,8 +1716,7 @@ class AtomPubRepository(object):
             else:
                 # this repo requires fileable objects to be filed
                 raise InvalidArgumentException
-
-        return parentFolder.createDocument(name, properties, StringIO.StringIO(contentString),
+        return parentFolder.createDocument(name, properties, BytesIO(contentString.encode('utf-8')),
                                            contentType, contentEncoding)
 
     def createDocument(self,
@@ -1814,9 +1781,8 @@ class AtomPubRepository(object):
                                 contentType, contentEncoding)
 
         # post the Atom entry
-        result = self._cmisClient.binding.post(postUrl.encode('utf-8'),
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(postUrl,
+                                               self._cmisClient.session,
                                                xmlDoc.toxml(encoding='utf-8'),
                                                ATOM_XML_ENTRY_TYPE)
 
@@ -1959,9 +1925,8 @@ class AtomPubRepository(object):
         elif collectionType == TYPES_COLL:
             return self.getTypeDefinitions()
 
-        result = self._cmisClient.binding.get(self.getCollectionLink(collectionType).encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(self.getCollectionLink(collectionType),
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -2078,9 +2043,8 @@ class AtomPubResultSet(ResultSet):
         """
         link = self._getLink(rel)
         if link:
-            result = self._cmisClient.binding.get(link.encode('utf-8'),
-                                                  self._cmisClient.username,
-                                                  self._cmisClient.password)
+            result = self._cmisClient.binding.get(link,
+                                                  self._cmisClient.session)
 
             # return the result
             self._xmlDoc = result
@@ -2302,9 +2266,8 @@ class AtomPubDocument(AtomPubCmisObject)
         entryXmlDoc = getEntryXmlDoc(self._repository, properties=properties)
 
         # post it to to the checkedout collection URL
-        result = self._cmisClient.binding.post(checkoutUrl.encode('utf-8'),
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(checkoutUrl,
+                                               self._cmisClient.session,
                                                entryXmlDoc.toxml(encoding='utf-8'),
                                                ATOM_XML_ENTRY_TYPE)
 
@@ -2434,9 +2397,8 @@ class AtomPubDocument(AtomPubCmisObject)
         # Get the self link
         # Do a PUT of the empty ATOM to the self link
         url = self._getSelfLink()
-        result = self._cmisClient.binding.put(url.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.put(url,
+                                              self._cmisClient.session,
                                               entryXmlDoc.toxml(encoding='utf-8'),
                                               ATOM_XML_TYPE,
                                               **kwargs)
@@ -2503,9 +2465,8 @@ class AtomPubDocument(AtomPubCmisObject)
         versionsUrl = self._getLink(VERSION_HISTORY_REL)
 
         # invoke the URL
-        result = self._cmisClient.binding.get(versionsUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(versionsUrl,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -2546,13 +2507,9 @@ class AtomPubDocument(AtomPubCmisObject)
             srcUrl = contentElements[0].attributes['src'].value
 
             # the cmis client class parses non-error responses
-            result, content = Rest().get(srcUrl.encode('utf-8'),
-                                         username=self._cmisClient.username,
-                                         password=self._cmisClient.password,
-                                         **self._cmisClient.extArgs)
-            if result['status'] != '200':
-                raise CmisException(result['status'])
-            return StringIO.StringIO(content)
+            response = self._cmisClient.binding.get(
+                srcUrl, self._cmisClient.session)
+            return BytesIO(response.content)
         else:
             # otherwise, try to return the value of the content element
             if contentElements[0].childNodes:
@@ -2595,9 +2552,8 @@ class AtomPubDocument(AtomPubCmisObject)
             args = {"changeToken": self.properties['cmis:changeToken']}
 
         # put the content file
-        result = self._cmisClient.binding.put(srcUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.put(srcUrl,
+                                              self._cmisClient.session,
                                               contentFile.read(),
                                               mimetype,
                                               **args)
@@ -2634,9 +2590,8 @@ class AtomPubDocument(AtomPubCmisObject)
             args = {"changeToken": self.properties['cmis:changeToken']}
 
         # delete the content stream
-        self._cmisClient.binding.delete(srcUrl.encode('utf-8'),
-                                        self._cmisClient.username,
-                                        self._cmisClient.password,
+        self._cmisClient.binding.delete(srcUrl,
+                                        self._cmisClient.session,
                                         **args)
 
     checkedOut = property(isCheckedOut)
@@ -2654,9 +2609,8 @@ class AtomPubDocument(AtomPubCmisObject)
             raise NotSupportedException('Root folder does not support getObjectParents')
 
         # invoke the URL
-        result = self._cmisClient.binding.get(parentUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(parentUrl,
+                                              self._cmisClient.session,
                                               filter='cmis:path',
                                               includeRelativePathSegment=True)
 
@@ -2721,9 +2675,8 @@ class AtomPubFolder(AtomPubCmisObject):
         entryXml = getEntryXmlDoc(self._repository, properties=properties)
 
         # post the Atom entry
-        result = self._cmisClient.binding.post(postUrl.encode('utf-8'),
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(postUrl,
+                                               self._cmisClient.session,
                                                entryXml.toxml(encoding='utf-8'),
                                                ATOM_XML_ENTRY_TYPE)
 
@@ -2826,9 +2779,8 @@ class AtomPubFolder(AtomPubCmisObject):
         # get the appropriate 'down' link
         childrenUrl = self.getChildrenLink()
         # invoke the URL
-        result = self._cmisClient.binding.get(childrenUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(childrenUrl,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -2911,9 +2863,8 @@ class AtomPubFolder(AtomPubCmisObject):
         descendantsUrl = self.getDescendantsLink()
 
         # invoke the URL
-        result = self._cmisClient.binding.get(descendantsUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(descendantsUrl,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -2948,9 +2899,8 @@ class AtomPubFolder(AtomPubCmisObject):
         # Get the descendants link and do a GET against it
         url = self._getLink(FOLDER_TREE_REL)
         assert url is not None, 'Unable to determine folder tree link'
-        result = self._cmisClient.binding.get(url.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # return the result set
@@ -2966,9 +2916,8 @@ class AtomPubFolder(AtomPubCmisObject):
         # get the appropriate 'up' link
         parentUrl = self._getLink(UP_REL)
         # invoke the URL
-        result = self._cmisClient.binding.get(parentUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password)
+        result = self._cmisClient.binding.get(parentUrl,
+                                              self._cmisClient.session)
 
         # return the result set
         return AtomPubFolder(self._cmisClient, self._repository, xmlDoc=result)
@@ -2996,9 +2945,8 @@ class AtomPubFolder(AtomPubCmisObject):
 
         # Get the descendants link and do a DELETE against it
         url = self._getLink(DOWN_REL, CMIS_TREE_TYPE_P)
-        result = self._cmisClient.binding.delete(url.encode('utf-8'),
-                                                 self._cmisClient.username,
-                                                 self._cmisClient.password,
+        result = self._cmisClient.binding.delete(url,
+                                                 self._cmisClient.session,
                                                  **kwargs)
 
     def addObject(self, cmisObject, **kwargs):
@@ -3030,9 +2978,8 @@ class AtomPubFolder(AtomPubCmisObject):
         postUrl = self.getChildrenLink()
 
         # post the Atom entry
-        self._cmisClient.binding.post(postUrl.encode('utf-8'),
-                                      self._cmisClient.username,
-                                      self._cmisClient.password,
+        self._cmisClient.binding.post(postUrl,
+                                      self._cmisClient.session,
                                       cmisObject.xmlDoc.toxml(encoding='utf-8'),
                                       ATOM_XML_ENTRY_TYPE,
                                       **kwargs)
@@ -3052,9 +2999,8 @@ class AtomPubFolder(AtomPubCmisObject):
         args = {"removeFrom": self.getObjectId()}
 
         # post the Atom entry to the unfiled collection
-        self._cmisClient.binding.post(postUrl.encode('utf-8'),
-                                      self._cmisClient.username,
-                                      self._cmisClient.password,
+        self._cmisClient.binding.post(postUrl,
+                                      self._cmisClient.session,
                                       cmisObject.xmlDoc.toxml(encoding='utf-8'),
                                       ATOM_XML_ENTRY_TYPE,
                                       **args)
@@ -3320,9 +3266,8 @@ class AtomPubObjectType(ObjectType):
         template = templates['typebyid']['template']
         params = {'{id}': self._typeId}
         byTypeIdUrl = multiple_replace(params, template)
-        result = self._cmisClient.binding.get(byTypeIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+        result = self._cmisClient.binding.get(byTypeIdUrl,
+                                              self._cmisClient.session,
                                               **kwargs)
 
         # instantiate CmisObject objects with the results and return the list
@@ -3752,9 +3697,8 @@ class AtomPubChangeEntry(ChangeEntry):
         if len(aclEls) == 1:
             return AtomPubACL(aceList=aclEls[0])
         elif aclUrl:
-            result = self._cmisClient.binding.get(aclUrl.encode('utf-8'),
-                                                  self._cmisClient.username,
-                                                  self._cmisClient.password)
+            result = self._cmisClient.binding.get(aclUrl,
+                                                  self._cmisClient.session)
             return AtomPubACL(xmlDoc=result)
 
     def getChangeTime(self):
@@ -4015,13 +3959,12 @@ def getEntryXmlDoc(repo=None, objectType
         # and that element takes precedence over ATOM_NS content if it is
         # present, so it seems reasonable to use CMIS_RA content for now
         # and encode everything.
-
-        fileData = contentFile.read().encode("base64")
+        fileData = base64.b64encode(contentFile.read())
         mediaElement = entryXmlDoc.createElementNS(CMISRA_NS, 'cmisra:mediatype')
         mediaElementText = entryXmlDoc.createTextNode(mimetype)
         mediaElement.appendChild(mediaElementText)
         base64Element = entryXmlDoc.createElementNS(CMISRA_NS, 'cmisra:base64')
-        base64ElementText = entryXmlDoc.createTextNode(fileData)
+        base64ElementText = entryXmlDoc.createTextNode(to_native(fileData))
         base64Element.appendChild(base64ElementText)
         contentElement = entryXmlDoc.createElementNS(CMISRA_NS, 'cmisra:content')
         contentElement.appendChild(mediaElement)

Modified: chemistry/cmislib/branches/py3_compat/src/cmislib/browser/binding.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/branches/py3_compat/src/cmislib/browser/binding.py?rev=1836994&r1=1836993&r2=1836994&view=diff
==============================================================================
--- chemistry/cmislib/branches/py3_compat/src/cmislib/browser/binding.py (original)
+++ chemistry/cmislib/branches/py3_compat/src/cmislib/browser/binding.py Sun Jul 29 16:55:46 2018
@@ -23,8 +23,10 @@ provider.
 """
 import json
 import logging
-import sys
-import time
+from collections import OrderedDict
+from io import BytesIO
+
+from requests_toolbelt.multipart.encoder import MultipartEncoder
 
 from cmislib import messages
 from cmislib.cmis_services import Binding, RepositoryServiceIfc
@@ -32,17 +34,8 @@ from cmislib.domain import CmisId, CmisO
     ChangeEntry
 from cmislib.exceptions import CmisException, InvalidArgumentException, \
     NotSupportedException, ObjectNotFoundException
-from cmislib.net import RESTService as Rest
-from cmislib.util import parsePropValueByType, parseDateTimeValue, safe_quote, \
-    safe_urlencode, iteritems, itervalues
-
-if sys.version_info >= (3,):
-    import io as StringIO
-else:
-    import StringIO
-
-
-CMIS_FORM_TYPE = 'application/x-www-form-urlencoded;charset=utf-8'
+from cmislib.util import parsePropValueByType, parseDateTimeValue, iteritems, \
+    itervalues
 
 moduleLogger = logging.getLogger('cmislib.browser.binding')
 
@@ -57,11 +50,21 @@ class BrowserBinding(Binding):
 
     def __init__(self, **kwargs):
         self.extArgs = kwargs
+        self.user_agent = 'cmislib/browser +http://chemistry.apache.org/'
 
     def getRepositoryService(self):
         return RepositoryService()
 
-    def get(self, url, username, password, **kwargs):
+    def _get_http_headers(self, **kwargs):
+        headers = {}
+        if kwargs:
+            if 'headers' in kwargs:
+                headers = kwargs['headers']
+                del kwargs['headers']
+        headers['User-Agent'] = self.user_agent
+        return headers
+
+    def get(self, url, session, **kwargs):
 
         """
         Does a get against the CMIS service. More than likely, you will not
@@ -78,18 +81,13 @@ class BrowserBinding(Binding):
         if len(self.extArgs) > 0:
             kwargs.update(self.extArgs)
 
-        resp, content = Rest().get(url,
-                                   username=username,
-                                   password=password,
-                                   **kwargs)
-        result = None
-        if resp['status'] != '200':
-            self._processCommonErrors(resp, url)
-        else:
-            result = json.loads(content)
-        return result
+        headers = self._get_http_headers(**kwargs)
+        response = session.get(url, params=kwargs, headers=headers)
+        if 'application/json' in response.headers.get('content-type'):
+            return response.json()
+        return response
 
-    def post(self, url, payload, contentType, username, password, **kwargs):
+    def post(self, url, session, payload, contentType, **kwargs):
 
         """
         Does a post against the CMIS service. More than likely, you will not
@@ -103,19 +101,13 @@ class BrowserBinding(Binding):
         # merge the cmis client extended args with the ones that got passed in
         if len(self.extArgs) > 0:
             kwargs.update(self.extArgs)
-
-        result = None
-        resp, content = Rest().post(url,
-                                    payload,
-                                    contentType,
-                                    username=username,
-                                    password=password,
-                                    **kwargs)
-        if resp['status'] != '200' and resp['status'] != '201':
-            self._processCommonErrors(resp, url)
-        elif content is not None and content != "":
-            result = json.loads(content)
-        return result
+        headers = self._get_http_headers(**kwargs)
+        headers['Content-Type'] = contentType
+        result = session.post(
+            url, params=kwargs, data=payload, headers=headers)
+        if result.text:
+            return result.json()
+        return None
 
 
 class RepositoryService(RepositoryServiceIfc):
@@ -130,7 +122,7 @@ class RepositoryService(RepositoryServic
         Gets the repository for the specified repository ID.
         """
 
-        result = client.binding.get(client.repositoryUrl, client.username, client.password, **client.extArgs)
+        result = client.binding.get(client.repositoryUrl, client.session, **client.extArgs)
 
         if repositoryId in result:
             return BrowserRepository(client, result[repositoryId])
@@ -143,7 +135,7 @@ class RepositoryService(RepositoryServic
         Gets all of the repositories for this client.
         """
 
-        result = client.binding.get(client.repositoryUrl, client.username, client.password, **client.extArgs)
+        result = client.binding.get(client.repositoryUrl, client.session, **client.extArgs)
 
         repositories = []
         for repo in itervalues(result):
@@ -159,7 +151,7 @@ class RepositoryService(RepositoryServic
         list.
         """
 
-        result = client.binding.get(client.repositoryUrl, client.username, client.password, **client.extArgs)
+        result = client.binding.get(client.repositoryUrl, client.session, **client.extArgs)
         # instantiate a Repository object with the first workspace
         # element we find
         repository = None
@@ -218,12 +210,15 @@ class BrowserCmisObject(object):
             self._extArgs.update(kwargs)
         else:
             self._extArgs = kwargs
-
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=object"
-        self.data = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                                 self._cmisClient.username,
-                                                 self._cmisClient.password,
-                                                 **self._extArgs)
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'object',
+        }
+        params.update(self._extArgs)
+        url = self._repository.getRootFolderUrl()
+        self.data = self._cmisClient.binding.get(url,
+                                                 self._cmisClient.session,
+                                                 **params)
         self._initData()
 
         # if a returnVersion arg was passed in, it is possible we got back
@@ -265,11 +260,15 @@ class BrowserCmisObject(object):
         if not self.getAllowableActions()['canGetObjectParents']:
             raise NotSupportedException('Object does not support getObjectParents')
 
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=parents"
-        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'parents',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         # return the result set
         return BrowserResultSet(self._cmisClient, self._repository, {'objects': result}, serializer=ChildrenSerializer())
 
@@ -376,18 +375,17 @@ class BrowserCmisObject(object):
         """
 
         # get the root folder URL
-        updateUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.id
-
-        props = {"cmisaction": "update"}
-
+        url = self._repository.getRootFolderUrl()
+        props = {
+            "objectId": self.id,
+            "cmisaction": "update"}
         setProps(properties, props, initialIndex=0)
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        result = self._cmisClient.binding.post(updateUrl.encode('utf-8'),
-                                               safe_urlencode(props),
-                                               'application/x-www-form-urlencoded',
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type)
 
         self.data = result
         self._initData()
@@ -404,19 +402,18 @@ class BrowserCmisObject(object):
         >>> doc.move(sub1, sub2)
         """
 
-        moveUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "move",
                  "sourceFolderId": sourceFolder.id,
                  "targetFolderId": targetFolder.id}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        self._cmisClient.binding.post(moveUrl.encode('utf-8'),
-                                      safe_urlencode(props),
-                                      'application/x-www-form-urlencoded',
-                                      self._cmisClient.username,
-                                      self._cmisClient.password)
+        self._cmisClient.binding.post(url,
+                                      self._cmisClient.session,
+                                      data,
+                                      data.content_type)
 
         return
 
@@ -434,17 +431,16 @@ class BrowserCmisObject(object):
         The optional allVersions argument is supported.
         """
 
-        delUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "delete"}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        self._cmisClient.binding.post(delUrl.encode('utf-8'),
-                                      safe_urlencode(props),
-                                      'application/x-www-form-urlencoded',
-                                      self._cmisClient.username,
-                                      self._cmisClient.password,
+        self._cmisClient.binding.post(url,
+                                      self._cmisClient.session,
+                                      data,
+                                      data.content_type,
                                       **kwargs)
 
         return
@@ -482,13 +478,12 @@ class BrowserCmisObject(object):
             'cmis:targetId': targetObj.getObjectId(),
             'cmis:objectTypeId': relTypeId
         }, props)
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        result = self._cmisClient.binding.post(url.encode('utf-8'),
-                                               safe_urlencode(props),
-                                               'application/x-www-form-urlencoded',
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type)
         return getSpecializedObject(BrowserCmisObject(self._cmisClient, self._repository, data=result))
 
     def getRelationships(self, **kwargs):
@@ -514,11 +509,15 @@ class BrowserCmisObject(object):
          - includeAllowableActions
         """
 
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=relationships"
-        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'relationships',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         # return the result set
         return BrowserResultSet(self._cmisClient, self._repository, result, serializer=RelationShipsSerializer())
 
@@ -553,10 +552,15 @@ class BrowserCmisObject(object):
         if self._repository.getCapabilities()['ACL']:
             # if the ACL capability is discover or manage, this must be
             # supported
-            aclUrl = self._repository.getRootFolderUrl() + "?cmisselector=object&objectId=" + self.getObjectId() + "&includeACL=true"
-            result = self._cmisClient.binding.get(aclUrl.encode('utf-8'),
-                                                  self._cmisClient.username,
-                                                  self._cmisClient.password)
+            url = self._repository.getRootFolderUrl()
+            params = {
+                'objectId': self.getObjectId(),
+                'cmisselector': 'object',
+                'includeACL': True
+            }
+            result = self._cmisClient.binding.get(url,
+                                                  self._cmisClient.session,
+                                                  **params)
             return BrowserACL(data=result['acl'])
         else:
             raise NotSupportedException
@@ -581,26 +585,28 @@ class BrowserCmisObject(object):
             if not isinstance(acl, ACL):
                 raise CmisException('The ACL to apply must be an instance of the ACL class.')
             # get the root folder URL
-            aclUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.id + "&cmisaction=applyACL"
+            url = self._repository.getRootFolderUrl()
 
-            fields = {}
+            props = {
+                'objectId': self.id,
+                'cmisaction': 'applyACL'
+            }
             for i, entry in enumerate(acl.getAddedAces()):
-                fields['addACEPrincipal[%d]' % i] = entry.principalId
+                props['addACEPrincipal[%d]' % i] = entry.principalId
                 for j, perm in enumerate(entry.permissions):
-                    fields['addACEPermission[%d][%d]' % (i, j)] = perm
+                    props['addACEPermission[%d][%d]' % (i, j)] = perm
             for i, entry in enumerate(acl.getRemovedAces()):
-                fields['removeACEPrincipal[%d]' % i] = entry.principalId
+                props['removeACEPrincipal[%d]' % i] = entry.principalId
                 for j, perm in enumerate(entry.permissions):
-                    fields['removeACEPermission[%d][%d]' % (i, j)] = perm
+                    props['removeACEPermission[%d][%d]' % (i, j)] = perm
 
-            contentType, body = encode_multipart_formdata(fields, None, None)
+            data = encode_multipart_formdata(props, None, None)
 
             # invoke the URL
-            result = self._cmisClient.binding.post(aclUrl.encode('utf-8'),
-                                                   body,
-                                                   contentType,
-                                                   self._cmisClient.username,
-                                                   self._cmisClient.password)
+            result = self._cmisClient.binding.post(url,
+                                                   self._cmisClient.session,
+                                                   data,
+                                                   data.content_type)
 
             # return the result set
             return BrowserACL(data=result)
@@ -777,11 +783,14 @@ class BrowserRepository(object):
          - includeAllowableActions
         """
 
-        byPathUrl = self.getRootFolderUrl() + safe_quote(path) + "?cmisselector=object"
-        result = self._cmisClient.binding.get(byPathUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self.getRootFolderUrl() + path
+        params = {
+            'cmisselector': 'object',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         return getSpecializedObject(BrowserCmisObject(self._cmisClient, self, data=result, **kwargs), **kwargs)
 
     def getSupportedPermissions(self):
@@ -985,15 +994,16 @@ class BrowserRepository(object):
         cmis:policy
         """
 
-        typesUrl = self.getRepositoryUrl() + "?cmisselector=typeChildren"
-
+        url = self.getRepositoryUrl()
+        params = {
+            'cmisselector': 'typeChildren',
+        }
         if typeId is not None:
-            typesUrl += "&typeId=%s" % (safe_quote(typeId))
-
-        result = self._cmisClient.binding.get(typesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+            params["typeId"] = typeId
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         types = []
         for res in result['types']:
             objectType = BrowserObjectType(self._cmisClient,
@@ -1045,17 +1055,19 @@ class BrowserRepository(object):
         17
         """
 
-        typesUrl = self.getRepositoryUrl() + "?cmisselector=typeDescendants"
-
+        url = self.getRepositoryUrl()
+        params = {
+            'cmisselector': 'typeDescendants',
+        }
         if typeId is not None:
-            typesUrl += "&typeId=%s" % (safe_quote(typeId))
+            params['typeId'] = typeId
         if depth is not None:
-            typesUrl += "&depth=%s" % (depth)
+            params['depth'] = depth
+        params.update(kwargs)
 
-        result = self._cmisClient.binding.get(typesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         serializer = TreeSerializer(treeType='type')
         types = serializer.getEntries(self._cmisClient, self, result)
         return types
@@ -1076,12 +1088,14 @@ class BrowserRepository(object):
         cmis:policy
         """
 
-        typesUrl = self.getRepositoryUrl() + "?cmisselector=typeChildren"
-
-        result = self._cmisClient.binding.get(typesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self.getRepositoryUrl()
+        params = {
+            'cmisselector': 'typeChildren',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         types = []
         for res in result['types']:
             objectType = BrowserObjectType(self._cmisClient,
@@ -1099,11 +1113,14 @@ class BrowserRepository(object):
         >>> folderType = repo.getTypeDefinition('cmis:folder')
         """
         # localhost:8080/chemistry/browser/A1?cmisselector=typeDefinition&typeId=cmis:folder
-        typesUrl = self.getRepositoryUrl() + "?cmisselector=typeDefinition" + \
-            "&typeId=" + typeId
-        result = self._cmisClient.binding.get(typesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password)
+        url = self.getRepositoryUrl()
+        params = {
+            'cmisselector': 'typeDefinition',
+            'typeId': typeId
+        }
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
 
         return BrowserObjectType(self._cmisClient,
                                  self,
@@ -1135,12 +1152,14 @@ class BrowserRepository(object):
          - includeAllowableActions
         """
 
-        typesUrl = self.getRepositoryUrl() + "?cmisselector=checkedOut"
-
-        result = self._cmisClient.binding.get(typesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self.getRepositoryUrl()
+        params = {
+            'cmisselector': 'checkedOut',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
 
         return BrowserResultSet(self._cmisClient,
                                 self,
@@ -1213,14 +1232,16 @@ class BrowserRepository(object):
         """
 
         # build the CMIS query XML that we're going to POST
-        queryUrl = self.getRepositoryUrl() + "?cmisaction=query&q=" + safe_quote(statement)
-
+        props = {
+            'cmisaction': 'query',
+            'q': statement
+        }
+        data = encode_multipart_formdata(props, None, None)
         # do the POST
-        result = self._cmisClient.binding.post(queryUrl.encode('utf-8'),
-                                               None,
-                                               CMIS_FORM_TYPE,
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(self.getRepositoryUrl(),
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type,
                                                **kwargs)
 
         # return the result set
@@ -1274,12 +1295,14 @@ class BrowserRepository(object):
         if self.getCapabilities()['Changes'] is None:
             raise NotSupportedException(messages.NO_CHANGE_LOG_SUPPORT)
 
-        changesUrl = self.getRepositoryUrl() + "?cmisselector=contentChanges"
-
-        result = self._cmisClient.binding.get(changesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self.getRepositoryUrl()
+        params = {
+            'cmisselector': 'contentChanges',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
 
         return BrowserResultSet(self._cmisClient,
                                 self,
@@ -1299,9 +1322,6 @@ class BrowserRepository(object):
         the repository supports unfiled objects, you do not have to pass in
         a parent :class:`Folder` otherwise it is required.
 
-        This method is essentially a convenience method that wraps your string
-        with a StringIO and then calls createDocument.
-
         >>> repo.createDocumentFromString('testdoc5', parentFolder=testFolder, contentString='Hello, World!', contentType='text/plain')
         <cmislib.model.Document object at 0x101352ed0>
         """
@@ -1317,7 +1337,7 @@ class BrowserRepository(object):
                 # this repo requires fileable objects to be filed
                 raise InvalidArgumentException
 
-        return parentFolder.createDocument(name, properties, StringIO.StringIO(contentString),
+        return parentFolder.createDocument(name, properties, contentString,
                                            contentType, contentEncoding)
 
     def createDocument(self,
@@ -1351,7 +1371,6 @@ class BrowserRepository(object):
          - addACEs
          - removeACEs
         """
-
         # if you didn't pass in a parent folder
         if parentFolder is None:
             # if the repository doesn't require fileable objects to be filed
@@ -1363,7 +1382,7 @@ class BrowserRepository(object):
                 raise InvalidArgumentException
 
         # get the root folder URL
-        createDocUrl = self.getRootFolderUrl()
+        url = self.getRootFolderUrl()
 
         props = {"objectId": parentFolder.id,
                  "cmisaction": "createDocument",
@@ -1379,16 +1398,10 @@ class BrowserRepository(object):
 
         setProps(properties, props, initialIndex=2)
 
-        contentType, body = encode_multipart_formdata(props, contentFile, contentType)
+        data = encode_multipart_formdata(props, contentFile, contentType)
 
-        # invoke the URL
-        result = self._cmisClient.binding.post(createDocUrl.encode('utf-8'),
-                                               body,
-                                               contentType,
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
-
-        # return the result set
+        result = self._cmisClient.binding.post(
+            url, self._cmisClient.session, data, data.content_type)
         return BrowserDocument(self._cmisClient, self, data=result)
 
     def createDocumentFromSource(self,
@@ -1693,17 +1706,16 @@ class BrowserDocument(BrowserCmisObject)
         True
         """
 
-        coUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "checkOut"}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        result = self._cmisClient.binding.post(coUrl.encode('utf-8'),
-                                               safe_urlencode(props),
-                                               'application/x-www-form-urlencoded',
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type)
 
         return getSpecializedObject(BrowserCmisObject(self._cmisClient, self._repository, data=result))
 
@@ -1720,17 +1732,16 @@ class BrowserDocument(BrowserCmisObject)
         False
         """
 
-        coUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "cancelCheckOut"}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        self._cmisClient.binding.post(coUrl.encode('utf-8'),
-                                      safe_urlencode(props),
-                                      'application/x-www-form-urlencoded',
-                                      self._cmisClient.username,
-                                      self._cmisClient.password)
+        self._cmisClient.binding.post(url,
+                                      self._cmisClient.session,
+                                      data,
+                                      data.content_type)
 
         return
 
@@ -1818,6 +1829,8 @@ class BrowserDocument(BrowserCmisObject)
             kwargs['major'] = 'false'
 
         props = {
+            'objectId': self.id,
+            'cmisaction': 'checkin',
             'checkinComment': checkinComment or "",
         }
         props.update(kwargs)
@@ -1828,16 +1841,15 @@ class BrowserDocument(BrowserCmisObject)
             props["propertyValue[%s]" % propCount] = value
             propCount += 1
 
-        ciUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.id + "&cmisaction=checkin"
+        url = self._repository.getRootFolderUrl()
 
-        contentType, body = encode_multipart_formdata(props, contentFile, contentType)
+        data = encode_multipart_formdata(props, contentFile, contentType)
 
         # invoke the URL
-        result = self._cmisClient.binding.post(ciUrl.encode('utf-8'),
-                                               body,
-                                               contentType,
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type)
 
         return getSpecializedObject(BrowserCmisObject(self._cmisClient, self._repository, data=result))
 
@@ -1899,13 +1911,16 @@ class BrowserDocument(BrowserCmisObject)
         """
 
         # get the version history link
-        versionsUrl = self._repository.getRootFolderUrl() + '?cmisselector=versions' + '&objectId=' + self.getObjectId()
-
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'versions',
+        }
+        params.update(kwargs)
         # invoke the URL
-        result = self._cmisClient.binding.get(versionsUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
 
         # return the result set
         return BrowserResultSet(self._cmisClient, self._repository, data={'objects': result}, serializer=VersionsSerializer())
@@ -1932,14 +1947,15 @@ class BrowserDocument(BrowserCmisObject)
         if not self.getAllowableActions()['canGetContentStream']:
             return None
 
-        contentUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=content"
-        result, content = Rest().get(contentUrl.encode('utf-8'),
-                                     self._cmisClient.username,
-                                     self._cmisClient.password,
-                                     **self._cmisClient.extArgs)
-        if result['status'] != '200':
-            raise CmisException(result['status'])
-        return StringIO.StringIO(content)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'content',
+        }
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
+        return BytesIO(result.content)
 
     def setContentStream(self, contentFile, contentType=None):
 
@@ -1951,16 +1967,18 @@ class BrowserDocument(BrowserCmisObject)
         """
 
         # get the root folder URL
-        createDocUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.id + "&cmisaction=setContent"
-
-        contentType, body = encode_multipart_formdata(None, contentFile, contentType)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.id,
+            'cmisaction': 'setContent'
+        }
+        data = encode_multipart_formdata(params, contentFile, contentType)
 
         # invoke the URL
-        result = self._cmisClient.binding.post(createDocUrl.encode('utf-8'),
-                                               body,
-                                               contentType,
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type)
 
         # return the result set
         return BrowserDocument(self._cmisClient, self._repository, data=result)
@@ -1974,20 +1992,19 @@ class BrowserDocument(BrowserCmisObject)
         if not self.allowableActions['canDeleteContentStream']:
             raise CmisException('Not allowed to delete the content stream')
 
-        delUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "deleteContent"}
 
         if 'cmis:changeToken' in self.properties:
             props["changeToken"] = self.properties['cmis:changeToken']
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        self._cmisClient.binding.post(delUrl.encode('utf-8'),
-                                      safe_urlencode(props),
-                                      'application/x-www-form-urlencoded',
-                                      self._cmisClient.username,
-                                      self._cmisClient.password)
+        self._cmisClient.binding.post(url,
+                                      self._cmisClient.session,
+                                      data,
+                                      data.content_type)
 
         return
 
@@ -2011,16 +2028,15 @@ class BrowserDocument(BrowserCmisObject)
 
         renditions = []
 
-        contentUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=renditions&renditionFilter=*"
-        result, content = Rest().get(contentUrl.encode('utf-8'),
-                                     self._cmisClient.username,
-                                     self._cmisClient.password,
-                                     **self._cmisClient.extArgs)
-        if result['status'] != '200':
-            raise CmisException(result['status'])
-
-        resultObj = json.loads(content)
-        for rendObj in resultObj:
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'renditions',
+            'renditionFilter': '*'
+        }
+        result = self._cmisClient.binding.get(
+            url, self._cmisClient.session, **params)
+        for rendObj in result:
             renditions.append(BrowserRendition(rendObj))
 
         return renditions
@@ -2034,10 +2050,15 @@ class BrowserDocument(BrowserCmisObject)
         of cmis:path with the relativePathSegment.
         """
 
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=parents&includerelativepathsegment=true"
-        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'parents',
+            'includerelativepathsegment': True
+        }
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
 
         paths = []
 
@@ -2084,7 +2105,7 @@ class BrowserFolder(BrowserCmisObject):
         """
 
         # get the root folder URL
-        createFolderUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "createFolder",
@@ -2100,12 +2121,12 @@ class BrowserFolder(BrowserCmisObject):
 
         setProps(properties, props, initialIndex=2)
 
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        result = self._cmisClient.binding.post(createFolderUrl.encode('utf-8'),
-                                               safe_urlencode(props),
-                                               'application/x-www-form-urlencoded',
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type,
                                                **kwargs)
 
         # return the result set
@@ -2123,9 +2144,6 @@ class BrowserFolder(BrowserCmisObject):
         the repository supports unfiled objects, you do not have to pass in
         a parent :class:`Folder` otherwise it is required.
 
-        This method is essentially a convenience method that wraps your string
-        with a StringIO and then calls createDocument.
-
         >>> testFolder.createDocumentFromString('testdoc3', contentString='hello, world', contentType='text/plain')
         """
 
@@ -2207,11 +2225,16 @@ class BrowserFolder(BrowserCmisObject):
          - includePathSegment
         """
 
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=children"
-        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'children',
+        }
+        params.update(kwargs)
+
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         # return the result set
         return BrowserResultSet(self._cmisClient, self._repository, result, serializer=ChildrenSerializer())
 
@@ -2247,11 +2270,15 @@ class BrowserFolder(BrowserCmisObject):
 
         """
 
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=descendants"
-        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'descendants',
+        }
+        params.update(kwargs)
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         # return the result set
         return BrowserResultSet(self._cmisClient, self._repository, result, serializer=TreeSerializer())
 
@@ -2281,11 +2308,16 @@ class BrowserFolder(BrowserCmisObject):
          u'subfolder'
         """
 
-        byObjectIdUrl = self._repository.getRootFolderUrl() + "?objectId=" + self.getObjectId() + "&cmisselector=foldertree"
-        result = self._cmisClient.binding.get(byObjectIdUrl.encode('utf-8'),
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
-                                              **kwargs)
+        url = self._repository.getRootFolderUrl()
+        params = {
+            'objectId': self.getObjectId(),
+            'cmisselector': 'foldertree',
+        }
+        params.update(kwargs)
+
+        result = self._cmisClient.binding.get(url,
+                                              self._cmisClient.session,
+                                              **params)
         # return the result set
         return BrowserResultSet(self._cmisClient, self._repository, result, serializer=TreeSerializer())
 
@@ -2313,17 +2345,16 @@ class BrowserFolder(BrowserCmisObject):
          - continueOnFailure
         """
 
-        delUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"objectId": self.id,
                  "cmisaction": "deleteTree"}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        self._cmisClient.binding.post(delUrl.encode('utf-8'),
-                                      safe_urlencode(props),
-                                      'application/x-www-form-urlencoded',
-                                      self._cmisClient.username,
-                                      self._cmisClient.password,
+        self._cmisClient.binding.post(url,
+                                      self._cmisClient.session,
+                                      data,
+                                      data.content_type,
                                       **kwargs)
 
         return
@@ -2352,18 +2383,17 @@ class BrowserFolder(BrowserCmisObject):
         """
         # TODO need to add support (and unit test) for allVersions
 
-        addUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"folderId": self.id,
                  "cmisaction": "addObjectToFolder",
                  "objectId": cmisObject.id}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        result = self._cmisClient.binding.post(addUrl.encode('utf-8'),
-                                               safe_urlencode(props),
-                                               'application/x-www-form-urlencoded',
-                                               self._cmisClient.username,
-                                               self._cmisClient.password,
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type,
                                                **kwargs)
 
         return getSpecializedObject(BrowserCmisObject(self._cmisClient, self._repository, data=result))
@@ -2375,18 +2405,17 @@ class BrowserFolder(BrowserCmisObject):
         support unfiling for this to work.
         """
 
-        remUrl = self._repository.getRootFolderUrl()
+        url = self._repository.getRootFolderUrl()
 
         props = {"folderId": self.id,
                  "cmisaction": "removeObjectFromFolder",
                  "objectId": cmisObject.id}
-
+        data = encode_multipart_formdata(props, None, None)
         # invoke the URL
-        result = self._cmisClient.binding.post(remUrl.encode('utf-8'),
-                                               safe_urlencode(props),
-                                               'application/x-www-form-urlencoded',
-                                               self._cmisClient.username,
-                                               self._cmisClient.password)
+        result = self._cmisClient.binding.post(url,
+                                               self._cmisClient.session,
+                                               data,
+                                               data.content_type)
 
         return getSpecializedObject(BrowserCmisObject(self._cmisClient, self._repository, data=result))
 
@@ -2622,8 +2651,7 @@ class BrowserObjectType(ObjectType):
         kwargs['cmisselector'] = 'typeDefinition'
         kwargs['typeId'] = self.getTypeId()
         result = self._cmisClient.binding.get(typesUrl,
-                                              self._cmisClient.username,
-                                              self._cmisClient.password,
+                                              self._cmisClient.session,
                                               **kwargs)
         self.data = result
 
@@ -3210,7 +3238,7 @@ def setProps(properties, props, initialI
     i = initialIndex
     for key, val in properties.items():
         props["propertyId[%s]" % i] = key
-        if hasattr(val, '__iter__'):
+        if isinstance(val, (list, tuple) ):
             j = 0
             for v in val:
                 props["propertyValue[%s][%s]" % (i, j)] = v
@@ -3252,36 +3280,22 @@ def encode_multipart_formdata(fields, co
     """
     fields is a sequence of (name, value) elements for regular form fields.
     files is a sequence of (name, filename, value) elements for data to be uploaded as files
-    Return (content_type, body) ready for httplib.HTTP instance
+    Return MultipartEncoder for requests.post method
     """
-
-    boundary = 'aPacHeCheMIStrycMisLIb%s' % (int(time.time()))
-    crlf = '\r\n'
-    L = []
+    _fields = OrderedDict()
     fileName = None
     if fields:
         for (key, value) in iteritems(fields):
-            if key == 'cmis:name':
-                fileName = value
-            L.append('--' + boundary)
-            L.append('Content-Disposition: form-data; name="%s"' % key)
-            L.append('Content-Type: text/plain; charset=utf-8')
-            L.append('')
-            L.append(value.encode('utf-8'))
-
+            if contentFile and value == 'cmis:name':
+                fileName = fields['propertyValue' + key[-3:]]
+            _fields[key] = (None, value, 'text/plain;charset=utf-8')
     if contentFile:
-        L.append('--' + boundary)
-        L.append('Content-Disposition: form-data; name="%s"; filename=%s' % ('content', fileName))
-        L.append('Content-Type: %s' % contentType)
-        L.append('Content-Transfer-Encoding: binary')
-        L.append('')
-        L.append(contentFile.read())
-
-    L.append('--' + boundary + '--')
-    L.append('')
-    body = crlf.join(L)
-    content_type = 'multipart/form-data; boundary=%s' % boundary
-    return content_type, body
+        _fields['content'] = (fileName or '', contentFile, contentType or 'application/binary')
+
+    m = MultipartEncoder(
+        fields=_fields
+    )
+    return m
 
 
 class ResultsSerializer(object):

Modified: chemistry/cmislib/branches/py3_compat/src/cmislib/cmis_services.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/branches/py3_compat/src/cmislib/cmis_services.py?rev=1836994&r1=1836993&r2=1836994&view=diff
==============================================================================
--- chemistry/cmislib/branches/py3_compat/src/cmislib/cmis_services.py (original)
+++ chemistry/cmislib/branches/py3_compat/src/cmislib/cmis_services.py Sun Jul 29 16:55:46 2018
@@ -41,30 +41,31 @@ class Binding(object):
 
         pass
 
-    def _processCommonErrors(self, error, url):
+    def _processCommonErrors(self, response):
 
         """
         Maps HTTPErrors that are common to all to exceptions. Only errors
         that are truly global, like 401 not authorized, should be handled
         here. Callers should handle the rest.
         """
-
-        if error['status'] == '401':
-            raise PermissionDeniedException(error['status'], url)
-        elif error['status'] == '400':
-            raise InvalidArgumentException(error['status'], url)
-        elif error['status'] == '404':
-            raise ObjectNotFoundException(error['status'], url)
-        elif error['status'] == '403':
-            raise PermissionDeniedException(error['status'], url)
-        elif error['status'] == '405':
-            raise NotSupportedException(error['status'], url)
-        elif error['status'] == '409':
-            raise UpdateConflictException(error['status'], url)
-        elif error['status'] == '500':
-            raise RuntimeException(error['status'], url)
+        status_code = response.status_code
+        url = response.url
+        if status_code == 401:
+            raise PermissionDeniedException(status_code, url, response.text)
+        elif status_code == 400:
+            raise InvalidArgumentException(status_code, url, response.text)
+        elif status_code == 404:
+            raise ObjectNotFoundException(status_code, url, response.text)
+        elif status_code == 403:
+            raise PermissionDeniedException(status_code, url, response.text)
+        elif status_code == 405:
+            raise NotSupportedException(status_code, url, response.text)
+        elif status_code == 409:
+            raise UpdateConflictException(status_code, url, response.text)
+        elif status_code == 500:
+            raise RuntimeException(status_code, url, response.text)
         else:
-            raise CmisException(error['status'], url)
+            raise CmisException(status_code, url, response.text)
 
 
 class RepositoryServiceIfc(object):

Modified: chemistry/cmislib/branches/py3_compat/src/cmislib/domain.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/branches/py3_compat/src/cmislib/domain.py?rev=1836994&r1=1836993&r2=1836994&view=diff
==============================================================================
--- chemistry/cmislib/branches/py3_compat/src/cmislib/domain.py (original)
+++ chemistry/cmislib/branches/py3_compat/src/cmislib/domain.py Sun Jul 29 16:55:46 2018
@@ -2026,14 +2026,14 @@ class ACE(object):
         """Getter for permissions"""
         return self._permissions
 
-    def __cmp__(self, other):
+    def __eq__(self, other):
         if (
             isinstance(other, self.__class__) and
             self.principalId == other.principalId and
             self.direct == other.direct and
             not(set(self.permissions) ^ set(other.permissions))):
-            return 0
-        return -1
+            return True
+        return False
 
     def copy(self):
         """