Only in Python_WebDAV_Library-0.4.2: MANIFEST.in diff -ru Python_WebDAV_Library-0.4.2-old/src/davlib.py Python_WebDAV_Library-0.4.2/src/davlib.py --- Python_WebDAV_Library-0.4.2-old/src/davlib.py 2012-12-20 08:27:31.000000000 +0900 +++ Python_WebDAV_Library-0.4.2/src/davlib.py 2013-04-06 16:07:53.836805115 +0900 @@ -200,14 +200,14 @@ def delete(self, url, extra_hdrs={ }): return self._request('DELETE', url, extra_hdrs=extra_hdrs) - def propfind(self, url, body=None, depth=None, extra_hdrs={ }): + def propfind(self, url, body=None, depth=None, extra_hdrs={}): headers = extra_hdrs.copy() headers['Content-Type'] = XML_CONTENT_TYPE if depth is not None: headers['Depth'] = str(depth) return self._request('PROPFIND', url, body, headers) - def proppatch(self, url, body, extra_hdrs={ }): + def proppatch(self, url, body, extra_hdrs={}): headers = extra_hdrs.copy() headers['Content-Type'] = XML_CONTENT_TYPE return self._request('PROPPATCH', url, body, headers) @@ -261,17 +261,19 @@ # Higher-level methods for typical client use # - def allprops(self, url, depth=None): + def allprops(self, url, depth=None, extra_hdrs={}): body = XML_DOC_HEADER + \ '' - return self.propfind(url, body, depth=depth) + return self.propfind(url, body, depth=depth, extra_hdrs=extra_hdrs) - def propnames(self, url, depth=None): + def propnames(self, url, depth=None, extra_hdrs={}): body = XML_DOC_HEADER + \ '' - return self.propfind(url, body, depth) + return self.propfind(url, body, depth, extra_hdrs=extra_hdrs) def getprops(self, url, *names, **kw): + """kw can have keys: 'ns', 'depth', and 'extra_hdrs' + """ assert names, 'at least one property name must be provided' if kw.has_key('ns'): xmlns = ' xmlns:NS="' + kw['ns'] + '"' @@ -284,14 +286,17 @@ del kw['depth'] else: depth = 0 + extra_hdrs = kw.pop('extra_hdrs',{}) assert not kw, 'unknown arguments' body = XML_DOC_HEADER + \ '<' + ns + \ string.joinfields(names, '/><' + ns) + \ '/>' - return self.propfind(url, body, depth) + return self.propfind(url, body, depth,extra_hdrs=extra_hdrs) def delprops(self, url, *names, **kw): + """kw can have keys 'ns', and 'extra_hdrs' + """ assert names, 'at least one property name must be provided' if kw.has_key('ns'): xmlns = ' xmlns:NS="' + kw['ns'] + '"' @@ -299,15 +304,19 @@ del kw['ns'] else: xmlns = ns = '' + extra_hdrs=kw.pop('extra_hdrs',{}) assert not kw, 'unknown arguments' body = XML_DOC_HEADER + \ '<' + ns + \ string.joinfields(names, '/><' + ns) + \ '/>' - return self.proppatch(url, body) + return self.proppatch(url, body,extra_hdrs=extra_hdrs) def setprops(self, url, *xmlprops, **props): + """ + props can have keys extra_hdrs, which is passed to proppatch + """ assert xmlprops or props, 'at least one property must be provided' xmlprops = list(xmlprops) if props.has_key('ns'): @@ -316,6 +325,7 @@ del props['ns'] else: xmlns = ns = '' + extra_hdrs = props.pop('extra_hdrs',{}) for key, value in props.items(): if value: xmlprops.append('<%s%s>%s' % (ns, key, value, ns, key)) @@ -327,10 +337,10 @@ '>' + \ elems + \ '' - return self.proppatch(url, body) + return self.proppatch(url, body,extra_hdrs=extra_hdrs) def get_lock(self, url, owner='', timeout=None, depth=None): response = self.lock(url, owner, timeout, depth) response.parse_lock_response() return response.locktoken - \ No newline at end of file + diff -ru Python_WebDAV_Library-0.4.2-old/src/webdav/Connection.py Python_WebDAV_Library-0.4.2/src/webdav/Connection.py --- Python_WebDAV_Library-0.4.2-old/src/webdav/Connection.py 2012-12-20 08:27:23.000000000 +0900 +++ Python_WebDAV_Library-0.4.2/src/webdav/Connection.py 2013-04-06 16:08:07.845843326 +0900 @@ -71,10 +71,16 @@ def __init__(self, *args, **kwArgs): DAV.__init__(self, *args, **kwArgs) self.__authorizationInfo = None + self.__userAgent = None self.logger = getDefaultLogger() self.isConnectedToCatacomb = True self.serverTypeChecked = False self._lock = RLock() + + def setUserAgent(self, useragent): + """sets the User-Agent header + """ + self.__userAgent = useragent def _request(self, method, url, body=None, extra_hdrs={}): @@ -89,7 +95,10 @@ self.__authorizationInfo.update(method=method, uri=url) extraHeaders["AUTHORIZATION"] = self.__authorizationInfo.authorization - + + if self.__userAgent is not None: + extraHeaders['User-Agent'] = self.__userAgent + # encode message parts body = _toUtf8(body) url = _urlEncode(url) @@ -155,7 +164,7 @@ except ResponseFormatError: raise WebdavError("Invalid WebDAV response.") response.close() - for status in unicode(response.msr).strip().split('\n'): + for status in unicode(str(response.msr),encoding='utf-8').strip().split('\n'): self.logger.debug("RESPONSE (Multi-Status): " + status) elif method == 'LOCK' and status == Constants.CODE_SUCCEEDED: response.parse_lock_response() diff -ru Python_WebDAV_Library-0.4.2-old/src/webdav/WebdavClient.py Python_WebDAV_Library-0.4.2/src/webdav/WebdavClient.py --- Python_WebDAV_Library-0.4.2-old/src/webdav/WebdavClient.py 2012-12-20 08:27:23.000000000 +0900 +++ Python_WebDAV_Library-0.4.2/src/webdav/WebdavClient.py 2013-04-06 16:08:07.845843326 +0900 @@ -139,13 +139,13 @@ if not(davHeader) or davHeader.find("2") < 0: # DAV class 2 supported ? raise WebdavError("URL does not support WebDAV", 0) - def options(self): + def options(self,extra_hdrs={}): """ Send an OPTIONS request to server and return all HTTP headers. @return: map of all HTTP headers returned by the OPTIONS method. """ - response = self.connection.options(self.path) + response = self.connection.options(self.path,extra_hdrs=extra_hdrs) result = {} result.update(response.msg) self.connection.logger.debug("OPTION returns: " + str(result.keys())) @@ -224,7 +224,7 @@ # delegate Delta-V methods return getattr(self.versionHandler, name) - def copy(self, toUrl, infinity=True): + def copy(self, toUrl, infinity=True, extra_hdrs={}): """ Copies this resource. @@ -235,13 +235,13 @@ self.connection.logger.debug("Copy to " + repr(toUrl)); _checkUrl(toUrl) if infinity: - response = self.connection.copy(self.path, toUrl) + response = self.connection.copy(self.path, toUrl,extra_hdrs=extra_hdrs) else: - response = self.connection.copy(self.path, toUrl, 0) + response = self.connection.copy(self.path, toUrl, 0,extra_hdrs=extra_hdrs) if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0: raise WebdavError("Request failed: " + response.msr.reason, response.msr.code) - def delete(self, lockToken=None): + def delete(self, lockToken=None,extra_hdrs={}): """ Deletes this resource. @@ -253,11 +253,12 @@ header = {} if lockToken: header = lockToken.toHeader() + header.udpate(extra_hdrs) response = self.connection.delete(self.path, header) if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0: raise WebdavError("Request failed: " + response.msr.reason, response.msr.code) - def move(self, toUrl): + def move(self, toUrl, extra_hdrs={}): """ Moves this resource to the given path or renames it. @@ -265,12 +266,12 @@ """ self.connection.logger.debug("Move to " + repr(toUrl)); _checkUrl(toUrl) - response = self.connection.move(self.path, toUrl) + response = self.connection.move(self.path, toUrl, extra_hdrs=extra_hdrs) if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0: raise WebdavError("Request failed: " + response.msr.reason, response.msr.code) - def lock(self, owner): + def lock(self, owner, extra_hdrs={}): """ Locks this resource for exclusive write access. This means that for succeeding write operations the returned lock token has to be passed. @@ -280,22 +281,22 @@ @return: lock token string (automatically generated) @rtype: L{LockToken} """ - response = self.connection.lock(self.path, owner) + response = self.connection.lock(self.path, owner, extra_hdrs=extra_hdrs) if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0: raise WebdavError("Request failed: " + response.msr.reason, response.msr.code) return LockToken(self.url, response.locktoken) - def unlock(self, lockToken): + def unlock(self, lockToken, extra_hdrs={}): """ Removes the lock from this resource. @param lockToken: which has been return by the lock() methode @type lockToken: L{LockToken} """ - self.connection.unlock(self.path, lockToken.token) + self.connection.unlock(self.path, lockToken.token, extra_hdrs=extra_hdrs) - def deleteContent(self, lockToken=None): + def deleteContent(self, lockToken=None, extra_hdrs={}): """ Delete binary data at permanent storage. @@ -307,6 +308,7 @@ header = {} if lockToken: header = lockToken.toHeader() + header.update(extra_hdrs) self.connection.put(self.path, "", extra_hdrs=header) def uploadContent(self, content, lockToken=None, extra_hdrs={}): @@ -337,7 +339,7 @@ self.connection.logger.debug(response.read()) response.close() - def uploadFile(self, newFile, lockToken=None): + def uploadFile(self, newFile, lockToken=None, extra_hdrs={}): """ Write binary data to permanent storage. @@ -351,6 +353,7 @@ header = {} if lockToken: header = lockToken.toHeader() + header.update(extra_hdrs) self.connection.putFile(self.path, newFile, header=header) def downloadContent(self, extra_hdrs={}): @@ -385,8 +388,9 @@ """ assert names, "Property names are missing." ignore404 = kwargs.pop('ignore404', False) + extra_hdrs = kwargs.pop('extra_hdrs',{}) body = createFindBody(names, self.defaultNamespace) - response = self.connection.propfind(self.path, body, depth=0) + response = self.connection.propfind(self.path, body, depth=0, extra_hdrs=extra_hdrs) properties = self._filter_property_response(response) if not ignore404 and properties.errorCount > 0 : raise WebdavError("Property is missing on '%s': %s" % (self.path, properties.reason), properties.code) @@ -421,36 +425,36 @@ raise WebdavError("Property is missing: " + results.reason) return results[(nameSpace, name)] - def readAllProperties(self): + def readAllProperties(self, extra_hdrs={}): """ Reads all properties of this resource. @return: a map from property names to DOM Element or String values. """ - response = self.connection.allprops(self.path, depth=0) + response = self.connection.allprops(self.path, depth=0,extra_hdrs=extra_hdrs) return self._filter_property_response(response) - def readAllPropertyNames(self): + def readAllPropertyNames(self,extra_hdrs={}): """ Returns the names of all properties attached to this resource. @return: List of property names """ - response = self.connection.propnames(self.path, depth=0) + response = self.connection.propnames(self.path, depth=0,extra_hdrs=extra_hdrs) return self._filter_property_response(response) - def readStandardProperties(self): + def readStandardProperties(self,extra_hdrs={}): """ Read all WebDAV live properties. @return: A L{LiveProperties} instance which contains a getter method for each live property. """ body = createFindBody(LiveProperties.NAMES, Constants.NS_DAV) - response = self.connection.propfind(self.path, body, depth=0) + response = self.connection.propfind(self.path, body, depth=0,extra_hdrs=extra_hdrs) properties = self._filter_property_response(response) return LiveProperties(properties) - def writeProperties(self, properties, lockToken=None): + def writeProperties(self, properties, lockToken=None, extra_hdrs={}): """ Sets or updates the given properties. @@ -465,12 +469,13 @@ header = {} if lockToken: header = lockToken.toHeader() + header.update(extra_hdrs) body = createUpdateBody(properties, self.defaultNamespace) response = self.connection.proppatch(self.path, body, header) if response.msr.errorCount > 0: raise WebdavError("Request failed: " + response.msr.reason, response.msr.code) - def deleteProperties(self, lockToken=None, *names): + def deleteProperties(self, lockToken=None, *names, **kw): """ Removes the given properties from this resource. @@ -484,13 +489,14 @@ header = {} if lockToken: header = lockToken.toHeader() + header.update(kw.pop('extra_hdrs',{})) body = createDeleteBody(names, self.defaultNamespace) response = self.connection.proppatch(self.path, body, header) if response.msr.errorCount > 0: raise WebdavError("Request failed: " + response.msr.reason, response.msr.code) # ACP extension - def setAcl(self, acl, lockToken=None): + def setAcl(self, acl, lockToken=None, extra_hdrs={}): """ Sets ACEs in the non-inherited and non-protected ACL or the resource. This is the implementation of the ACL method of the WebDAV ACP. @@ -504,6 +510,7 @@ headers = {} if lockToken: headers = lockToken.toHeader() + headers.update(extra_hdrs) headers['Content-Type'] = XML_CONTENT_TYPE body = acl.toXML() response = self.connection._request('ACL', self.path, body, headers) @@ -598,7 +605,7 @@ if not (isCollection and isCollection.children): raise WebdavError("'%s' not a collection!" % self.url, 0) - def addCollection(self, name, lockToken=None): + def addCollection(self, name, lockToken=None, extra_hdrs={}): """ Make a new WebDAV collection resource within this collection. @@ -612,6 +619,7 @@ header = {} if lockToken: header = lockToken.toHeader() + header.update(extra_hdrs) if self.validateResourceNames: validateResourceName(name) if name[-1] != '/': # Collection URL must end with slash @@ -641,7 +649,7 @@ resource_.writeProperties(properties, lockToken) return resource_ - def deleteResource(self, name, lockToken=None): + def deleteResource(self, name, lockToken=None, extra_hdrs={}): """ Delete a collection which is contained within this collection @@ -655,13 +663,14 @@ header = {} if lockToken: header = lockToken.toHeader() + header.update(extra_hdrs) if self.validateResourceNames: validateResourceName(name) response = self.connection.delete(self.path + name, header) if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0: raise WebdavError("Request failed: %s" % response.msr.reason, response.msr.code) - def lockAll(self, owner): + def lockAll(self, owner, extra_hdrs={}): """ Locks this collection resource for exclusive write access. This means that for succeeding write operations the returned lock token has to be passed. @@ -673,10 +682,10 @@ @rtype: L{LockToken} """ assert isinstance(owner, types.StringType) or isinstance(owner, types.UnicodeType) - response = self.connection.lock(self.path, owner, depth=Constants.HTTP_HEADER_DEPTH_INFINITY) + response = self.connection.lock(self.path, owner, depth=Constants.HTTP_HEADER_DEPTH_INFINITY, extra_hdrs=extra_hdrs) return LockToken(self.url, response.locktoken) - def listResources(self): + def listResources(self,extra_hdrs={}): """ Describe all members within this collection. @@ -688,6 +697,7 @@ response = self.connection.getprops(self.path, depth=1, ns=Constants.NS_DAV, + extra_hdrs=extra_hdrs, *LiveProperties.NAMES) result = {} for path, properties in response.msr.items(): @@ -718,7 +728,7 @@ collectionContents.append((myWebDavStorer, properties_)) return collectionContents - def findProperties(self, *names): + def findProperties(self, *names, **kw): """ Retrieve given properties for this collection and all directly contained resources. @@ -728,10 +738,11 @@ assert isinstance(names, types.ListType) or isinstance(names, types.TupleType), \ "Argument name has type %s" % str(type(names)) body = createFindBody(names, self.defaultNamespace) - response = self.connection.propfind(self.path, body, depth=1) + extra_hdrs = kw.pop('extra_hdrs',{}) + response = self.connection.propfind(self.path, body, depth=1,extra_hdrs=extra_hdrs) return response.msr - def deepFindProperties(self, *names): + def deepFindProperties(self, *names, **kw): """ Retrieve given properties for this collection and all contained (nested) resources. @@ -746,21 +757,22 @@ assert isinstance(names, types.ListType.__class__) or isinstance(names, types.TupleType), \ "Argument name has type %s" % str(type(names)) body = createFindBody(names, self.defaultNamespace) - response = self.connection.propfind(self.path, body, depth=Constants.HTTP_HEADER_DEPTH_INFINITY) + extra_hdrs = kw.pop('extra_hdrs',{}) + response = self.connection.propfind(self.path, body, depth=Constants.HTTP_HEADER_DEPTH_INFINITY,extra_hdrs=extra_hdrs) return response.msr - def findAllProperties(self): + def findAllProperties(self,extra_hdrs={}): """ Retrieve all properties for this collection and all directly contained resources. @return: a map from resource URI to a map from property name to value. """ - response = self.connection.allprops(self.path, depth=1) + response = self.connection.allprops(self.path, depth=1,extra_hdrs=extra_hdrs) return response.msr # DASL extension - def search(self, conditions, selects): + def search(self, conditions, selects,extra_hdrs={}): """ Search for contained resources which match the given search condition. @@ -769,6 +781,7 @@ """ assert isinstance(conditions, ConditionTerm) headers = { 'Content-Type' : XML_CONTENT_TYPE, "depth": Constants.HTTP_HEADER_DEPTH_INFINITY} + headers.update(extra_hdrs) body = createSearchBody(selects, self.path, conditions) response = self.connection._request('SEARCH', self.path, body, headers) return response.msr diff -ru Python_WebDAV_Library-0.4.2-old/src/webdav/WebdavResponse.py Python_WebDAV_Library-0.4.2/src/webdav/WebdavResponse.py --- Python_WebDAV_Library-0.4.2-old/src/webdav/WebdavResponse.py 2012-12-20 08:27:23.000000000 +0900 +++ Python_WebDAV_Library-0.4.2/src/webdav/WebdavResponse.py 2013-04-06 16:08:07.845843326 +0900 @@ -110,7 +110,7 @@ key, len(value), ", ".join([prop[1] for prop in value.keys()]), value.errorCount) else: result += "Resource at %s returned " % key + unicode(value) - return result.encode(sys.stdout.encoding or "ascii", "replace") + return result.encode(sys.getfilesystemencoding() or "ascii", "replace") def _scan(self, root): for child in root.children: