diff --git a/cterasdk/asynchronous/core/files/browser.py b/cterasdk/asynchronous/core/files/browser.py index 405d4d40..637f103e 100644 --- a/cterasdk/asynchronous/core/files/browser.py +++ b/cterasdk/asynchronous/core/files/browser.py @@ -115,10 +115,9 @@ async def permalink(self, path): :param str path: Path. """ p = self.normalize(path) - contents = [e async for e in await io.listdir(self._core, - p.parent, 1, False, p.name, 1)] # pylint: disable=unnecessary-comprehension - if contents and contents[0].name == p.name: - return contents[0].permalink + async for e in await io.listdir(self._core, p.parent, 1, False, p.name, 1): + if e.name == p.name: + return e.permalink raise FileNotFoundError('File not found.', path) def normalize(self, entries): diff --git a/cterasdk/asynchronous/core/types.py b/cterasdk/asynchronous/core/types.py index fb74fa5c..7a714421 100644 --- a/cterasdk/asynchronous/core/types.py +++ b/cterasdk/asynchronous/core/types.py @@ -21,6 +21,7 @@ def __init__( # pylint: disable=redefined-builtin, too-many-arguments self, type, guid, deleted, name, folder_id=None, modified=None, file_timestamp=None, size=None, id=None, acl=None, gvsn=None, parent_guid=None, portal_modified_date=None, virtual_portal_id=None): + super().__init__() self.type = type self.guid = guid self.folder_id = folder_id diff --git a/cterasdk/audit/postman.py b/cterasdk/audit/postman.py index 779dc9ad..0675eded 100644 --- a/cterasdk/audit/postman.py +++ b/cterasdk/audit/postman.py @@ -15,6 +15,7 @@ class Collection(Object): __instance = None def __init__(self): + super().__init__() self.info = Info() self.item = [] Collection.__instance = self @@ -36,6 +37,7 @@ def serialize(self): class Info(Object): def __init__(self): + super().__init__() self.name = f'{str(uuid.uuid4())}' self.schema = "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" @@ -43,6 +45,7 @@ def __init__(self): class Command(Object): def __init__(self, name, request): + super().__init__() self.name = name self.request = request self.response = [] @@ -51,6 +54,7 @@ def __init__(self, name, request): class Request(Object): def __init__(self, method, url): + super().__init__() self.method = method self.header = None self.url = url @@ -65,6 +69,7 @@ def request_body(self, data): class Header(Object): def __init__(self, key, value): + super().__init__() self.key = key self.value = value self.type = 'text' @@ -159,6 +164,7 @@ class Body(Object): """Request Body""" def __init__(self, mode): + super().__init__() self.mode = mode @@ -217,6 +223,7 @@ def json(body): class URL(Object): def __init__(self, raw, protocol, host, port, path, query): + super().__init__() self.raw = raw self.protocol = protocol self.host = host diff --git a/cterasdk/cio/core.py b/cterasdk/cio/core.py index 03bf17c7..536135f0 100644 --- a/cterasdk/cio/core.py +++ b/cterasdk/cio/core.py @@ -81,6 +81,7 @@ def instance(src, dest=None): return SrcDstParam.__instance def __init__(self, src, dest=None): + super().__init__() self._classname = self.__class__.__name__ self.src = src self.dest = dest @@ -97,6 +98,7 @@ def instance(): return ActionResourcesParam.__instance def __init__(self): + super().__init__() self._classname = self.__class__.__name__ self.urls = [] ActionResourcesParam.__instance = self # pylint: disable=unused-private-member @@ -115,6 +117,7 @@ def instance(path, access, expire_on): return CreateShareParam.__instance def __init__(self, path, access, expire_on): + super().__init__() self._classname = self.__class__.__name__ self.url = path self.share = Object() @@ -131,6 +134,7 @@ def __init__(self, path, access, expire_on): class FetchResourcesParam(Object): def __init__(self): + super().__init__() self._classname = 'FetchResourcesParam' self.start = 0 self.limit = 100 diff --git a/cterasdk/clients/async_requests.py b/cterasdk/clients/async_requests.py index c80e025c..6d3ac117 100644 --- a/cterasdk/clients/async_requests.py +++ b/cterasdk/clients/async_requests.py @@ -134,6 +134,13 @@ def __init__(self, url, **kwargs): super().__init__('DELETE', url, **kwargs) +class PropfindRequest(BaseRequest): + """PROPFIND""" + + def __init__(self, url, **kwargs): + super().__init__('PROPFIND', url, **kwargs) + + class MkcolRequest(BaseRequest): """MKCOL""" diff --git a/cterasdk/clients/base.py b/cterasdk/clients/base.py index 94e07aa4..1d2ae989 100644 --- a/cterasdk/clients/base.py +++ b/cterasdk/clients/base.py @@ -68,7 +68,7 @@ def __init__(self, builder=None, session=None, settings=None, authenticator=None default_settings = ClientSessionSettings() if settings: - default_settings.update(**settings.kwargs) + default_settings.update(**settings) self._session = session if session else async_requests.Session(default_settings, TraceSettings()) diff --git a/cterasdk/clients/clients.py b/cterasdk/clients/clients.py index 7d94324f..207b121f 100644 --- a/cterasdk/clients/clients.py +++ b/cterasdk/clients/clients.py @@ -59,6 +59,11 @@ class AsyncWebDAV(AsyncClient): async def download(self, path, **kwargs): return await super().get(path, **kwargs) + async def propfind(self, path): + request = async_requests.PropfindRequest(self._builder(path)) + response = await self.async_request(request) + return await response.dav() + async def mkcol(self, path): request = async_requests.MkcolRequest(self._builder(path)) response = await self.async_request(request) @@ -175,6 +180,9 @@ async def json(self): async def xml(self): return Deserializers.XML(await self._response.read()) + async def dav(self): + return Deserializers.DAV(await self._response.read()) + @async_requests.decorate_stream_error async def read(self, n=-1): return await self._response.content.read(n) @@ -251,6 +259,11 @@ class WebDAV(Client): def download(self, path, **kwargs): return super().handle(path, **kwargs) + def propfind(self, path): + request = async_requests.PropfindRequest(self._builder(path)) + response = self.request(request) + return response.dav() + def mkcol(self, path): request = async_requests.MkcolRequest(self._builder(path)) response = self.request(request) @@ -403,6 +416,9 @@ def json(self): # pylint: disable=invalid-overridden-method def xml(self): # pylint: disable=invalid-overridden-method return execute(super().xml) + def dav(self): # pylint: disable=invalid-overridden-method + return execute(super().dav) + @staticmethod def new(): async def new_response(response): diff --git a/cterasdk/clients/common.py b/cterasdk/clients/common.py index fe79173e..ca57295b 100644 --- a/cterasdk/clients/common.py +++ b/cterasdk/clients/common.py @@ -1,5 +1,5 @@ from . import async_requests -from ..convert import tojsonstr, toxmlstr, fromjsonstr, fromxmlstr +from ..convert import tojsonstr, toxmlstr, fromjsonstr, fromxmlstr, fromdavxmlstr class Serializers: @@ -11,6 +11,7 @@ class Serializers: class Deserializers: JSON = fromjsonstr XML = fromxmlstr + DAV = fromdavxmlstr class MultipartForm: diff --git a/cterasdk/clients/errors.py b/cterasdk/clients/errors.py index 7d960e39..d51496aa 100644 --- a/cterasdk/clients/errors.py +++ b/cterasdk/clients/errors.py @@ -8,6 +8,7 @@ class ClientError(Object): def __init__(self, exception, message): + super().__init__() self.request = Object() self.request.method = exception.request_info.method self.request.url = str(exception.request_info.real_url) diff --git a/cterasdk/common/object.py b/cterasdk/common/object.py index a7468f66..65fd324b 100644 --- a/cterasdk/common/object.py +++ b/cterasdk/common/object.py @@ -1,13 +1,29 @@ import re import json import logging +from collections.abc import MutableMapping -class Object: # pylint: disable=too-many-instance-attributes +class Object(MutableMapping): # pylint: disable=too-many-instance-attributes - @property - def kwargs(self): - return json.loads(str(self)) + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + + def __getitem__(self, key): + return getattr(self, key) + + def __setitem__(self, key, value): + setattr(self, key, value) + + def __delitem__(self, key): + delattr(self, key) + + def __iter__(self): + return iter(self.__dict__) + + def __len__(self): + return len(self.__dict__) def __str__(self): return json.dumps(self, default=lambda o: o.__dict__, indent=5) @@ -19,6 +35,7 @@ def __repr__(self): class Device(Object): def __init__(self, uid, version, firmware): + super().__init__() self.namespace = 'http://www.w3.org/2001/XMLSchema-instance' self.location = '../../db/resources/db.xsd' self.id = uid diff --git a/cterasdk/common/types.py b/cterasdk/common/types.py index c67dad5b..145d3e6f 100644 --- a/cterasdk/common/types.py +++ b/cterasdk/common/types.py @@ -28,6 +28,7 @@ def convert(rule, classname, property_name, assignment=None): class Operator(Object): def __init__(self, right): + super().__init__() self._classname = self.__class__.__name__ # pylint: disable=protected-access self.right = right @@ -75,6 +76,7 @@ class AfterOperator(Operator): class AdvancedFilterRule(Object): def __init__(self, classname, field, operator): + super().__init__() self._classname = self.__class__.__name__ # pylint: disable=protected-access self.className = classname self.fieldName = field @@ -283,6 +285,7 @@ def root(included): class FileEntry(Object): def __init__(self, name, display_name=None, included=None): + super().__init__() self._classname = self.__class__.__name__ # pylint: disable=protected-access self.name = name self.displayName = display_name @@ -300,6 +303,7 @@ class BackupSet(Object): def __init__(self, name, directory_tree=None, filter_rules=None, defaults_dirs=None, template_dirs=None, enabled=True, boolean_function=None, comment=None): + super().__init__() self._classname = self.__class__.__name__ # pylint: disable=protected-access self.name = name self.isEnabled = enabled @@ -334,6 +338,7 @@ def __init__(self, apps): class TaskSchedule(Object): def __init__(self): + super().__init__() self._classname = 'TaskSchedule' # pylint: disable=protected-access self.mode = None @@ -447,6 +452,7 @@ class ADDomainIDMapping(Object): :param int end: The maximum id to use for mapping """ def __init__(self, domain, start, end): + super().__init__() self._classname = 'ADDomainIDMapping' self.domainFlatName = domain self.minID = start @@ -499,6 +505,7 @@ def build(self): class SoftwareUpdatesTopic(Object): def __init__(self, enabled, reboot_after_update, reboot_when): + super().__init__() self._classname = "SoftwareUpdatesSettings" self.enabled = enabled if enabled else None self.rebootAfterUpdate = reboot_after_update if reboot_after_update else None diff --git a/cterasdk/common/utils.py b/cterasdk/common/utils.py index 203c1958..ac5ea1da 100644 --- a/cterasdk/common/utils.py +++ b/cterasdk/common/utils.py @@ -116,6 +116,7 @@ def __init__(self, uid, tenant=None, classname=None, name=None, more=None): :param str,optional name: Base object name :param str,optional more: Base object more info """ + super().__init__() self.uid = uid self.tenant = tenant self.classname = classname diff --git a/cterasdk/convert/__init__.py b/cterasdk/convert/__init__.py index e827bee9..29c6a097 100644 --- a/cterasdk/convert/__init__.py +++ b/cterasdk/convert/__init__.py @@ -1,2 +1,2 @@ -from .deserializers import fromjsonstr, fromxmlstr # noqa: E402, F401 +from .deserializers import fromjsonstr, fromxmlstr, fromdavxmlstr # noqa: E402, F401 from .serializers import tojsonstr, toxmlstr # noqa: E402, F401 diff --git a/cterasdk/convert/deserializers.py b/cterasdk/convert/deserializers.py index b4639918..ac41b215 100644 --- a/cterasdk/convert/deserializers.py +++ b/cterasdk/convert/deserializers.py @@ -84,6 +84,10 @@ def fromjsonstr(fromstr): return root.value +def fromdavxmlstr(string): + return fromstring(string) + + def fromxmlstr(string): # pylint: disable=too-many-branches,too-many-statements if not string: diff --git a/cterasdk/core/files/browser.py b/cterasdk/core/files/browser.py index a564791d..6ed9e461 100644 --- a/cterasdk/core/files/browser.py +++ b/cterasdk/core/files/browser.py @@ -118,9 +118,9 @@ def permalink(self, path): :param str path: Path. """ p = self.normalize(path) - contents = [e for e in io.listdir(self._core, p.parent, 1, False, p.name, 1)] # pylint: disable=unnecessary-comprehension - if contents and contents[0].name == p.name: - return contents[0].permalink + for e in io.listdir(self._core, p.parent, 1, False, p.name, 1): + if e.name == p.name: + return e.permalink raise FileNotFoundError('File not found.', path) def normalize(self, entries): diff --git a/cterasdk/core/query.py b/cterasdk/core/query.py index ad75749a..7bbed9bf 100644 --- a/cterasdk/core/query.py +++ b/cterasdk/core/query.py @@ -80,12 +80,14 @@ def fromValue(value, ref): class Filter(Object): def __init__(self, field): + super().__init__() self.field = field class FilterBuilder(Object): def __init__(self, name, reference=False): + super().__init__() self.filter = Filter(name) self.reference = reference @@ -145,6 +147,7 @@ def setValue(self, value): class QueryParams(Object): def __init__(self): + super().__init__() self.startFrom = 0 self.countLimit = 50 diff --git a/cterasdk/core/types.py b/cterasdk/core/types.py index aa3b24b9..c6222fab 100644 --- a/cterasdk/core/types.py +++ b/cterasdk/core/types.py @@ -428,6 +428,7 @@ def secondary(self): class AccessControlRule(Object): def __init__(self, group, role): + super().__init__() self._classname = 'AccessControlRule' self.group = group self.role = role @@ -610,6 +611,7 @@ def build(self): class Task(Object): def __init__(self, task_id, name): + super().__init__() self.id = task_id self.name = name @@ -701,6 +703,7 @@ def build(self): class ExtendedAttribute(Object): def __init__(self, name, supported): + super().__init__() self._classname = 'ExtendedAttributesInfo' # pylint: disable=protected-access self.name = name self.supported = supported @@ -758,6 +761,7 @@ class RoleSettings(Object): # pylint: disable=too-many-instance-attributes def __init__(self, name, sudo, enable_remote_wipe, enable_sso, enable_seeding_export, enable_seeding_import, access_end_user_folders, update_settings, update_roles, update_account_emails, update_account_password, manage_cloud_drives, manage_plans, manage_users, manage_logs, allow_folders_files_permanent_delete, can_manage_legal_holds, can_manage_compliance_settings): + super().__init__() self.name = name self.sudo = sudo self.enable_remote_wipe = enable_remote_wipe diff --git a/cterasdk/direct/types.py b/cterasdk/direct/types.py index c22650e1..b6fc3167 100644 --- a/cterasdk/direct/types.py +++ b/cterasdk/direct/types.py @@ -209,6 +209,7 @@ class ChunkMetadata(Object): :ivar int length: Part Length """ def __init__(self, url, index, offset, length): + super().__init__() self.url = url self.index = index self.offset = offset @@ -221,5 +222,6 @@ class FileMetadata(Object): """ def __init__(self, f): + super().__init__() self.encryption_key = utils.utf8_decode(base64.b64encode(f.encryption_key)) self.chunks = [ChunkMetadata(chunk.url, chunk.index, chunk.offset, chunk.length) for chunk in f.chunks] diff --git a/cterasdk/edge/ctera_migrate.py b/cterasdk/edge/ctera_migrate.py index 03802c32..dead3d7a 100644 --- a/cterasdk/edge/ctera_migrate.py +++ b/cterasdk/edge/ctera_migrate.py @@ -41,7 +41,7 @@ def list_tasks(self, deleted=False): :rtype: list(cterasdk.common.object.Object) """ tasks = self._edge.migrate.get('/tasks/list', params={'deleted': int(deleted)}).tasks # pylint: disable=W0212 - return [Task.from_server_object(task) for task in tasks.__dict__.values()] if tasks else [] + return [Task.from_server_object(task) for task in tasks.values()] if tasks else [] def delete(self, tasks): """ @@ -247,6 +247,7 @@ class Task(Object): """Class representing a migration tool task""" def __init__(self, task_id, task_type, name, created_at=None, source=None, source_type=None, last_status=None, shares=None, notes=None): + super().__init__() self.id = task_id self.type = {v: k for k, v in TaskType.__dict__.items() if not k.startswith('_')}.get(task_type).lower() self.name = name diff --git a/cterasdk/edge/query.py b/cterasdk/edge/query.py index 7add202f..4efe1389 100644 --- a/cterasdk/edge/query.py +++ b/cterasdk/edge/query.py @@ -43,6 +43,7 @@ def iterator(edge, path, param=None, name=None, callback_response=None): class QueryParam(Object): def __init__(self): + super().__init__() self.startFrom = 0 self.countLimit = 50 diff --git a/cterasdk/edge/types.py b/cterasdk/edge/types.py index d32d764d..fe2f1149 100644 --- a/cterasdk/edge/types.py +++ b/cterasdk/edge/types.py @@ -302,6 +302,7 @@ class DeduplicationStatus(Object): """ def __init__(self, size, usage): + super().__init__() self.size = size self.usage = usage diff --git a/cterasdk/lib/session/base.py b/cterasdk/lib/session/base.py index 329a2b37..3cbfe1c5 100644 --- a/cterasdk/lib/session/base.py +++ b/cterasdk/lib/session/base.py @@ -10,6 +10,7 @@ class BaseUser(Object): """Base User Account""" def __init__(self, name, domain=None): + super().__init__() self.name = name self.domain = domain @@ -32,6 +33,7 @@ def __init__(self, address, product): :param str address: Hostname or IP address :param cterasdk.lib.session.types.Product product: Product """ + super().__init__() self.address = address self.product = product self.connection_status = ConnectionStatus.Disconnected diff --git a/cterasdk/lib/session/edge.py b/cterasdk/lib/session/edge.py index 6e3ec161..4e351c92 100644 --- a/cterasdk/lib/session/edge.py +++ b/cterasdk/lib/session/edge.py @@ -9,6 +9,7 @@ class Connection(Object): """Connection""" def __init__(self, remote, source=None): + super().__init__() self.remote = remote if source: self.source = source diff --git a/cterasdk/objects/asynchronous/core.py b/cterasdk/objects/asynchronous/core.py index 94a2f78c..f11a4bdd 100644 --- a/cterasdk/objects/asynchronous/core.py +++ b/cterasdk/objects/asynchronous/core.py @@ -39,6 +39,10 @@ def __init__(self, core): def upload(self): return self._upload.upload + @property + def propfind(self): + return self._webdav.propfind + @property def download(self): return self._webdav.get diff --git a/cterasdk/objects/asynchronous/edge.py b/cterasdk/objects/asynchronous/edge.py index 7f660fdf..dd4f36ce 100644 --- a/cterasdk/objects/asynchronous/edge.py +++ b/cterasdk/objects/asynchronous/edge.py @@ -32,6 +32,10 @@ def download_zip(self): def upload(self): return self._edge.default.form_data # pylint: disable=protected-access + @property + def propfind(self): + return self._webdav.propfind + @property def mkdir(self): return self._webdav.mkcol diff --git a/cterasdk/objects/synchronous/core.py b/cterasdk/objects/synchronous/core.py index 55dc53a3..9dedb080 100644 --- a/cterasdk/objects/synchronous/core.py +++ b/cterasdk/objects/synchronous/core.py @@ -32,6 +32,10 @@ def __init__(self, core): def upload(self): return self._upload.upload + @property + def propfind(self): + return self._webdav.propfind + @property def download(self): return self._webdav.download diff --git a/cterasdk/objects/synchronous/edge.py b/cterasdk/objects/synchronous/edge.py index 9d706ecc..50728c72 100644 --- a/cterasdk/objects/synchronous/edge.py +++ b/cterasdk/objects/synchronous/edge.py @@ -46,6 +46,10 @@ def download_zip(self): def upload(self): return self._edge.default.form_data # pylint: disable=protected-access + @property + def propfind(self): + return self._webdav.propfind + @property def mkdir(self): return self._webdav.mkcol