Skip to content

Commit 804a60b

Browse files
authored
Merge pull request #10 from iamtatsuki05/feature/update_template
update template
2 parents b246b61 + a899918 commit 804a60b

13 files changed

Lines changed: 1808 additions & 1447 deletions

File tree

.github/workflows/test_poetry.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ jobs:
1717

1818
strategy:
1919
matrix:
20-
python-version: [3.10.11]
20+
python-version: [3.12]
2121

2222
steps:
2323
- name: Checkout repository

docker/cpu/Dockerfile

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
FROM ubuntu:22.04 AS base
1+
FROM ubuntu:24.04 AS base
22

3-
ARG PYTHON_VERSION=3.10
3+
ARG PYTHON_VERSION=3.12
44

55
ENV DEBIAN_FRONTEND=noninteractive
66
ENV WORKDIR /app/
@@ -28,18 +28,21 @@ ENV LANG en_US.UTF-8
2828
ENV LANGUAGE en_US
2929

3030
# install Python
31-
RUN apt-get update && apt-get -yV upgrade && DEBIAN_FRONTEND=noninteractive apt-get -yV install \
32-
build-essential libssl-dev libffi-dev \
33-
python${PYTHON_VERSION} python${PYTHON_VERSION}-distutils python${PYTHON_VERSION}-dev \
34-
&& ln -s /usr/bin/python${PYTHON_VERSION} /usr/local/bin/python3 \
35-
&& ln -s /usr/bin/python${PYTHON_VERSION} /usr/local/bin/python \
36-
&& apt-get clean \
37-
&& rm -rf /var/lib/apt/lists/*
38-
39-
## install pip
40-
RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py \
41-
&& python3 get-pip.py \
42-
&& pip3 --no-cache-dir install --upgrade pip
31+
RUN apt-get update \
32+
&& apt-get install -y --no-install-recommends \
33+
software-properties-common \
34+
&& add-apt-repository ppa:deadsnakes/ppa -y \
35+
&& apt-get update \
36+
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
37+
build-essential libssl-dev libffi-dev \
38+
python${PYTHON_VERSION} \
39+
python${PYTHON_VERSION}-dev \
40+
python3-pip \
41+
# python${PYTHON_VERSION}-distutils \ # for python3.12
42+
&& ln -s /usr/bin/python${PYTHON_VERSION} /usr/local/bin/python3 \
43+
&& ln -s /usr/bin/python${PYTHON_VERSION} /usr/local/bin/python \
44+
&& apt-get purge -y --auto-remove software-properties-common \
45+
&& rm -rf /var/lib/apt/lists/*
4346

4447
## install Poetry
4548
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv

pyproject.toml

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "project"
33
version = "0.1.0"
44
description = "Add your description here"
5-
requires-python = ">=3.10"
5+
requires-python = ">=3.12"
66
dependencies = [
77
"python-dotenv>=1.0.0",
88
"setuptools>=69.0.3",
@@ -12,19 +12,19 @@ dependencies = [
1212
"selenium>=4.16.0",
1313
"fastapi>=0.108.0",
1414
"uvicorn>=0.25.0",
15-
"matplotlib>=3.5.1",
15+
"matplotlib>=3.9.0",
1616
"pandas>=1.4.2",
1717
"seaborn>=0.11.2",
1818
"japanize-matplotlib>=1.1.3",
19-
"numpy>=1.22.3",
20-
"jupyterlab>=3.3.4",
19+
"numpy>=2.2.0",
2120
"tqdm>=4.64.0",
22-
"scikit-learn>=1.1.1",
21+
"scikit-learn>=1.6.0",
2322
"openpyxl>=3.1.2",
2423
"polars>=0.20.31",
2524
"aiohttp>=3.9.5",
2625
"tenacity>=8.4.1",
2726
"playwright>=1.44.0",
27+
"toml>=0.10.2",
2828
]
2929

3030
[tool.hatch.build.targets.wheel]
@@ -33,17 +33,20 @@ packages = ["src/project", "src"]
3333
[tool.uv]
3434
dev-dependencies = [
3535
"jupyterlab>=3.3.4",
36+
"marimo>=0.13.3",
3637
"mypy>=1.11.2",
3738
"nbstripout>=0.7.1",
3839
"pre-commit>=4.0.1",
3940
"pytest>=8.3.3",
4041
"ruff>=0.6.9",
4142
"tox>=4.21.2",
43+
"types-pyyaml>=6.0.12.20250402",
44+
"types-toml>=0.10.8.20240310",
4245
]
4346

4447
[tool.ruff]
4548
line-length = 119
46-
target-version = "py310"
49+
target-version = "py312"
4750
exclude = [".git", ".venv", "__pycache__", "data", "dist", "misc", "notebooks", "prof", "tmp", "workspacea", ".tox"]
4851

4952
[tool.ruff.format]
@@ -68,7 +71,7 @@ split-on-trailing-comma = true
6871
keep-runtime-typing = true
6972

7073
[tool.mypy]
71-
python_version="3.10"
74+
python_version="3.12"
7275
files = "src"
7376
ignore_missing_imports = true
7477
disallow_untyped_defs = true
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import asyncio
2+
from typing import Any, Callable
3+
4+
5+
def sync_to_async_func(sync_func: Callable) -> Callable:
6+
"""
7+
同期関数を非同期関数として使えるように変換する
8+
"""
9+
10+
async def wrapper(*args: Any, **kwargs: Any) -> Any:
11+
return await asyncio.to_thread(sync_func, *args, **kwargs)
12+
13+
wrapper.__name__ = sync_func.__name__
14+
wrapper.__doc__ = sync_func.__doc__
15+
return wrapper
16+
17+
18+
def async_to_sync_func(async_func: Callable) -> Callable:
19+
"""
20+
非同期関数を同期関数として使えるように変換する
21+
"""
22+
23+
def wrapper(*args: Any, **kwargs: Any) -> Any:
24+
return asyncio.run(async_func(*args, **kwargs))
25+
26+
wrapper.__name__ = async_func.__name__
27+
wrapper.__doc__ = async_func.__doc__
28+
return wrapper
29+
30+
31+
async def run_async_function_with_semaphore(
32+
async_func: Callable, concurrency_sema: asyncio.Semaphore | None, *args: Any, **kwargs: Any
33+
) -> Any:
34+
"""
35+
指定した関数 func を、セマフォで同時実行数を制限して呼び出す関数。
36+
concurrency_sema が None の場合は制限しない。
37+
"""
38+
if concurrency_sema is not None:
39+
async with concurrency_sema:
40+
return await async_func(*args, **kwargs)
41+
else:
42+
return await async_func(*args, **kwargs)

src/project/common/utils/file/__init__.py

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from pathlib import Path
2+
from typing import Any
3+
4+
from project.common.utils.file.json import load_json
5+
from project.common.utils.file.toml import load_toml
6+
from project.common.utils.file.yaml import load_yaml
7+
8+
9+
def load_config(path: str | Path) -> dict[str, Any]:
10+
"""
11+
Load configuration from a file (JSON, YAML, or TOML).
12+
"""
13+
ext = Path(path).suffix.lower()
14+
if ext == '.json':
15+
return load_json(path)
16+
elif ext in ('.yaml', '.yml'):
17+
return load_yaml(path)
18+
elif ext == '.toml':
19+
return load_toml(path)
20+
else:
21+
raise ValueError(f'Unsupported config file format: {ext}')
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import json
2+
from pathlib import Path
3+
4+
5+
def load_json(path: str | Path) -> dict | list:
6+
with Path(path).open(mode='r', encoding='utf-8') as fin:
7+
data = json.load(fin)
8+
return data
9+
10+
11+
def save_as_indented_json(
12+
data: dict | list,
13+
path: str | Path,
14+
parents: bool = True,
15+
exist_ok: bool = True,
16+
) -> None:
17+
path = Path(path)
18+
path.parent.mkdir(parents=parents, exist_ok=exist_ok)
19+
with path.open(mode='w', encoding='utf-8') as fout:
20+
json.dump(data, fout, ensure_ascii=False, indent=4, separators=(',', ': '))
21+
return
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from pathlib import Path
2+
3+
import jsonlines
4+
5+
6+
def load_jsonlines(path: str | Path) -> list[dict]:
7+
data_list = []
8+
with jsonlines.open(str(path)) as reader:
9+
for data in reader:
10+
data_list.append(data)
11+
return data_list
12+
13+
14+
def save_as_jsonlines(
15+
data: list[dict],
16+
path: str | Path,
17+
parents: bool = True,
18+
exist_ok: bool = True,
19+
) -> None:
20+
path = Path(path)
21+
path.parent.mkdir(parents=parents, exist_ok=exist_ok)
22+
with jsonlines.open(str(path), mode='w') as writer:
23+
for datum in data:
24+
writer.write(datum)
25+
return
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from pathlib import Path
2+
3+
import toml
4+
5+
6+
def load_toml(path: str | Path) -> dict:
7+
with Path(path).open(mode='r', encoding='utf-8') as fin:
8+
data = toml.load(fin)
9+
return data
10+
11+
12+
def save_as_toml(
13+
data: dict,
14+
path: str | Path,
15+
parents: bool = True,
16+
exist_ok: bool = True,
17+
) -> None:
18+
path = Path(path)
19+
path.parent.mkdir(parents=parents, exist_ok=exist_ok)
20+
with path.open(mode='w', encoding='utf-8') as fout:
21+
toml.dump(data, fout)
22+
return
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from pathlib import Path
2+
3+
import yaml
4+
5+
6+
def load_yaml(path: str | Path) -> dict | list:
7+
with Path(path).open(mode='r', encoding='utf-8') as fin:
8+
data = yaml.safe_load(fin)
9+
return data
10+
11+
12+
def save_as_indented_yaml(
13+
data: dict | list,
14+
path: str | Path,
15+
parents: bool = True,
16+
exist_ok: bool = True,
17+
) -> None:
18+
path = Path(path)
19+
path.parent.mkdir(parents=parents, exist_ok=exist_ok)
20+
with path.open(mode='w', encoding='utf-8') as fout:
21+
yaml.dump(data, fout, allow_unicode=True, indent=4, default_flow_style=False)
22+
return

0 commit comments

Comments
 (0)