AtCoderStudyBooster 0.3.1__py3-none-any.whl → 0.3.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/cli.py ADDED
@@ -0,0 +1,86 @@
1
+ from importlib.metadata import metadata
2
+
3
+ import rich_click as click
4
+ from click_aliases import ClickAliasedGroup
5
+ from rich.console import Console
6
+ from rich.panel import Panel
7
+ from rich.table import Table
8
+ from rich.traceback import install
9
+ from rich_click import RichGroup
10
+
11
+ from atcdr.download import download
12
+ from atcdr.generate import generate
13
+ from atcdr.login import login
14
+ from atcdr.logout import logout
15
+ from atcdr.markdown import markdown
16
+ from atcdr.open import open_files
17
+ from atcdr.submit import submit
18
+ from atcdr.test import test
19
+
20
+
21
+ # ─── RichClick + ClickAliases 両対応の Group クラス ───
22
+ class AliasedRichGroup(ClickAliasedGroup, RichGroup):
23
+ def format_commands(self, ctx, console, *args, **kwargs):
24
+ console = Console()
25
+ commands = self.list_commands(ctx)
26
+
27
+ table = Table(show_header=False, box=None, pad_edge=False)
28
+ table.add_column('command', style='bold cyan', no_wrap=True)
29
+ table.add_column('help', style='')
30
+
31
+ for name in commands:
32
+ cmd = self.get_command(ctx, name)
33
+ if not cmd or getattr(cmd, 'hidden', False):
34
+ continue
35
+
36
+ aliases = self._commands.get(name, [])
37
+ alias_part = f"[dim]({', '.join(aliases)})[/]" if aliases else ''
38
+
39
+ short = (
40
+ cmd.get_short_help_str()
41
+ if hasattr(cmd, 'get_short_help_str')
42
+ else cmd.short_help or ''
43
+ )
44
+ table.add_row(f'{name}{alias_part}', short)
45
+
46
+ panel = Panel(table, title='Commands', expand=False)
47
+ console.print(panel)
48
+
49
+
50
+ # ─── CLI 定義 ──────────────────────────────────────────
51
+ _meta = metadata('AtCoderStudyBooster')
52
+ _NAME = _meta['Name']
53
+ _VERSION = _meta['Version']
54
+
55
+ click.rich_click.MAX_WIDTH = 100
56
+ click.rich_click.SHOW_ARGUMENTS = True
57
+ click.rich_click.STYLE_HELPTEXT_FIRST_LINE = 'bold cyan'
58
+ click.rich_click.STYLE_HELPTEXT = 'dim'
59
+
60
+
61
+ @click.group(
62
+ cls=AliasedRichGroup,
63
+ context_settings={'help_option_names': ['-h', '--help']},
64
+ )
65
+ @click.version_option(
66
+ _VERSION,
67
+ '-v',
68
+ '--version',
69
+ prog_name=_NAME,
70
+ message='%(prog)s %(version)s',
71
+ )
72
+ def cli():
73
+ install()
74
+
75
+
76
+ cli.add_command(test, aliases=['t'])
77
+ cli.add_command(download, aliases=['d'])
78
+ cli.add_command(open_files, 'open', aliases=['o'])
79
+ cli.add_command(generate, aliases=['g'])
80
+ cli.add_command(markdown, aliases=['md'])
81
+ cli.add_command(submit, aliases=['s'])
82
+ cli.add_command(login)
83
+ cli.add_command(logout)
84
+
85
+ if __name__ == '__main__':
86
+ cli()
atcdr/download.py CHANGED
@@ -4,6 +4,7 @@ import time
4
4
  from typing import Callable, List, Union, cast
5
5
 
6
6
  import questionary as q
7
+ import rich_click as click
7
8
  from rich import print
8
9
  from rich.prompt import Prompt
9
10
 
@@ -242,11 +243,32 @@ def interactive_download() -> None:
242
243
  print('[bold red]無効な選択です[/]')
243
244
 
244
245
 
246
+ @click.command(short_help='AtCoderの問題をダウンロード')
247
+ @click.argument('first', nargs=1, type=str, required=False)
248
+ @click.argument('second', nargs=1, type=str, required=False)
245
249
  def download(
246
- first: Union[str, int, None] = None,
247
- second: Union[str, int, None] = None,
250
+ first: Union[str, None] = None,
251
+ second: Union[str, None] = None,
248
252
  base_path: str = '.',
249
253
  ) -> None:
254
+ """
255
+ AtCoderの問題をダウンロードします
256
+
257
+ download
258
+ 対話形式でダウンロードを開始します。
259
+
260
+ download abc012
261
+ コンテスト abc012 の全問題をダウンロード
262
+
263
+ download A 120
264
+ 難易度Aの120番問題をダウンロード
265
+
266
+ download 120..130 B
267
+ ABCの120~130番のB問題をダウンロード
268
+
269
+ download 120
270
+ ABCの120番問題をダウンロード
271
+ """
250
272
  if first is None:
251
273
  interactive_download()
252
274
  return
atcdr/generate.py CHANGED
@@ -2,12 +2,13 @@ import json
2
2
  import os
3
3
  import re
4
4
 
5
+ import rich_click as click
5
6
  from rich.console import Console
6
7
  from rich.panel import Panel
7
8
  from rich.syntax import Syntax
8
9
 
9
10
  from atcdr.test import ResultStatus, TestRunner, create_renderable_test_info
10
- from atcdr.util.execute import execute_files
11
+ from atcdr.util.fileops import add_file_selector
11
12
  from atcdr.util.filetype import (
12
13
  FILE_EXTENSIONS,
13
14
  Filename,
@@ -181,31 +182,21 @@ Please provide an updated version of the code in {lang2str(lang)}."""
181
182
  return
182
183
 
183
184
 
184
- def generate(
185
- *source: str,
186
- lang: str = 'Python',
187
- model: str = Model.GPT41_MINI.value,
188
- without_test: bool = False,
189
- template: bool = False,
190
- ) -> None:
185
+ @click.command(short_help='コードを生成')
186
+ @add_file_selector('files', filetypes=[Lang.HTML])
187
+ @click.option('--lang', default='Python', help='出力するプログラミング言語')
188
+ @click.option('--model', default=Model.GPT41_MINI.value, help='使用するGPTモデル')
189
+ @click.option('--without-test', is_flag=True, help='テストケースを省略して生成')
190
+ @click.option('--template', is_flag=True, help='テンプレートを生成')
191
+ def generate(files, lang, model, without_test, template):
192
+ """HTMLファイルからコード生成またはテンプレート出力を行います。"""
191
193
  la = str2lang(lang)
192
194
  model_enum = Model(model)
193
195
 
194
- if template:
195
- execute_files(
196
- *source,
197
- func=lambda file: generate_template(file, la),
198
- target_filetypes=[Lang.HTML],
199
- )
200
- elif without_test:
201
- execute_files(
202
- *source,
203
- func=lambda file: generate_code(file, la, model_enum),
204
- target_filetypes=[Lang.HTML],
205
- )
206
- else:
207
- execute_files(
208
- *source,
209
- func=lambda file: solve_problem(file, la, model_enum),
210
- target_filetypes=[Lang.HTML],
211
- )
196
+ for path in files:
197
+ if template:
198
+ generate_template(path, la)
199
+ elif without_test:
200
+ generate_code(path, la, model_enum)
201
+ else:
202
+ solve_problem(path, la, model_enum)
atcdr/login.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import threading
2
2
  import time
3
3
 
4
+ import rich_click as click
4
5
  import webview
5
6
  from requests import Session
6
7
  from rich.console import Console
@@ -13,7 +14,9 @@ ATCODER_HOME_URL = 'https://atcoder.jp/home'
13
14
  console = Console()
14
15
 
15
16
 
17
+ @click.command(short_help='AtCoderへログイン')
16
18
  def login() -> None:
19
+ """AtCoderへログインします."""
17
20
  session = load_session()
18
21
  if validate_session(session):
19
22
  console.print('[green][+][/] すでにログインしています. ')
atcdr/logout.py CHANGED
@@ -1,3 +1,4 @@
1
+ import rich_click as click
1
2
  import webview
2
3
  from rich import print
3
4
 
@@ -6,7 +7,9 @@ from atcdr.util.session import delete_session, load_session, validate_session
6
7
  ATCODER_LOGIN_URL = 'https://atcoder.jp/login'
7
8
 
8
9
 
10
+ @click.command(short_help='AtCoderへログアウト')
9
11
  def logout() -> None:
12
+ """AtCoderからログアウトします."""
10
13
  session = load_session()
11
14
  if not validate_session(session):
12
15
  print('[red][-][/] ログインしていません.')
atcdr/markdown.py CHANGED
@@ -1,9 +1,10 @@
1
1
  import os
2
2
 
3
+ import rich_click as click
3
4
  from rich.console import Console
4
5
  from rich.markdown import Markdown
5
6
 
6
- from atcdr.util.execute import execute_files
7
+ from atcdr.util.fileops import add_file_selector
7
8
  from atcdr.util.filetype import FILE_EXTENSIONS, Lang
8
9
  from atcdr.util.parse import ProblemHTML
9
10
 
@@ -21,19 +22,22 @@ def save_markdown(html_path: str, lang: str) -> None:
21
22
  console.print('[green][+][/green] Markdownファイルを作成しました.')
22
23
 
23
24
 
24
- def print_markdown(md_path: str) -> None:
25
+ def print_markdown(html_path: str, lang: str) -> None:
25
26
  console = Console()
26
- with open(md_path, 'r', encoding='utf-8') as f:
27
- md = f.read()
27
+ with open(html_path, 'r', encoding='utf-8') as f:
28
+ html = ProblemHTML(f.read())
29
+ md = html.make_problem_markdown(lang)
28
30
  console.print(Markdown(md))
29
31
 
30
32
 
31
- def markdown(*args: str, lang: str = 'ja', save: bool = False) -> None:
32
- if save:
33
- execute_files(
34
- *args,
35
- func=lambda html_path: save_markdown(html_path, lang),
36
- target_filetypes=[Lang.HTML],
37
- )
38
- else:
39
- execute_files(*args, func=print_markdown, target_filetypes=[Lang.MARKDOWN])
33
+ @click.command(short_help='Markdown形式で問題を表示します')
34
+ @add_file_selector('files', filetypes=[Lang.HTML])
35
+ @click.option('--lang', default='ja', help='出力する言語を指定')
36
+ @click.option('--save', is_flag=True, help='変換結果をファイルに保存')
37
+ def markdown(files, lang, save):
38
+ """Markdown形式で問題を表示します"""
39
+ for path in files:
40
+ if save:
41
+ save_markdown(path, lang)
42
+ else:
43
+ print_markdown(path, lang)
atcdr/open.py CHANGED
@@ -3,7 +3,8 @@ from rich.panel import Panel
3
3
  from rich.console import Console
4
4
 
5
5
  from atcdr.util.filetype import Lang
6
- from atcdr.util.execute import execute_files
6
+ from atcdr.util.fileops import add_file_selector
7
+ import rich_click as click
7
8
  from atcdr.util.parse import ProblemHTML
8
9
 
9
10
 
@@ -39,5 +40,9 @@ def open_html(file: str) -> None:
39
40
  )
40
41
 
41
42
 
42
- def open_files(*args: str) -> None:
43
- execute_files(*args, func=open_html, target_filetypes=[Lang.HTML])
43
+ @click.command(short_help='HTMLファイルを開く')
44
+ @add_file_selector('files', filetypes=[Lang.HTML])
45
+ def open_files(files):
46
+ """指定したHTMLファイルをブラウザで開きます。"""
47
+ for path in files:
48
+ open_html(path)
atcdr/submit.py CHANGED
@@ -5,6 +5,7 @@ from typing import Dict, List, NamedTuple, Optional
5
5
 
6
6
  import questionary as q
7
7
  import requests
8
+ import rich_click as click
8
9
  import webview
9
10
  from bs4 import BeautifulSoup as bs
10
11
  from rich import print
@@ -19,7 +20,7 @@ from atcdr.test import (
19
20
  TestRunner,
20
21
  create_renderable_test_info,
21
22
  )
22
- from atcdr.util.execute import execute_files
23
+ from atcdr.util.fileops import add_file_selector
23
24
  from atcdr.util.filetype import (
24
25
  COMPILED_LANGUAGES,
25
26
  INTERPRETED_LANGUAGES,
@@ -289,9 +290,13 @@ def submit_source(path: str, no_test: bool, no_feedback: bool) -> None:
289
290
  print_status_submission(api_status_link, path, session)
290
291
 
291
292
 
292
- def submit(*args: str, no_test: bool = False, no_feedback: bool = False) -> None:
293
- execute_files(
294
- *args,
295
- func=lambda path: submit_source(path, no_test, no_feedback),
296
- target_filetypes=COMPILED_LANGUAGES + INTERPRETED_LANGUAGES,
297
- )
293
+ @click.command(short_help='ソースを提出')
294
+ @add_file_selector('files', filetypes=COMPILED_LANGUAGES + INTERPRETED_LANGUAGES)
295
+ @click.option('--no-test', is_flag=True, default=False, help='テストをスキップ')
296
+ @click.option(
297
+ '--no-feedback', is_flag=True, default=False, help='フィードバックをスキップ'
298
+ )
299
+ def submit(files, no_test, no_feedback):
300
+ """指定したファイルをAtCoderへ提出します。"""
301
+ for path in files:
302
+ submit_source(path, no_test, no_feedback)
atcdr/test.py CHANGED
@@ -6,6 +6,7 @@ from dataclasses import dataclass, field
6
6
  from enum import Enum
7
7
  from typing import Dict, List, Optional, Tuple, Union
8
8
 
9
+ import rich_click as click
9
10
  from rich.console import Group, RenderableType
10
11
  from rich.live import Live
11
12
  from rich.markup import escape
@@ -17,7 +18,7 @@ from rich.syntax import Syntax
17
18
  from rich.table import Table
18
19
  from rich.text import Text
19
20
 
20
- from atcdr.util.execute import execute_files
21
+ from atcdr.util.fileops import add_file_selector
21
22
  from atcdr.util.filetype import (
22
23
  COMPILED_LANGUAGES,
23
24
  INTERPRETED_LANGUAGES,
@@ -424,9 +425,9 @@ def run_test(path_of_code: str) -> None:
424
425
  render_results(test)
425
426
 
426
427
 
427
- def test(*args: str) -> None:
428
- execute_files(
429
- *args,
430
- func=run_test,
431
- target_filetypes=INTERPRETED_LANGUAGES + COMPILED_LANGUAGES,
432
- )
428
+ @click.command(short_help='テストを実行')
429
+ @add_file_selector('files', filetypes=COMPILED_LANGUAGES + INTERPRETED_LANGUAGES)
430
+ def test(files):
431
+ """指定したソースコードをサンプルケースでテストします。"""
432
+ for path in files:
433
+ run_test(path)
atcdr/util/fileops.py ADDED
@@ -0,0 +1,102 @@
1
+ import functools
2
+ import glob
3
+ import os
4
+ from typing import List, Tuple
5
+
6
+ import questionary as q
7
+ import rich_click as click
8
+
9
+ from atcdr.util.filetype import FILE_EXTENSIONS, Lang
10
+
11
+
12
+ def collect_files(
13
+ patterns: Tuple[str, ...],
14
+ exts: Tuple[str, ...],
15
+ recursive: bool,
16
+ ) -> List[str]:
17
+ # 1) ベース候補
18
+ if recursive:
19
+ candidates = []
20
+ for root, _, files in os.walk('.'):
21
+ for f in files:
22
+ candidates.append(os.path.join(root, f))
23
+ else:
24
+ candidates = [f for f in os.listdir('.') if os.path.isfile(f)]
25
+
26
+ # 2) パターン+glob 展開
27
+ matched = set()
28
+ pats = patterns or ['*']
29
+ for pat in pats:
30
+ for m in glob.glob(pat, recursive=recursive):
31
+ if os.path.isfile(m):
32
+ matched.add(m)
33
+ if '*' not in pat and os.path.isfile(pat):
34
+ matched.add(pat)
35
+
36
+ if exts:
37
+ matched = {f for f in matched if os.path.splitext(f)[1] in exts}
38
+
39
+ return sorted(matched)
40
+
41
+
42
+ def select_files_interactively(files: List[str]) -> List[str]:
43
+ target_file = q.select(
44
+ message='複数のファイルが見つかりました.ファイルを選択してください:',
45
+ choices=[q.Choice(title=file, value=file) for file in files],
46
+ instruction='\n 十字キーで移動, [enter]で実行',
47
+ pointer='❯',
48
+ qmark='',
49
+ style=q.Style(
50
+ [
51
+ ('qmark', 'fg:#2196F3 bold'),
52
+ ('question', 'fg:#2196F3 bold'),
53
+ ('answer', 'fg:#FFB300 bold'),
54
+ ('pointer', 'fg:#FFB300 bold'),
55
+ ('highlighted', 'fg:#FFB300 bold'),
56
+ ('selected', 'fg:#FFB300 bold'),
57
+ ]
58
+ ),
59
+ ).ask()
60
+ return target_file
61
+
62
+
63
+ def add_file_selector(
64
+ arg_name: str,
65
+ filetypes: list[Lang],
66
+ ):
67
+ def decorator(f):
68
+ @click.argument(arg_name, nargs=-1, type=click.STRING)
69
+ @click.pass_context
70
+ @functools.wraps(f)
71
+ def wrapper(ctx: click.Context, **kwargs):
72
+ # Click から渡される元のパターン一覧を取得
73
+ patterns: tuple[str, ...] = kwargs.pop(arg_name)
74
+
75
+ # 1) 拡張子リストを作成
76
+ exts = [FILE_EXTENSIONS[lang] for lang in filetypes]
77
+
78
+ # 2) ファイル収集 (非再帰固定)
79
+ files = collect_files(patterns, tuple(exts), recursive=False)
80
+ if not files:
81
+ click.echo('対象ファイルが見つかりません。')
82
+ ctx.exit(1)
83
+
84
+ # 3) 候補が1つなら即実行
85
+ if len(files) == 1:
86
+ return ctx.invoke(f, **{arg_name: files}, **kwargs)
87
+
88
+ # 4) 引数なしなら対話選択、それ以外はまとめて渡す
89
+ if not patterns:
90
+ selected = select_files_interactively(files)
91
+ if not selected:
92
+ click.echo('ファイルが選択されませんでした。')
93
+ ctx.exit(1)
94
+ selected_list = [selected]
95
+ return ctx.invoke(f, **{arg_name: selected_list}, **kwargs)
96
+
97
+ # 5) patterns 指定ありならマッチ全件を渡す
98
+ return ctx.invoke(f, **{arg_name: files}, **kwargs)
99
+
100
+ return wrapper
101
+
102
+ return decorator
@@ -1,17 +1,18 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: AtCoderStudyBooster
3
- Version: 0.3.1
3
+ Version: 0.3.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: fire
11
- Requires-Dist: markdownify>=0.13.1
10
+ Requires-Dist: click-aliases>=1.0.5
11
+ Requires-Dist: markdownify==0.13.1
12
12
  Requires-Dist: pywebview>=5.4
13
13
  Requires-Dist: questionary>=2.0.1
14
14
  Requires-Dist: requests
15
+ Requires-Dist: rich-click>=1.8.8
15
16
  Requires-Dist: rich>=13.7.1
16
17
  Requires-Dist: tiktoken
17
18
  Requires-Dist: types-beautifulsoup4>=4.12.0.20240511
@@ -22,14 +23,21 @@ Description-Content-Type: text/markdown
22
23
 
23
24
  ## 概要
24
25
 
25
- AtCoderStudyBoosterはAtCoderの学習を加速させるためのCLIツールです。問題をローカルにダウンロードし、テスト、提出、解答の作成をサポートするツールです。Pythonが入っていることが必須です。Pythonが入っている環境なら、`pip install AtCoderStudyBooster`でインストールできます。
26
+ 🚧 このプロジェクトはまだ実験段階です。日々のAtCoder学習に役立つ機能を順次追加しています。
27
+
28
+ AtCoderStudyBoosterはAtCoderの学習を加速させるためのCLIツールです。問題をローカルにダウンロードし、テスト、提出、解答の作成をサポートするツールです。Pythonが入っていることが必須です。Pythonが入っている環境なら、`pip install AtCoderStudyBooster`でインストールできます。(Python3.8以上が必要です)
29
+
30
+ キャプチャ認証が導入されたあとでも、CLIから半自動でログイン&提出できます。ただしキャプチャをGUIから人力で解く必要があります。キャプチャー認証をバイパスするものではありません。
26
31
 
27
32
  このツールは以下のプロジェクトに強く影響を受けています。
28
33
  [online-judge-tools](https://github.com/online-judge-tools)
29
34
  [atcoder-cli](https://github.com/Tatamo/atcoder-cli)
30
35
 
36
+
31
37
  ## 利用ケース
32
38
 
39
+ まずは`download`コマンドを利用して問題をローカルにダウンロードしてみましょう。
40
+
33
41
  ### B問題の練習したい場合
34
42
 
35
43
  ABCコンテストの223から226のB問題だけを集中的に練習したい場合、次のコマンドを実行します。
@@ -0,0 +1,21 @@
1
+ atcdr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ atcdr/cli.py,sha256=xiCnGf14VHtLcRlVHXNpLKW3FIxOHS2duTRDTsG8a5w,2595
3
+ atcdr/download.py,sha256=gJ5ZPQJd06fxWOUzC_GFBY-d7KIyaURoPwO86_QdU4A,11711
4
+ atcdr/generate.py,sha256=i-rznjOQpBcAmlI0CGGC8CEY3Nx35SoxQgGaPSh6Oz8,8183
5
+ atcdr/login.py,sha256=gro9gj-nF4pGz4KepkaNSMj8PRGdSJtaVcBe7YKUPzU,4697
6
+ atcdr/logout.py,sha256=WYFifFDZtdcFZ0z3BhqsmdK_JbufjmBdF4q5dDkLbHQ,753
7
+ atcdr/markdown.py,sha256=RpYdXMWgBd2qcMj-WmUrSyF0VdLfyUms-FsTRXfdgRw,1485
8
+ atcdr/open.py,sha256=aRmhg7_TcZU6iPBM0u7lUQhTpPF5Eo227MxS3JUSm1M,1293
9
+ atcdr/submit.py,sha256=T579xpIyLeXp69D8UW_2mNC8vcjJ3d-iFT9rJvoVJ7I,9975
10
+ atcdr/test.py,sha256=y9ENvL4Gdirup07tfFBjJJXA-HeiWZpSW1ncpNwiKOs,13672
11
+ atcdr/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ atcdr/util/fileops.py,sha256=jxJ_d-R3XG-CLQemwwxgeNQcvNAE_7Q-3nOQ1npG3ig,3293
13
+ atcdr/util/filetype.py,sha256=pceB08trkwNkdzKJx4fFfOWpz9jYMBRDwXLW4un0sRM,2254
14
+ atcdr/util/gpt.py,sha256=vH10Waa7KXlz6-5pEUBuIbxTbDH3Hys7k9Tt7prvFX4,3772
15
+ atcdr/util/parse.py,sha256=SJ4khlH5iWaSwyORmQLi84npMwh5u2omCeg0q7ScEAE,6974
16
+ atcdr/util/problem.py,sha256=wEoMC5KVQu5l-i4V-ZCR30Z30Zov0VCNtLVIbL-0iI0,2594
17
+ atcdr/util/session.py,sha256=LwlSN86sfnkE9a-opL4qvKYHsCgiMy7eFCdcXdo79eg,4889
18
+ atcoderstudybooster-0.3.3.dist-info/METADATA,sha256=4_jttlJ8DMACriCozvDLlmhEWoUM91EL9YdpMEkjbOI,6836
19
+ atcoderstudybooster-0.3.3.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
20
+ atcoderstudybooster-0.3.3.dist-info/entry_points.txt,sha256=-stL-IwnheQGlYAdm82RuZu8CGgSakU0aVIVlA7DmFA,40
21
+ atcoderstudybooster-0.3.3.dist-info/RECORD,,
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ atcdr = atcdr.cli:cli
atcdr/main.py DELETED
@@ -1,47 +0,0 @@
1
- from importlib.metadata import metadata
2
-
3
- import fire # type: ignore
4
- from rich.traceback import install
5
-
6
- from atcdr.download import download
7
- from atcdr.generate import generate
8
- from atcdr.login import login
9
- from atcdr.logout import logout
10
- from atcdr.markdown import markdown
11
- from atcdr.open import open_files
12
- from atcdr.submit import submit
13
- from atcdr.test import test
14
-
15
-
16
- def get_version() -> None:
17
- meta = metadata('AtCoderStudyBooster')
18
- print(meta['Name'], meta['Version'])
19
-
20
-
21
- MAP_COMMANDS: dict = {
22
- 'test': test,
23
- 't': test,
24
- 'download': download,
25
- 'd': download,
26
- 'open': open_files,
27
- 'o': open_files,
28
- 'generate': generate,
29
- 'g': generate,
30
- 'markdown': markdown,
31
- 'md': markdown,
32
- 'login': login,
33
- 'logout': logout,
34
- 'submit': submit,
35
- 's': submit,
36
- '--version': get_version,
37
- '-v': get_version,
38
- }
39
-
40
-
41
- def main():
42
- install()
43
- fire.Fire(MAP_COMMANDS)
44
-
45
-
46
- if __name__ == '__main__':
47
- main()
atcdr/util/execute.py DELETED
@@ -1,63 +0,0 @@
1
- import os
2
- from typing import Callable, List
3
-
4
- import questionary as q
5
- from rich import print
6
-
7
- from atcdr.util.filetype import FILE_EXTENSIONS, Filename, Lang
8
-
9
-
10
- def execute_files(
11
- *args: str, func: Callable[[Filename], None], target_filetypes: List[Lang]
12
- ) -> None:
13
- target_extensions = [FILE_EXTENSIONS[lang] for lang in target_filetypes]
14
-
15
- files = [
16
- file
17
- for file in os.listdir('.')
18
- if os.path.isfile(file) and os.path.splitext(file)[1] in target_extensions
19
- ]
20
-
21
- if not files:
22
- print(
23
- '対象のファイルが見つかりません.\n対象ファイルが存在するディレクトリーに移動してから実行してください。'
24
- )
25
- return
26
-
27
- if not args:
28
- if len(files) == 1:
29
- func(files[0])
30
- else:
31
- target_file = q.select(
32
- message='複数のファイルが見つかりました.ファイルを選択してください:',
33
- choices=[q.Choice(title=file, value=file) for file in files],
34
- instruction='\n 十字キーで移動, [enter]で実行',
35
- pointer='❯❯❯',
36
- qmark='',
37
- style=q.Style(
38
- [
39
- ('qmark', 'fg:#2196F3 bold'),
40
- ('question', 'fg:#2196F3 bold'),
41
- ('answer', 'fg:#FFB300 bold'),
42
- ('pointer', 'fg:#FFB300 bold'),
43
- ('highlighted', 'fg:#FFB300 bold'),
44
- ('selected', 'fg:#FFB300 bold'),
45
- ]
46
- ),
47
- ).ask()
48
- list(map(func, [target_file]))
49
- else:
50
- target_files = set()
51
- for arg in args:
52
- if arg == '*':
53
- target_files.update(files)
54
- elif arg.startswith('*.'):
55
- ext = arg[1:] # ".py" のような拡張子を取得
56
- target_files.update(file for file in files if file.endswith(ext))
57
- else:
58
- if arg in files:
59
- target_files.add(arg)
60
- else:
61
- print(f'エラー: {arg} は存在しません。')
62
-
63
- list(map(func, target_files))
@@ -1,21 +0,0 @@
1
- atcdr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- atcdr/download.py,sha256=roscCz_6bq4Ab6XNc1KpYywMc37XTfmH7ciEhEPYu5M,11056
3
- atcdr/generate.py,sha256=ckjI7CuPO5_1DDrMch8EFtQK5F0102ZDJFAzpjlxqqg,8024
4
- atcdr/login.py,sha256=kNs2vUSuYqSn5oOJGVbQOluJXKi3zr5ZQBXfai3VU08,4575
5
- atcdr/logout.py,sha256=uBFt3idW4Ik2TypBFuQjXJpYWWDNWZM42--B5Xlcbtc,622
6
- atcdr/main.py,sha256=tcNUcmOFh5hSKmFMgsD6g9k467x6rOI5rSMb8aPfL78,953
7
- atcdr/markdown.py,sha256=v3Sh5vl20V6dTkspwzf5SxLKJLw6J2Xj1HX3F185X2I,1227
8
- atcdr/open.py,sha256=l5QbrefXuZxn8LoqjfAE5p5EwRBJeg5VqopbjMXdG3Y,1121
9
- atcdr/submit.py,sha256=IxVz2QyotDjQqvfqFgyNWuDBDeI-CmVKYqaIMIInDIY,9694
10
- atcdr/test.py,sha256=Q7HHggbAix6iqClzm01YCs7Db9v01D5NNzmSztY8dbc,13521
11
- atcdr/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
- atcdr/util/execute.py,sha256=r4rYmbNQH5kIzdqAeo9SGvqJZyFX4yBIdmg9cTKeiYE,2221
13
- atcdr/util/filetype.py,sha256=pceB08trkwNkdzKJx4fFfOWpz9jYMBRDwXLW4un0sRM,2254
14
- atcdr/util/gpt.py,sha256=vH10Waa7KXlz6-5pEUBuIbxTbDH3Hys7k9Tt7prvFX4,3772
15
- atcdr/util/parse.py,sha256=SJ4khlH5iWaSwyORmQLi84npMwh5u2omCeg0q7ScEAE,6974
16
- atcdr/util/problem.py,sha256=wEoMC5KVQu5l-i4V-ZCR30Z30Zov0VCNtLVIbL-0iI0,2594
17
- atcdr/util/session.py,sha256=LwlSN86sfnkE9a-opL4qvKYHsCgiMy7eFCdcXdo79eg,4889
18
- atcoderstudybooster-0.3.1.dist-info/METADATA,sha256=FElAss6sLM-k7pAmZJteKHgrl8uPsZCV95jiyJAHaac,6243
19
- atcoderstudybooster-0.3.1.dist-info/WHEEL,sha256=C2FUgwZgiLbznR-k0b_5k3Ai_1aASOXDss3lzCUsUug,87
20
- atcoderstudybooster-0.3.1.dist-info/entry_points.txt,sha256=_bhz0R7vp2VubKl_eIokDO8Wz9TdqvYA7Q59uWfy6Sk,42
21
- atcoderstudybooster-0.3.1.dist-info/RECORD,,
@@ -1,2 +0,0 @@
1
- [console_scripts]
2
- atcdr = atcdr.main:main