datamule 1.2.6__tar.gz → 1.2.7__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.
Files changed (65) hide show
  1. {datamule-1.2.6 → datamule-1.2.7}/PKG-INFO +1 -1
  2. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/document.py +2 -2
  3. datamule-1.2.7/datamule/document/mappings/ex102_abs.py +63 -0
  4. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/processing.py +36 -9
  5. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/table.py +44 -6
  6. {datamule-1.2.6 → datamule-1.2.7}/datamule.egg-info/PKG-INFO +1 -1
  7. {datamule-1.2.6 → datamule-1.2.7}/datamule.egg-info/SOURCES.txt +1 -0
  8. {datamule-1.2.6 → datamule-1.2.7}/setup.py +1 -1
  9. {datamule-1.2.6 → datamule-1.2.7}/datamule/__init__.py +0 -0
  10. {datamule-1.2.6 → datamule-1.2.7}/datamule/config.py +0 -0
  11. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/__init__.py +0 -0
  12. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/__init__.py +0 -0
  13. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/atsn.py +0 -0
  14. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/cfportal.py +0 -0
  15. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/ex99a_sdr.py +0 -0
  16. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/ex99c_sdr.py +0 -0
  17. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/ex99g_sdr.py +0 -0
  18. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/ex99i_sdr.py +0 -0
  19. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/information_table.py +0 -0
  20. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/nmfp.py +0 -0
  21. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/npx.py +0 -0
  22. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/onefourtyfour.py +0 -0
  23. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/ownership.py +0 -0
  24. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/proxy_voting_record.py +0 -0
  25. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/sbs.py +0 -0
  26. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/sbsef.py +0 -0
  27. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/schedule13.py +0 -0
  28. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/sdr.py +0 -0
  29. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/submission_metadata.py +0 -0
  30. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/ta.py +0 -0
  31. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/thirteenfhr.py +0 -0
  32. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/twentyfivense.py +0 -0
  33. {datamule-1.2.6 → datamule-1.2.7}/datamule/document/mappings/twentyfourf2nt.py +0 -0
  34. {datamule-1.2.6 → datamule-1.2.7}/datamule/helper.py +0 -0
  35. {datamule-1.2.6 → datamule-1.2.7}/datamule/index.py +0 -0
  36. {datamule-1.2.6 → datamule-1.2.7}/datamule/mapping_dicts/__init__.py +0 -0
  37. {datamule-1.2.6 → datamule-1.2.7}/datamule/mapping_dicts/txt_mapping_dicts.py +0 -0
  38. {datamule-1.2.6 → datamule-1.2.7}/datamule/mapping_dicts/xml_mapping_dicts.py +0 -0
  39. {datamule-1.2.6 → datamule-1.2.7}/datamule/package_updater.py +0 -0
  40. {datamule-1.2.6 → datamule-1.2.7}/datamule/portfolio.py +0 -0
  41. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/__init__.py +0 -0
  42. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/infrastructure/__init__.py +0 -0
  43. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/infrastructure/submissions_metadata.py +0 -0
  44. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/submissions/__init__.py +0 -0
  45. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/submissions/downloader.py +0 -0
  46. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/submissions/eftsquery.py +0 -0
  47. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/submissions/monitor.py +0 -0
  48. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/submissions/streamer.py +0 -0
  49. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/submissions/textsearch.py +0 -0
  50. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/utils.py +0 -0
  51. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/xbrl/__init__.py +0 -0
  52. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/xbrl/downloadcompanyfacts.py +0 -0
  53. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/xbrl/filter_xbrl.py +0 -0
  54. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/xbrl/streamcompanyfacts.py +0 -0
  55. {datamule-1.2.6 → datamule-1.2.7}/datamule/sec/xbrl/xbrlmonitor.py +0 -0
  56. {datamule-1.2.6 → datamule-1.2.7}/datamule/seclibrary/__init__.py +0 -0
  57. {datamule-1.2.6 → datamule-1.2.7}/datamule/seclibrary/bq.py +0 -0
  58. {datamule-1.2.6 → datamule-1.2.7}/datamule/seclibrary/downloader.py +0 -0
  59. {datamule-1.2.6 → datamule-1.2.7}/datamule/seclibrary/query.py +0 -0
  60. {datamule-1.2.6 → datamule-1.2.7}/datamule/sheet.py +0 -0
  61. {datamule-1.2.6 → datamule-1.2.7}/datamule/submission.py +0 -0
  62. {datamule-1.2.6 → datamule-1.2.7}/datamule.egg-info/dependency_links.txt +0 -0
  63. {datamule-1.2.6 → datamule-1.2.7}/datamule.egg-info/requires.txt +0 -0
  64. {datamule-1.2.6 → datamule-1.2.7}/datamule.egg-info/top_level.txt +0 -0
  65. {datamule-1.2.6 → datamule-1.2.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: datamule
3
- Version: 1.2.6
3
+ Version: 1.2.7
4
4
  Summary: Making it easier to use SEC filings.
5
5
  Home-page: https://github.com/john-friedman/datamule-python
6
6
  Author: John Friedman
@@ -141,7 +141,7 @@ class Document:
141
141
  with open(output_filename, 'w',encoding='utf-8') as f:
142
142
  json.dump(self.data, f, indent=2)
143
143
 
144
- def to_tabular(self):
144
+ def tables(self):
145
145
  if self.type == 'submission_metadata':
146
146
  return process_tabular_data(self)
147
147
  elif self.extension != '.xml':
@@ -155,7 +155,7 @@ class Document:
155
155
  output_folder = Path(output_folder)
156
156
  output_folder.mkdir(exist_ok=True)
157
157
 
158
- tables = self.to_tabular()
158
+ tables = self.tables()
159
159
 
160
160
  if not tables:
161
161
  return
@@ -0,0 +1,63 @@
1
+ # Assets dictionary mapping
2
+ assets_dict_ex102_abs = {
3
+ 'assetNumber': 'assetNumber',
4
+ 'DefeasedStatusCode': 'DefeasedStatusCode',
5
+ 'defeasanceOptionStartDate': 'defeasanceOptionStartDate',
6
+ 'mostRecentDebtServiceCoverageNetOperatingIncomePercentage': 'mostRecentDebtServiceCoverageNetOperatingIncomePercentage',
7
+ 'mostRecentDebtServiceAmount': 'mostRecentDebtServiceAmount',
8
+ 'debtServiceCoverageSecuritizationCode': 'debtServiceCoverageSecuritizationCode',
9
+ 'debtServiceCoverageNetOperatingIncomeSecuritizationPercentage': 'debtServiceCoverageNetOperatingIncomeSecuritizationPercentage',
10
+ 'valuationSecuritizationDate': 'valuationSecuritizationDate',
11
+ 'physicalOccupancySecuritizationPercentage': 'physicalOccupancySecuritizationPercentage',
12
+ 'revenueSecuritizationAmount': 'revenueSecuritizationAmount',
13
+ 'valuationSourceSecuritizationCode': 'valuationSourceSecuritizationCode',
14
+ 'financialsSecuritizationDate': 'financialsSecuritizationDate',
15
+ 'mostRecentNetCashFlowAmount': 'mostRecentNetCashFlowAmount',
16
+ 'operatingExpensesAmount': 'operatingExpensesAmount',
17
+ 'operatingExpensesSecuritizationAmount': 'operatingExpensesSecuritizationAmount',
18
+ 'netOperatingIncomeNetCashFlowSecuritizationCode': 'netOperatingIncomeNetCashFlowSecuritizationCode',
19
+ 'mostRecentValuationSourceCode': 'mostRecentValuationSourceCode',
20
+ 'mostRecentDebtServiceCoverageNetCashFlowpercentage': 'mostRecentDebtServiceCoverageNetCashFlowpercentage',
21
+ 'debtServiceCoverageNetCashFlowSecuritizationPercentage': 'debtServiceCoverageNetCashFlowSecuritizationPercentage',
22
+ 'mostRecentAnnualLeaseRolloverReviewDate': 'mostRecentAnnualLeaseRolloverReviewDate',
23
+ 'mostRecentRevenueAmount': 'mostRecentRevenueAmount',
24
+ 'mostRecentPhysicalOccupancyPercentage': 'mostRecentPhysicalOccupancyPercentage',
25
+ 'mostRecentNetOperatingIncomeAmount': 'mostRecentNetOperatingIncomeAmount',
26
+ 'netOperatingIncomeSecuritizationAmount': 'netOperatingIncomeSecuritizationAmount',
27
+ 'netOperatingIncomeNetCashFlowCode': 'netOperatingIncomeNetCashFlowCode',
28
+ 'mostRecentFinancialsStartDate': 'mostRecentFinancialsStartDate',
29
+ 'mostRecentFinancialsEndDate': 'mostRecentFinancialsEndDate',
30
+ 'accession': 'accession',
31
+ 'valuationSecuritizationAmount': 'valuationSecuritizationAmount',
32
+ 'mostRecentValuationDate': 'mostRecentValuationDate',
33
+ 'mostRecentValuationAmount': 'mostRecentValuationAmount',
34
+ 'mostRecentDebtServiceCoverageCode': 'mostRecentDebtServiceCoverageCode',
35
+ 'netCashFlowFlowSecuritizationAmount': 'netCashFlowFlowSecuritizationAmount'
36
+ }
37
+
38
+ # Properties dictionary mapping
39
+ properties_dict_ex102_abs = {
40
+ 'unitsBedsRoomsNumber': 'unitsBedsRoomsNumber',
41
+ 'propertyCounty': 'propertyCounty',
42
+ 'squareFeetLargestTenantNumber': 'squareFeetLargestTenantNumber',
43
+ 'netRentableSquareFeetNumber': 'netRentableSquareFeetNumber',
44
+ 'leaseExpirationThirdLargestTenantDate': 'leaseExpirationThirdLargestTenantDate',
45
+ 'leaseExpirationLargestTenantDate': 'leaseExpirationLargestTenantDate',
46
+ 'propertyZip': 'propertyZip',
47
+ 'squareFeetThirdLargestTenantNumber': 'squareFeetThirdLargestTenantNumber',
48
+ 'propertyStatusCode': 'propertyStatusCode',
49
+ 'propertyState': 'propertyState',
50
+ 'yearBuiltNumber': 'yearBuiltNumber',
51
+ 'propertyCity': 'propertyCity',
52
+ 'propertyName': 'propertyName',
53
+ 'propertyAddress': 'propertyAddress',
54
+ 'yearLastRenovated': 'yearLastRenovated',
55
+ 'leaseExpirationSecondLargestTenantDate': 'leaseExpirationSecondLargestTenantDate',
56
+ 'thirdLargestTenant': 'thirdLargestTenant',
57
+ 'unitsBedsRoomsSecuritizationNumber': 'unitsBedsRoomsSecuritizationNumber',
58
+ 'propertyTypeCode': 'propertyTypeCode',
59
+ 'largestTenant': 'largestTenant',
60
+ 'squareFeetSecondLargestTenantNumber': 'squareFeetSecondLargestTenantNumber',
61
+ 'netRentableSquareFeetSecuritizationNumber': 'netRentableSquareFeetSecuritizationNumber',
62
+ 'secondLargestTenant': 'secondLargestTenant'
63
+ }
@@ -22,6 +22,8 @@ def process_tabular_data(self):
22
22
  # complete mark:
23
23
  elif self.type in ["N-PX","N-PX/A"]:
24
24
  tables = process_npx(self.data, self.accession)
25
+ elif self.type in ["EX-102"]:
26
+ tables = process_ex102_abs(self.data, self.accession)
25
27
 
26
28
  elif self.type in ["SBSEF","SBSEF/A","SBSEF-V","SBSEF-W"]:
27
29
  tables = process_sbsef(self.data, self.accession)
@@ -70,8 +72,7 @@ def process_tabular_data(self):
70
72
  tables = process_reg_a(self.data, self.accession)
71
73
  # elif self.type in ["SBSE","SBSE/A","SBSE-A","SBSE-A/A","SBSE-BD","SBSE-BD/A","SBSE-C","SBSE-W","SBSE-CCO-RPT","SBSE-CCO-RPT/A"]:
72
74
  # tables = process_sbs(self.data, self.accession)
73
- # elif self.type in ["EX-102"]:
74
- # tables = process_ex102_abs(self.data, self.accession)
75
+
75
76
  elif self.type == "PROXY VOTING RECORD":
76
77
  tables = process_proxy_voting_record(self.data, self.accession)
77
78
  elif self.type == 'submission_metadata':
@@ -589,13 +590,39 @@ def process_reg_a(data, accession):
589
590
 
590
591
  # return tables
591
592
 
592
- # def process_ex102_abs(data, accession):
593
- # tables = []
594
- # asset_data = safe_get(data, ['assetData'])
595
- # if asset_data:
596
- # tables.append(Table(_flatten_dict(asset_data), 'abs', accession))
597
- # raise NotImplementedError("Need to implement the rest of the ABS processing")
598
- # return tables
593
+ def process_ex102_abs(data, accession):
594
+ tables = []
595
+ data = safe_get(data, ['assetData', 'assets'])
596
+
597
+ # Create assets list: all items without their 'property' field
598
+ assets = [{k: v for k, v in item.items() if k != 'property'} for item in data]
599
+
600
+ # Create properties list in a more vectorized way
601
+ properties = []
602
+
603
+ # Handle dictionary properties
604
+ properties.extend([
605
+ item['property'] | {'assetNumber': item['assetNumber']}
606
+ for item in data
607
+ if 'property' in item and isinstance(item['property'], dict)
608
+ ])
609
+
610
+ # Handle list properties - flatten in one operation
611
+ properties.extend([
612
+ prop | {'assetNumber': item['assetNumber']}
613
+ for item in data
614
+ if 'property' in item and isinstance(item['property'], list)
615
+ for prop in item['property']
616
+ if isinstance(prop, dict)
617
+ ])
618
+
619
+ if assets:
620
+ tables.append(Table(_flatten_dict(assets), 'assets_ex102_absee', accession))
621
+
622
+ if properties:
623
+ tables.append(Table(_flatten_dict(properties), 'properties_ex102_absee', accession))
624
+
625
+ return tables
599
626
 
600
627
  # def process_ma(data, accession):
601
628
  # tables = []
@@ -19,6 +19,10 @@ from .mappings.twentyfivense import *
19
19
  from .mappings.twentyfourf2nt import *
20
20
  from .mappings.information_table import *
21
21
  from .mappings.submission_metadata import *
22
+ from .mappings.ex102_abs import *
23
+
24
+ from pathlib import Path
25
+ import csv
22
26
  # need to check if mappings correctly create new columns
23
27
  class Table():
24
28
  def __init__(self, data, type,accession):
@@ -27,11 +31,18 @@ class Table():
27
31
  self.type = type
28
32
  self.data = data
29
33
  self.accession = accession
30
- self.columns = self.determine_columns()
34
+ self.columns = self.determine_columns_complete()
35
+
36
+ def determine_columns_complete(self):
37
+ if not self.data:
38
+ return []
39
+ return list(set().union(*(row.keys() for row in self.data)))
40
+
31
41
 
32
42
  def determine_columns(self):
33
43
  if len(self.data) == 0:
34
44
  return []
45
+
35
46
  return self.data[0].keys()
36
47
 
37
48
  def add_column(self,column_name,value):
@@ -227,7 +238,11 @@ class Table():
227
238
  mapping_dict = item_9_24f2nt_dict
228
239
  elif self.type == 'signature_info_schedule_a':
229
240
  mapping_dict = signature_24f2nt_dict
230
-
241
+ # ABS
242
+ elif self.type == 'assets_ex102_absee':
243
+ mapping_dict = assets_dict_ex102_abs
244
+ elif self.type =='properties_ex102_absee':
245
+ mapping_dict = properties_dict_ex102_abs
231
246
  # submission metadata
232
247
  elif self.type == 'document_submission_metadata':
233
248
  mapping_dict = document_submission_metadata_dict
@@ -250,9 +265,6 @@ class Table():
250
265
  for old_key, new_key in mapping_dict.items():
251
266
  if old_key in row:
252
267
  ordered_row[new_key] = row.pop(old_key)
253
- else:
254
- # if the old key is not present, set the new key to None
255
- ordered_row[new_key] = None
256
268
 
257
269
  # Then add any remaining keys that weren't in the mapping
258
270
  for key, value in row.items():
@@ -262,4 +274,30 @@ class Table():
262
274
  row.clear()
263
275
  row.update(ordered_row)
264
276
 
265
- self.determine_columns()
277
+ # Update the columns after mapping
278
+ columns = set(self.columns)
279
+ # remove the old columns that are now in the mapping
280
+ columns.difference_update(mapping_dict.keys())
281
+ # add the new columns from the mapping
282
+ columns.update(mapping_dict.values())
283
+ # add the accession column to the columns
284
+ columns.add('accession')
285
+
286
+ self.columns = list(columns)
287
+
288
+ def write_csv(self, output_file):
289
+ output_file = Path(output_file)
290
+ fieldnames = self.columns
291
+
292
+ # Check if the file already exists
293
+ if output_file.exists():
294
+ # Append to existing file without writing header
295
+ with open(output_file, 'a', newline='') as csvfile:
296
+ writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_ALL)
297
+ writer.writerows(self.data)
298
+ else:
299
+ # Create new file with header
300
+ with open(output_file, 'w', newline='') as csvfile:
301
+ writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_ALL)
302
+ writer.writeheader()
303
+ writer.writerows(self.data)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: datamule
3
- Version: 1.2.6
3
+ Version: 1.2.7
4
4
  Summary: Making it easier to use SEC filings.
5
5
  Home-page: https://github.com/john-friedman/datamule-python
6
6
  Author: John Friedman
@@ -19,6 +19,7 @@ datamule/document/table.py
19
19
  datamule/document/mappings/__init__.py
20
20
  datamule/document/mappings/atsn.py
21
21
  datamule/document/mappings/cfportal.py
22
+ datamule/document/mappings/ex102_abs.py
22
23
  datamule/document/mappings/ex99a_sdr.py
23
24
  datamule/document/mappings/ex99c_sdr.py
24
25
  datamule/document/mappings/ex99g_sdr.py
@@ -30,7 +30,7 @@ if not file_path.exists():
30
30
  setup(
31
31
  name="datamule",
32
32
  author="John Friedman",
33
- version="1.2.6",
33
+ version="1.2.7",
34
34
  description="Making it easier to use SEC filings.",
35
35
  packages=find_packages(include=['datamule', 'datamule.*']),
36
36
  url="https://github.com/john-friedman/datamule-python",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes