AtCoderStudyBooster 0.1.1__py3-none-any.whl → 0.3__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.
- atcdr/download.py +117 -94
- atcdr/generate.py +76 -23
- atcdr/main.py +5 -0
- atcdr/markdown.py +39 -0
- atcdr/open.py +27 -20
- atcdr/test.py +304 -142
- atcdr/util/execute.py +63 -0
- atcdr/util/filetype.py +105 -0
- atcdr/util/problem.py +36 -32
- {atcoderstudybooster-0.1.1.dist-info → atcoderstudybooster-0.3.dist-info}/METADATA +3 -3
- atcoderstudybooster-0.3.dist-info/RECORD +17 -0
- atcdr/util/filename.py +0 -137
- atcoderstudybooster-0.1.1.dist-info/RECORD +0 -15
- {atcoderstudybooster-0.1.1.dist-info → atcoderstudybooster-0.3.dist-info}/WHEEL +0 -0
- {atcoderstudybooster-0.1.1.dist-info → atcoderstudybooster-0.3.dist-info}/entry_points.txt +0 -0
atcdr/util/filetype.py
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
import os
|
2
|
+
from enum import Enum
|
3
|
+
from typing import Dict, List, Optional, TypeAlias
|
4
|
+
|
5
|
+
# ファイル名と拡張子の型エイリアスを定義
|
6
|
+
Filename: TypeAlias = str
|
7
|
+
Extension: TypeAlias = str
|
8
|
+
|
9
|
+
|
10
|
+
class Lang(Enum):
|
11
|
+
PYTHON = 'Python'
|
12
|
+
JAVASCRIPT = 'JavaScript'
|
13
|
+
JAVA = 'Java'
|
14
|
+
C = 'C'
|
15
|
+
CPP = 'C++'
|
16
|
+
CSHARP = 'C#'
|
17
|
+
RUBY = 'Ruby'
|
18
|
+
PHP = 'php'
|
19
|
+
GO = 'Go'
|
20
|
+
RUST = 'Rust'
|
21
|
+
HTML = 'HTML'
|
22
|
+
MARKDOWN = 'markdown'
|
23
|
+
JSON = 'json'
|
24
|
+
|
25
|
+
|
26
|
+
# ファイル拡張子と対応する言語の辞書
|
27
|
+
FILE_EXTENSIONS: Dict[Lang, str] = {
|
28
|
+
Lang.PYTHON: '.py',
|
29
|
+
Lang.JAVASCRIPT: '.js',
|
30
|
+
Lang.JAVA: '.java',
|
31
|
+
Lang.C: '.c',
|
32
|
+
Lang.CPP: '.cpp',
|
33
|
+
Lang.CSHARP: '.cs',
|
34
|
+
Lang.RUBY: '.rb',
|
35
|
+
Lang.PHP: '.php',
|
36
|
+
Lang.GO: '.go',
|
37
|
+
Lang.RUST: '.rs',
|
38
|
+
Lang.HTML: '.html',
|
39
|
+
Lang.MARKDOWN: '.md',
|
40
|
+
Lang.JSON: '.json',
|
41
|
+
}
|
42
|
+
|
43
|
+
# ドキュメント言語のリスト
|
44
|
+
DOCUMENT_LANGUAGES: List[Lang] = [
|
45
|
+
Lang.HTML,
|
46
|
+
Lang.MARKDOWN,
|
47
|
+
Lang.JSON,
|
48
|
+
]
|
49
|
+
|
50
|
+
# コンパイル型言語のリスト
|
51
|
+
COMPILED_LANGUAGES: List[Lang] = [
|
52
|
+
Lang.JAVA,
|
53
|
+
Lang.C,
|
54
|
+
Lang.CPP,
|
55
|
+
Lang.CSHARP,
|
56
|
+
Lang.GO,
|
57
|
+
Lang.RUST,
|
58
|
+
]
|
59
|
+
|
60
|
+
# インタプリター型言語のリスト
|
61
|
+
INTERPRETED_LANGUAGES: List[Lang] = [
|
62
|
+
Lang.PYTHON,
|
63
|
+
Lang.JAVASCRIPT,
|
64
|
+
Lang.RUBY,
|
65
|
+
Lang.PHP,
|
66
|
+
]
|
67
|
+
|
68
|
+
|
69
|
+
def str2lang(lang: str) -> Lang:
|
70
|
+
lang_map = {
|
71
|
+
'py': Lang.PYTHON,
|
72
|
+
'python': Lang.PYTHON,
|
73
|
+
'js': Lang.JAVASCRIPT,
|
74
|
+
'javascript': Lang.JAVASCRIPT,
|
75
|
+
'java': Lang.JAVA,
|
76
|
+
'c': Lang.C,
|
77
|
+
'cpp': Lang.CPP,
|
78
|
+
'c++': Lang.CPP,
|
79
|
+
'csharp': Lang.CSHARP,
|
80
|
+
'cs': Lang.CSHARP,
|
81
|
+
'c#': Lang.CSHARP,
|
82
|
+
'rb': Lang.RUBY,
|
83
|
+
'ruby': Lang.RUBY,
|
84
|
+
'php': Lang.PHP,
|
85
|
+
'go': Lang.GO,
|
86
|
+
'rs': Lang.RUST,
|
87
|
+
'rust': Lang.RUST,
|
88
|
+
'html': Lang.HTML,
|
89
|
+
'md': Lang.MARKDOWN,
|
90
|
+
'markdown': Lang.MARKDOWN,
|
91
|
+
'json': Lang.JSON,
|
92
|
+
}
|
93
|
+
return lang_map[lang.lower()]
|
94
|
+
|
95
|
+
|
96
|
+
def lang2str(lang: Lang) -> str:
|
97
|
+
return lang.value
|
98
|
+
|
99
|
+
|
100
|
+
def detect_language(path: str) -> Optional[Lang]:
|
101
|
+
ext = os.path.splitext(path)[1] # ファイルの拡張子を取得
|
102
|
+
lang = next(
|
103
|
+
(lang for lang, extension in FILE_EXTENSIONS.items() if extension == ext), None
|
104
|
+
)
|
105
|
+
return lang
|
atcdr/util/problem.py
CHANGED
@@ -1,46 +1,48 @@
|
|
1
1
|
import re
|
2
2
|
from enum import Enum
|
3
|
-
from typing import
|
3
|
+
from typing import Match, Optional
|
4
4
|
|
5
5
|
from bs4 import BeautifulSoup as bs
|
6
|
-
from bs4 import
|
6
|
+
from bs4 import Tag
|
7
7
|
from markdownify import MarkdownConverter # type: ignore
|
8
8
|
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def repair_html(html: str) -> str:
|
11
|
+
html = html.replace('//img.atcoder.jp', 'https://img.atcoder.jp')
|
12
|
+
html = html.replace(
|
13
|
+
'<meta http-equiv="Content-Language" content="en">',
|
14
|
+
'<meta http-equiv="Content-Language" content="ja">',
|
15
|
+
)
|
16
|
+
html = html.replace('LANG = "en"', 'LANG="ja"')
|
17
|
+
html = remove_unnecessary_emptylines(html)
|
18
|
+
return html
|
14
19
|
|
15
20
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
self.condition_part: Optional[str] = None
|
20
|
-
self.io_part: Optional[str] = None
|
21
|
-
self.test_part: Optional[list[str]] = None
|
21
|
+
def get_title_from_html(html: str) -> str:
|
22
|
+
title: Optional[Match[str]] = re.search(r'<title>([^<]*)</title>', html)
|
23
|
+
return title.group(1).strip() if title else ''
|
22
24
|
|
23
|
-
def divide_problem_part(self, task_statement: Union[Tag, NavigableString]) -> None:
|
24
|
-
if not isinstance(task_statement, Tag):
|
25
|
-
return
|
26
25
|
|
27
|
-
|
26
|
+
def title_to_filename(title: str) -> str:
|
27
|
+
title = re.sub(r'[\\/*?:"<>| !@#$%^&()+=\[\]{};,\']', '', title)
|
28
|
+
title = re.sub(r'^[A-Z]-', '', title)
|
29
|
+
return title
|
28
30
|
|
29
|
-
if len(parts) >= 2:
|
30
|
-
self.problem_part = str(parts[0])
|
31
|
-
self.condition_part = str(parts[1])
|
32
31
|
|
33
|
-
|
34
|
-
|
35
|
-
|
32
|
+
def find_link_from_html(html: str) -> str:
|
33
|
+
soup = bs(html, 'html.parser')
|
34
|
+
meta_tag = soup.find('meta', property='og:url')
|
35
|
+
if isinstance(meta_tag, Tag) and 'content' in meta_tag.attrs:
|
36
|
+
content = meta_tag['content']
|
37
|
+
if isinstance(content, list):
|
38
|
+
return content[0] # 必要に応じて、最初の要素を返す
|
39
|
+
return content
|
40
|
+
return ''
|
36
41
|
|
37
|
-
if len(io_parts) > 0:
|
38
|
-
self.io_part = str(
|
39
|
-
io_parts[0]
|
40
|
-
) # .find_all() はリストを返すので、str()でキャスト
|
41
42
|
|
42
|
-
|
43
|
-
|
43
|
+
class Lang(Enum):
|
44
|
+
JA = 'ja'
|
45
|
+
EN = 'en'
|
44
46
|
|
45
47
|
|
46
48
|
class CustomMarkdownConverter(MarkdownConverter):
|
@@ -57,10 +59,10 @@ def custom_markdownify(html, **options):
|
|
57
59
|
return CustomMarkdownConverter(**options).convert(html)
|
58
60
|
|
59
61
|
|
60
|
-
def remove_unnecessary_emptylines(
|
61
|
-
|
62
|
-
|
63
|
-
return
|
62
|
+
def remove_unnecessary_emptylines(text):
|
63
|
+
text = re.sub(r'\n\s*\n\s*\n+', '\n\n', text)
|
64
|
+
text = text.strip()
|
65
|
+
return text
|
64
66
|
|
65
67
|
|
66
68
|
def abstract_problem_part(html_content: str, lang: str) -> str:
|
@@ -81,7 +83,9 @@ def abstract_problem_part(html_content: str, lang: str) -> str:
|
|
81
83
|
|
82
84
|
|
83
85
|
def make_problem_markdown(html_content: str, lang: str) -> str:
|
86
|
+
title = get_title_from_html(html_content)
|
84
87
|
problem_part = abstract_problem_part(html_content, lang)
|
85
88
|
problem_md = custom_markdownify(problem_part)
|
89
|
+
problem_md = f'# {title}\n{problem_md}'
|
86
90
|
problem_md = remove_unnecessary_emptylines(problem_md)
|
87
91
|
return problem_md
|
@@ -1,19 +1,19 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: AtCoderStudyBooster
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.3
|
4
4
|
Summary: A tool to download and manage AtCoder problems.
|
5
5
|
Project-URL: Homepage, https://github.com/yuta6/AtCoderStudyBooster
|
6
6
|
Author-email: yuta6 <46110512+yuta6@users.noreply.github.com>
|
7
7
|
License: MIT
|
8
8
|
Requires-Python: >=3.8
|
9
9
|
Requires-Dist: beautifulsoup4
|
10
|
-
Requires-Dist: colorama
|
11
10
|
Requires-Dist: fire
|
12
11
|
Requires-Dist: markdownify>=0.13.1
|
12
|
+
Requires-Dist: questionary>=2.0.1
|
13
13
|
Requires-Dist: requests
|
14
|
+
Requires-Dist: rich>=13.7.1
|
14
15
|
Requires-Dist: tiktoken
|
15
16
|
Requires-Dist: types-beautifulsoup4>=4.12.0.20240511
|
16
|
-
Requires-Dist: types-colorama>=0.4.15.20240311
|
17
17
|
Requires-Dist: types-requests>=2.32.0.20240712
|
18
18
|
Requires-Dist: yfinance
|
19
19
|
Description-Content-Type: text/markdown
|
@@ -0,0 +1,17 @@
|
|
1
|
+
atcdr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
+
atcdr/download.py,sha256=aqJEmrLop_Mj8GNJjoWRcSzWU0z9iNc9vtZOjhWXx3U,8945
|
3
|
+
atcdr/generate.py,sha256=0yWX-5PS-FR6LTaP3muHq6a7rFB2a1Oek48mF45exoA,6972
|
4
|
+
atcdr/main.py,sha256=y2IkXwcAyKZ_1y5PgU93GpXzo5lKak9oxo0XV_9d5Fo,727
|
5
|
+
atcdr/markdown.py,sha256=jEktnYgrDYcgIuhxRpJImAzNpFmfSPkRikAesfMxAVk,1125
|
6
|
+
atcdr/open.py,sha256=2UlmNWdieoMrPu1xSUWf-8sBB9Y19r0t6V9zDRBSPes,924
|
7
|
+
atcdr/test.py,sha256=eNHEv_y2tNBW9BbfzbGxRjUjbZB7Skxp1UVZkUJyj24,12021
|
8
|
+
atcdr/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
atcdr/util/cost.py,sha256=0c9H8zLley7xZDLuYU4zJmB8m71qcO1WEIQOoEavD_4,3168
|
10
|
+
atcdr/util/execute.py,sha256=tcYflnVo_38LdaOGDUAuqfSfcA54bTrCaTRShH7kwUw,1750
|
11
|
+
atcdr/util/filetype.py,sha256=n8alyOdrItoFZzLIssDoXg7i5LamHM9DaY1legUzOD0,2007
|
12
|
+
atcdr/util/gpt.py,sha256=Lto6SJHZGer8cC_Nq8lJVnaET2R7apFQteo6ZEFpjdM,3304
|
13
|
+
atcdr/util/problem.py,sha256=WprmpOZm6xpyvksIS3ou1uHqFnBO1FUZWadsLziG1bY,2484
|
14
|
+
atcoderstudybooster-0.3.dist-info/METADATA,sha256=xnKGPQ0_6d592dSluNqZ17xodV23Rvi1h7CGFjsIv84,4467
|
15
|
+
atcoderstudybooster-0.3.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
16
|
+
atcoderstudybooster-0.3.dist-info/entry_points.txt,sha256=_bhz0R7vp2VubKl_eIokDO8Wz9TdqvYA7Q59uWfy6Sk,42
|
17
|
+
atcoderstudybooster-0.3.dist-info/RECORD,,
|
atcdr/util/filename.py
DELETED
@@ -1,137 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
from enum import Enum
|
3
|
-
from typing import Callable, Dict, List, TypeAlias
|
4
|
-
|
5
|
-
# ファイル名と拡張子の型エイリアスを定義
|
6
|
-
Filename: TypeAlias = str
|
7
|
-
Extension: TypeAlias = str
|
8
|
-
|
9
|
-
|
10
|
-
class Lang(Enum):
|
11
|
-
PYTHON = 'Python'
|
12
|
-
JAVASCRIPT = 'JavaScript'
|
13
|
-
JAVA = 'Java'
|
14
|
-
C = 'C'
|
15
|
-
CPP = 'C++'
|
16
|
-
CSHARP = 'C#'
|
17
|
-
RUBY = 'Ruby'
|
18
|
-
PHP = 'php'
|
19
|
-
GO = 'Go'
|
20
|
-
RUST = 'Rust'
|
21
|
-
HTML = 'HTML'
|
22
|
-
MARKDOWN = 'markdown'
|
23
|
-
JSON = 'json'
|
24
|
-
|
25
|
-
|
26
|
-
# ファイル拡張子と対応する言語の辞書
|
27
|
-
FILE_EXTENSIONS: Dict[Lang, Extension] = {
|
28
|
-
Lang.PYTHON: '.py',
|
29
|
-
Lang.JAVASCRIPT: '.js',
|
30
|
-
Lang.JAVA: '.java',
|
31
|
-
Lang.C: '.c',
|
32
|
-
Lang.CPP: '.cpp',
|
33
|
-
Lang.CSHARP: '.cs',
|
34
|
-
Lang.RUBY: '.rb',
|
35
|
-
Lang.PHP: '.php',
|
36
|
-
Lang.GO: '.go',
|
37
|
-
Lang.RUST: '.rs',
|
38
|
-
Lang.HTML: '.html',
|
39
|
-
Lang.MARKDOWN: '.md',
|
40
|
-
Lang.JSON: '.json',
|
41
|
-
}
|
42
|
-
|
43
|
-
DOCUMENT_LANGUAGES: List[Lang] = [
|
44
|
-
Lang.HTML,
|
45
|
-
Lang.MARKDOWN,
|
46
|
-
Lang.JSON,
|
47
|
-
]
|
48
|
-
|
49
|
-
# ソースコードファイルと言語のリスト
|
50
|
-
SOURCE_LANGUAGES: List[Lang] = [
|
51
|
-
Lang.PYTHON,
|
52
|
-
Lang.JAVASCRIPT,
|
53
|
-
Lang.JAVA,
|
54
|
-
Lang.C,
|
55
|
-
Lang.CPP,
|
56
|
-
Lang.CSHARP,
|
57
|
-
Lang.RUBY,
|
58
|
-
Lang.PHP,
|
59
|
-
Lang.GO,
|
60
|
-
Lang.RUST,
|
61
|
-
]
|
62
|
-
|
63
|
-
|
64
|
-
def str2lang(lang: str) -> Lang:
|
65
|
-
lang_map = {
|
66
|
-
'py': Lang.PYTHON,
|
67
|
-
'python': Lang.PYTHON,
|
68
|
-
'js': Lang.JAVASCRIPT,
|
69
|
-
'javascript': Lang.JAVASCRIPT,
|
70
|
-
'java': Lang.JAVA,
|
71
|
-
'c': Lang.C,
|
72
|
-
'cpp': Lang.CPP,
|
73
|
-
'c++': Lang.CPP,
|
74
|
-
'csharp': Lang.CSHARP,
|
75
|
-
'c#': Lang.CSHARP,
|
76
|
-
'rb': Lang.RUBY,
|
77
|
-
'ruby': Lang.RUBY,
|
78
|
-
'php': Lang.PHP,
|
79
|
-
'go': Lang.GO,
|
80
|
-
'rs': Lang.RUST,
|
81
|
-
'rust': Lang.RUST,
|
82
|
-
'html': Lang.HTML,
|
83
|
-
'md': Lang.MARKDOWN,
|
84
|
-
'markdown': Lang.MARKDOWN,
|
85
|
-
'json': Lang.JSON,
|
86
|
-
}
|
87
|
-
return lang_map[lang.lower()]
|
88
|
-
|
89
|
-
|
90
|
-
def lang2str(lang: Lang) -> str:
|
91
|
-
return lang.value
|
92
|
-
|
93
|
-
|
94
|
-
def execute_files(
|
95
|
-
*args: str, func: Callable[[Filename], None], target_filetypes: List[Lang]
|
96
|
-
) -> None:
|
97
|
-
target_extensions = [FILE_EXTENSIONS[lang] for lang in target_filetypes]
|
98
|
-
|
99
|
-
files = [
|
100
|
-
file
|
101
|
-
for file in os.listdir('.')
|
102
|
-
if os.path.isfile(file) and os.path.splitext(file)[1] in target_extensions
|
103
|
-
]
|
104
|
-
|
105
|
-
if not files:
|
106
|
-
print(
|
107
|
-
'対象のファイルが見つかりません.\n対象ファイルが存在するディレクトリーに移動してから実行してください。'
|
108
|
-
)
|
109
|
-
return
|
110
|
-
|
111
|
-
if not args:
|
112
|
-
if len(files) == 1:
|
113
|
-
func(files[0])
|
114
|
-
else:
|
115
|
-
print('複数のファイルが見つかりました。以下のファイルから選択してください:')
|
116
|
-
for i, file in enumerate(files):
|
117
|
-
print(f'{i + 1}. {file}')
|
118
|
-
choice = int(input('ファイル番号を入力してください: ')) - 1
|
119
|
-
if 0 <= choice < len(files):
|
120
|
-
func(files[choice])
|
121
|
-
else:
|
122
|
-
print('無効な選択です')
|
123
|
-
else:
|
124
|
-
target_files = set()
|
125
|
-
for arg in args:
|
126
|
-
if arg == '*':
|
127
|
-
target_files.update(files)
|
128
|
-
elif arg.startswith('*.'):
|
129
|
-
ext = arg[1:] # ".py" のような拡張子を取得
|
130
|
-
target_files.update(file for file in files if file.endswith(ext))
|
131
|
-
else:
|
132
|
-
if arg in files:
|
133
|
-
target_files.add(arg)
|
134
|
-
else:
|
135
|
-
print(f'エラー: {arg} は存在しません。')
|
136
|
-
|
137
|
-
list(map(func, target_files))
|
@@ -1,15 +0,0 @@
|
|
1
|
-
atcdr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
atcdr/download.py,sha256=UYOkKoFaN7Rj2p-13MOjvgq26QzdvoNmWKBaUW6cCKs,7995
|
3
|
-
atcdr/generate.py,sha256=Bh0QHRUVeI8u5FvXbJssbs6gr55XtUkNT2p897FlUgs,5521
|
4
|
-
atcdr/main.py,sha256=i-TFxFk7bFMtKZxtDgI7aPoZAF-dsXqNoz3O_ZsGvb4,605
|
5
|
-
atcdr/open.py,sha256=vbOy3fthklhZ7_WIWNGyS2H3iK2FHLeClDt_tloJ_b0,924
|
6
|
-
atcdr/test.py,sha256=it3QjFxdlR0GY6Hc0c2Qdke71Z4dj5eLhfuWVZU9cZA,7969
|
7
|
-
atcdr/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
|
-
atcdr/util/cost.py,sha256=0c9H8zLley7xZDLuYU4zJmB8m71qcO1WEIQOoEavD_4,3168
|
9
|
-
atcdr/util/filename.py,sha256=taCgSwIpB5iCjWZrYWAGRncRyUUl9exoNfsP-KLF2bs,2984
|
10
|
-
atcdr/util/gpt.py,sha256=Lto6SJHZGer8cC_Nq8lJVnaET2R7apFQteo6ZEFpjdM,3304
|
11
|
-
atcdr/util/problem.py,sha256=iDfNGfoCk_sy9RQRZ4vVqd1ViyT8HSWe_ekKUb4PdKs,2412
|
12
|
-
atcoderstudybooster-0.1.1.dist-info/METADATA,sha256=6ncUVzTFelY1WHUoNP4NNLIqsjHiDAh_54Lgsg3OruI,4478
|
13
|
-
atcoderstudybooster-0.1.1.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
14
|
-
atcoderstudybooster-0.1.1.dist-info/entry_points.txt,sha256=_bhz0R7vp2VubKl_eIokDO8Wz9TdqvYA7Q59uWfy6Sk,42
|
15
|
-
atcoderstudybooster-0.1.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|