krx-hj3415 2.0.0__py3-none-any.whl → 2.2.0__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.
- krx_hj3415/__init__.py +0 -0
- {krx → krx_hj3415}/cli.py +13 -15
- krx_hj3415/domain/diff.py +33 -0
- krx_hj3415/domain/types.py +30 -0
- krx/samsungfund.py → krx_hj3415/provider/krx300_samsungfund_excel.py +8 -14
- krx/universe_service.py → krx_hj3415/usecases/sync_universe.py +56 -31
- {krx_hj3415-2.0.0.dist-info → krx_hj3415-2.2.0.dist-info}/METADATA +1 -1
- krx_hj3415-2.2.0.dist-info/RECORD +11 -0
- krx_hj3415-2.2.0.dist-info/entry_points.txt +3 -0
- krx/__init__.py +0 -12
- krx/models.py +0 -52
- krx_hj3415-2.0.0.dist-info/RECORD +0 -10
- krx_hj3415-2.0.0.dist-info/entry_points.txt +0 -3
- {krx_hj3415-2.0.0.dist-info → krx_hj3415-2.2.0.dist-info}/WHEEL +0 -0
- {krx_hj3415-2.0.0.dist-info → krx_hj3415-2.2.0.dist-info}/licenses/LICENSE +0 -0
krx_hj3415/__init__.py
ADDED
|
File without changes
|
{krx → krx_hj3415}/cli.py
RENAMED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
#
|
|
1
|
+
# krx_hj3415/cli.py
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
5
|
import typer
|
|
6
6
|
|
|
7
|
-
from .
|
|
7
|
+
from db2_hj3415.mongo import mongo_from_env
|
|
8
|
+
from db2_hj3415.settings import get_settings
|
|
9
|
+
from db2_hj3415.universe.repo import ensure_indexes as ensure_indexes_universe
|
|
10
|
+
from db2_hj3415.nfs.repo import ensure_indexes as ensure_indexes_nfs
|
|
11
|
+
|
|
12
|
+
from krx_hj3415.usecases.sync_universe import run_sync, apply_removed
|
|
8
13
|
|
|
9
14
|
app = typer.Typer(no_args_is_help=True)
|
|
10
15
|
|
|
@@ -27,15 +32,10 @@ async def _maybe_await_close(mongo: object) -> None:
|
|
|
27
32
|
await out
|
|
28
33
|
|
|
29
34
|
|
|
30
|
-
async def
|
|
31
|
-
from db2.settings import get_settings
|
|
32
|
-
from db2.nfs import ensure_indexes
|
|
33
|
-
from db2.universe import ensure_indexes_universe # 네 db2에 구현돼있다는 가정
|
|
34
|
-
|
|
35
|
+
async def _mongo_bootstrap(db) -> None:
|
|
35
36
|
s = get_settings()
|
|
36
|
-
|
|
37
|
-
await
|
|
38
|
-
await ensure_indexes_universe(db)
|
|
37
|
+
await ensure_indexes_universe(db, snapshot_ttl_days=s.SNAPSHOT_TTL_DAYS)
|
|
38
|
+
await ensure_indexes_nfs(db, snapshot_ttl_days=s.SNAPSHOT_TTL_DAYS)
|
|
39
39
|
|
|
40
40
|
|
|
41
41
|
@app.command()
|
|
@@ -53,14 +53,12 @@ def sync(
|
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
55
|
async def _run():
|
|
56
|
-
from db2.mongo import mongo_from_env
|
|
57
|
-
|
|
58
56
|
mongo = mongo_from_env()
|
|
59
57
|
db = mongo.get_db()
|
|
60
58
|
try:
|
|
61
|
-
await
|
|
59
|
+
await _mongo_bootstrap(db)
|
|
62
60
|
|
|
63
|
-
d = await
|
|
61
|
+
d = await run_sync(db, universe=universe, max_days=max_days, snapshot=snapshot)
|
|
64
62
|
|
|
65
63
|
typer.echo(f"\n=== UNIVERSE SYNC: {d.universe} ===")
|
|
66
64
|
typer.echo(f"asof: {d.asof.isoformat()}")
|
|
@@ -82,7 +80,7 @@ def sync(
|
|
|
82
80
|
|
|
83
81
|
if apply and d.removed:
|
|
84
82
|
typer.echo("\n=== APPLY REMOVED TO NFS ===")
|
|
85
|
-
r = await
|
|
83
|
+
r = await apply_removed(db, removed_codes=d.removed_codes)
|
|
86
84
|
typer.echo(
|
|
87
85
|
f"latest_deleted={r.get('latest_deleted', 0)}, "
|
|
88
86
|
f"snapshots_deleted={r.get('snapshots_deleted', 0)}"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# krx_hj3415/domain/diff.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Iterable
|
|
6
|
+
from .types import UniverseDiff, CodeItem
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _to_code_map(items: Iterable[CodeItem]) -> dict[str, CodeItem]:
|
|
10
|
+
return {it.code: it for it in items}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def diff_universe(
|
|
14
|
+
*,
|
|
15
|
+
universe: str,
|
|
16
|
+
asof: datetime,
|
|
17
|
+
new_items: list[CodeItem],
|
|
18
|
+
old_items: list[CodeItem],
|
|
19
|
+
) -> UniverseDiff:
|
|
20
|
+
new_map = _to_code_map(new_items)
|
|
21
|
+
old_map = _to_code_map(old_items)
|
|
22
|
+
|
|
23
|
+
added = [new_map[c] for c in sorted(new_map.keys() - old_map.keys())]
|
|
24
|
+
removed = [old_map[c] for c in sorted(old_map.keys() - new_map.keys())]
|
|
25
|
+
kept = len(new_map.keys() & old_map.keys())
|
|
26
|
+
|
|
27
|
+
return UniverseDiff(
|
|
28
|
+
universe=universe,
|
|
29
|
+
asof=asof,
|
|
30
|
+
added=added,
|
|
31
|
+
removed=removed,
|
|
32
|
+
kept_count=kept,
|
|
33
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# krx_hj3415/domain/types.py
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from datetime import datetime
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass(frozen=True)
|
|
9
|
+
class CodeItem:
|
|
10
|
+
code: str
|
|
11
|
+
name: str
|
|
12
|
+
asof: datetime
|
|
13
|
+
market: str | None = None # 확장 대비(예: KRX/KOSPI/KOSDAQ/NYSE/NASDAQ 등)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class UniverseDiff:
|
|
18
|
+
universe: str
|
|
19
|
+
asof: datetime
|
|
20
|
+
added: list[CodeItem]
|
|
21
|
+
removed: list[CodeItem]
|
|
22
|
+
kept_count: int
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def added_codes(self) -> list[str]:
|
|
26
|
+
return [x.code for x in self.added]
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def removed_codes(self) -> list[str]:
|
|
30
|
+
return [x.code for x in self.removed]
|
|
@@ -1,35 +1,29 @@
|
|
|
1
|
-
#
|
|
1
|
+
# krx_hj3415/provider/krx300_samsungfund_excel.py
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import random
|
|
5
5
|
import time
|
|
6
|
-
from dataclasses import dataclass
|
|
7
|
-
from datetime import datetime, timedelta, timezone
|
|
8
|
-
from io import BytesIO
|
|
9
|
-
from typing import Iterable
|
|
10
|
-
|
|
11
6
|
import pandas as pd
|
|
12
7
|
import requests
|
|
8
|
+
from datetime import datetime, timedelta, timezone
|
|
9
|
+
from io import BytesIO
|
|
13
10
|
|
|
14
|
-
from .
|
|
11
|
+
from domain_hj3415.common.time import utcnow
|
|
12
|
+
from krx_hj3415.domain.types import CodeItem
|
|
15
13
|
|
|
16
14
|
|
|
17
15
|
FUND_ID = "2ETFA4"
|
|
18
16
|
BASE_URL = "https://www.samsungfund.com/excel_pdf.do"
|
|
19
17
|
|
|
20
18
|
|
|
21
|
-
def _utcnow() -> datetime:
|
|
22
|
-
return datetime.now(timezone.utc)
|
|
23
|
-
|
|
24
|
-
|
|
25
19
|
def _looks_like_excel(content: bytes) -> bool:
|
|
26
20
|
# xls(ole) or xlsx(zip) 대충 체크
|
|
27
|
-
return content.startswith(b"\
|
|
21
|
+
return content.startswith(b"\xd0\xcf\x11\xe0") or content.startswith(b"PK\x03\x04")
|
|
28
22
|
|
|
29
23
|
|
|
30
24
|
def find_valid_url(*, max_days: int = 15, timeout: int = 8) -> tuple[str, datetime]:
|
|
31
25
|
for delta in range(1, max_days + 1):
|
|
32
|
-
day = (
|
|
26
|
+
day = (utcnow() - timedelta(days=delta)).astimezone(timezone.utc)
|
|
33
27
|
date_str = day.strftime("%Y%m%d")
|
|
34
28
|
url = f"{BASE_URL}?fId={FUND_ID}&gijunYMD={date_str}"
|
|
35
29
|
|
|
@@ -84,4 +78,4 @@ def parse_krx300_items(excel_bytes: bytes, *, asof: datetime) -> list[CodeItem]:
|
|
|
84
78
|
def fetch_krx300_items(*, max_days: int = 15) -> tuple[datetime, list[CodeItem]]:
|
|
85
79
|
excel_bytes, asof_day, _url = download_excel_bytes(max_days=max_days)
|
|
86
80
|
items = parse_krx300_items(excel_bytes, asof=asof_day)
|
|
87
|
-
return asof_day, items
|
|
81
|
+
return asof_day, items
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
#
|
|
1
|
+
# krx_hj3415/usecases/sync_universe.py
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
from typing import Any, Iterable
|
|
7
|
-
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, Iterable, cast
|
|
8
6
|
from pymongo.asynchronous.database import AsyncDatabase
|
|
9
7
|
|
|
10
|
-
from .
|
|
11
|
-
from .samsungfund import fetch_krx300_items
|
|
12
|
-
|
|
8
|
+
from domain_hj3415.common.time import utcnow
|
|
13
9
|
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
from db2_hj3415.nfs.repo import delete_codes_from_nfs
|
|
11
|
+
from db2_hj3415.universe.repo import (
|
|
12
|
+
upsert_latest as upsert_universe_latest,
|
|
13
|
+
insert_snapshot as insert_universe_snapshot,
|
|
14
|
+
)
|
|
15
|
+
from db2_hj3415.universe.repo import get_latest as get_universe_latest
|
|
16
16
|
|
|
17
|
+
from contracts_hj3415.universe.dto import UniverseItemDTO, Market
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
from krx_hj3415.domain.types import CodeItem, UniverseDiff
|
|
20
|
+
from krx_hj3415.domain.diff import diff_universe
|
|
21
|
+
from krx_hj3415.provider.krx300_samsungfund_excel import fetch_krx300_items
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def _payload_to_items(payload: Any) -> list[CodeItem]:
|
|
@@ -32,7 +33,11 @@ def _payload_to_items(payload: Any) -> list[CodeItem]:
|
|
|
32
33
|
return []
|
|
33
34
|
|
|
34
35
|
data = payload
|
|
35
|
-
if
|
|
36
|
+
if (
|
|
37
|
+
isinstance(data, dict)
|
|
38
|
+
and "payload" in data
|
|
39
|
+
and isinstance(data["payload"], dict)
|
|
40
|
+
):
|
|
36
41
|
data = data["payload"]
|
|
37
42
|
|
|
38
43
|
if isinstance(data, dict) and "items" in data:
|
|
@@ -56,7 +61,7 @@ def _payload_to_items(payload: Any) -> list[CodeItem]:
|
|
|
56
61
|
asof = asof_raw
|
|
57
62
|
else:
|
|
58
63
|
# fallback: 현재 시각 (정확도가 중요하면 ISO parse 추가)
|
|
59
|
-
asof =
|
|
64
|
+
asof = utcnow()
|
|
60
65
|
out.append(CodeItem(code=code, name=name, asof=asof, market=market))
|
|
61
66
|
return out
|
|
62
67
|
|
|
@@ -66,7 +71,31 @@ async def refresh_krx300(*, max_days: int = 15) -> tuple[datetime, list[CodeItem
|
|
|
66
71
|
return fetch_krx300_items(max_days=max_days)
|
|
67
72
|
|
|
68
73
|
|
|
69
|
-
|
|
74
|
+
def to_universe_item_dtos(items: Iterable[Any], *, market: str = "KRX") -> list[UniverseItemDTO]:
|
|
75
|
+
out: list[UniverseItemDTO] = []
|
|
76
|
+
for it in items:
|
|
77
|
+
if it is None:
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
if isinstance(it, dict):
|
|
81
|
+
code = (it.get("code") or "").strip()
|
|
82
|
+
name = it.get("name")
|
|
83
|
+
else:
|
|
84
|
+
code = (getattr(it, "code", "") or "").strip()
|
|
85
|
+
name = getattr(it, "name", None)
|
|
86
|
+
|
|
87
|
+
if not code:
|
|
88
|
+
continue
|
|
89
|
+
|
|
90
|
+
dto: UniverseItemDTO = {"code": code, "market": cast(Market, market)}
|
|
91
|
+
if isinstance(name, str) and name.strip():
|
|
92
|
+
dto["name"] = name.strip()
|
|
93
|
+
|
|
94
|
+
out.append(dto)
|
|
95
|
+
return out
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
async def run_sync(
|
|
70
99
|
db: AsyncDatabase,
|
|
71
100
|
*,
|
|
72
101
|
universe: str = "krx300",
|
|
@@ -86,23 +115,27 @@ async def refresh_and_diff(
|
|
|
86
115
|
asof, new_items = await refresh_krx300(max_days=max_days)
|
|
87
116
|
|
|
88
117
|
# --- 2) load old ---
|
|
89
|
-
from db2.universe import get_universe_latest # ✅ db2에 구현돼있다고 가정
|
|
90
118
|
old_doc = await get_universe_latest(db, universe=universe)
|
|
91
119
|
old_items = _payload_to_items(old_doc)
|
|
92
120
|
|
|
93
121
|
# --- 3) diff ---
|
|
94
|
-
d = diff_universe(
|
|
122
|
+
d = diff_universe(
|
|
123
|
+
universe=universe, asof=asof, new_items=new_items, old_items=old_items
|
|
124
|
+
)
|
|
95
125
|
|
|
96
126
|
# --- 4) save ---
|
|
97
|
-
|
|
98
|
-
|
|
127
|
+
await upsert_universe_latest(
|
|
128
|
+
db, universe=universe, items=to_universe_item_dtos(new_items), asof=asof
|
|
129
|
+
)
|
|
99
130
|
if snapshot:
|
|
100
|
-
await insert_universe_snapshot(
|
|
131
|
+
await insert_universe_snapshot(
|
|
132
|
+
db, universe=universe, items=to_universe_item_dtos(new_items), asof=asof
|
|
133
|
+
)
|
|
101
134
|
|
|
102
135
|
return d
|
|
103
136
|
|
|
104
137
|
|
|
105
|
-
async def
|
|
138
|
+
async def apply_removed(
|
|
106
139
|
db: AsyncDatabase,
|
|
107
140
|
*,
|
|
108
141
|
removed_codes: Iterable[str],
|
|
@@ -114,12 +147,4 @@ async def apply_removed_to_nfs(
|
|
|
114
147
|
if not codes:
|
|
115
148
|
return {"latest_deleted": 0, "snapshots_deleted": 0}
|
|
116
149
|
|
|
117
|
-
|
|
118
|
-
# 예: delete_codes_from_all_endpoints(db, codes)
|
|
119
|
-
try:
|
|
120
|
-
from db2.nfs import delete_codes_from_all_endpoints # ✅ 네가 추가했다고 가정
|
|
121
|
-
return await delete_codes_from_all_endpoints(db, codes=codes)
|
|
122
|
-
except Exception:
|
|
123
|
-
# fallback: 이미 있는 delete_codes_from_nfs(endpoint=None) 사용
|
|
124
|
-
from db2.nfs import delete_codes_from_nfs
|
|
125
|
-
return await delete_codes_from_nfs(db, codes=codes, endpoint=None) # type: ignore[arg-type]
|
|
150
|
+
return await delete_codes_from_nfs(db, codes=codes, endpoint=None)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
krx_hj3415/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
krx_hj3415/cli.py,sha256=F6ZpX8k1fNwtsRv59ixv3d1dPSnmWyxwXZbzu61ViWI,3174
|
|
3
|
+
krx_hj3415/domain/diff.py,sha256=m6nl73Anjx2si6vr9a-FXdH5iKVHh_4kXF9RHgplSdY,847
|
|
4
|
+
krx_hj3415/domain/types.py,sha256=-ERCYZXLX0LGjqEthcrBUpNWgBf2tJ5NgHE5Zxg2pls,663
|
|
5
|
+
krx_hj3415/provider/krx300_samsungfund_excel.py,sha256=WCQAeBsED5Cp9-4lZcptifwX1yY_-XRAP4iO8w5kb0A,2776
|
|
6
|
+
krx_hj3415/usecases/sync_universe.py,sha256=jlhMdKJsFbBD87kX0Y4eiuQdxVDWcpv07OJ45_bMFlg,4489
|
|
7
|
+
krx_hj3415-2.2.0.dist-info/entry_points.txt,sha256=qasj01Y1e0MIVlUXOraAZCAxDTn07CyMVV58hrYDamA,42
|
|
8
|
+
krx_hj3415-2.2.0.dist-info/licenses/LICENSE,sha256=QBiVGQuKAESeCfQE344Ik2ex6g2zfYdu9WqrRWydxIs,1068
|
|
9
|
+
krx_hj3415-2.2.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
10
|
+
krx_hj3415-2.2.0.dist-info/METADATA,sha256=ob5DNLcwjFtsTKN5dTpEVNS06YKpJAc-qZV54I4Wxw4,2309
|
|
11
|
+
krx_hj3415-2.2.0.dist-info/RECORD,,
|
krx/__init__.py
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# krx/__init__.py
|
|
2
|
-
from .models import CodeItem, UniverseDiff
|
|
3
|
-
from .samsungfund import fetch_krx300_items
|
|
4
|
-
from .universe_service import refresh_and_diff, apply_removed_to_nfs
|
|
5
|
-
|
|
6
|
-
__all__ = [
|
|
7
|
-
"CodeItem",
|
|
8
|
-
"UniverseDiff",
|
|
9
|
-
"fetch_krx300_items",
|
|
10
|
-
"refresh_and_diff",
|
|
11
|
-
"apply_removed_to_nfs",
|
|
12
|
-
]
|
krx/models.py
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# krx/models.py
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from datetime import datetime
|
|
6
|
-
from typing import Any, Iterable
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass(frozen=True)
|
|
10
|
-
class CodeItem:
|
|
11
|
-
code: str
|
|
12
|
-
name: str
|
|
13
|
-
asof: datetime
|
|
14
|
-
market: str | None = None # 확장 대비(예: KRX/KOSPI/KOSDAQ/NYSE/NASDAQ 등)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
@dataclass(frozen=True)
|
|
18
|
-
class UniverseDiff:
|
|
19
|
-
universe: str
|
|
20
|
-
asof: datetime
|
|
21
|
-
added: list[CodeItem]
|
|
22
|
-
removed: list[CodeItem]
|
|
23
|
-
kept_count: int
|
|
24
|
-
|
|
25
|
-
@property
|
|
26
|
-
def added_codes(self) -> list[str]:
|
|
27
|
-
return [x.code for x in self.added]
|
|
28
|
-
|
|
29
|
-
@property
|
|
30
|
-
def removed_codes(self) -> list[str]:
|
|
31
|
-
return [x.code for x in self.removed]
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
def _to_code_map(items: Iterable[CodeItem]) -> dict[str, CodeItem]:
|
|
35
|
-
return {it.code: it for it in items}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def diff_universe(*, universe: str, asof: datetime, new_items: list[CodeItem], old_items: list[CodeItem]) -> UniverseDiff:
|
|
39
|
-
new_map = _to_code_map(new_items)
|
|
40
|
-
old_map = _to_code_map(old_items)
|
|
41
|
-
|
|
42
|
-
added = [new_map[c] for c in sorted(new_map.keys() - old_map.keys())]
|
|
43
|
-
removed = [old_map[c] for c in sorted(old_map.keys() - new_map.keys())]
|
|
44
|
-
kept = len(new_map.keys() & old_map.keys())
|
|
45
|
-
|
|
46
|
-
return UniverseDiff(
|
|
47
|
-
universe=universe,
|
|
48
|
-
asof=asof,
|
|
49
|
-
added=added,
|
|
50
|
-
removed=removed,
|
|
51
|
-
kept_count=kept,
|
|
52
|
-
)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
krx/__init__.py,sha256=eqkijmpo1DwxMnxdBMYwgOj7yGynD6F8m8WjZpZ8RSk,302
|
|
2
|
-
krx/cli.py,sha256=dE9n_AYZxT8VIndlitLsTJmp5T59lAGqLeV64P0WfJ4,3191
|
|
3
|
-
krx/models.py,sha256=l35-C8jH32UOEBnHhFklE13P5ZDTg9Wft__WhSSqbxg,1342
|
|
4
|
-
krx/samsungfund.py,sha256=m6add740cBQFgxZ5rW9xYXp_JBKKK03Y-bzb01GVq4w,2815
|
|
5
|
-
krx/universe_service.py,sha256=xBhDSl1iGBgSQDZ8x7SZ8zzz2H4eS5j19HKOgxMJggo,4224
|
|
6
|
-
krx_hj3415-2.0.0.dist-info/entry_points.txt,sha256=OR4WCHhNKwt2oBeySB2bSapcjl5SADj7kvEcxo44dPo,35
|
|
7
|
-
krx_hj3415-2.0.0.dist-info/licenses/LICENSE,sha256=QBiVGQuKAESeCfQE344Ik2ex6g2zfYdu9WqrRWydxIs,1068
|
|
8
|
-
krx_hj3415-2.0.0.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
9
|
-
krx_hj3415-2.0.0.dist-info/METADATA,sha256=XvX6CAl-qmD4ROEoO4OZz3oxXv1QQm7sFbYkIr73Xiw,2309
|
|
10
|
-
krx_hj3415-2.0.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|