iogp 1.0.1__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.
iogp-1.0.1/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ __pycache__
2
+ *.pyc
3
+ README.html
4
+ tags
5
+ .local
6
+ build
7
+ dist
8
+ .vscode
iogp-1.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018-2023 Vlad Ioan Topan
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.
iogp-1.0.1/PKG-INFO ADDED
@@ -0,0 +1,91 @@
1
+ Metadata-Version: 2.1
2
+ Name: iogp
3
+ Version: 1.0.1
4
+ Summary: Python common task, general purpose library (serialization, networking, etc.).
5
+ Project-URL: Homepage, https://gitlab.com/vtopan/iogp
6
+ Author-email: Vlad Topan <vtopan@gmail.removethispart.com>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2018-2023 Vlad Ioan Topan
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+ License-File: LICENSE
29
+ Classifier: License :: OSI Approved :: MIT License
30
+ Classifier: Programming Language :: Python
31
+ Classifier: Programming Language :: Python :: 3
32
+ Requires-Python: >=3.9
33
+ Description-Content-Type: text/markdown
34
+
35
+ # iogp
36
+
37
+ Python common task, general purpose library (serialization, networking, etc.).
38
+ Note: this project used to be called iolib - it was renamed for PyPI.
39
+
40
+ ## iogp.net
41
+
42
+ - provides the `download()` function
43
+ - automatic caching of downloads
44
+ - supports cookies, authentication, etc.
45
+ - can spoof user agents (or the entire GET request) - see the `USER_AGENTS` dict in `net/net.py`
46
+ - examples:
47
+ - `text = iogp.net.download('https://google.com')`
48
+ - `info = {}; iogp.net.download('https://1.1.1.1', info=info, cache=0)` => `info['code'] == 200`,
49
+ `info['headers']['Content-Type']`, etc.
50
+
51
+
52
+ ## iogp.db
53
+
54
+ - provides a persistence / caching / storage object `DataCache` that can store e.g. the results from a downloaded URL
55
+ - use `DataStore` to also get in-memory caching of values
56
+ - `ObjCache()` wraps `DataCache` to generate the storage filename automatically
57
+ - usage:
58
+
59
+ ~~~Python
60
+ from iogp.db import DataCache
61
+
62
+ fn = 'objects.db'
63
+
64
+ db = DataCache(fn)
65
+ db['key1'] = {'some':['serializable', 'object', 0]}
66
+ db['some-other-key'] = 0
67
+ db.close()
68
+
69
+ db = DataCache(fn)
70
+ print(db['key1'])
71
+ print('key2' in db, 'some-other-key' in db)
72
+ ~~~
73
+
74
+
75
+ ## iogp.win
76
+
77
+ - ctypes wrapper over some Windows-specific functions
78
+ - example - iterating all windows and retrieving the window title for each one:
79
+
80
+ ~~~Python
81
+ import iogp.win as win
82
+
83
+ def callback(hwnd, lparam):
84
+ size = 512
85
+ buf = win.unicode_buffer(size)
86
+ win.GetWindowText(hwnd, buf, size)
87
+ print(f'[-] Handle: {hwnd}, title: {buf.value}')
88
+ return 1 # 0 to stop
89
+
90
+ win.EnumWindows(win.WNDENUMPROC(callback), 0)
91
+ ~~~
iogp-1.0.1/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # iogp
2
+
3
+ Python common task, general purpose library (serialization, networking, etc.).
4
+ Note: this project used to be called iolib - it was renamed for PyPI.
5
+
6
+ ## iogp.net
7
+
8
+ - provides the `download()` function
9
+ - automatic caching of downloads
10
+ - supports cookies, authentication, etc.
11
+ - can spoof user agents (or the entire GET request) - see the `USER_AGENTS` dict in `net/net.py`
12
+ - examples:
13
+ - `text = iogp.net.download('https://google.com')`
14
+ - `info = {}; iogp.net.download('https://1.1.1.1', info=info, cache=0)` => `info['code'] == 200`,
15
+ `info['headers']['Content-Type']`, etc.
16
+
17
+
18
+ ## iogp.db
19
+
20
+ - provides a persistence / caching / storage object `DataCache` that can store e.g. the results from a downloaded URL
21
+ - use `DataStore` to also get in-memory caching of values
22
+ - `ObjCache()` wraps `DataCache` to generate the storage filename automatically
23
+ - usage:
24
+
25
+ ~~~Python
26
+ from iogp.db import DataCache
27
+
28
+ fn = 'objects.db'
29
+
30
+ db = DataCache(fn)
31
+ db['key1'] = {'some':['serializable', 'object', 0]}
32
+ db['some-other-key'] = 0
33
+ db.close()
34
+
35
+ db = DataCache(fn)
36
+ print(db['key1'])
37
+ print('key2' in db, 'some-other-key' in db)
38
+ ~~~
39
+
40
+
41
+ ## iogp.win
42
+
43
+ - ctypes wrapper over some Windows-specific functions
44
+ - example - iterating all windows and retrieving the window title for each one:
45
+
46
+ ~~~Python
47
+ import iogp.win as win
48
+
49
+ def callback(hwnd, lparam):
50
+ size = 512
51
+ buf = win.unicode_buffer(size)
52
+ win.GetWindowText(hwnd, buf, size)
53
+ print(f'[-] Handle: {hwnd}, title: {buf.value}')
54
+ return 1 # 0 to stop
55
+
56
+ win.EnumWindows(win.WNDENUMPROC(callback), 0)
57
+ ~~~
@@ -0,0 +1,26 @@
1
+ /*-
2
+ * Copyright (c) 2003-2010 Tim Kientzle
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions
7
+ * are met:
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ * notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ * notice, this list of conditions and the following disclaimer in the
12
+ * documentation and/or other materials provided with the distribution.
13
+ *
14
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+ *
25
+ * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.50 2008/05/26 17:00:22 kientzle Exp $
26
+ */
@@ -0,0 +1,6 @@
1
+ __ver__ = '1.0.1'
2
+
3
+ from .data import AttrDict
4
+ from .db import DataCache, DataStore
5
+ from .net import PCap, Packet, download
6
+ from .win import get_window_size
@@ -0,0 +1,10 @@
1
+ """
2
+ iogp.data: Various data processing tools.
3
+
4
+ Author: Vlad Topan (vtopan/gmail)
5
+ """
6
+ from .fileid import get_file_type, get_ft_category, get_ft_ext, FT_UNKNOWN, FT_EMPTY, FT_CATEGORY
7
+ from .carve import extract_embedded_files
8
+ from .ds import AttrDict, Config, dict_to_AttrDict
9
+ from .archive import Archive
10
+ from .str import ellipsis
@@ -0,0 +1,260 @@
1
+ """
2
+ iogp.data.archive: Archive processing APIs.
3
+
4
+ On Windows, archiveint.dll (libarchive 3.3.2?) is used (ships with Windows 10).
5
+ Code from libarchive's archive.h is used, license in external/libarchive.license.
6
+
7
+ Author: Vlad Topan (vtopan/gmail)
8
+ """
9
+ import os
10
+ import ctypes
11
+ from ctypes import c_void_p, Structure, c_int, c_char_p, POINTER, byref
12
+ if os.name == 'nt':
13
+ from ctypes import WINFUNCTYPE, windll
14
+
15
+
16
+ ARCHIVE_FORMAT_BASE_MASK = 0xff0000
17
+ ARCHIVE_FORMAT_CPIO = 0x10000
18
+ ARCHIVE_FORMAT_CPIO_POSIX = (ARCHIVE_FORMAT_CPIO | 1)
19
+ ARCHIVE_FORMAT_CPIO_BIN_LE = (ARCHIVE_FORMAT_CPIO | 2)
20
+ ARCHIVE_FORMAT_CPIO_BIN_BE = (ARCHIVE_FORMAT_CPIO | 3)
21
+ ARCHIVE_FORMAT_CPIO_SVR4_NOCRC = (ARCHIVE_FORMAT_CPIO | 4)
22
+ ARCHIVE_FORMAT_CPIO_SVR4_CRC = (ARCHIVE_FORMAT_CPIO | 5)
23
+ ARCHIVE_FORMAT_CPIO_AFIO_LARGE = (ARCHIVE_FORMAT_CPIO | 6)
24
+ ARCHIVE_FORMAT_SHAR = 0x20000
25
+ ARCHIVE_FORMAT_SHAR_BASE = (ARCHIVE_FORMAT_SHAR | 1)
26
+ ARCHIVE_FORMAT_SHAR_DUMP = (ARCHIVE_FORMAT_SHAR | 2)
27
+ ARCHIVE_FORMAT_TAR = 0x30000
28
+ ARCHIVE_FORMAT_TAR_USTAR = (ARCHIVE_FORMAT_TAR | 1)
29
+ ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE = (ARCHIVE_FORMAT_TAR | 2)
30
+ ARCHIVE_FORMAT_TAR_PAX_RESTRICTED = (ARCHIVE_FORMAT_TAR | 3)
31
+ ARCHIVE_FORMAT_TAR_GNUTAR = (ARCHIVE_FORMAT_TAR | 4)
32
+ ARCHIVE_FORMAT_ISO9660 = 0x40000
33
+ ARCHIVE_FORMAT_ISO9660_ROCKRIDGE = (ARCHIVE_FORMAT_ISO9660 | 1)
34
+ ARCHIVE_FORMAT_ZIP = 0x50000
35
+ ARCHIVE_FORMAT_EMPTY = 0x60000
36
+ ARCHIVE_FORMAT_AR = 0x70000
37
+ ARCHIVE_FORMAT_AR_GNU = (ARCHIVE_FORMAT_AR | 1)
38
+ ARCHIVE_FORMAT_AR_BSD = (ARCHIVE_FORMAT_AR | 2)
39
+ ARCHIVE_FORMAT_MTREE = 0x80000
40
+ ARCHIVE_FORMAT_RAW = 0x90000
41
+ ARCHIVE_FORMAT_XAR = 0xA0000
42
+ ARCHIVE_FORMAT_LHA = 0xB0000
43
+ ARCHIVE_FORMAT_CAB = 0xC0000
44
+ ARCHIVE_FORMAT_RAR = 0xD0000
45
+ ARCHIVE_FORMAT_7ZIP = 0xE0000
46
+ ARCHIVE_FORMAT_WARC = 0xF0000
47
+ ARCHIVE_FORMAT_RAR_V5 = 0x100000
48
+
49
+ ARCHIVE_EOF = 1 # Found end of archive.
50
+ ARCHIVE_OK = 0 # Operation was successful.
51
+ ARCHIVE_RETRY = (-10) # Retry might succeed.
52
+ ARCHIVE_WARN = (-20) # Partial success.
53
+ ARCHIVE_FAILED = (-25) # Current operation cannot complete.
54
+ ARCHIVE_FATAL = (-30) # No more operations are possible.
55
+
56
+ MODE_READ = 0
57
+ MODE_WRITE = 1
58
+
59
+ DEF_BUFFER_SIZE = 16384
60
+
61
+ struct_archive = c_void_p
62
+ struct_archive_entry = c_void_p
63
+
64
+ if os.name == 'nt':
65
+ ARCHIVEINT_LIB = windll.archiveint
66
+ # todo: load libarchive.so on POSIX if available instead of crashing
67
+
68
+ get_zlib_version = WINFUNCTYPE(c_char_p)(('archive_zlib_version', ARCHIVEINT_LIB))
69
+ get_zlib_version.errcheck = lambda res, _1, _2: res.decode('utf8')
70
+
71
+ archive_read_new = WINFUNCTYPE(struct_archive)(('archive_read_new', ARCHIVEINT_LIB))
72
+ archive_read_support_filter_all = WINFUNCTYPE(c_int, struct_archive)(('archive_read_support_filter_all', ARCHIVEINT_LIB))
73
+ archive_read_support_format_all = WINFUNCTYPE(c_int, struct_archive)(('archive_read_support_format_all', ARCHIVEINT_LIB))
74
+ archive_read_support_format_raw = WINFUNCTYPE(c_int, struct_archive)(('archive_read_support_format_raw', ARCHIVEINT_LIB))
75
+ archive_read_support_compression_all = WINFUNCTYPE(c_int, struct_archive)(('archive_read_support_compression_all', ARCHIVEINT_LIB))
76
+ archive_read_open_filename = WINFUNCTYPE(c_int, struct_archive, c_char_p, c_int)(('archive_read_open_filename', ARCHIVEINT_LIB))
77
+ archive_read_open_memory = WINFUNCTYPE(c_int, struct_archive, c_char_p, c_int)(('archive_read_open_memory', ARCHIVEINT_LIB))
78
+ archive_read_next_header = WINFUNCTYPE(c_int, struct_archive, POINTER(struct_archive_entry))(('archive_read_next_header', ARCHIVEINT_LIB))
79
+ archive_entry_pathname = WINFUNCTYPE(c_char_p, struct_archive_entry)(('archive_entry_pathname', ARCHIVEINT_LIB))
80
+ archive_entry_pathname.errcheck = lambda res, _1, _2: res.decode('utf8') if res else ''
81
+ archive_read_data = WINFUNCTYPE(c_int, struct_archive, c_char_p, c_int)(('archive_read_data', ARCHIVEINT_LIB))
82
+ archive_read_data_skip = WINFUNCTYPE(c_int, struct_archive)(('archive_read_data_skip', ARCHIVEINT_LIB))
83
+ archive_read_data_block = WINFUNCTYPE(c_int, struct_archive, POINTER(c_char_p), POINTER(c_int), POINTER(c_int))(('archive_read_data_block', ARCHIVEINT_LIB))
84
+ archive_read_free = WINFUNCTYPE(c_int, struct_archive)(('archive_read_free', ARCHIVEINT_LIB))
85
+ archive_read_close = WINFUNCTYPE(c_int, struct_archive)(('archive_read_close', ARCHIVEINT_LIB))
86
+ archive_compression_name = WINFUNCTYPE(c_char_p, struct_archive_entry)(('archive_compression_name', ARCHIVEINT_LIB))
87
+ archive_compression_name.errcheck = lambda res, _1, _2: res.decode('utf8') if res else ''
88
+ archive_format_name = WINFUNCTYPE(c_char_p, struct_archive_entry)(('archive_format_name', ARCHIVEINT_LIB))
89
+ archive_format_name.errcheck = lambda res, _1, _2: res.decode('utf8') if res else ''
90
+ archive_error_string = WINFUNCTYPE(c_char_p)(('archive_error_string', ARCHIVEINT_LIB))
91
+ archive_error_string.errcheck = lambda res, _1, _2: res.decode('utf8') if res else ''
92
+ else:
93
+ # todo: find alternatives on Linux
94
+ archive_read_new = None
95
+ archive_read_support_filter_all = None
96
+ archive_read_support_format_all = None
97
+ archive_read_support_compression_all = None
98
+ archive_read_open_filename = None
99
+ archive_read_open_memory = None
100
+ archive_read_free = None
101
+ archive_read_next_header = None
102
+ archive_entry_pathname = None
103
+ archive_read_data_block = None
104
+ archive_compression_name = None
105
+ archive_format_name = None
106
+
107
+
108
+ class ArchiveError(ValueError): pass
109
+
110
+
111
+
112
+ class Archive:
113
+ """
114
+ Archive object.
115
+ """
116
+
117
+ def __init__(self, filename_or_data=None):
118
+ self.mode = MODE_READ
119
+ self.archive = None
120
+ if filename_or_data:
121
+ self.open_archive(filename_or_data)
122
+
123
+
124
+ def last_error(self):
125
+ """
126
+ Returns the last error from libarchive.
127
+ """
128
+ return archive_error_string()
129
+
130
+
131
+ def open_archive(self, filename_or_data, buffer_size=DEF_BUFFER_SIZE):
132
+ """
133
+ Open an archive file or buffer for reading.
134
+ """
135
+ self.mode = MODE_READ
136
+ self.buffer_size = buffer_size
137
+ self.source = filename_or_data
138
+
139
+
140
+ def reset(self):
141
+ """
142
+ Reset (reopen) the archive.
143
+ """
144
+ self.close()
145
+ self.archive = arc = archive_read_new()
146
+ if archive_read_support_filter_all(arc) != ARCHIVE_OK:
147
+ raise ArchiveError(f'Failed enabling filters: {self.last_error()})!')
148
+ if archive_read_support_format_all(arc) != ARCHIVE_OK:
149
+ raise ArchiveError(f'Failed enabling formats: {self.last_error()})!')
150
+ #if archive_read_support_compression_all(arc) != ARCHIVE_OK:
151
+ # raise ArchiveError(f'Failed enabling compression: {self.last_error()})!')
152
+ if type(self.source) is str:
153
+ res = archive_read_open_filename(arc, self.source.encode('utf8'), self.buffer_size)
154
+ else:
155
+ res = archive_read_open_memory(arc, self.source, self.buffer_size)
156
+ if res != ARCHIVE_OK:
157
+ raise ArchiveError(f'Failed opening file or buffer: {res} ({self.last_error()})!')
158
+
159
+
160
+ def close(self):
161
+ """
162
+ Close the archive.
163
+ """
164
+ if self.archive:
165
+ archive_read_free(self.archive)
166
+ self.archive = None
167
+
168
+
169
+ def walk(self, callback=None):
170
+ """
171
+ Iterate archive member filenames returning tuples (name, entry_object).
172
+ """
173
+ if (not self.mode == MODE_READ) and self.source:
174
+ raise ArchiveError('No archive is opened for reading!')
175
+ self.reset()
176
+ entry = struct_archive_entry()
177
+ while archive_read_next_header(self.archive, ctypes.byref(entry)) == ARCHIVE_OK:
178
+ entry_name = archive_entry_pathname(entry)
179
+ if callback:
180
+ callback(entry_name, entry)
181
+ yield entry_name, entry
182
+
183
+
184
+
185
+ def list_members(self):
186
+ """
187
+ Iterate over member names.
188
+ """
189
+ for name, e in self.walk():
190
+ yield name
191
+
192
+
193
+ def read(self, filename=None):
194
+ """
195
+ Read an archive member (the current one if none given); returns None if the filename is given and not present.
196
+
197
+ Do NOT use this for large files - the data will be read to memory.
198
+ """
199
+ if not filename:
200
+ return self.read_crt_entry()
201
+ for name, e in self.walk():
202
+ if name == filename:
203
+ return self.read_crt_entry()
204
+
205
+
206
+ def read_crt_entry(self):
207
+ """
208
+ Read the current archive entry.
209
+ """
210
+ if (not self.mode == MODE_READ) and self.archive:
211
+ raise ArchiveError('No archive is opened for reading!')
212
+ chunk = c_char_p()
213
+ chunk_size = c_int()
214
+ offset = c_int(0)
215
+ lst = []
216
+ while 1:
217
+ res = archive_read_data_block(self.archive, byref(chunk), byref(chunk_size), byref(offset))
218
+ offset.value += chunk_size.value
219
+ if res == ARCHIVE_EOF:
220
+ break
221
+ elif res != ARCHIVE_OK:
222
+ raise ArchiveError(f'Failed reading current archive entry: {res} ({self.last_error()})!')
223
+ lst.append(chunk.value[:chunk_size.value])
224
+ return b''.join(lst)
225
+
226
+
227
+ def get_format(self):
228
+ """
229
+ Returns the format of the current archive.
230
+ """
231
+ if (not self.mode == MODE_READ) and self.source:
232
+ raise ArchiveError('No archive is opened for reading!')
233
+ if not self.archive:
234
+ self.reset()
235
+ return archive_compression_name(self.archive)
236
+
237
+
238
+ def get_entry_format(self):
239
+ """
240
+ Returns the format of the current archive entry.
241
+ """
242
+ if (not self.mode == MODE_READ) and self.archive:
243
+ raise ArchiveError('No archive is opened for reading!')
244
+ return archive_format_name(self.archive)
245
+
246
+
247
+
248
+ """
249
+ Example:
250
+
251
+ a = Archive('test.zip')
252
+ print(a.get_format())
253
+ for name in a.list_members():
254
+ print(name, a.get_entry_format())
255
+ if name == 'extractme.ext':
256
+ data = a.read()
257
+ open(name, 'wb').write(data)
258
+ print(a.read('test.py'))
259
+ a.close()
260
+ """