Skip to content

Commit 256650f

Browse files
committed
Update UT
1 parent cb953b4 commit 256650f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+236810
-133137
lines changed

absbox/local/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143

144144
validCutoffFields = {
145145
"资产池规模": "IssuanceBalance"
146-
,"IssuanceBalance": "IssuanceBalance"
146+
,"发行规模": "IssuanceBalance"
147147
,"CumulativeDefaults":"HistoryDefaults"
148148
,"累计违约余额":"HistoryDefaults"
149149
}

absbox/local/component.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from absbox.local.util import mkTag, mkTs, readTagStr, subMap, subMap2, renameKs, ensure100
22
from absbox.local.util import mapListValBy, uplift_m_list, mapValsBy, allList, getValWithKs, applyFnToKey,flat
33
from absbox.local.util import earlyReturnNone, mkFloatTs, mkRateTs, mkRatioTs, mkTbl, mapNone, guess_pool_flow_header
4-
from absbox.local.util import filter_by_tags, enumVals, lmap, readTagMap, patchDicts
4+
from absbox.local.util import filter_by_tags, enumVals, lmap, readTagMap, patchDicts,updateKs
55
from absbox.local.base import *
66

77
import sys
@@ -1193,6 +1193,7 @@ def mkWaterfall(r, x):
11931193
r[_w_tag] = lmap(mkAction, _v)
11941194
return mkWaterfall(r, x)
11951195

1196+
11961197
def mkRoundingType(x):
11971198
match x:
11981199
case ["floor", r]:
@@ -1202,6 +1203,7 @@ def mkRoundingType(x):
12021203
case _:
12031204
raise RuntimeError(f"Failed to match {x}:mkRoundingType")
12041205

1206+
12051207
def mkAssetRate(x):
12061208
match x:
12071209
case ["固定", r] | ["fix", r]:
@@ -1297,6 +1299,7 @@ def mkAccRule(x):
12971299
case _ :
12981300
raise RuntimeError(f"Failed to match {x}:mkAccRule")
12991301

1302+
13001303
def mkInvoiceFeeType(x):
13011304
match x :
13021305
case ("Fixed", amt) | ("固定", amt):
@@ -1312,6 +1315,7 @@ def mkInvoiceFeeType(x):
13121315
case _:
13131316
raise RuntimeError(f"Failed to match {x}:mkInvoiceFeeType")
13141317

1318+
13151319
def mkCapacity(x):
13161320
match x:
13171321
case ("固定", c) | ("Fixed", c):
@@ -1321,6 +1325,7 @@ def mkCapacity(x):
13211325
case _ :
13221326
raise RuntimeError(f"Failed to match {x}:mkCapacity")
13231327

1328+
13241329
def mkObligor(x:dict) -> dict:
13251330
def mkObligorFields(y:dict) -> dict:
13261331
if not y:
@@ -1462,7 +1467,7 @@ def id_by_pool_assets(z):
14621467
return "MDeal"
14631468
case {"assets": [], "futureCf": cfs} if cfs['contents'][1][0]['tag'] == 'MortgageFlow':
14641469
return "MDeal"
1465-
case {"assets": [{'tag': 'Installment'}, *rest]}:
1470+
case {"assets": [{'tag': 'Installment'}, *rest]} :
14661471
return "IDeal"
14671472
case {"assets": [{'tag': 'Lease'}, *rest]} | {"assets": [{'tag': 'RegularLease'}, *rest]}:
14681473
return "RDeal"
@@ -1474,28 +1479,34 @@ def id_by_pool_assets(z):
14741479
return "VDeal"
14751480
case {"assets": [{'tag': 'ProjectedFlowMix'}, *rest]} | {"assets": [{'tag': 'ProjectedFlowMixFloater'}, *rest]}:
14761481
return "PDeal"
1482+
case {"assets": [{'tag': 'IL'}, *rest]} | {"assets": [{'tag': 'MO'}, *rest]} | \
1483+
{"assets": [{'tag': 'LO'}, *rest]} | {"assets": [{'tag': 'LS'}, *rest]} | \
1484+
{"assets": [{'tag': 'FA'}, *rest]} | {"assets": [{'tag': 'RE'}, *rest]} | \
1485+
{"assets": [{'tag': 'PF'}, *rest]} :
1486+
return "UDeal"
14771487
case _:
1478-
raise RuntimeError(f"Failed to identify deal type {z}")
1488+
raise RuntimeError(f"Failed to identify pool type {z}")
14791489
y = None
14801490
match x:
1491+
# single pool
14811492
case {"pool":{"tag":"MultiPool","contents":{"PoolConsol":{"assets":[]}}}} if len(x['pool']['contents']['PoolConsol']['futureCf'])>0:
14821493
return id_by_pool_assets(x['pool']['contents']['PoolConsol'])
14831494
case {"pool":{"tag":"MultiPool","contents":{"PoolConsol":{"assets":assetList}}}} if len(assetList) > 1:
14841495
return id_by_pool_assets(x['pool']['contents']['PoolConsol'])
1496+
# multiple pools
14851497
case {"pool":{"tag":"MultiPool","contents":poolMap}}:
14861498
pools = list(map(id_by_pool_assets, poolMap & lens.Values().collect()))
1487-
14881499
if len(set(pools))>1:
14891500
return "UDeal"
14901501
else:
14911502
return pools[0]
1503+
# resec deals
14921504
case {"pool":{"tag":"ResecDeal"}}:
14931505
vs = [ v['deal'] for k,v in x["pool"]['contents'].items() ]
14941506
assetTypes = set(map(identify_deal_type, vs))
14951507
if len(assetTypes)>1:
14961508
return "UDeal"
14971509
else:
1498-
print(assetTypes, "<<<")
14991510
return list(assetTypes)[0]
15001511
case _:
15011512
raise RuntimeError(f"Failed to match pool type {x}")
@@ -1789,25 +1800,30 @@ def mkPoolType(assetDate, x, mixedFlag) -> dict:
17891800
{"deal":dealObj.json['contents'],"future":None,"futureScheduleCf":None,"issuanceStat":None}\
17901801
for ((bn,pct,sd),dealObj) in x['deals'].items()} ))
17911802
case x if all([ isinstance(_,dict) for _ in x.values() ]):
1792-
return mkTag(("MultiPool" ,{f"PoolName:{k}":mkPoolComp(vDate(assetDate),v,mixedFlag) for (k,v) in x.items()}))
1803+
return mkTag(("MultiPool"
1804+
,{f"PoolName:{k}":mkPoolComp(vDate(assetDate),v,mixedFlag)
1805+
for (k,v) in x.items()})
1806+
)
17931807
case _ :
17941808
raise RuntimeError("Failed to match pool type ",x)
17951809

17961810

17971811
def mkPoolComp(asOfDate, x, mixFlag) -> dict:
1798-
assetFactory = mkAsset if (not mixFlag) else mkAssetUnion
1799-
r = {"assets": [assetFactory(y) for y in getValWithKs(x, ['assets', "清单"],defaultReturn=[])]
1812+
assetFactory = mkAssetUnion if mixFlag else mkAsset
1813+
r = {"assets": [assetFactory(y) for y in getValWithKs(x, ['assets', "清单"], defaultReturn=[])]
18001814
, "asOfDate": asOfDate
1801-
, "issuanceStat": getValWithKs(x,["issuanceStat", "统计", "发行","Issuance"])
1802-
, "futureCf":mkCf(getValWithKs(x,['cashflow', '现金流归集表', '归集表'],[]))
1803-
, "extendPeriods":mkDatePattern(getValWithKs(x,['extendBy'], "MonthEnd"))}
1815+
, "issuanceStat": tz.pipe(getValWithKs(x, ["issuanceStat", "统计", "发行", "Issuance"],defaultReturn={})
1816+
, lambda y: updateKs(y, validCutoffFields)
1817+
)
1818+
, "futureCf":mkCf(getValWithKs(x, ['cashflow', '现金流归集表', '归集表'], []))
1819+
, "extendPeriods":mkDatePattern(getValWithKs(x, ['extendBy'], "MonthEnd"))}
18041820
return r
18051821

18061822

18071823
def mkPool(x: dict):
18081824
mapping = {"LDeal": "LPool", "MDeal": "MPool",
18091825
"IDeal": "IPool", "RDeal": "RPool", "FDeal":"FPool",
1810-
"VDeal": "VPool", "UDeal":"UPool"}
1826+
"VDeal": "VPool", "UDeal": "UPool"}
18111827
match x:
18121828
case {"清单": assets, "封包日": d} | {"assets": assets, "cutoffDate": d}:
18131829
_pool = {"assets": [mkAsset(a) for a in assets] , "asOfDate": d}
@@ -1898,7 +1914,8 @@ def mkCf(x:list):
18981914
else:
18991915
cfs = [mkTag(("MortgageFlow", _x+[0.0]*5+[None,None,None])) for _x in x]
19001916
return mkTag(("CashFlowFrame", [[0,"1900-01-01",None],cfs]))
1901-
1917+
1918+
19021919
def mkCashFlowFrame(x):
19031920
""" Make cashflow frame """
19041921
flows = x.get("flows",[])
@@ -2208,6 +2225,7 @@ def mkRateAssumption(x):
22082225
case _ :
22092226
raise RuntimeError(f"Failed to match RateAssumption:{x}")
22102227

2228+
22112229
def mkFundingPlan(x:tuple):
22122230
# IssueBondEvent mPre bondName accountName Bond mFormula mFormula
22132231
match x:
@@ -2229,6 +2247,7 @@ def mkRefiPlan(x:tuple):
22292247
case _:
22302248
raise RuntimeError(f"Failed to match mkRefinancePlan:{x}")
22312249

2250+
22322251
def mkInspect(x):
22332252
match x:
22342253
case (dp,ds) if isinstance(ds, tuple):

absbox/local/generic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def json(self) -> dict:
7070
"custom": tz.valmap(mkCustom, self.custom) if self.custom else None,
7171
"triggers": renameKs2({k: {_k: mkTrigger(_v) for (_k,_v) in v.items() } for (k, v) in self.trigger.items()},englishDealCycle) if self.trigger else None,
7272
"liqProvider": {ln: mkLiqProvider(ln, lo | {"start":lastCloseDate} )
73-
for ln,lo in self.liqFacility.items() } if self.liqFacility else None,
73+
for ln,lo in self.liqFacility.items() } if self.liqFacility else None,
7474
"ledgers": {ln: mkLedger(ln, v) for ln,v in self.ledgers.items()} if self.ledgers else None
7575
}
7676

absbox/local/util.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,19 @@ def applyFnToKey(m: dict, f, k, applyNone=False):
211211
return m
212212

213213

214-
def renameKs2(m: dict, kmapping):
214+
def renameKs2(m: dict, kmapping:dict) -> dict:
215215
''' Given a map, rename ks from a key-mapping '''
216216
assert isinstance(m, dict), "M is not a map"
217217
assert isinstance(kmapping, dict), f"Mapping is not a map: {kmapping}"
218218
assert set(m.keys()).issubset(set(kmapping.keys())), f"{m.keys()} not in {kmapping.keys()}"
219219
return {kmapping[k]: v for k, v in m.items()}
220220

221+
def updateKs(m: dict, kmapping:dict) -> dict:
222+
''' Given a map, update ks from a key-mapping '''
223+
assert isinstance(m, dict), "M is not a map"
224+
assert isinstance(kmapping, dict), f"Mapping is not a map: {kmapping}"
225+
226+
return {kmapping.get(k,k):v for k,v in m.items()}
221227

222228
def ensure100(xs, msg=""):
223229
assert sum(xs) == 1.0, f"Doesn't not sum up 100%: {msg}"
@@ -436,9 +442,11 @@ def enumVals(e) -> list:
436442
''' return a list of enum values '''
437443
return [_.value for _ in [*e]]
438444

445+
439446
def readCfFromLst(lst:list)-> pd.DataFrame:
440447
return None
441448

449+
442450
def tupleToDictWithKey(xs,key="name"):
443451
return dict([ (n,x|{key:n}) for (n,x) in xs ])
444452

absbox/report.py

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,7 @@ def toHtml(r:dict, p:str, style=OutputType.Plain, debug=False):
7979
,("MultiLedger", readLedgers(ledgerDf[1]))
8080
,("MultiTrigger", readTriggers(r.get("triggers",{})))
8181
])
82-
# section 5
83-
#triggerDf = ("Trigger", r.get("triggers",{}))
84-
#section5 = [ div[ h2(id=f"anchor-{_t}")[_t]
85-
# , [ div[ h3(id=f"anchor-{_t}-{k}")[k]
86-
# #, div[">",list(v.items())]
87-
# ,buildSection([ (j,k) for j,k in v.items()], title_=(h4,h5), anchor=f"{_t}-{k}")
88-
# ]
89-
# for k,v in x.items() if v is not None]
90-
# ]
91-
# for (_t, x) in [triggerDf] if x is not None]
82+
9283

9384
dealName = r['_deal']['contents']['name']
9485
c = html[

absbox/tests/benchmark/china/out/test01.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
}
6969
],
7070
"asOfDate": "2021-03-31",
71-
"issuanceStat": null,
71+
"issuanceStat": {},
7272
"futureCf": null,
7373
"extendPeriods": {
7474
"tag": "MonthEnd"

absbox/tests/benchmark/china/out/test02.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
}
6969
],
7070
"asOfDate": "2021-03-01",
71-
"issuanceStat": null,
71+
"issuanceStat": {},
7272
"futureCf": null,
7373
"extendPeriods": {
7474
"tag": "MonthEnd"

absbox/tests/benchmark/china/out/test03.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
}
7777
],
7878
"asOfDate": "2021-03-01",
79-
"issuanceStat": null,
79+
"issuanceStat": {},
8080
"futureCf": null,
8181
"extendPeriods": {
8282
"tag": "MonthEnd"

absbox/tests/benchmark/china/out/test04.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
}
6969
],
7070
"asOfDate": "2022-10-02",
71-
"issuanceStat": null,
71+
"issuanceStat": {},
7272
"futureCf": null,
7373
"extendPeriods": {
7474
"tag": "MonthEnd"

absbox/tests/benchmark/china/out/test05.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@
9999
}
100100
],
101101
"asOfDate": "2021-03-01",
102-
"issuanceStat": null,
102+
"issuanceStat": {},
103103
"futureCf": null,
104104
"extendPeriods": {
105105
"tag": "MonthEnd"

0 commit comments

Comments
 (0)