dictature 0.9.7__tar.gz → 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dictature-0.9.7/src/dictature.egg-info → dictature-0.10.0}/PKG-INFO +2 -1
- {dictature-0.9.7 → dictature-0.10.0}/README.md +1 -0
- {dictature-0.9.7 → dictature-0.10.0}/pyproject.toml +1 -1
- dictature-0.10.0/src/dictature/backend/webdav.py +141 -0
- {dictature-0.9.7 → dictature-0.10.0/src/dictature.egg-info}/PKG-INFO +2 -1
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature.egg-info/SOURCES.txt +1 -0
- {dictature-0.9.7 → dictature-0.10.0}/LICENSE +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/setup.cfg +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/__init__.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/backend/__init__.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/backend/directory.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/backend/misp.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/backend/mock.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/backend/sqlite.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/dictature.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/__init__.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/aes.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/gzip.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/hmac.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/mock.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/passthrough.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature/transformer/pipeline.py +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature.egg-info/dependency_links.txt +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/src/dictature.egg-info/top_level.txt +0 -0
- {dictature-0.9.7 → dictature-0.10.0}/tests/test_operations.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dictature
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.10.0
|
4
4
|
Summary: dictature -- A generic wrapper around dict-like interface with mulitple backends
|
5
5
|
Author-email: Adam Hlavacek <git@adamhlavacek.com>
|
6
6
|
Project-URL: Homepage, https://github.com/esoadamo/dictature
|
@@ -54,6 +54,7 @@ Currently, the following backends are supported:
|
|
54
54
|
- `DictatureBackendDirectory`: stores the data in a directory as json files
|
55
55
|
- `DictatureBackendSQLite`: stores the data in a SQLite database
|
56
56
|
- `DictatureBackendMISP`: stores the data in a MISP instance
|
57
|
+
- `DictatureBackendWebdav`: stores data in a WebDav share as files
|
57
58
|
|
58
59
|
### Transformers
|
59
60
|
|
@@ -41,6 +41,7 @@ Currently, the following backends are supported:
|
|
41
41
|
- `DictatureBackendDirectory`: stores the data in a directory as json files
|
42
42
|
- `DictatureBackendSQLite`: stores the data in a SQLite database
|
43
43
|
- `DictatureBackendMISP`: stores the data in a MISP instance
|
44
|
+
- `DictatureBackendWebdav`: stores data in a WebDav share as files
|
44
45
|
|
45
46
|
### Transformers
|
46
47
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "dictature"
|
7
|
-
version = "0.
|
7
|
+
version = "0.10.0"
|
8
8
|
description = "dictature -- A generic wrapper around dict-like interface with mulitple backends"
|
9
9
|
authors = [
|
10
10
|
{ name = "Adam Hlavacek", email = "git@adamhlavacek.com" }
|
@@ -0,0 +1,141 @@
|
|
1
|
+
import io
|
2
|
+
import posixpath
|
3
|
+
from typing import Iterable
|
4
|
+
|
5
|
+
try:
|
6
|
+
from webdav3.client import Client as WebdavClient
|
7
|
+
from webdav3.exceptions import (
|
8
|
+
WebDavException,
|
9
|
+
RemoteResourceNotFound,
|
10
|
+
RemoteParentNotFound,
|
11
|
+
MethodNotSupported,
|
12
|
+
)
|
13
|
+
except ImportError:
|
14
|
+
raise ImportError('Requires: pip install webdavclient3')
|
15
|
+
|
16
|
+
from .mock import DictatureTableMock, DictatureBackendMock, Value, ValueMode, ValueSerializer, ValueSerializerMode
|
17
|
+
|
18
|
+
|
19
|
+
class DictatureBackendWebdav(DictatureBackendMock):
|
20
|
+
def __init__(
|
21
|
+
self,
|
22
|
+
client: WebdavClient,
|
23
|
+
dir_prefix: str = 'db_',
|
24
|
+
item_prefix: str = 'item_'
|
25
|
+
) -> None:
|
26
|
+
self.__client = client
|
27
|
+
self.__dir_prefix = dir_prefix
|
28
|
+
self.__item_prefix = item_prefix
|
29
|
+
|
30
|
+
def keys(self) -> Iterable[str]:
|
31
|
+
try:
|
32
|
+
resources = self.__client.list(get_info=True)
|
33
|
+
|
34
|
+
for resource_info in resources:
|
35
|
+
name = posixpath.basename(posixpath.dirname(resource_info.get('path')))
|
36
|
+
is_dir = resource_info.get('isdir', False)
|
37
|
+
|
38
|
+
if not name:
|
39
|
+
continue
|
40
|
+
|
41
|
+
if is_dir and name.startswith(self.__dir_prefix):
|
42
|
+
table_name_encoded = name[len(self.__dir_prefix):]
|
43
|
+
# noinspection PyProtectedMember
|
44
|
+
yield DictatureTableWebdav._filename_decode(table_name_encoded, suffix='')
|
45
|
+
except RemoteResourceNotFound:
|
46
|
+
pass
|
47
|
+
|
48
|
+
def table(self, name: str) -> 'DictatureTableMock':
|
49
|
+
return DictatureTableWebdav(self.__client, name, self.__dir_prefix, self.__item_prefix)
|
50
|
+
|
51
|
+
|
52
|
+
class DictatureTableWebdav(DictatureTableMock):
|
53
|
+
def __init__(self, client: WebdavClient, name: str, db_prefix: str, prefix: str) -> None:
|
54
|
+
self.__client = client
|
55
|
+
self.__encoded_name = self._filename_encode(name, suffix='')
|
56
|
+
self.__path = posixpath.join(db_prefix + self.__encoded_name)
|
57
|
+
self.__prefix = prefix
|
58
|
+
self.__name_serializer = ValueSerializer(mode=ValueSerializerMode.filename_only)
|
59
|
+
self.__value_serializer = ValueSerializer(mode=ValueSerializerMode.any_string)
|
60
|
+
|
61
|
+
def keys(self) -> Iterable[str]:
|
62
|
+
try:
|
63
|
+
resources = self.__client.list(self.__path, get_info=True)
|
64
|
+
|
65
|
+
for resource_info in resources:
|
66
|
+
name = posixpath.basename(resource_info.get('path'))
|
67
|
+
is_dir = resource_info.get('isdir', False)
|
68
|
+
|
69
|
+
if not name:
|
70
|
+
continue
|
71
|
+
|
72
|
+
if not is_dir and name.startswith(self.__prefix):
|
73
|
+
item_name_encoded = name[len(self.__prefix):]
|
74
|
+
yield self._filename_decode(item_name_encoded, suffix='.txt')
|
75
|
+
|
76
|
+
except RemoteResourceNotFound:
|
77
|
+
pass
|
78
|
+
|
79
|
+
def drop(self) -> None:
|
80
|
+
try:
|
81
|
+
self.__client.clean(self.__path)
|
82
|
+
except RemoteResourceNotFound:
|
83
|
+
pass
|
84
|
+
|
85
|
+
def create(self) -> None:
|
86
|
+
try:
|
87
|
+
if not self.__client.check(self.__path):
|
88
|
+
self.__client.mkdir(self.__path)
|
89
|
+
except MethodNotSupported as e:
|
90
|
+
if not self.__client.check(self.__path):
|
91
|
+
raise e
|
92
|
+
|
93
|
+
def set(self, item: str, value: Value) -> None:
|
94
|
+
item_path = self.__item_path(item)
|
95
|
+
self.create()
|
96
|
+
|
97
|
+
save_data: str = self.__value_serializer.serialize(value)
|
98
|
+
data_bytes = save_data.encode('utf-8')
|
99
|
+
|
100
|
+
with io.BytesIO(data_bytes) as buffer:
|
101
|
+
self.__client.upload_to(buffer, item_path)
|
102
|
+
|
103
|
+
def get(self, item: str) -> Value:
|
104
|
+
item_path = self.__item_path(item)
|
105
|
+
buffer = io.BytesIO()
|
106
|
+
try:
|
107
|
+
self.__client.download_from(buffer, item_path)
|
108
|
+
buffer.seek(0)
|
109
|
+
save_data = buffer.read().decode('utf-8')
|
110
|
+
except RemoteResourceNotFound:
|
111
|
+
raise KeyError(item)
|
112
|
+
return self.__value_serializer.deserialize(save_data)
|
113
|
+
|
114
|
+
def delete(self, item: str) -> None:
|
115
|
+
"""
|
116
|
+
Deletes the file corresponding to the item. No error if not found.
|
117
|
+
Raises WebDavException for other deletion errors.
|
118
|
+
"""
|
119
|
+
item_path = self.__item_path(item)
|
120
|
+
try:
|
121
|
+
self.__client.clean(item_path)
|
122
|
+
except RemoteResourceNotFound:
|
123
|
+
pass
|
124
|
+
|
125
|
+
def __item_path(self, item: str) -> str:
|
126
|
+
encoded_item_name = self.__prefix + self._filename_encode(item, suffix='.txt')
|
127
|
+
full_path = posixpath.join(self.__path, encoded_item_name)
|
128
|
+
return full_path
|
129
|
+
|
130
|
+
@staticmethod
|
131
|
+
def _filename_encode(name: str, suffix: str = '.txt') -> str:
|
132
|
+
return ValueSerializer(mode=ValueSerializerMode.filename_only).serialize(Value(
|
133
|
+
value=name,
|
134
|
+
mode=ValueMode.string.value
|
135
|
+
)) + suffix
|
136
|
+
|
137
|
+
@staticmethod
|
138
|
+
def _filename_decode(name: str, suffix: str = '.txt') -> str:
|
139
|
+
if suffix and name.endswith(suffix):
|
140
|
+
name = name[:-len(suffix)]
|
141
|
+
return ValueSerializer(mode=ValueSerializerMode.filename_only).deserialize(name).value
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: dictature
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.10.0
|
4
4
|
Summary: dictature -- A generic wrapper around dict-like interface with mulitple backends
|
5
5
|
Author-email: Adam Hlavacek <git@adamhlavacek.com>
|
6
6
|
Project-URL: Homepage, https://github.com/esoadamo/dictature
|
@@ -54,6 +54,7 @@ Currently, the following backends are supported:
|
|
54
54
|
- `DictatureBackendDirectory`: stores the data in a directory as json files
|
55
55
|
- `DictatureBackendSQLite`: stores the data in a SQLite database
|
56
56
|
- `DictatureBackendMISP`: stores the data in a MISP instance
|
57
|
+
- `DictatureBackendWebdav`: stores data in a WebDav share as files
|
57
58
|
|
58
59
|
### Transformers
|
59
60
|
|
@@ -12,6 +12,7 @@ src/dictature/backend/directory.py
|
|
12
12
|
src/dictature/backend/misp.py
|
13
13
|
src/dictature/backend/mock.py
|
14
14
|
src/dictature/backend/sqlite.py
|
15
|
+
src/dictature/backend/webdav.py
|
15
16
|
src/dictature/transformer/__init__.py
|
16
17
|
src/dictature/transformer/aes.py
|
17
18
|
src/dictature/transformer/gzip.py
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|