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/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 Optional, Union
3
+ from typing import Match, Optional
4
4
 
5
5
  from bs4 import BeautifulSoup as bs
6
- from bs4 import NavigableString, Tag
6
+ from bs4 import Tag
7
7
  from markdownify import MarkdownConverter # type: ignore
8
8
 
9
9
 
10
- # TODO : そのうちgenerate.pyやtest.py, open.pyのHTMLのparse処理を全部まとめる
11
- class Lang(Enum):
12
- JA = 'ja'
13
- EN = 'en'
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
- class ProblemStruct:
17
- def __init__(self) -> None:
18
- self.problem_part: Optional[str] = None
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
- parts = task_statement.find_all('div', {'class': 'part'})
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
- io_div = task_statement.find('div', {'class': 'io-style'})
34
- if isinstance(io_div, Tag):
35
- io_parts = io_div.find_all('div', {'class': 'part'})
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
- # 2つ目以降のdivをtest_partに格納
43
- self.test_part = [str(part) for part in io_parts[1:]]
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(md_text):
61
- md_text = re.sub(r'\n\s*\n\s*\n+', '\n\n', md_text)
62
- md_text = md_text.strip()
63
- return md_text
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.1.1
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,,