kabukit 0.7.0__py3-none-any.whl → 0.7.2__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.
@@ -4,4 +4,4 @@ from .prices import plot_prices
4
4
  __all__ = [
5
5
  "plot_prices",
6
6
  "plot_topix_timeseries",
7
- ]
7
+ ]
kabukit/core/base.py CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import datetime
4
4
  from typing import TYPE_CHECKING
5
+ from zoneinfo import ZoneInfo
5
6
 
6
7
  import polars as pl
7
8
 
@@ -30,7 +31,7 @@ class Base:
30
31
  def write(self) -> Path:
31
32
  data_dir = self.data_dir()
32
33
  data_dir.mkdir(parents=True, exist_ok=True)
33
- path = datetime.datetime.today().strftime("%Y%m%d") # noqa: DTZ002
34
+ path = datetime.datetime.now(ZoneInfo("Asia/Tokyo")).strftime("%Y%m%d")
34
35
  filename = data_dir / f"{path}.parquet"
35
36
  self.data.write_parquet(filename)
36
37
  return filename
kabukit/core/info.py CHANGED
@@ -1,12 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
4
-
5
3
  from .base import Base
6
4
 
7
- if TYPE_CHECKING:
8
- from polars import DataFrame
9
-
10
5
 
11
6
  class Info(Base):
12
7
  pass
kabukit/core/list.py CHANGED
@@ -1,12 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
4
-
5
3
  from .base import Base
6
4
 
7
- if TYPE_CHECKING:
8
- from polars import DataFrame
9
-
10
5
 
11
6
  class List(Base):
12
7
  pass
kabukit/core/reports.py CHANGED
@@ -1,12 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import TYPE_CHECKING
4
-
5
3
  from .base import Base
6
4
 
7
- if TYPE_CHECKING:
8
- from polars import DataFrame
9
-
10
5
 
11
6
  class Reports(Base):
12
7
  pass
kabukit/edinet/client.py CHANGED
@@ -6,7 +6,9 @@ import zipfile
6
6
  from enum import StrEnum
7
7
  from typing import TYPE_CHECKING
8
8
 
9
+ import httpx
9
10
  from polars import DataFrame
11
+ from tenacity import retry, retry_if_exception, stop_after_attempt, wait_exponential
10
12
 
11
13
  from kabukit.core.client import Client
12
14
  from kabukit.utils.config import load_dotenv
@@ -24,6 +26,11 @@ API_VERSION = "v2"
24
26
  BASE_URL = f"https://api.edinet-fsa.go.jp/api/{API_VERSION}"
25
27
 
26
28
 
29
+ def is_retryable(e: BaseException) -> bool:
30
+ """Return True if the exception is a retryable network error."""
31
+ return isinstance(e, (httpx.ConnectTimeout, httpx.ReadTimeout, httpx.ConnectError))
32
+
33
+
27
34
  class AuthKey(StrEnum):
28
35
  """Environment variable keys for EDINET authentication."""
29
36
 
@@ -43,6 +50,12 @@ class EdinetClient(Client):
43
50
  if api_key:
44
51
  self.client.params = {"Subscription-Key": api_key}
45
52
 
53
+ @retry(
54
+ reraise=True,
55
+ stop=stop_after_attempt(3),
56
+ wait=wait_exponential(multiplier=1, min=2, max=10),
57
+ retry=retry_if_exception(is_retryable),
58
+ )
46
59
  async def get(self, url: str, params: QueryParamTypes) -> Response:
47
60
  resp = await self.client.get(url, params=params)
48
61
  resp.raise_for_status()
kabukit/edinet/doc.py CHANGED
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import datetime
4
4
  from typing import TYPE_CHECKING
5
+ from zoneinfo import ZoneInfo
5
6
 
6
7
  import polars as pl
7
8
 
@@ -11,7 +12,11 @@ if TYPE_CHECKING:
11
12
 
12
13
  def clean_list(df: DataFrame, date: str | datetime.date) -> DataFrame:
13
14
  if isinstance(date, str):
14
- date = datetime.datetime.strptime(date, "%Y-%m-%d").date() # noqa: DTZ007
15
+ date = (
16
+ datetime.datetime.strptime(date, "%Y-%m-%d")
17
+ .replace(tzinfo=ZoneInfo("Asia/Tokyo"))
18
+ .date()
19
+ )
15
20
 
16
21
  null_columns = [c for c in df.columns if df[c].dtype == pl.Null]
17
22
 
@@ -21,7 +26,11 @@ def clean_list(df: DataFrame, date: str | datetime.date) -> DataFrame:
21
26
  )
22
27
  .with_columns(
23
28
  pl.lit(date).alias("Date"),
24
- pl.col("^.+DateTime$").str.to_datetime("%Y-%m-%d %H:%M", strict=False),
29
+ pl.col("^.+DateTime$").str.to_datetime(
30
+ "%Y-%m-%d %H:%M",
31
+ strict=False,
32
+ time_zone="Asia/Tokyo",
33
+ ),
25
34
  pl.col("^period.+$").str.to_date("%Y-%m-%d", strict=False),
26
35
  pl.col("^.+Flag$").cast(pl.Int8).cast(pl.Boolean),
27
36
  pl.col("^.+Code$").cast(pl.String),
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ import polars as pl
4
+ from polars import DataFrame
5
+
6
+
7
+ def clean(df: DataFrame) -> DataFrame:
8
+ return df.with_columns(
9
+ pl.col("Date").str.to_date("%Y-%m-%d"),
10
+ pl.col("HolidayDivision").cast(pl.Categorical),
11
+ pl.col("HolidayDivision").eq("1").not_().alias("IsHoliday"),
12
+ )
kabukit/jquants/client.py CHANGED
@@ -1,9 +1,11 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import asyncio
3
4
  import datetime
4
5
  import os
5
6
  from enum import StrEnum
6
- from typing import TYPE_CHECKING
7
+ from typing import TYPE_CHECKING, final
8
+ from zoneinfo import ZoneInfo
7
9
 
8
10
  import polars as pl
9
11
  from polars import DataFrame
@@ -12,7 +14,7 @@ from kabukit.core.client import Client
12
14
  from kabukit.utils.config import load_dotenv, set_key
13
15
  from kabukit.utils.params import get_params
14
16
 
15
- from . import info, prices, statements, topix
17
+ from . import calendar, info, prices, statements, topix
16
18
 
17
19
  if TYPE_CHECKING:
18
20
  from collections.abc import AsyncIterator
@@ -21,6 +23,25 @@ if TYPE_CHECKING:
21
23
  from httpx import HTTPStatusError # noqa: F401
22
24
  from httpx._types import QueryParamTypes
23
25
 
26
+
27
+ @final
28
+ class _CalendarCache:
29
+ def __init__(self) -> None:
30
+ self._holidays: list[datetime.date] | None = None
31
+ self._lock = asyncio.Lock()
32
+
33
+ async def get_holidays(self, client: JQuantsClient) -> list[datetime.date]:
34
+ async with self._lock:
35
+ if self._holidays is None:
36
+ df = await client.get_calendar()
37
+ holidays = df.filter(pl.col("IsHoliday"))["Date"]
38
+ self._holidays = holidays.to_list()
39
+ return self._holidays
40
+
41
+
42
+ _calendar_cache_manager = _CalendarCache()
43
+
44
+
24
45
  API_VERSION = "v1"
25
46
  BASE_URL = f"https://api.jquants.com/{API_VERSION}"
26
47
 
@@ -128,32 +149,6 @@ class JQuantsClient(Client):
128
149
  self.set_id_token(id_token)
129
150
  return self
130
151
 
131
- async def get_info(
132
- self,
133
- code: str | None = None,
134
- date: str | datetime.date | None = None,
135
- *,
136
- clean: bool = True,
137
- ) -> DataFrame:
138
- """銘柄情報を取得する。
139
-
140
- Args:
141
- code (str, optional): 情報を取得する銘柄のコード。
142
- date (str | datetime.date, optional): 情報を取得する日付。
143
- clean (bool, optional): 取得したデータをクリーンアップするかどうか。
144
-
145
- Returns:
146
- 銘柄情報を含むDataFrame。
147
-
148
- Raises:
149
- HTTPStatusError: APIリクエストが失敗した場合。
150
- """
151
- params = get_params(code=code, date=date)
152
- url = "/listed/info"
153
- data = await self.get(url, params)
154
- df = DataFrame(data["info"])
155
- return info.clean(df) if clean else df
156
-
157
152
  async def iter_pages(
158
153
  self,
159
154
  url: str,
@@ -183,6 +178,32 @@ class JQuantsClient(Client):
183
178
  else:
184
179
  break
185
180
 
181
+ async def get_info(
182
+ self,
183
+ code: str | None = None,
184
+ date: str | datetime.date | None = None,
185
+ *,
186
+ clean: bool = True,
187
+ ) -> DataFrame:
188
+ """銘柄情報を取得する。
189
+
190
+ Args:
191
+ code (str, optional): 情報を取得する銘柄のコード。
192
+ date (str | datetime.date, optional): 情報を取得する日付。
193
+ clean (bool, optional): 取得したデータをクリーンアップするかどうか。
194
+
195
+ Returns:
196
+ 銘柄情報を含むDataFrame。
197
+
198
+ Raises:
199
+ HTTPStatusError: APIリクエストが失敗した場合。
200
+ """
201
+ params = get_params(code=code, date=date)
202
+ url = "/listed/info"
203
+ data = await self.get(url, params)
204
+ df = DataFrame(data["info"])
205
+ return info.clean(df) if clean else df
206
+
186
207
  async def get_prices(
187
208
  self,
188
209
  code: str | None = None,
@@ -240,7 +261,7 @@ class JQuantsClient(Client):
240
261
  clean: bool = True,
241
262
  ) -> DataFrame:
242
263
  """直近利用可能な日付の株価を取得する。"""
243
- today = datetime.date.today() # noqa: DTZ011
264
+ today = datetime.datetime.now(ZoneInfo("Asia/Tokyo")).date()
244
265
 
245
266
  for days in range(num_days):
246
267
  date = today - datetime.timedelta(days)
@@ -291,7 +312,11 @@ class JQuantsClient(Client):
291
312
 
292
313
  df = statements.clean(df)
293
314
 
294
- return statements.with_date(df) if with_date else df
315
+ if not with_date:
316
+ return df
317
+
318
+ holidays = await _calendar_cache_manager.get_holidays(self)
319
+ return statements.with_date(df, holidays=holidays)
295
320
 
296
321
  async def get_announcement(self) -> DataFrame:
297
322
  """翌日発表予定の決算情報を取得する。
@@ -310,7 +335,7 @@ class JQuantsClient(Client):
310
335
  if df.is_empty():
311
336
  return df
312
337
 
313
- return df.with_columns(pl.col("Date").str.to_date("%Y-%m-%d", strict=False))
338
+ return df.with_columns(pl.col("Date").str.to_date("%Y-%m-%d"))
314
339
 
315
340
  async def get_trades_spec(
316
341
  self,
@@ -341,7 +366,7 @@ class JQuantsClient(Client):
341
366
  if df.is_empty():
342
367
  return df
343
368
 
344
- return df.with_columns(pl.col("^.*Date$").str.to_date("%Y-%m-%d", strict=False))
369
+ return df.with_columns(pl.col("^.*Date$").str.to_date("%Y-%m-%d"))
345
370
 
346
371
  async def get_topix(
347
372
  self,
@@ -371,3 +396,38 @@ class JQuantsClient(Client):
371
396
  return df
372
397
 
373
398
  return topix.clean(df)
399
+
400
+ async def get_calendar(
401
+ self,
402
+ holidaydivision: str | None = None,
403
+ from_: str | datetime.date | None = None,
404
+ to: str | datetime.date | None = None,
405
+ ) -> DataFrame:
406
+ """東証およびOSEにおける営業日、休業日、ならびにOSEにおける祝日取引の有無の情報を取得する。
407
+
408
+ Args:
409
+ holidaydivision: 祝日区分。
410
+ - 非営業日: "0"
411
+ - 営業日: "1"
412
+ - 東証半日立会日: "2"
413
+ - 非営業日(祝日取引あり): "3"
414
+ from_: 取得期間の開始日。
415
+ to: 取得期間の終了日。
416
+
417
+ Returns:
418
+ 営業日・非営業日データを含むPolars DataFrame。
419
+
420
+ Raises:
421
+ HTTPStatusError: APIリクエストが失敗した場合。
422
+ """
423
+ params = get_params(holidaydivision=holidaydivision, from_=from_, to=to)
424
+
425
+ url = "/markets/trading_calendar"
426
+ name = "trading_calendar"
427
+
428
+ dfs = [df async for df in self.iter_pages(url, params, name)]
429
+ df = pl.concat(dfs)
430
+ if df.is_empty():
431
+ return df
432
+
433
+ return calendar.clean(df)
@@ -1,10 +1,8 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import datetime
4
- from functools import cache
5
4
  from typing import TYPE_CHECKING
6
5
 
7
- import holidays
8
6
  import polars as pl
9
7
 
10
8
  if TYPE_CHECKING:
@@ -80,27 +78,15 @@ def _cast_bool(df: DataFrame) -> DataFrame:
80
78
  )
81
79
 
82
80
 
83
- @cache
84
- def get_holidays(year: int | None = None, n: int = 10) -> list[datetime.date]:
85
- """指定した過去年数の日本の祝日を取得する。"""
86
- if year is None:
87
- year = datetime.datetime.now().year # noqa: DTZ005
88
-
89
- dates = holidays.country_holidays("JP", years=range(year - n, year + 1))
90
- return sorted(dates.keys())
91
-
92
-
93
- def with_date(df: DataFrame, year: int | None = None) -> DataFrame:
81
+ def with_date(df: DataFrame, holidays: list[datetime.date]) -> DataFrame:
94
82
  """`Date`列を追加する。
95
83
 
96
- 開示日が休日のとき、あるいは、開示時刻が15時以降の場合、Dateを開示日の翌営業日に設定する。
84
+ 開示日が休日のとき、あるいは、開示時刻が15時30分以降の場合、Dateを開示日の翌営業日に設定する。
97
85
  """
98
86
  is_after_hours = pl.col("DisclosedTime").is_null() | (
99
- pl.col("DisclosedTime") > datetime.time(15, 0)
87
+ pl.col("DisclosedTime") >= datetime.time(15, 30)
100
88
  )
101
89
 
102
- holidays = get_holidays(year=year)
103
-
104
90
  return df.select(
105
91
  pl.when(is_after_hours)
106
92
  .then(pl.col("DisclosedDate") + datetime.timedelta(days=1))
@@ -150,5 +150,5 @@ async def fetch(
150
150
  if callback:
151
151
  stream = (x if (r := callback(x)) is None else r async for x in stream)
152
152
 
153
- dfs = [df async for df in stream if not df.is_empty()]
153
+ dfs = [df async for df in stream if not df.is_empty()] # ty: ignore[not-iterable]
154
154
  return pl.concat(dfs) if dfs else pl.DataFrame()
kabukit/utils/date.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import datetime
4
+ from zoneinfo import ZoneInfo
4
5
 
5
6
 
6
7
  def get_dates(days: int | None = None, years: int | None = None) -> list[datetime.date]:
@@ -11,7 +12,7 @@ def get_dates(days: int | None = None, years: int | None = None) -> list[datetim
11
12
  years (int | None): 過去years年の日付リストを取得する。
12
13
  daysが指定されている場合は無視される。
13
14
  """
14
- end_date = datetime.date.today() # noqa: DTZ011
15
+ end_date = datetime.datetime.now(ZoneInfo("Asia/Tokyo")).date()
15
16
 
16
17
  if days is not None:
17
18
  start_date = end_date - datetime.timedelta(days=days)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: kabukit
3
- Version: 0.7.0
3
+ Version: 0.7.2
4
4
  Summary: A Python toolkit for Japanese financial market data, supporting J-Quants and EDINET APIs.
5
5
  Author: daizutabi
6
6
  Author-email: daizutabi <daizutabi@gmail.com>
@@ -28,15 +28,17 @@ License: MIT License
28
28
  Classifier: Development Status :: 4 - Beta
29
29
  Classifier: Programming Language :: Python
30
30
  Classifier: Programming Language :: Python :: 3.13
31
+ Classifier: Programming Language :: Python :: 3.14
31
32
  Requires-Dist: async-typer>=0.1.10
32
- Requires-Dist: holidays>=0.82
33
33
  Requires-Dist: httpx>=0.28.1
34
- Requires-Dist: platformdirs>=4.4.0
34
+ Requires-Dist: platformdirs>=4.5.0
35
35
  Requires-Dist: polars>=1.34.0
36
36
  Requires-Dist: python-dotenv>=1.1.1
37
- Requires-Dist: rich>=14.1.0
37
+ Requires-Dist: rich>=14.2.0
38
+ Requires-Dist: tenacity>=9.1.2
38
39
  Requires-Dist: tqdm>=4.67.1
39
40
  Requires-Dist: typer>=0.19.2
41
+ Requires-Dist: tzdata ; sys_platform == 'win32'
40
42
  Requires-Python: >=3.13
41
43
  Project-URL: Documentation, https://daizutabi.github.io/kabukit/
42
44
  Project-URL: Issues, https://github.com/daizutabi/kabukit/issues
@@ -3,7 +3,7 @@ kabukit/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
3
3
  kabukit/analysis/indicators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  kabukit/analysis/preprocess.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  kabukit/analysis/screener.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- kabukit/analysis/visualization/__init__.py,sha256=2_9-CnbpCbdMEfypQS9MmFmcJJL_G5V5R2HRWhuKgKM,136
6
+ kabukit/analysis/visualization/__init__.py,sha256=4ommaflk8WK9plu5HecUQuK9ORLZA050M7E1fGAbAeE,137
7
7
  kabukit/analysis/visualization/market.py,sha256=M45dPi7BUsYxl8JEy_aE_uIi4r7Y6Hv842QM7hEz0PM,886
8
8
  kabukit/analysis/visualization/prices.py,sha256=VS9WXBKcdOYsnVe-OR3cWP_nru3Oa-rBOK5SUwsxfyQ,1857
9
9
  kabukit/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -12,32 +12,33 @@ kabukit/cli/auth.py,sha256=E4M9ChDrtCb1DvYrAds33k6eKlXZUQCL9yCNPyTSnUk,2727
12
12
  kabukit/cli/cache.py,sha256=cHjpNPi1BnaPwXXIFEpbmjCA8Cvtov9yNcbRm12109M,1745
13
13
  kabukit/cli/get.py,sha256=z_bo1EdABkO0T4Mpdmb0qSIMVdWRWyopN7IX9VoTxxE,4815
14
14
  kabukit/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- kabukit/core/base.py,sha256=kHLTbqTX-ZFPpNjkIpe_fxsBzY4vD3Tjyf7zpyK20CY,1691
15
+ kabukit/core/base.py,sha256=WVFvv70n99GTqLkhkRnibLRgYP-eMh6lYY3R__q_YXY,1725
16
16
  kabukit/core/client.py,sha256=tVq1r3zpOfjmOtnRI1KPZHgTgBZYIpJzfw15i2kAM48,676
17
- kabukit/core/info.py,sha256=5BX7mDavF6g-b0KzHgKIFHUS5701BoaHtw1JcHSsy94,174
18
- kabukit/core/list.py,sha256=AjnXzC9XIu21l6IBEHHAS5VAnfxTfkAA9m1WAOZJNa8,174
17
+ kabukit/core/info.py,sha256=knL0rX18RNfra7iBhMK9H0GuaIapzYbxMeizkfuM1QM,88
18
+ kabukit/core/list.py,sha256=JQHE6aoYreE2Oik_LJ9x0xE7nmkGsx688XYASaVqooE,88
19
19
  kabukit/core/prices.py,sha256=dPNgCTFf-eE7-C-e_2vy9uqVZT7O55k2JKUNG1CPFX0,17728
20
- kabukit/core/reports.py,sha256=ch_xe84GbB17JTfmY3ArQqneQ2XOuvrAykBTAyNmWuM,177
20
+ kabukit/core/reports.py,sha256=G7p8IcUOHDopZJMxMLnYhss9hIq4gCKEXFixINQI_7w,91
21
21
  kabukit/core/statements.py,sha256=_n4-8G284e6y_MwhvUq4xBK4bapQHk-Zmwu09C_r7wU,2790
22
22
  kabukit/edinet/__init__.py,sha256=PKa4D-jVpeoOkdVp9NwwpgAiGEBjqvmJLmpzF-9SlVk,101
23
- kabukit/edinet/client.py,sha256=BlM7pjXpKweOo-ses41JiKinqRn4qerMN5NF7hgYKgg,3275
23
+ kabukit/edinet/client.py,sha256=HbxUvl6vKmfJ4-quIwCGspVOuHTMFbSolZXbhfG891U,3760
24
24
  kabukit/edinet/concurrent.py,sha256=2YPzIFuuOB8-gL3CnHIlP486QH5d21qjKNKGCFK7Hzk,4707
25
- kabukit/edinet/doc.py,sha256=6ZDgmm8DHmEMOA4NjNz-dHLMc7IzzYn-nVyMQGLWb8I,1220
25
+ kabukit/edinet/doc.py,sha256=plxJ-o5-8NzllHY7Sn0M8KbyIenDAfh5XISLfpq27Ag,1410
26
26
  kabukit/jquants/__init__.py,sha256=xY0H6x4_51ZBqbrT2TdmGGFbTD-hosZiDzVIz4UXPv0,112
27
- kabukit/jquants/client.py,sha256=eznqnueUMF2_px5dpCwry53FLyE2nKkI-L8nCu31rhk,12323
27
+ kabukit/jquants/calendar.py,sha256=Vz4Degedgx8qENHWri2MTkIbkuIRfO28CXRq7bZaHGE,333
28
+ kabukit/jquants/client.py,sha256=kp3xr8LH8NxO4lerzVseFPBvnUZw4grrpULExN89UoU,14241
28
29
  kabukit/jquants/concurrent.py,sha256=86xYD_zPLnR24xZhfSS0mAcUM-dvUvpozzyKASSHiwo,3345
29
30
  kabukit/jquants/info.py,sha256=MZbtg0L-YIkegWnCd3AvTs1AopV3z58ImgOnxgJgJbw,997
30
31
  kabukit/jquants/prices.py,sha256=oApQpdgzHwPw11XHpdg8ccZS7kybGtV8APZlpD2L3Yw,882
31
32
  kabukit/jquants/schema.py,sha256=aILl9cp9JDOaT2o3UlfavPGQC5s7n0ZkVBGKiTzdogs,9768
32
- kabukit/jquants/statements.py,sha256=fW9YGuqK5W64aWdYtVFzgF14L9H68HPdIfYWxSjc9yg,3173
33
+ kabukit/jquants/statements.py,sha256=CHJKwM44-TAUPMrieA1VVwHT89KpcXxEfJcbh9y-dWI,2752
33
34
  kabukit/jquants/topix.py,sha256=oU84WAbmd4U77fuKvj_EUpZv3Pu_Sf0HEW4Y0dB8508,326
34
35
  kabukit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
36
  kabukit/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- kabukit/utils/concurrent.py,sha256=aTiCS6nqQtWBy29xykLHSU1LTr6LuGraxEnZco99EIM,4692
37
+ kabukit/utils/concurrent.py,sha256=qR3gvhUBYOjwtVT_Hluy1g-XaaFL9ysHvZz3WUE8G1k,4720
37
38
  kabukit/utils/config.py,sha256=fqUdlhVjgiWEcsLFmPckp-dXUleVz8Ypdy_NnrMIBfY,708
38
- kabukit/utils/date.py,sha256=DEC6Ac5LS8eiW6JtrmcD3U1pX4qzXtx4ale0swpO4Ag,937
39
+ kabukit/utils/date.py,sha256=eB5ONCkqnvOiAg1Hvg1pN4OkrxLR47urvOAD5BF5yL0,982
39
40
  kabukit/utils/params.py,sha256=qcaJbf6CWPUoZAZsYDTaZSnBUWeAersbWnR_iiYW9GM,1108
40
- kabukit-0.7.0.dist-info/WHEEL,sha256=eh7sammvW2TypMMMGKgsM83HyA_3qQ5Lgg3ynoecH3M,79
41
- kabukit-0.7.0.dist-info/entry_points.txt,sha256=vvX771TemoM-35vVizW3JJ70HvRXnd2tX4P1Btzyoxs,46
42
- kabukit-0.7.0.dist-info/METADATA,sha256=kqpmNY2iY7O-uNJLB26-z48YXY7x96UkWYcZlHvIraQ,3263
43
- kabukit-0.7.0.dist-info/RECORD,,
41
+ kabukit-0.7.2.dist-info/WHEEL,sha256=X16MKk8bp2DRsAuyteHJ-9qOjzmnY0x1aj0P1ftqqWA,78
42
+ kabukit-0.7.2.dist-info/entry_points.txt,sha256=vvX771TemoM-35vVizW3JJ70HvRXnd2tX4P1Btzyoxs,46
43
+ kabukit-0.7.2.dist-info/METADATA,sha256=bOioHG440DSt2ywamoIM3vqD87lp1qMUPgkZUZy1u30,3363
44
+ kabukit-0.7.2.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.8.24
2
+ Generator: uv 0.9.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any