zipmanager 0.1.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 SimplePythonCoder
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ graft zipmanager
2
+ include pyproject.toml
3
+ include setup.py
4
+ global-exclude *.py[cod]
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.1
2
+ Name: zipmanager
3
+ Version: 0.1.0
4
+ Summary: Allows you to manage zip folders as data
5
+ Home-page: https://github.com/SimplePythonCoder/zipmanager
6
+ Author: SimplePythonCoder
7
+ Author-email:
8
+ License: MIT
9
+ Project-URL: Source, https://github.com/SimplePythonCoder/zipmanager
10
+ Project-URL: Issues, https://github.com/SimplePythonCoder/zipmanager/issues
11
+ Keywords: zip
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+
21
+ # zipmanager
22
+ ## What does this package do ?
23
+ It allows you to create and handle zip folders as data without needing to save them.
24
+
25
+ ## Usage
26
+ ```python
27
+ from zipmanager import ZipFolder
28
+
29
+ file_data = b'some_data'
30
+
31
+ zip_folder = ZipFolder({'file_name.file_extension': file_data})
32
+ # file extension not required
33
+ # ZipFile will hold all the files given in the dictionary
34
+
35
+ file_data = zip_folder['file_name.file_extension']
36
+ # will return the file data
37
+ ```
38
+
39
+ ## Main functions
40
+ ```python
41
+ from zipmanager import ZipFolder
42
+ file_data = b'some_data'
43
+ zip_folder = ZipFolder({'file_name.file_extension': file_data})
44
+
45
+ # list of functions:
46
+ zip_folder.add_files({'new_file': 'new_data'}) # add files to zip. read more at docstring.
47
+ zip_folder.delete_file('new_file') # removes file from zip
48
+
49
+ zip_folder.get('file_name') # returns None if file was not found
50
+ # or
51
+ zip_folder['file_name']
52
+
53
+ zip_folder.save() # saves zip in given location (empty is './temp.zip')
54
+ ```
55
+
56
+ ## File extension features
57
+ json and text files data is automatically returned as a dict or str respectively:
58
+ ```python
59
+ from zipmanager import ZipFolder
60
+
61
+ file_data = b'{"key": "value"}'
62
+
63
+ zip_folder = ZipFolder({'file_name.json': file_data})
64
+ # .json extension is required to return a dict
65
+
66
+ data = zip_folder['file_name.json']
67
+ # will return a dict type
68
+
69
+ # same for .txt
70
+ file_data = {'key': 'value'}
71
+ zip_folder = ZipFolder({'file_name.txt': file_data})
72
+ data = zip_folder['file_name.txt']
73
+ # will return a string
74
+ ```
@@ -0,0 +1,54 @@
1
+ # zipmanager
2
+ ## What does this package do ?
3
+ It allows you to create and handle zip folders as data without needing to save them.
4
+
5
+ ## Usage
6
+ ```python
7
+ from zipmanager import ZipFolder
8
+
9
+ file_data = b'some_data'
10
+
11
+ zip_folder = ZipFolder({'file_name.file_extension': file_data})
12
+ # file extension not required
13
+ # ZipFile will hold all the files given in the dictionary
14
+
15
+ file_data = zip_folder['file_name.file_extension']
16
+ # will return the file data
17
+ ```
18
+
19
+ ## Main functions
20
+ ```python
21
+ from zipmanager import ZipFolder
22
+ file_data = b'some_data'
23
+ zip_folder = ZipFolder({'file_name.file_extension': file_data})
24
+
25
+ # list of functions:
26
+ zip_folder.add_files({'new_file': 'new_data'}) # add files to zip. read more at docstring.
27
+ zip_folder.delete_file('new_file') # removes file from zip
28
+
29
+ zip_folder.get('file_name') # returns None if file was not found
30
+ # or
31
+ zip_folder['file_name']
32
+
33
+ zip_folder.save() # saves zip in given location (empty is './temp.zip')
34
+ ```
35
+
36
+ ## File extension features
37
+ json and text files data is automatically returned as a dict or str respectively:
38
+ ```python
39
+ from zipmanager import ZipFolder
40
+
41
+ file_data = b'{"key": "value"}'
42
+
43
+ zip_folder = ZipFolder({'file_name.json': file_data})
44
+ # .json extension is required to return a dict
45
+
46
+ data = zip_folder['file_name.json']
47
+ # will return a dict type
48
+
49
+ # same for .txt
50
+ file_data = {'key': 'value'}
51
+ zip_folder = ZipFolder({'file_name.txt': file_data})
52
+ data = zip_folder['file_name.txt']
53
+ # will return a string
54
+ ```
@@ -0,0 +1,6 @@
1
+ [build-system]
2
+ requires = [
3
+ "setuptools>=69.2.0",
4
+ "wheel",
5
+ ]
6
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,32 @@
1
+ import pathlib
2
+
3
+ from setuptools import setup, find_packages
4
+
5
+ # Setting up
6
+ setup(
7
+ name="zipmanager",
8
+ version='0.1.0',
9
+ license="MIT",
10
+ author="SimplePythonCoder",
11
+ author_email="",
12
+ url='https://github.com/SimplePythonCoder/zipmanager',
13
+ description='Allows you to manage zip folders as data',
14
+ long_description=pathlib.Path('README.md').read_text(),
15
+ long_description_content_type="text/markdown",
16
+ packages=find_packages(),
17
+ include_package_data=True,
18
+ install_requires=[],
19
+ keywords=['zip'],
20
+ python_requires='>=3.11',
21
+ classifiers=[
22
+ 'Development Status :: 3 - Alpha',
23
+ 'Intended Audience :: Developers',
24
+ 'Programming Language :: Python :: 3.11',
25
+ 'Operating System :: Microsoft :: Windows',
26
+ 'Topic :: Utilities',
27
+ ],
28
+ project_urls={
29
+ 'Source': 'https://github.com/SimplePythonCoder/zipmanager',
30
+ 'Issues': 'https://github.com/SimplePythonCoder/zipmanager/issues'
31
+ }
32
+ )
@@ -0,0 +1,19 @@
1
+
2
+ class NonBytesInput(Exception):
3
+ def __init__(self, file_name):
4
+ super().__init__(f'File {file_name} data must be bytes')
5
+
6
+
7
+ class FileNameConflict(Exception):
8
+ def __init__(self, file_name):
9
+ super().__init__(f'File {file_name} already exists in the zip folder')
10
+
11
+
12
+ class FileNotFound(Exception):
13
+ def __init__(self, file_name):
14
+ super().__init__(f'File {file_name} does no exist in the zip folder')
15
+
16
+
17
+ class ExternalClassOperation(Exception):
18
+ def __init__(self, type_name):
19
+ super().__init__(f'type {type_name.__name__} cannot interact with the ZipFile class')
@@ -0,0 +1,32 @@
1
+ import sys
2
+ import json
3
+
4
+ from .Exceptions import NonBytesInput
5
+
6
+
7
+ class File:
8
+
9
+ @staticmethod
10
+ def __raise(exception):
11
+ raise exception
12
+
13
+ @classmethod
14
+ def pack(cls, name, data):
15
+ match name.split('.')[-1]:
16
+ case 'json':
17
+ return json.dumps(json.loads(data)) if type(data) is bytes else json.dumps(data)
18
+ case 'txt':
19
+ return data.decode() if type(data) is bytes else data if type(
20
+ data) is str else cls.__raise(NonBytesInput(name))
21
+ case _:
22
+ return data if type(data) is bytes else cls.__raise(NonBytesInput(name))
23
+
24
+ @staticmethod
25
+ def unpack(name, data):
26
+ match name.split('.')[-1]:
27
+ case 'json':
28
+ return json.loads(data)
29
+ case 'txt':
30
+ return data.decode() if type(data) is bytes else data
31
+ case _:
32
+ return data
@@ -0,0 +1 @@
1
+ from .main import ZipFolder
@@ -0,0 +1,126 @@
1
+ import io
2
+ import zipfile
3
+ import base64
4
+
5
+ from .Exceptions import FileNameConflict, ExternalClassOperation, FileNotFound
6
+ from .File import File
7
+
8
+
9
+ class ZipFolder:
10
+
11
+ def __init__(self, data: dict[str, dict] | dict[str, str] | dict[str, bytes] | str | bytes):
12
+ match data:
13
+ case dict():
14
+ self.__raw_zip = self.__create_zip(data)
15
+ case str():
16
+ self.__raw_zip = self.__b64_to_zip(data)
17
+ case bytes():
18
+ self.__raw_zip = self.__bytes_to_zip(data)
19
+
20
+ def __eq__(self, other):
21
+ self.__check_class(other)
22
+ return self.raw_files() == other.raw_files()
23
+
24
+ def __add__(self, other):
25
+ self.__check_class(other)
26
+ self.add_files(other.raw_files())
27
+ return self
28
+
29
+ def __getitem__(self, file_name):
30
+ if file_name in self.file_list:
31
+ return File.unpack(file_name, self.__raw_zip.open(file_name).read())
32
+ raise FileNotFound(file_name)
33
+
34
+ def __str__(self):
35
+ return (f'Zipfile Object {hex(id(self)).upper()} / '
36
+ f'file number: {len(self.file_list)} / '
37
+ f'size: {self.get_size():,} bytes / '
38
+ f'compressed size: {self.get_size(compressed=True):,} bytes')
39
+
40
+ def get_size(self, file_name=None, compressed=False):
41
+ size = 0
42
+ match file_name:
43
+ case str():
44
+ if file_name in self.file_list:
45
+ return getattr(self.__raw_zip.getinfo(file_name), 'compress_size' if compressed else 'file_size')
46
+ else:
47
+ raise FileNotFound(file_name)
48
+ case _:
49
+ for file in self.__raw_zip.filelist:
50
+ size += getattr(file, 'compress_size' if compressed else 'file_size')
51
+ return size
52
+
53
+ def get(self, file_name):
54
+ if file_name in self.file_list:
55
+ return File.unpack(file_name, self.__raw_zip.open(file_name).read())
56
+ return None
57
+
58
+ def add_files(self, data):
59
+ """
60
+ add files to the zip file.
61
+ you can add folders by adding the folder name before the filename separated by a '/'.
62
+ :param data: dict of filename as key and data as value
63
+ :type data: dict[str, dict] | dict[str, str] | dict[str, bytes]
64
+ :return:
65
+ """
66
+ for file in data.keys():
67
+ if file in self.file_list:
68
+ raise FileNameConflict(file)
69
+ self.__raw_zip = self.__create_zip(dict(self.raw_files(), **data))
70
+
71
+ def delete_file(self, file_name):
72
+ if file_name in self.file_list:
73
+ self.__raw_zip = self.__edit_zip([file for file in self.file_list if file != file_name])
74
+
75
+ def raw_files(self):
76
+ return {file: File.unpack(file, self.__raw_zip.open(file).read())
77
+ for file in self.file_list}
78
+
79
+ @property
80
+ def file_list(self):
81
+ return [file.filename for file in self.__raw_zip.filelist]
82
+
83
+ def get_b64(self):
84
+ return base64.b64encode(self.__edit_zip(byte=True).read()).decode()
85
+
86
+ def __check_class(self, other):
87
+ if type(self) is not type(other):
88
+ raise ExternalClassOperation(type(other))
89
+
90
+ @staticmethod
91
+ def __create_zip(files):
92
+ zip_buffer = io.BytesIO()
93
+ with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as file_zip:
94
+ for file_name, data in files.items():
95
+ file_zip.writestr(f'{file_name}', data=File.pack(file_name, data))
96
+ zip_buffer.seek(0)
97
+ return zipfile.ZipFile(zip_buffer, 'r')
98
+
99
+ def __edit_zip(self, files=None, byte=False):
100
+ if files is None:
101
+ files = self.file_list
102
+ zip_buffer = io.BytesIO()
103
+ with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as file_zip:
104
+ for file_name in files:
105
+ file_zip.writestr(f'{file_name}', data=File.pack(file_name, self[file_name]))
106
+ zip_buffer.seek(0)
107
+ return zipfile.ZipFile(zip_buffer, 'r') if not byte else zip_buffer
108
+
109
+ @staticmethod
110
+ def __bytes_to_zip(data):
111
+ return zipfile.ZipFile(io.BytesIO(data), 'r')
112
+
113
+ @staticmethod
114
+ def __b64_to_zip(data):
115
+ return zipfile.ZipFile(io.BytesIO(base64.b64decode(data)), 'r')
116
+
117
+ def save(self, path_with_name='./temp.zip'):
118
+ """
119
+ saves the zip folder to the given location.
120
+ path must be with name (extension optional).
121
+ :param path_with_name: path for save location (empty will save it to current folder)
122
+ :type path_with_name: str
123
+ :return:
124
+ """
125
+ with open(path_with_name if path_with_name.endswith('.zip') else path_with_name + '.zip', 'wb') as zfh:
126
+ zfh.write(self.__edit_zip(byte=True).read())
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.1
2
+ Name: zipmanager
3
+ Version: 0.1.0
4
+ Summary: Allows you to manage zip folders as data
5
+ Home-page: https://github.com/SimplePythonCoder/zipmanager
6
+ Author: SimplePythonCoder
7
+ Author-email:
8
+ License: MIT
9
+ Project-URL: Source, https://github.com/SimplePythonCoder/zipmanager
10
+ Project-URL: Issues, https://github.com/SimplePythonCoder/zipmanager/issues
11
+ Keywords: zip
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Operating System :: Microsoft :: Windows
16
+ Classifier: Topic :: Utilities
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+
21
+ # zipmanager
22
+ ## What does this package do ?
23
+ It allows you to create and handle zip folders as data without needing to save them.
24
+
25
+ ## Usage
26
+ ```python
27
+ from zipmanager import ZipFolder
28
+
29
+ file_data = b'some_data'
30
+
31
+ zip_folder = ZipFolder({'file_name.file_extension': file_data})
32
+ # file extension not required
33
+ # ZipFile will hold all the files given in the dictionary
34
+
35
+ file_data = zip_folder['file_name.file_extension']
36
+ # will return the file data
37
+ ```
38
+
39
+ ## Main functions
40
+ ```python
41
+ from zipmanager import ZipFolder
42
+ file_data = b'some_data'
43
+ zip_folder = ZipFolder({'file_name.file_extension': file_data})
44
+
45
+ # list of functions:
46
+ zip_folder.add_files({'new_file': 'new_data'}) # add files to zip. read more at docstring.
47
+ zip_folder.delete_file('new_file') # removes file from zip
48
+
49
+ zip_folder.get('file_name') # returns None if file was not found
50
+ # or
51
+ zip_folder['file_name']
52
+
53
+ zip_folder.save() # saves zip in given location (empty is './temp.zip')
54
+ ```
55
+
56
+ ## File extension features
57
+ json and text files data is automatically returned as a dict or str respectively:
58
+ ```python
59
+ from zipmanager import ZipFolder
60
+
61
+ file_data = b'{"key": "value"}'
62
+
63
+ zip_folder = ZipFolder({'file_name.json': file_data})
64
+ # .json extension is required to return a dict
65
+
66
+ data = zip_folder['file_name.json']
67
+ # will return a dict type
68
+
69
+ # same for .txt
70
+ file_data = {'key': 'value'}
71
+ zip_folder = ZipFolder({'file_name.txt': file_data})
72
+ data = zip_folder['file_name.txt']
73
+ # will return a string
74
+ ```
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ pyproject.toml
5
+ setup.py
6
+ zipmanager/Exceptions.py
7
+ zipmanager/File.py
8
+ zipmanager/__init__.py
9
+ zipmanager/main.py
10
+ zipmanager.egg-info/PKG-INFO
11
+ zipmanager.egg-info/SOURCES.txt
12
+ zipmanager.egg-info/dependency_links.txt
13
+ zipmanager.egg-info/top_level.txt
@@ -0,0 +1 @@
1
+ zipmanager