reflexive 1.2.0__tar.gz → 1.2.2__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.
- {reflexive-1.2.0 → reflexive-1.2.2}/PKG-INFO +1 -1
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.13-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.13.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.14-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.14.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.15-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.15.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.16-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.16.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.17-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.17.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.18-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.18.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.19-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.19.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.20-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.0.20.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.1.0-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.1.0.tar.gz +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.1.1-py3-none-any.whl +0 -0
- reflexive-1.2.2/old reflexive dist/reflexive-1.1.1.tar.gz +0 -0
- {reflexive-1.2.0 → reflexive-1.2.2}/pyproject.toml +1 -1
- reflexive-1.2.2/src/reflexive/__init__.py +15 -0
- {reflexive-1.2.0 → reflexive-1.2.2}/src/reflexive/analyse.py +1 -2
- {reflexive-1.2.0 → reflexive-1.2.2}/src/reflexive/cfg.py +2 -4
- {reflexive-1.2.0 → reflexive-1.2.2}/src/reflexive/session.py +1 -2
- {reflexive-1.2.0 → reflexive-1.2.2}/src/reflexive/util.py +9 -7
- {reflexive-1.2.0 → reflexive-1.2.2}/src/reflexive/visualise.py +170 -1
- reflexive-1.2.2/tests/__init__.py +0 -0
- reflexive-1.2.2/tests/test_reflexive.py +110 -0
- reflexive-1.2.0/src/reflexive/__init__.py +0 -5
- {reflexive-1.2.0 → reflexive-1.2.2}/.gitignore +0 -0
- {reflexive-1.2.0 → reflexive-1.2.2}/LICENSE +0 -0
- {reflexive-1.2.0 → reflexive-1.2.2}/README.md +0 -0
- {reflexive-1.2.0 → reflexive-1.2.2}/pixi.lock +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Make classes available at top level
|
|
2
|
+
|
|
3
|
+
from reflexive.cfg import Config
|
|
4
|
+
from reflexive.session import (
|
|
5
|
+
AWS,
|
|
6
|
+
S3,
|
|
7
|
+
Comprehend)
|
|
8
|
+
|
|
9
|
+
# import reflexive.util
|
|
10
|
+
from reflexive.analyse import Nlp
|
|
11
|
+
from reflexive.visualise import (
|
|
12
|
+
Display,
|
|
13
|
+
RES_graph)
|
|
14
|
+
|
|
15
|
+
__all__ = ["Config","AWS","S3","Comprehend","Nlp","Display","RES_graph"]
|
|
@@ -6,7 +6,6 @@ import re
|
|
|
6
6
|
from reflexive import util
|
|
7
7
|
from reflexive import cfg
|
|
8
8
|
from reflexive import session
|
|
9
|
-
import reflexive as rfx
|
|
10
9
|
|
|
11
10
|
import logging
|
|
12
11
|
logging.basicConfig(level=logging.DEBUG)
|
|
@@ -290,7 +289,7 @@ class Nlp:
|
|
|
290
289
|
for grp in targetedSentiment_results:
|
|
291
290
|
for mention in grp["Mentions"]:
|
|
292
291
|
if mention['Score'] >= threshold:
|
|
293
|
-
if
|
|
292
|
+
if "NEUTRAL" not in mention['MentionSentiment']['Sentiment']:
|
|
294
293
|
k = mention['MentionSentiment']['Sentiment']
|
|
295
294
|
text = str.lower(mention['Text'])
|
|
296
295
|
sents.setdefault(k,{text}).add(text)
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
from datetime import datetime
|
|
4
|
-
import json
|
|
5
|
-
import reflexive as rfx
|
|
6
4
|
|
|
7
|
-
logging.basicConfig(level=logging.DEBUG)
|
|
5
|
+
#logging.basicConfig(level=logging.DEBUG)
|
|
8
6
|
logger = logging.getLogger(__name__)
|
|
9
7
|
|
|
10
8
|
class Config:
|
|
@@ -74,7 +72,7 @@ class Config:
|
|
|
74
72
|
if not os.path.exists(data_dir):
|
|
75
73
|
logger.warning("Path does not exist, creating directory")
|
|
76
74
|
os.makedirs(data_dir)
|
|
77
|
-
logger.info(
|
|
75
|
+
logger.info("Created %s",repr(data_dir))
|
|
78
76
|
self.local_path = local_path
|
|
79
77
|
if not date_string:
|
|
80
78
|
date_string = datetime.today().strftime('%Y%m%d')
|
|
@@ -5,7 +5,6 @@ import tarfile
|
|
|
5
5
|
import json
|
|
6
6
|
|
|
7
7
|
from reflexive import cfg
|
|
8
|
-
import reflexive as rfx
|
|
9
8
|
|
|
10
9
|
import logging
|
|
11
10
|
logging.basicConfig(level=logging.DEBUG)
|
|
@@ -19,7 +18,7 @@ class AWS:
|
|
|
19
18
|
def __init__(self,config:cfg.Config):
|
|
20
19
|
# on initialisation create a new session with provided profile (or with default profile)
|
|
21
20
|
#logger.error(config.get_parameters())
|
|
22
|
-
if config
|
|
21
|
+
if config is None:
|
|
23
22
|
config = cfg.Config()
|
|
24
23
|
self.config = config
|
|
25
24
|
self.new_session()
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import os
|
|
2
|
-
|
|
2
|
+
import json
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from sklearn.preprocessing import MinMaxScaler
|
|
3
5
|
import logging
|
|
4
6
|
logging.basicConfig(level=logging.DEBUG)
|
|
5
7
|
logger = logging.getLogger(__name__)
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
# File functions
|
|
10
12
|
def get_data_path_name(config,name,ext):
|
|
@@ -20,7 +22,7 @@ def set_sub_dir(config,sub_dir=None):
|
|
|
20
22
|
logger.info(f"Creating subdirectory: {local_dir}")
|
|
21
23
|
os.makedirs(local_dir)
|
|
22
24
|
else:
|
|
23
|
-
local_dir = local_path
|
|
25
|
+
local_dir = config.local_path
|
|
24
26
|
return local_dir
|
|
25
27
|
|
|
26
28
|
|
|
@@ -46,12 +48,12 @@ def filter_dict_by_value(ngrams,min_val=3):
|
|
|
46
48
|
|
|
47
49
|
# Input a series and output a list of lists with each maxn elements
|
|
48
50
|
def series_to_chunked_list(series,maxn=25):
|
|
49
|
-
|
|
50
|
-
return __chunk_list(
|
|
51
|
+
lst = list(series)
|
|
52
|
+
return __chunk_list(lst,maxn)
|
|
51
53
|
|
|
52
54
|
# Chunk a list into a list of lists with maxn elements
|
|
53
|
-
def __chunk_list(
|
|
54
|
-
return [
|
|
55
|
+
def __chunk_list(lst,maxn=25):
|
|
56
|
+
return [lst[i:i + maxn] for i in range(0, len(lst), maxn)]
|
|
55
57
|
|
|
56
58
|
# Count named entities
|
|
57
59
|
def count_entities(entities):
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
from graph_tool.all import (
|
|
2
|
+
Graph,
|
|
3
|
+
graph_draw,
|
|
4
|
+
ungroup_vector_property,
|
|
5
|
+
group_vector_property
|
|
6
|
+
)
|
|
7
|
+
import cairo
|
|
8
|
+
|
|
9
|
+
from spacy import displacy
|
|
10
|
+
|
|
1
11
|
from reflexive import session
|
|
2
12
|
from reflexive import cfg
|
|
3
13
|
|
|
@@ -183,4 +193,163 @@ class Display:
|
|
|
183
193
|
b = v[0]
|
|
184
194
|
e = v[1]
|
|
185
195
|
#print("New offsets:",len(new_offsets[k]))
|
|
186
|
-
return new_offsets
|
|
196
|
+
return new_offsets
|
|
197
|
+
|
|
198
|
+
class RES_text:
|
|
199
|
+
|
|
200
|
+
def __init__(self):
|
|
201
|
+
self._setup()
|
|
202
|
+
|
|
203
|
+
def _setup(self):
|
|
204
|
+
return None
|
|
205
|
+
|
|
206
|
+
def show(self):
|
|
207
|
+
#displacy.render(disp_data,manual=True,style="ent", options=cfg.display_options)
|
|
208
|
+
return None
|
|
209
|
+
|
|
210
|
+
class RES_graph:
|
|
211
|
+
|
|
212
|
+
#
|
|
213
|
+
gt_props = {0:{ "lbl":"RR",
|
|
214
|
+
"pos":(0.2,6.5),
|
|
215
|
+
"clr":"#00AEEF"},
|
|
216
|
+
1:{ "lbl":"NR",
|
|
217
|
+
"pos":(5,10),
|
|
218
|
+
"clr":"#ED1B23"},
|
|
219
|
+
2:{ "lbl":"AR",
|
|
220
|
+
"pos":(9.8,6.5),
|
|
221
|
+
"clr":"#00A64F"},
|
|
222
|
+
3:{ "lbl":"AF",
|
|
223
|
+
"pos":(7.9,1),
|
|
224
|
+
"clr":"#EC008C"},
|
|
225
|
+
4:{ "lbl":"EP",
|
|
226
|
+
"pos":(2.1,1),
|
|
227
|
+
"clr":"#FFF200"}}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
# re_props = {"RR":{
|
|
231
|
+
# "idx": 0,
|
|
232
|
+
# "pos":(0.2,6.5),
|
|
233
|
+
# "clr":"#00AEEF"},
|
|
234
|
+
# "NR":{
|
|
235
|
+
# "idx": 1,
|
|
236
|
+
# "pos":(5,10),
|
|
237
|
+
# "clr":"#ED1B23"},
|
|
238
|
+
# "AR":{
|
|
239
|
+
# "idx": 2,
|
|
240
|
+
# "pos":(9.8,6.5),
|
|
241
|
+
# "clr":"#00A64F"},
|
|
242
|
+
# "AF":{
|
|
243
|
+
# "idx": 3,
|
|
244
|
+
# "pos":(7.9,1),
|
|
245
|
+
# "clr":"#EC008C"},
|
|
246
|
+
# "EP":{
|
|
247
|
+
# "idx": 4,
|
|
248
|
+
# "pos":(2.1,1),
|
|
249
|
+
# "clr":"#FFF200"}}
|
|
250
|
+
|
|
251
|
+
#
|
|
252
|
+
edges = dict()
|
|
253
|
+
#
|
|
254
|
+
iso_vertices = set()
|
|
255
|
+
#
|
|
256
|
+
v_label = None
|
|
257
|
+
#
|
|
258
|
+
v_color = None
|
|
259
|
+
#
|
|
260
|
+
v_pos = None
|
|
261
|
+
|
|
262
|
+
#
|
|
263
|
+
def __init__(self,matrix=None):
|
|
264
|
+
self._setup(matrix)
|
|
265
|
+
|
|
266
|
+
#
|
|
267
|
+
def _setup(self,matrix):
|
|
268
|
+
if matrix:
|
|
269
|
+
# Edges from matrix
|
|
270
|
+
self.edges = self._matrix_to_dict(matrix)
|
|
271
|
+
self.graph = Graph(g=self.edges.keys(),directed=False)
|
|
272
|
+
self.e_weight = self.graph.new_ep("double",vals=self.edges.values())
|
|
273
|
+
# Handle colour of isolated vertices
|
|
274
|
+
default_clrs = self._get_prop_values('clr')
|
|
275
|
+
actual_clrs = []
|
|
276
|
+
for i in range(5):
|
|
277
|
+
if i in self.iso_vertices:
|
|
278
|
+
clr = "#cccccc"
|
|
279
|
+
else:
|
|
280
|
+
clr = default_clrs[i]
|
|
281
|
+
actual_clrs.append(clr)
|
|
282
|
+
self.v_color = self.graph.new_vp("string",vals=actual_clrs)
|
|
283
|
+
else:
|
|
284
|
+
# No edges
|
|
285
|
+
self.graph = Graph(g=self._empty_edge_dict(),directed=False)
|
|
286
|
+
self.e_weight = self.graph.new_ep("double")
|
|
287
|
+
self.v_color = self.graph.new_vp("string",val="#cccccc")
|
|
288
|
+
# Vertex properties common to all graphs
|
|
289
|
+
self.v_label = self.graph.new_vp("string",vals=self._get_prop_values('lbl'))
|
|
290
|
+
self.v_pos = self.graph.new_vp("vector<double>",vals=self._get_prop_values('pos'))
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
#
|
|
295
|
+
def _matrix_to_dict(self,matrix):
|
|
296
|
+
edges = {}
|
|
297
|
+
for r,row in enumerate(matrix):
|
|
298
|
+
# if empty row, add to iso_vertices
|
|
299
|
+
if sum(row) == 0:
|
|
300
|
+
self.iso_vertices.add(r)
|
|
301
|
+
else:
|
|
302
|
+
for c,weight in enumerate(row):
|
|
303
|
+
if weight > 0:
|
|
304
|
+
edge = tuple(sorted((r,c)))
|
|
305
|
+
#print("r,c:",edge," - ",weight)
|
|
306
|
+
edges[edge] = weight
|
|
307
|
+
return edges
|
|
308
|
+
|
|
309
|
+
#
|
|
310
|
+
def _empty_edge_dict(self):
|
|
311
|
+
empty_edges = {}
|
|
312
|
+
for idx in self.gt_props.keys():
|
|
313
|
+
empty_edges[idx] = []
|
|
314
|
+
return empty_edges
|
|
315
|
+
|
|
316
|
+
#
|
|
317
|
+
def _get_prop_values(self,key):
|
|
318
|
+
values_list = self.gt_props.values()
|
|
319
|
+
return [p[key] for p in values_list]
|
|
320
|
+
|
|
321
|
+
# flip coordinates for graph-tool
|
|
322
|
+
def _flipY(self,vpositions):
|
|
323
|
+
x, y = ungroup_vector_property(vpositions, [0, 1])
|
|
324
|
+
y.fa *= -1
|
|
325
|
+
y.fa -= y.fa.min()
|
|
326
|
+
return group_vector_property([x, y])
|
|
327
|
+
|
|
328
|
+
#
|
|
329
|
+
def show(self,inline=True):
|
|
330
|
+
graph = self.graph
|
|
331
|
+
positions = self._flipY(self.v_pos)
|
|
332
|
+
labels = self.v_label
|
|
333
|
+
colors = self.v_color
|
|
334
|
+
weights = self.e_weight
|
|
335
|
+
graph_draw(graph, inline=inline,output_size=(300,300),fit_view=0.7,
|
|
336
|
+
pos=positions,
|
|
337
|
+
vertex_text=labels,
|
|
338
|
+
vertex_font_family="sans serif",
|
|
339
|
+
vertex_font_size=18,
|
|
340
|
+
vertex_font_weight=cairo.FONT_WEIGHT_BOLD,
|
|
341
|
+
vertex_fill_color=colors,
|
|
342
|
+
vertex_size = 50,
|
|
343
|
+
vertex_halo=False,
|
|
344
|
+
vertex_pen_width=1.2,
|
|
345
|
+
vertex_color="#999999",
|
|
346
|
+
edge_pen_width=weights)
|
|
347
|
+
|
|
348
|
+
def get_vertex_labels(self):
|
|
349
|
+
return self._get_prop_values('lbl')
|
|
350
|
+
|
|
351
|
+
def get_vertex_colours(self):
|
|
352
|
+
return self._get_prop_values('clr')
|
|
353
|
+
|
|
354
|
+
def get_vertex_positions(self):
|
|
355
|
+
return self._get_prop_values('pos')
|
|
File without changes
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
logging.basicConfig(level=logging.INFO)
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import time
|
|
11
|
+
|
|
12
|
+
import reflexive as rfx
|
|
13
|
+
|
|
14
|
+
# Create a config with a profile (local credentials) - leave blank for 'default' profile
|
|
15
|
+
cfg = rfx.cfg.Config('r3-admin')
|
|
16
|
+
# Set default parameters - specify name_prefix, local_path, and date_string for custom options
|
|
17
|
+
parameters = cfg.set_parameters()
|
|
18
|
+
#print("After set_parameters:",parameters)
|
|
19
|
+
|
|
20
|
+
# Create a session with AWS using profile - some parameters require AWS session (like account number)
|
|
21
|
+
aws = rfx.session.AWS(cfg)
|
|
22
|
+
#print("aws parameters:",cfg.get_parameters())
|
|
23
|
+
|
|
24
|
+
# Set the parameters for S3 - required for comprehend
|
|
25
|
+
parameters = cfg.set_s3_parameters(s3_access_point="qut-gibsonap-reflexive",s3_bucket_name="au-edu-qld-qut-gibsonap-reflexive")
|
|
26
|
+
#print("After set_s3_parameters:",parameters)
|
|
27
|
+
|
|
28
|
+
# Set comprehend parameters
|
|
29
|
+
parameters = cfg.set_comprehend_parameters(comprehend_service_role_name="AmazonComprehendServiceRole-gibsonap-reflexive")
|
|
30
|
+
#print("After set_comprehend_parameters:",parameters)
|
|
31
|
+
|
|
32
|
+
# Set custom entity recogniser parameters
|
|
33
|
+
parameters = cfg.set_comprehend_custom_entity_parameters(reflexive_entity_name="ReflexiveExpressionRecogniser",reflexive_entity_version="v17")
|
|
34
|
+
#print("After set_comprehend_custom_entity_parameters:",parameters)
|
|
35
|
+
|
|
36
|
+
# Display all parameters stored in Config
|
|
37
|
+
params_fmt = json.dumps(parameters, indent=2)
|
|
38
|
+
#print(params_fmt)
|
|
39
|
+
|
|
40
|
+
# Create a new S3 client
|
|
41
|
+
s3 = rfx.session.S3(aws)
|
|
42
|
+
s3_client = s3.client()
|
|
43
|
+
|
|
44
|
+
# Create a new Comprehend client
|
|
45
|
+
comp = rfx.session.Comprehend(aws)
|
|
46
|
+
comp_client = comp.client()
|
|
47
|
+
|
|
48
|
+
# Perform test analysis
|
|
49
|
+
test_dict = {"text":["This is a test text. I hope that this will work for some basic analysis. Previously, this has not been as straight forward as I thought. Perhaps this time may be different. With any luck, this will not be a frustrating experience, but I hope that it will just work straight away. I can only hope!"]}
|
|
50
|
+
test_series = pd.Series(test_dict['text'])
|
|
51
|
+
df = pd.DataFrame.from_dict(test_dict)
|
|
52
|
+
#print(df.describe())
|
|
53
|
+
|
|
54
|
+
nlp = rfx.analyse.Nlp(aws)
|
|
55
|
+
|
|
56
|
+
# Text length - this is needed for comprehend analytics
|
|
57
|
+
df = nlp.text_length(df)
|
|
58
|
+
df = nlp.remove_IQR_outliers(df)
|
|
59
|
+
#print(df.describe())
|
|
60
|
+
|
|
61
|
+
# Domain terms
|
|
62
|
+
#domain_terms = {"hedge":['hope','perhaps','luck'],"emotion":['hope','frustrating']}
|
|
63
|
+
#nlp.add_domain_terms(domain_terms)
|
|
64
|
+
#df = nlp.match_domain_terms(df)
|
|
65
|
+
#print(df['domain_counts'])
|
|
66
|
+
|
|
67
|
+
# Ngrams
|
|
68
|
+
#top_ngrams = nlp.get_top_ngrams(df['text'],2)
|
|
69
|
+
#print(top_ngrams)
|
|
70
|
+
#df = nlp.match_top_ngrams(df)
|
|
71
|
+
#print(df)
|
|
72
|
+
|
|
73
|
+
# Comprehend analysis
|
|
74
|
+
# results = nlp.comprehend_analysis(comp,df)
|
|
75
|
+
# print(results)
|
|
76
|
+
# errors = nlp.check_results(results)
|
|
77
|
+
# print(errors)
|
|
78
|
+
# if errors=={}:
|
|
79
|
+
# print("No errors, so adding results to dataframe")
|
|
80
|
+
# df = nlp.add_results_to_df(results,df)
|
|
81
|
+
# print(df)
|
|
82
|
+
|
|
83
|
+
# df.to_pickle(f"{cfg.local_path}comp_df.pkl")
|
|
84
|
+
df = pd.read_pickle(f"{cfg.local_path}comp_df.pkl")
|
|
85
|
+
|
|
86
|
+
# Comprehend analytics
|
|
87
|
+
df = nlp.comprehend_analytics(df)
|
|
88
|
+
df.to_csv(f"{cfg.local_path}comp_analytics.csv")
|
|
89
|
+
print("DONE!!")
|
|
90
|
+
|
|
91
|
+
# Reflexive expression analysis
|
|
92
|
+
response = nlp.analyse_reflexive_expressions(df,s3,comp)
|
|
93
|
+
print(response)
|
|
94
|
+
job_id = comp.get_current_job_id()
|
|
95
|
+
time.sleep(5)
|
|
96
|
+
status = comp.check_job_status()
|
|
97
|
+
print(status)
|
|
98
|
+
time.sleep(5)
|
|
99
|
+
details = comp.get_job_details()
|
|
100
|
+
print(details)
|
|
101
|
+
|
|
102
|
+
while status=="IN_PROGRESS":
|
|
103
|
+
time.sleep(10)
|
|
104
|
+
status = comp.check_job_status()
|
|
105
|
+
print(status)
|
|
106
|
+
|
|
107
|
+
result = comp.download_and_extract(s3)
|
|
108
|
+
print(result)
|
|
109
|
+
|
|
110
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|