Skip to content

Commit 8a2fdf6

Browse files
black fmt
1 parent e9a5bff commit 8a2fdf6

7 files changed

Lines changed: 250 additions & 132 deletions

File tree

pymort/XML.py

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,49 @@
77

88
# The following classes represent the xml elements in the XTbML file https://mort.soa.org/About.aspx
99

10+
1011
@dataclass
1112
class AxisDef:
1213
"""
1314
Corresponds to the XML element having the same name.
1415
"""
16+
1517
ScaleType: str
1618
AxisName: str
1719
MinScaleValue: int
1820
MaxScaleValue: int
1921
Increment: int
2022

23+
2124
@dataclass
2225
class MetaData:
2326
"""
2427
Corresponds to the XML element having the same name.
2528
"""
29+
2630
ScalingFactor: float
2731
DataType: str
2832
Nation: str
2933
TableDescription: str
3034
AxisDefs: List[AxisDef]
3135

36+
3237
@dataclass
3338
class Table:
3439
"""
3540
Corresponds to the XML element having the same name.
3641
"""
42+
3743
MetaData: MetaData
3844
Values: pd.DataFrame
3945

46+
4047
@dataclass
4148
class ContentClassification:
4249
"""
4350
Corresponds to the XML element having the same name.
4451
"""
52+
4553
TableIdentity: int
4654
ProviderDomain: str
4755
ProviderName: str
@@ -52,11 +60,12 @@ class ContentClassification:
5260
Comments: str
5361
KeyWords: List[str]
5462

63+
5564
class MortXML:
5665
"""A Python wrapper for XML mortality tables.
5766
58-
A tree of nested Python classes that represent an `XML standard <https://mort.soa.org/About.aspx/>`_
59-
used by tables hosted at `mort.soa.org <https://mort.soa.org/>`_.
67+
A tree of nested Python classes that represent an `XML standard <https://mort.soa.org/About.aspx/>`_
68+
used by tables hosted at `mort.soa.org <https://mort.soa.org/>`_.
6069
6170
Corresponds to the `XTbML` root element in the XML file.
6271
@@ -65,43 +74,50 @@ class MortXML:
6574
tables (List[Table]): Corresponds to Table XML elements.
6675
6776
"""
77+
6878
def __init__(self, id: int):
6979
"""
7080
Takes the id of a table and returns the PyXML object.
7181
72-
Args:
82+
Args:
7383
id (int): The id of the table to be loaded.
7484
"""
7585
root = ET.fromstring(importlib.resources.read_text(data, f"t{id}.xml"))
76-
self.ContentClassification: ContentClassification = createContentClassification(root.find('./ContentClassification'))
86+
self.ContentClassification: ContentClassification = createContentClassification(
87+
root.find("./ContentClassification")
88+
)
7789
self.Tables: List[Table] = createTables(root)
7890

91+
7992
# The following functions turn XML elements into Python objects.
8093

94+
8195
def createAxisDef(axisDef: ET.Element) -> AxisDef:
82-
'''
96+
"""
8397
Given an xml <AxisDef> element, return an AxisDef object
84-
'''
98+
"""
8599
return AxisDef(
86-
axisDef.find('./ScaleType').text,
87-
axisDef.find('./AxisName').text,
88-
int(axisDef.find('./MinScaleValue').text),
89-
int(axisDef.find('./MaxScaleValue').text),
90-
int(axisDef.find('./Increment').text)
100+
axisDef.find("./ScaleType").text,
101+
axisDef.find("./AxisName").text,
102+
int(axisDef.find("./MinScaleValue").text),
103+
int(axisDef.find("./MaxScaleValue").text),
104+
int(axisDef.find("./Increment").text),
91105
)
92106

107+
93108
def createMetaData(metadata: ET.Element) -> MetaData:
94-
'''
109+
"""
95110
Given an xml <MetaData> element, return a MetaData object
96-
'''
111+
"""
97112
return MetaData(
98-
float(metadata.find('./ScalingFactor').text),
99-
metadata.find('./DataType').text,
100-
metadata.find('./Nation').text,
101-
metadata.find('./TableDescription').text,
102-
[createAxisDef(axisDef) for axisDef in metadata.findall('./AxisDef')]
113+
float(metadata.find("./ScalingFactor").text),
114+
metadata.find("./DataType").text,
115+
metadata.find("./Nation").text,
116+
metadata.find("./TableDescription").text,
117+
[createAxisDef(axisDef) for axisDef in metadata.findall("./AxisDef")],
103118
)
104119

120+
105121
def getAxisVals(axis: ET.Element) -> pd.DataFrame:
106122
"""
107123
Take the bottom level `Axis` tag (having no "t" attribute).
@@ -115,14 +131,15 @@ def getAxisVals(axis: ET.Element) -> pd.DataFrame:
115131
if "t" in axis.attrib:
116132
rowT = int(axis.attrib["t"])
117133
colTs = ts
118-
df = pd.DataFrame({"Age": [rowT]*len(vals), "Duration": colTs, "vals": vals})
134+
df = pd.DataFrame({"Age": [rowT] * len(vals), "Duration": colTs, "vals": vals})
119135
df.set_index(["Age", "Duration"], inplace=True)
120136
return df
121-
else: # one dimensional
137+
else: # one dimensional
122138
df = pd.DataFrame({"Age": ts, "vals": vals})
123139
df.set_index("Age", inplace=True)
124140
return df
125141

142+
126143
def createValues(table: ET.Element) -> pd.DataFrame:
127144
"""
128145
Take the top level `Table` tag and return a list
@@ -132,31 +149,36 @@ def createValues(table: ET.Element) -> pd.DataFrame:
132149
for axis in axes:
133150
dfs.append(getAxisVals(axis))
134151
return pd.concat(dfs)
135-
152+
153+
136154
def createTable(table: ET.Element) -> Table:
137-
'''
155+
"""
138156
Given an xml <Table> element, return a Table object
139-
'''
140-
metaData = createMetaData(table.find('./MetaData'))
157+
"""
158+
metaData = createMetaData(table.find("./MetaData"))
141159
values = createValues(table)
142160
return Table(metaData, values)
143161

162+
144163
def createTables(root: ET.Element) -> List[Table]:
145-
'''Given the root of an xml tree, return a list of Table objects'''
146-
return [createTable(table) for table in root.findall('./Table')]
164+
"""Given the root of an xml tree, return a list of Table objects"""
165+
return [createTable(table) for table in root.findall("./Table")]
166+
147167

148-
def createContentClassification(contentClassification: ET.Element) -> ContentClassification:
149-
'''
168+
def createContentClassification(
169+
contentClassification: ET.Element,
170+
) -> ContentClassification:
171+
"""
150172
Given an xml <ContentClassification> element, return a ContentClassification object
151-
'''
173+
"""
152174
return ContentClassification(
153-
int(contentClassification.find('./TableIdentity').text),
154-
contentClassification.find('./ProviderDomain').text,
155-
contentClassification.find('./ProviderName').text,
156-
contentClassification.find('./TableReference').text,
157-
contentClassification.find('./ContentType').text,
158-
contentClassification.find('./TableName').text,
159-
contentClassification.find('./TableDescription').text,
160-
contentClassification.find('./Comments').text,
161-
[keyword.text for keyword in contentClassification.findall('./KeyWord')]
162-
)
175+
int(contentClassification.find("./TableIdentity").text),
176+
contentClassification.find("./ProviderDomain").text,
177+
contentClassification.find("./ProviderName").text,
178+
contentClassification.find("./TableReference").text,
179+
contentClassification.find("./ContentType").text,
180+
contentClassification.find("./TableName").text,
181+
contentClassification.find("./TableDescription").text,
182+
contentClassification.find("./Comments").text,
183+
[keyword.text for keyword in contentClassification.findall("./KeyWord")],
184+
)

pymort/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@
22

33
from .relational import Relational, getIdGroup
44
from .XML import MortXML
5-
6-
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"""These are the XML files retrieved at the date given in the directory name"""
1+
"""These are the XML files retrieved at the date given in the directory name"""

pymort/relational.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from typing import Tuple
77
from itertools import groupby
88

9+
910
class Relational:
1011
"""Rate tables with primary/foreign keys.
1112
@@ -18,17 +19,26 @@ class Relational:
1819
metadata (pd.DataFrame): Composite primary key of `id`, `Age` is a MultiIndex. Column `vals` stores rates.
1920
2021
"""
22+
2123
def __init__(self):
2224
# These pickled files are generated using `scripts/createRelational.py`.
23-
self.metadata: pd.DataFrame = pickle.loads(importlib.resources.read_binary(pickled_tables, 'meta.pickle'))
24-
self.select: pd.DataFrame = pickle.loads(importlib.resources.read_binary(pickled_tables, 'sel.pickle'))
25-
self.ultimate: pd.DataFrame = pickle.loads(importlib.resources.read_binary(pickled_tables, 'ult.pickle'))
25+
self.metadata: pd.DataFrame = pickle.loads(
26+
importlib.resources.read_binary(pickled_tables, "meta.pickle")
27+
)
28+
self.select: pd.DataFrame = pickle.loads(
29+
importlib.resources.read_binary(pickled_tables, "sel.pickle")
30+
)
31+
self.ultimate: pd.DataFrame = pickle.loads(
32+
importlib.resources.read_binary(pickled_tables, "ult.pickle")
33+
)
34+
2635

2736
@dataclass
2837
class IdGroup:
2938
"""
3039
An IdGroup is a group of IDs that have the same study and grouping in the Relational().metadata pandas table
3140
"""
41+
3242
study: str
3343
grouping: str
3444
ids: Tuple[int]
@@ -45,9 +55,13 @@ def getIdGroup(targetId: int) -> IdGroup:
4555
meta.reset_index(inplace=True)
4656
# ensure that study/grouping groups are all consecutive
4757
meta.sort_values(by=["study", "grouping", "id"], inplace=True)
48-
for k, g in groupby(zip(meta.study, meta.grouping, meta.id, meta.gender, meta.risk), key=lambda x: (x[0], x[1])):
58+
for k, g in groupby(
59+
zip(meta.study, meta.grouping, meta.id, meta.gender, meta.risk),
60+
key=lambda x: (x[0], x[1]),
61+
):
4962
groupIds, genders, risks = zip(*[x[2:] for x in g])
5063
if targetId in groupIds:
5164
return IdGroup(k[0], k[1], groupIds, genders, risks)
52-
raise KeyError("Your table identifier is not in the pandas table Relational().metadata")
53-
65+
raise KeyError(
66+
"Your table identifier is not in the pandas table Relational().metadata"
67+
)

0 commit comments

Comments
 (0)