From 743f8b96bb9d961a3e7f9f2c45b2be1beb5f9233 Mon Sep 17 00:00:00 2001 From: "evgeny.ezhov" Date: Sun, 3 Dec 2017 09:42:43 +0300 Subject: [PATCH] Added method for settings of WebDAV resource property values in batch. Prepared for release 0.5 --- LICENSE.md | 2 +- README.rst | 6 +++++- setup.py | 2 +- tests/test_client_it.py | 35 +++++++++++++++++++++++++++++++--- tests/test_client_unit.py | 40 +++++++++++++++++++++++++++++++++++---- webdav3/client.py | 35 +++++++++++++++++++++++----------- 6 files changed, 99 insertions(+), 21 deletions(-) diff --git a/LICENSE.md b/LICENSE.md index 3d19f99..44f0948 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -python setup.py register -r pypitestCOPYRIGHT AND PERMISSION NOTICE +COPYRIGHT AND PERMISSION NOTICE Copyright (c) 2016, The WDC Project, and many contributors, see the THANKS file. diff --git a/README.rst b/README.rst index fab0694..e13d46e 100644 --- a/README.rst +++ b/README.rst @@ -7,10 +7,14 @@ But uses `requests` instead of `PyCURL` Release Notes ============= + +Version 0.5 – 03.12.2017 +* Added method for setting of WebDAV resource property values in batch + Version 0.4 - 27.11.2017 * Refactoring of WebDAV client and making it works in following methods: - Checking is remote resource directory - - Fixed problem when connection lost during request executing and nothing was happened, now it raises an exception. + - Fixed problem when connection lost during request executing and nothing was happened, now it raises an exception Version 0.3 - 18.10.2017 * Refactoring of WebDAV client and making it works in following methods: diff --git a/setup.py b/setup.py index df7a5dc..e1df794 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ from setuptools import setup, find_packages from setuptools.command.install import install as InstallCommand from setuptools.command.test import test as TestCommand -version = "0.4" +version = "0.5" requirements = "libxml2-dev libxslt-dev python-dev" diff --git a/tests/test_client_it.py b/tests/test_client_it.py index a72cb3c..9bf8ae6 100644 --- a/tests/test_client_it.py +++ b/tests/test_client_it.py @@ -160,10 +160,18 @@ class ClientTestCase(TestCase): self.assertTrue('created' in result) self.assertTrue('modified' in result) - def test_get_property(self): + def test_directory_is_dir(self): + self._prepare_for_downloading() + self.assertTrue(self.client.is_dir(self.remote_path_dir), 'Should return True for directory') + + def test_file_is_not_dir(self): + self._prepare_for_downloading() + self.assertFalse(self.client.is_dir(self.remote_path_file), 'Should return False for file') + + def test_get_property_of_non_exist(self): self._prepare_for_downloading() result = self.client.get_property(remote_path=self.remote_path_file, option={'name': 'aProperty'}) - self.assertEquals(result, None) + self.assertEquals(result, None, 'For not found property should return value as None') def test_set_property(self): self._prepare_for_downloading() @@ -174,7 +182,28 @@ class ClientTestCase(TestCase): }) result = self.client.get_property(remote_path=self.remote_path_file, option={'namespace': 'test', 'name': 'aProperty'}) - self.assertEquals(result, "aValue") + self.assertEquals(result, 'aValue', 'Property value should be set') + + def test_set_property_batch(self): + self._prepare_for_downloading() + self.client.set_property_batch(remote_path=self.remote_path_file, option=[ + { + 'namespace': 'test', + 'name': 'aProperty', + 'value': 'aValue' + }, + { + 'namespace': 'test', + 'name': 'aProperty2', + 'value': 'aValue2' + } + ]) + result = self.client.get_property(remote_path=self.remote_path_file, + option={'namespace': 'test', 'name': 'aProperty'}) + self.assertEquals(result, 'aValue', 'First property value should be set') + result = self.client.get_property(remote_path=self.remote_path_file, + option={'namespace': 'test', 'name': 'aProperty2'}) + self.assertEquals(result, 'aValue2', 'Second property value should be set') def _prepare_for_downloading(self): if not self.client.check(remote_path=self.remote_path_dir): diff --git a/tests/test_client_unit.py b/tests/test_client_unit.py index 83732f2..40a1fe4 100644 --- a/tests/test_client_unit.py +++ b/tests/test_client_unit.py @@ -72,24 +72,56 @@ class ClientTestCase(TestCase): result = utils.parse_get_property_response(content=content, name='aProperty') self.assertEquals(result, 'aValue') - def test_create_set_property_request_content(self): + def test_create_set_one_property_request_content(self): option = { 'namespace': 'test', 'name': 'aProperty', 'value': 'aValue' } - result = utils.create_set_property_request_content(option=option) + result = utils.create_set_property_batch_request_content(options=[option]) self.assertEquals(result, '\n' 'aValue') - def test_create_set_property_request_content_name_only(self): + def test_create_set_one_property_request_content_name_only(self): option = { 'name': 'aProperty' } - result = utils.create_set_property_request_content(option=option) + result = utils.create_set_property_batch_request_content(options=[option]) self.assertEquals(result, '\n' '') + def test_create_set_property_batch_request_content(self): + options = [ + { + 'namespace': 'test', + 'name': 'aProperty', + 'value': 'aValue' + }, + { + 'namespace': 'test2', + 'name': 'aProperty2', + 'value': 'aValue2' + } + ] + result = utils.create_set_property_batch_request_content(options=options) + self.assertEquals(result, '\n' + 'aValueaValue2' + '') + + def test_create_set_property_batch_request_content_name_only(self): + options = [ + { + 'name': 'aProperty' + }, + { + 'name': 'aProperty2' + } + ] + result = utils.create_set_property_batch_request_content(options=options) + self.assertEquals(result, '\n' + '' + '') + def test_etree_to_string(self): tree = ElementTree(Element('test')) result = utils.etree_to_string(tree) diff --git a/webdav3/client.py b/webdav3/client.py index aa07880..2452572 100644 --- a/webdav3/client.py +++ b/webdav3/client.py @@ -575,7 +575,6 @@ class Client(object): path = self.get_full_path(urn) return WebDavXmlUtils.parse_info_response(content=response.content, path=path, hostname=self.webdav.hostname) - # TODO refactor code below and write tests for it. @wrap_connection_error def is_dir(self, remote_path): """Checks is the remote resource directory. @@ -623,11 +622,24 @@ class Client(object): `name`: the name of property which will be set, `value`: (optional) the value of property which will be set. Defaults is empty string. """ + self.set_property_batch(remote_path=remote_path, option=[option]) + + @wrap_connection_error + def set_property_batch(self, remote_path, option): + """Sets batch metadata properties of remote resource on WebDAV server in batch. + More information you can find by link http://webdav.org/specs/rfc4918.html#METHOD_PROPPATCH + + :param remote_path: the path to remote resource. + :param option: the property attributes as list of dictionaries with following keys: + `namespace`: (optional) the namespace for XML property which will be set, + `name`: the name of property which will be set, + `value`: (optional) the value of property which will be set. Defaults is empty string. + """ urn = Urn(remote_path) if not self.check(urn.path()): raise RemoteResourceNotFound(urn.path()) - data = WebDavXmlUtils.create_set_property_request_content(option) + data = WebDavXmlUtils.create_set_property_batch_request_content(option) self.execute_request(action='set_property', path=urn.quote(), data=data) def resource(self, remote_path): @@ -874,10 +886,10 @@ class WebDavXmlUtils: :return: True in case the remote resource is directory and False otherwise. """ response = WebDavXmlUtils.extract_response_for_path(content=content, path=path, hostname=hostname) - type = response.find(".//{DAV:}resourcetype") - if type is None: - raise MethodNotSupported(name="is_dir", server=self.webdav.hostname) - dir_type = type.find("{DAV:}collection") + resource_type = response.find(".//{DAV:}resourcetype") + if resource_type is None: + raise MethodNotSupported(name="is_dir", server=hostname) + dir_type = resource_type.find("{DAV:}collection") return True if dir_type is not None else False @@ -908,10 +920,10 @@ class WebDavXmlUtils: return tree.xpath('//*[local-name() = $name]', name=name)[0].text @staticmethod - def create_set_property_request_content(option): - """Creates an XML for requesting of setting a property value for remote WebDAV resource. + def create_set_property_batch_request_content(options): + """Creates an XML for requesting of setting a property values for remote WebDAV resource in batch. - :param option: the property attributes as dictionary with following keys: + :param options: the property attributes as list of dictionaries with following keys: `namespace`: (optional) the namespace for XML property which will be set, `name`: the name of property which will be set, `value`: (optional) the value of property which will be set. Defaults is empty string. @@ -920,8 +932,9 @@ class WebDavXmlUtils: root_node = etree.Element('propertyupdate', xmlns='DAV:') set_node = etree.SubElement(root_node, 'set') prop_node = etree.SubElement(set_node, 'prop') - opt_node = etree.SubElement(prop_node, option['name'], xmlns=option.get('namespace', '')) - opt_node.text = option.get('value', '') + for option in options: + opt_node = etree.SubElement(prop_node, option['name'], xmlns=option.get('namespace', '')) + opt_node.text = option.get('value', '') tree = etree.ElementTree(root_node) return WebDavXmlUtils.etree_to_string(tree)