datamule 2.2.1__py3-none-any.whl → 2.2.3__py3-none-any.whl
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.
- datamule/document/document.py +192 -61
- datamule/sentiment/__init__.py +0 -0
- datamule/tags/config.py +9 -1
- datamule/{utils → tags}/dictionaries.py +48 -7
- datamule/tags/utils.py +28 -1
- {datamule-2.2.1.dist-info → datamule-2.2.3.dist-info}/METADATA +1 -1
- {datamule-2.2.1.dist-info → datamule-2.2.3.dist-info}/RECORD +9 -8
- {datamule-2.2.1.dist-info → datamule-2.2.3.dist-info}/WHEEL +0 -0
- {datamule-2.2.1.dist-info → datamule-2.2.3.dist-info}/top_level.txt +0 -0
datamule/document/document.py
CHANGED
@@ -13,11 +13,47 @@ from pathlib import Path
|
|
13
13
|
import webbrowser
|
14
14
|
from secsgml.utils import bytes_to_str
|
15
15
|
import tempfile
|
16
|
-
import warnings
|
17
16
|
from .tables.tables import Tables
|
18
17
|
|
19
|
-
from ..tags.utils import get_cusip_using_regex, get_isin_using_regex, get_figi_using_regex,get_all_tickers, get_full_names,get_full_names_dictionary_lookup
|
18
|
+
from ..tags.utils import get_cusip_using_regex, get_isin_using_regex, get_figi_using_regex,get_all_tickers, get_full_names,get_full_names_dictionary_lookup, analyze_lm_sentiment_fragment
|
20
19
|
|
20
|
+
class DataWithTags(dict):
|
21
|
+
def __init__(self, data, document):
|
22
|
+
super().__init__(data)
|
23
|
+
self._document = document
|
24
|
+
self._tags = None
|
25
|
+
|
26
|
+
@property
|
27
|
+
def tags(self):
|
28
|
+
if self._tags is None:
|
29
|
+
self._tags = Tags(self._document, mode='data') # New fragment-based behavior
|
30
|
+
return self._tags
|
31
|
+
|
32
|
+
@property
|
33
|
+
def similarity(self):
|
34
|
+
if not hasattr(self, '_similarity'):
|
35
|
+
self._similarity = Similarity(self._document, mode='data')
|
36
|
+
return self._similarity
|
37
|
+
|
38
|
+
class TextWithTags(str):
|
39
|
+
def __new__(cls, content, document):
|
40
|
+
instance = str.__new__(cls, content)
|
41
|
+
instance._document = document
|
42
|
+
instance._tags = None
|
43
|
+
return instance
|
44
|
+
|
45
|
+
@property
|
46
|
+
def tags(self):
|
47
|
+
if self._tags is None:
|
48
|
+
self._tags = Tags(self._document, mode='text') # Original behavior
|
49
|
+
return self._tags
|
50
|
+
|
51
|
+
@property
|
52
|
+
def similarity(self):
|
53
|
+
if not hasattr(self, '_similarity'):
|
54
|
+
self._similarity = Similarity(self._document, mode='text')
|
55
|
+
return self._similarity
|
56
|
+
|
21
57
|
|
22
58
|
class Tickers:
|
23
59
|
def __init__(self, document):
|
@@ -27,11 +63,7 @@ class Tickers:
|
|
27
63
|
def _get_tickers_data(self):
|
28
64
|
"""Get all tickers data once and cache it"""
|
29
65
|
if self._tickers_data is None:
|
30
|
-
|
31
|
-
if self.document.extension not in ['.htm', '.html', '.txt']:
|
32
|
-
self._tickers_data = {}
|
33
|
-
else:
|
34
|
-
self._tickers_data = get_all_tickers(self.document.text)
|
66
|
+
self._tickers_data = get_all_tickers(self.document.text)
|
35
67
|
return self._tickers_data
|
36
68
|
|
37
69
|
def __getattr__(self, exchange_name):
|
@@ -57,14 +89,14 @@ class Tickers:
|
|
57
89
|
data = self._get_tickers_data()
|
58
90
|
return str(data)
|
59
91
|
|
60
|
-
class
|
61
|
-
def __init__(self, document):
|
92
|
+
class TextAnalysisBase:
|
93
|
+
def __init__(self, document, mode='text'):
|
62
94
|
from ..tags.config import _active_dictionaries,_loaded_dictionaries
|
63
|
-
self.not_supported = document.extension not in ['.htm', '.html', '.txt']
|
64
95
|
self.document = document
|
65
|
-
self.
|
96
|
+
self.mode = mode # 'text' or 'data'
|
66
97
|
self.dictionaries = {}
|
67
98
|
self.processors = {}
|
99
|
+
self._text_sources = None
|
68
100
|
|
69
101
|
# Load global dictionaries with their data and processors
|
70
102
|
active_dicts = _active_dictionaries
|
@@ -73,76 +105,166 @@ class Tags:
|
|
73
105
|
self.dictionaries[dict_name] = dict_info['data']
|
74
106
|
if dict_info['processor'] is not None:
|
75
107
|
self.processors[dict_name] = dict_info['processor']
|
76
|
-
|
77
108
|
|
78
|
-
def
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
109
|
+
def _get_text_sources(self):
|
110
|
+
"""Get text sources based on mode - either single text or multiple fragments"""
|
111
|
+
if self._text_sources is None:
|
112
|
+
if self.mode == 'text':
|
113
|
+
# Original behavior - single text source
|
114
|
+
self._text_sources = [{'id': None, 'text': str(self.document.text)}]
|
115
|
+
else: # mode == 'data'
|
116
|
+
# New behavior - multiple text fragments
|
117
|
+
self._text_sources = []
|
118
|
+
self._extract_text_fragments(self.document.data, '')
|
119
|
+
return self._text_sources
|
120
|
+
|
121
|
+
def _extract_text_fragments(self, data, parent_id=''):
|
122
|
+
"""Extract all text fragments with their document IDs from parsed data"""
|
123
|
+
if isinstance(data, dict):
|
124
|
+
for key, value in data.items():
|
125
|
+
if key in ["text", "title"] and isinstance(value, str):
|
126
|
+
# Use the current dictionary's parent key as the fragment ID
|
127
|
+
self._text_sources.append({
|
128
|
+
'id': parent_id,
|
129
|
+
'text': value
|
130
|
+
})
|
131
|
+
elif isinstance(value, (dict, list)):
|
132
|
+
# Pass the current key as the parent_id for the next level
|
133
|
+
self._extract_text_fragments(value, key)
|
134
|
+
elif isinstance(data, list):
|
135
|
+
for i, item in enumerate(data):
|
136
|
+
if isinstance(item, (dict, list)):
|
137
|
+
self._extract_text_fragments(item, parent_id)
|
138
|
+
|
139
|
+
def _format_results(self, results, fragment_id):
|
140
|
+
"""Format results based on mode"""
|
141
|
+
if self.mode == 'text':
|
142
|
+
# Original format: (match, start, end)
|
143
|
+
return results
|
144
|
+
else:
|
145
|
+
# New format: (match, fragment_id, start, end)
|
146
|
+
return [(match, fragment_id, start, end) for match, start, end in results]
|
147
|
+
|
148
|
+
class Tags(TextAnalysisBase):
|
149
|
+
def __init__(self, document, mode='text'):
|
150
|
+
super().__init__(document, mode)
|
151
|
+
self._tickers = None
|
83
152
|
|
84
153
|
@property
|
85
154
|
def cusips(self):
|
86
|
-
if not self
|
87
|
-
|
155
|
+
if not hasattr(self, '_cusips'):
|
156
|
+
self._cusips = []
|
157
|
+
sources = self._get_text_sources()
|
88
158
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
159
|
+
for source in sources:
|
160
|
+
if 'sc13dg_cusips' in self.dictionaries:
|
161
|
+
keywords = self.dictionaries['sc13dg_cusips']
|
162
|
+
results = get_cusip_using_regex(source['text'], keywords)
|
163
|
+
elif "13fhr_information_table_cusips" in self.dictionaries:
|
164
|
+
keywords = self.dictionaries['13fhr_information_table_cusips']
|
165
|
+
results = get_cusip_using_regex(source['text'], keywords)
|
166
|
+
else:
|
167
|
+
results = get_cusip_using_regex(source['text'])
|
168
|
+
|
169
|
+
# Format results based on mode
|
170
|
+
formatted_results = self._format_results(results, source['id'])
|
171
|
+
self._cusips.extend(formatted_results)
|
172
|
+
|
173
|
+
return self._cusips
|
96
174
|
|
97
175
|
@property
|
98
176
|
def isins(self):
|
99
|
-
if not self
|
100
|
-
|
177
|
+
if not hasattr(self, '_isins'):
|
178
|
+
self._isins = []
|
179
|
+
sources = self._get_text_sources()
|
101
180
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
181
|
+
for source in sources:
|
182
|
+
if 'npx_isins' in self.dictionaries:
|
183
|
+
keywords = self.dictionaries['npx_isins']
|
184
|
+
results = get_isin_using_regex(source['text'], keywords)
|
185
|
+
else:
|
186
|
+
results = get_isin_using_regex(source['text'])
|
187
|
+
|
188
|
+
formatted_results = self._format_results(results, source['id'])
|
189
|
+
self._isins.extend(formatted_results)
|
190
|
+
|
191
|
+
return self._isins
|
109
192
|
|
110
193
|
@property
|
111
194
|
def figis(self):
|
112
|
-
if not self
|
113
|
-
|
195
|
+
if not hasattr(self, '_figis'):
|
196
|
+
self._figis = []
|
197
|
+
sources = self._get_text_sources()
|
114
198
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
199
|
+
for source in sources:
|
200
|
+
if 'npx_figis' in self.dictionaries:
|
201
|
+
keywords = self.dictionaries['npx_figis']
|
202
|
+
results = get_figi_using_regex(source['text'], keywords)
|
203
|
+
else:
|
204
|
+
results = get_figi_using_regex(source['text'])
|
205
|
+
|
206
|
+
formatted_results = self._format_results(results, source['id'])
|
207
|
+
self._figis.extend(formatted_results)
|
208
|
+
|
209
|
+
return self._figis
|
122
210
|
|
123
211
|
@property
|
124
212
|
def tickers(self):
|
213
|
+
# Tickers work differently - they need the full document context
|
214
|
+
# Keep original behavior for now
|
125
215
|
if self._tickers is None:
|
126
216
|
self._tickers = Tickers(self.document)
|
127
217
|
return self._tickers
|
128
218
|
|
129
219
|
@property
|
130
220
|
def persons(self):
|
131
|
-
if not self._check_support():
|
132
|
-
return None
|
133
|
-
|
134
221
|
if not hasattr(self, '_persons'):
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
222
|
+
self._persons = []
|
223
|
+
sources = self._get_text_sources()
|
224
|
+
|
225
|
+
for source in sources:
|
226
|
+
if '8k_2024_persons' in self.processors:
|
227
|
+
results = get_full_names_dictionary_lookup(source['text'], self.processors['8k_2024_persons'])
|
228
|
+
elif 'ssa_baby_first_names' in self.dictionaries:
|
229
|
+
results = get_full_names(source['text'], self.dictionaries['ssa_baby_first_names'])
|
230
|
+
else:
|
231
|
+
results = get_full_names(source['text'])
|
232
|
+
|
233
|
+
formatted_results = self._format_results(results, source['id'])
|
234
|
+
self._persons.extend(formatted_results)
|
235
|
+
|
144
236
|
return self._persons
|
145
|
-
|
237
|
+
|
238
|
+
class Similarity(TextAnalysisBase):
|
239
|
+
@property
|
240
|
+
def loughran_mcdonald(self):
|
241
|
+
if not hasattr(self, '_loughran_mcdonald'):
|
242
|
+
self._loughran_mcdonald = []
|
243
|
+
sources = self._get_text_sources()
|
244
|
+
|
245
|
+
if 'loughran_mcdonald' in self.processors:
|
246
|
+
lm_processors = self.processors['loughran_mcdonald']
|
247
|
+
|
248
|
+
for source in sources:
|
249
|
+
results = analyze_lm_sentiment_fragment(source['text'], lm_processors)
|
250
|
+
|
251
|
+
if self.mode == 'text':
|
252
|
+
# Single result for whole document
|
253
|
+
self._loughran_mcdonald = results
|
254
|
+
break
|
255
|
+
else:
|
256
|
+
# Per-fragment results with fragment_id
|
257
|
+
fragment_result = {
|
258
|
+
'fragment_id': source['id'],
|
259
|
+
**results
|
260
|
+
}
|
261
|
+
self._loughran_mcdonald.append(fragment_result)
|
262
|
+
else:
|
263
|
+
# No processors available
|
264
|
+
self._loughran_mcdonald = [] if self.mode == 'data' else {}
|
265
|
+
|
266
|
+
return self._loughran_mcdonald
|
267
|
+
|
146
268
|
|
147
269
|
class Document:
|
148
270
|
def __init__(self, type, content, extension,accession,filing_date,path=None):
|
@@ -168,8 +290,6 @@ class Document:
|
|
168
290
|
self._tables = None
|
169
291
|
self._text = None
|
170
292
|
|
171
|
-
self.tags = Tags(self)
|
172
|
-
|
173
293
|
|
174
294
|
|
175
295
|
#_load_text_content
|
@@ -354,15 +474,26 @@ class Document:
|
|
354
474
|
def data(self):
|
355
475
|
if self._data is None:
|
356
476
|
self.parse()
|
477
|
+
|
478
|
+
if self._data is None:
|
479
|
+
self._data = {}
|
480
|
+
|
481
|
+
if not isinstance(self._data, DataWithTags):
|
482
|
+
self._data = DataWithTags(self._data, self)
|
483
|
+
|
357
484
|
return self._data
|
358
485
|
|
359
486
|
@property
|
360
487
|
def text(self):
|
361
488
|
if self._text is None:
|
362
489
|
if self.extension in ['.htm','.html']:
|
363
|
-
self._preprocess_html_content()
|
490
|
+
self._preprocess_html_content() # Still sets self._text to plain string
|
364
491
|
elif self.extension == '.txt':
|
365
|
-
self._preprocess_txt_content()
|
492
|
+
self._preprocess_txt_content() # Still sets self._text to plain string
|
493
|
+
|
494
|
+
# Convert the plain string to TextWithTags
|
495
|
+
plain_text = self._text
|
496
|
+
self._text = TextWithTags(plain_text, self)
|
366
497
|
return self._text
|
367
498
|
|
368
499
|
def write_json(self, output_filename=None):
|
File without changes
|
datamule/tags/config.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from
|
1
|
+
from .dictionaries import download_dictionary, load_dictionary
|
2
2
|
|
3
3
|
_active_dictionaries = []
|
4
4
|
_loaded_dictionaries = {}
|
@@ -26,6 +26,14 @@ def set_dictionaries(dictionaries, overwrite=False):
|
|
26
26
|
'data': raw_data,
|
27
27
|
'processor': processor
|
28
28
|
}
|
29
|
+
elif dict_name == 'loughran_mcdonald':
|
30
|
+
from .utils import create_lm_processors
|
31
|
+
processors = create_lm_processors(raw_data)
|
32
|
+
|
33
|
+
_loaded_dictionaries[dict_name] = {
|
34
|
+
'data': raw_data,
|
35
|
+
'processor': processors
|
36
|
+
}
|
29
37
|
else:
|
30
38
|
_loaded_dictionaries[dict_name] = {
|
31
39
|
'data': raw_data,
|
@@ -1,16 +1,19 @@
|
|
1
1
|
from pathlib import Path
|
2
2
|
import urllib.request
|
3
3
|
import json
|
4
|
+
import csv
|
4
5
|
urls = {
|
5
6
|
"ssa_baby_first_names": "https://raw.githubusercontent.com/john-friedman/datamule-data/master/data/dictionaries/ssa_baby_first_names.txt",
|
6
7
|
"npx_figis" : "https://raw.githubusercontent.com/john-friedman/datamule-data/master/data/dictionaries/npx_figis.txt",
|
7
8
|
"npx_isins" : "https://raw.githubusercontent.com/john-friedman/datamule-data/master/data/dictionaries/npx_isins.txt",
|
8
9
|
"sc13dg_cusips" : "https://raw.githubusercontent.com/john-friedman/datamule-data/master/data/dictionaries/sc13dg_cusips.txt",
|
9
|
-
"8k_2024_persons" : "https://raw.githubusercontent.com/john-friedman/datamule-data/master/data/dictionaries/8k_2024_persons.json"
|
10
|
+
"8k_2024_persons" : "https://raw.githubusercontent.com/john-friedman/datamule-data/master/data/dictionaries/8k_2024_persons.json",
|
11
|
+
"13fhr_information_table_cusips" : "https://raw.githubusercontent.com/john-friedman/datamule-data/refs/heads/master/data/dictionaries/13fhr_information_table_cusips.txt",
|
12
|
+
"loughran_mcdonald" : "https://drive.usercontent.google.com/u/0/uc?id=1cfg_w3USlRFS97wo7XQmYnuzhpmzboAY&export=download"
|
10
13
|
}
|
11
14
|
|
12
15
|
|
13
|
-
def download_dictionary(name,overwrite=False):
|
16
|
+
def download_dictionary(name, overwrite=False):
|
14
17
|
url = urls[name]
|
15
18
|
|
16
19
|
# Create dictionaries directory in datamule folder
|
@@ -19,13 +22,19 @@ def download_dictionary(name,overwrite=False):
|
|
19
22
|
|
20
23
|
# check if file exists first
|
21
24
|
if not overwrite:
|
22
|
-
|
25
|
+
if name == "loughran_mcdonald":
|
26
|
+
filename = "loughran_mcdonald.csv"
|
27
|
+
else:
|
28
|
+
filename = url.split('/')[-1]
|
23
29
|
file_path = dict_dir / filename
|
24
30
|
if file_path.exists():
|
25
31
|
return
|
26
32
|
|
27
33
|
# Extract filename from URL
|
28
|
-
|
34
|
+
if name == "loughran_mcdonald":
|
35
|
+
filename = "loughran_mcdonald.csv"
|
36
|
+
else:
|
37
|
+
filename = url.split('/')[-1]
|
29
38
|
file_path = dict_dir / filename
|
30
39
|
|
31
40
|
print(f"Downloading {name} dictionary to {file_path}")
|
@@ -35,7 +44,11 @@ def download_dictionary(name,overwrite=False):
|
|
35
44
|
def load_dictionary(name):
|
36
45
|
# Get or download the dictionary file
|
37
46
|
dict_dir = Path.home() / ".datamule" / "dictionaries"
|
38
|
-
|
47
|
+
|
48
|
+
if name == "loughran_mcdonald":
|
49
|
+
filename = "loughran_mcdonald.csv"
|
50
|
+
else:
|
51
|
+
filename = urls[name].split('/')[-1]
|
39
52
|
file_path = dict_dir / filename
|
40
53
|
|
41
54
|
# Download if doesn't exist
|
@@ -67,10 +80,38 @@ def load_dictionary(name):
|
|
67
80
|
for line in f:
|
68
81
|
cusip_set.add(line.strip())
|
69
82
|
return cusip_set
|
83
|
+
elif name == "13fhr_information_table_cusips":
|
84
|
+
cusip_set = set()
|
85
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
86
|
+
for line in f:
|
87
|
+
cusip_set.add(line.strip())
|
88
|
+
return cusip_set
|
70
89
|
elif name == "8k_2024_persons":
|
71
|
-
|
72
90
|
with open(file_path, 'r', encoding='utf-8') as f:
|
73
91
|
persons_list = json.load(f)
|
74
92
|
return persons_list
|
93
|
+
elif name == "loughran_mcdonald":
|
94
|
+
# Load the Loughran-McDonald dictionary using base Python CSV
|
95
|
+
lm_dict = {}
|
96
|
+
categories = ['Negative', 'Positive', 'Uncertainty', 'Litigious',
|
97
|
+
'Strong_Modal', 'Weak_Modal', 'Constraining']
|
98
|
+
|
99
|
+
# Initialize category sets
|
100
|
+
for category in categories:
|
101
|
+
lm_dict[category.lower()] = set()
|
102
|
+
|
103
|
+
with open(file_path, 'r', encoding='utf-8') as f:
|
104
|
+
reader = csv.DictReader(f)
|
105
|
+
for row in reader:
|
106
|
+
word = row['Word'].lower()
|
107
|
+
for category in categories:
|
108
|
+
value = row.get(category)
|
109
|
+
# Check if value exists and is not 0 (words added in specific years)
|
110
|
+
if value and str(value).strip() != '0':
|
111
|
+
lm_dict[category.lower()].add(word)
|
112
|
+
|
113
|
+
return lm_dict
|
75
114
|
else:
|
76
|
-
raise ValueError("dictionary not found")
|
115
|
+
raise ValueError("dictionary not found")
|
116
|
+
|
117
|
+
download_dictionary('loughran_mcdonald')
|
datamule/tags/utils.py
CHANGED
@@ -142,4 +142,31 @@ def get_full_names_dictionary_lookup(text, processor):
|
|
142
142
|
for keyword, start_pos, end_pos in keywords_found:
|
143
143
|
matches.append((keyword, start_pos, end_pos))
|
144
144
|
|
145
|
-
return matches
|
145
|
+
return matches
|
146
|
+
|
147
|
+
|
148
|
+
def create_lm_processors(lm_dict):
|
149
|
+
processors = {}
|
150
|
+
|
151
|
+
for category_key, word_set in lm_dict.items():
|
152
|
+
processor = KeywordProcessor(case_sensitive=False)
|
153
|
+
for word in word_set:
|
154
|
+
processor.add_keyword(word)
|
155
|
+
processors[category_key] = processor
|
156
|
+
|
157
|
+
return processors
|
158
|
+
|
159
|
+
def analyze_lm_sentiment_fragment(text, processors):
|
160
|
+
"""Analyze sentiment for a single text fragment"""
|
161
|
+
if not text or not text.strip():
|
162
|
+
return {}
|
163
|
+
|
164
|
+
word_count = len(text.split())
|
165
|
+
results = {}
|
166
|
+
|
167
|
+
for category, processor in processors.items():
|
168
|
+
matches = processor.extract_keywords(text.lower(), span_info=True)
|
169
|
+
results[category] = len(matches)
|
170
|
+
|
171
|
+
results['total_words'] = word_count
|
172
|
+
return results
|
@@ -15,7 +15,7 @@ datamule/datamule/datamule_mysql_rds.py,sha256=Q6_h24-SNECWK60RnM6UQjUIp5dhJmfn3
|
|
15
15
|
datamule/datamule/downloader.py,sha256=mVg1SApfij_9-dTpcm_YB26Bxc_Yq1FR8xv2k50MHqU,18579
|
16
16
|
datamule/datamule/sec_connector.py,sha256=VwOaODpHoAWy8JIky6kLR1-orW_PB61RHw7pIGRpkow,3288
|
17
17
|
datamule/document/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
-
datamule/document/document.py,sha256=
|
18
|
+
datamule/document/document.py,sha256=oOib-bFPZ0rsIk8WBgBVY73CwuU18MZDmXnAQ8fTVD8,26124
|
19
19
|
datamule/document/tables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
datamule/document/tables/tables.py,sha256=8riSAof6o-Gxoo0SkiQAE61fw8NmzDnEhJe6dATzmvA,4487
|
21
21
|
datamule/document/tables/tables_13fhr.py,sha256=-6tWcaTyNsb0XuW0WMBrYir9Zn1wLZL0laKxRYfPNyg,4265
|
@@ -48,15 +48,16 @@ datamule/sec/xbrl/streamcompanyfacts.py,sha256=Qq88PqW5_j1k3Aqrl0KRmKeF54D6Wbb6H
|
|
48
48
|
datamule/sec/xbrl/xbrlmonitor.py,sha256=TKFVfSyyUUfUgFQw4WxEVs4g8Nh-2C0tygNIRmTqW3Y,5848
|
49
49
|
datamule/seclibrary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
50
50
|
datamule/seclibrary/bq.py,sha256=C8sb_rpXTvchprrFLcbRar4Qi0XWW25tnv1YsHSS5o4,18025
|
51
|
+
datamule/sentiment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
51
52
|
datamule/tags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
52
|
-
datamule/tags/config.py,sha256=
|
53
|
+
datamule/tags/config.py,sha256=w7386pyvnWYPNwgMVT_Nw5ivXibOeFuSuMEI7lRsGrk,1495
|
54
|
+
datamule/tags/dictionaries.py,sha256=1v2OoN1KnM3HbFHxATxe7LhVRoXe64ecRRgA3oak210,4587
|
53
55
|
datamule/tags/regex.py,sha256=Zr1dlnb8OfecDkI2DFCI8DUBr9LI50fapQyBAYNEZrg,4487
|
54
|
-
datamule/tags/utils.py,sha256=
|
56
|
+
datamule/tags/utils.py,sha256=hexmz_3YnoPrC98A5DTz1xa8o58xZ1yKbzQYP1XiQts,6100
|
55
57
|
datamule/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
58
|
datamule/utils/construct_submissions_data.py,sha256=NB_hvfxlRXPyt4Fgc-5qA8vJRItkLhBedCSTaxwW7Jg,5887
|
57
|
-
datamule/utils/dictionaries.py,sha256=VImvQWlP8IohB76rDd83bZcT184LBOpOaXPOH46fA6Y,2795
|
58
59
|
datamule/utils/format_accession.py,sha256=60RtqoNqoT9zSKVb1DeOv1gncJxzPTFMNW4SNOVmC_g,476
|
59
|
-
datamule-2.2.
|
60
|
-
datamule-2.2.
|
61
|
-
datamule-2.2.
|
62
|
-
datamule-2.2.
|
60
|
+
datamule-2.2.3.dist-info/METADATA,sha256=cca85xqYigHxQbSRJPlOwyJ6pbVp-87YYk0wUBXcMr8,585
|
61
|
+
datamule-2.2.3.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
62
|
+
datamule-2.2.3.dist-info/top_level.txt,sha256=iOfgmtSMFVyr7JGl_bYSTDry79JbmsG4p8zKq89ktKk,9
|
63
|
+
datamule-2.2.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|