kattis-cli 1.1.2__tar.gz → 1.2.0__tar.gz

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.
Files changed (37) hide show
  1. {kattis_cli-1.1.2 → kattis_cli-1.2.0}/PKG-INFO +20 -7
  2. {kattis_cli-1.1.2 → kattis_cli-1.2.0}/README.md +18 -0
  3. {kattis_cli-1.1.2 → kattis_cli-1.2.0}/pyproject.toml +21 -14
  4. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/main/c.txt +8 -0
  5. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/main/cpp.txt +15 -0
  6. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/main/java.txt +14 -0
  7. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/main/python.txt +21 -0
  8. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/main/python3.txt +22 -0
  9. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/c/Makefile +0 -0
  10. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/c/src/problemid/problemid.c +0 -0
  11. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/c/tests/test_problemid.c +0 -0
  12. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/cpp/Makefile +0 -0
  13. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/cpp/src/problemid/problemid.cpp +0 -0
  14. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/cpp/tests/test_problemid.cpp +0 -0
  15. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/python3/Makefile +0 -0
  16. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/python3/src/problemid/__init__.py +0 -0
  17. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/python3/src/problemid/problemid.py +0 -0
  18. kattis_cli-1.2.0/src/kattis_cli/kattis_templates/project_structure/python3/tests/test_problemid.py +0 -0
  19. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/main.py +24 -9
  20. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/solution_tester.py +9 -2
  21. kattis_cli-1.2.0/src/kattis_cli/template.py +161 -0
  22. kattis_cli-1.2.0/src/kattis_cli/utils/__init__.py +0 -0
  23. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/utils/config.py +3 -3
  24. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/utils/languages.py +4 -3
  25. {kattis_cli-1.1.2 → kattis_cli-1.2.0}/LICENSE +0 -0
  26. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/.kattis-cli.toml +0 -0
  27. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/__init__.py +0 -0
  28. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/client.py +0 -0
  29. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/download.py +0 -0
  30. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/fireworks.py +0 -0
  31. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/kattis.py +0 -0
  32. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/kattis_setup.py +0 -0
  33. {kattis_cli-1.1.2/kattis_cli/utils → kattis_cli-1.2.0/src/kattis_cli/kattis_templates}/__init__.py +0 -0
  34. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/settings.py +0 -0
  35. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/ui.py +0 -0
  36. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/utils/run_program.py +0 -0
  37. {kattis_cli-1.1.2 → kattis_cli-1.2.0/src}/kattis_cli/utils/utility.py +0 -0
@@ -1,19 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kattis-cli
3
- Version: 1.1.2
3
+ Version: 1.2.0
4
4
  Summary: A command-line tool for Kattis
5
5
  License-File: LICENSE
6
6
  Author: Ram Basnet
7
7
  Author-email: rbasnet@coloradomesa.edu
8
8
  Requires-Python: >=3.10.0,<4.0.0
9
+ Classifier: Programming Language :: Python :: 3
9
10
  Classifier: License :: OSI Approved :: MIT License
10
11
  Classifier: Operating System :: OS Independent
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.10
13
- Classifier: Programming Language :: Python :: 3.11
14
- Classifier: Programming Language :: Python :: 3.12
15
- Classifier: Programming Language :: Python :: 3.13
16
- Classifier: Programming Language :: Python :: 3.14
17
12
  Requires-Dist: beautifulsoup4 (>=4.12.2,<5.0.0)
18
13
  Requires-Dist: click (>=8.1.7,<9.0.0)
19
14
  Requires-Dist: lxml (>=6.0.1,<7.0.0)
@@ -138,6 +133,24 @@ kattis info
138
133
 
139
134
  ![Problem info](./images/kattis_info.png)
140
135
 
136
+ ### Creating project template
137
+
138
+ - create project template files for a given programming language
139
+ - src style default templates are created in the home directory under **.kattis-templates** folder
140
+ - you can overwrite/create new templates following the structure provided `kattis_templates`
141
+ - local languages codes supported are:
142
+ - python3
143
+ - c++
144
+ - java
145
+ - c
146
+ - nodejs
147
+
148
+ ```bash
149
+ kattis template --help
150
+ # create python3 project template for cold problem
151
+ kattis template -l python3 -p cold -s
152
+ ```
153
+
141
154
  ### Test a solution locally
142
155
 
143
156
  ![Test](images/kattis_test.png)
@@ -110,6 +110,24 @@ kattis info
110
110
 
111
111
  ![Problem info](./images/kattis_info.png)
112
112
 
113
+ ### Creating project template
114
+
115
+ - create project template files for a given programming language
116
+ - src style default templates are created in the home directory under **.kattis-templates** folder
117
+ - you can overwrite/create new templates following the structure provided `kattis_templates`
118
+ - local languages codes supported are:
119
+ - python3
120
+ - c++
121
+ - java
122
+ - c
123
+ - nodejs
124
+
125
+ ```bash
126
+ kattis template --help
127
+ # create python3 project template for cold problem
128
+ kattis template -l python3 -p cold -s
129
+ ```
130
+
113
131
  ### Test a solution locally
114
132
 
115
133
  ![Test](images/kattis_test.png)
@@ -1,31 +1,39 @@
1
- [tool.poetry]
1
+
2
+ # PEP 621 metadata table for tools that expect [project].
3
+ [project]
2
4
  name = "kattis-cli"
3
- version = "1.1.2"
4
- authors = ["Ram Basnet <rbasnet@coloradomesa.edu>"]
5
+ version = "1.2.0"
5
6
  description = "A command-line tool for Kattis"
6
7
  readme = "README.md"
7
- repository = "https://github.com/rambasnet/kattis-cli"
8
+ authors = [
9
+ { name = "Ram Basnet", email = "rbasnet@coloradomesa.edu" }
10
+ ]
11
+
8
12
  classifiers = [
9
13
  "Programming Language :: Python :: 3",
10
14
  "License :: OSI Approved :: MIT License",
11
15
  "Operating System :: OS Independent",
12
16
  ]
13
17
 
14
- # PEP 621 metadata table for tools that expect [project].
15
- [project]
16
- name = "kattis-cli"
17
- version = "1.1.2"
18
- description = "A command-line tool for Kattis"
19
- readme = "README.md"
20
- authors = [
21
- { name = "Ram Basnet", email = "rbasnet@coloradomesa.edu" }
18
+ [tool.setuptools]
19
+ include-package-data = true
20
+
21
+ [tool.setuptools.package-data]
22
+ # Include the kattis_templates package data inside the installed package
23
+ # (files under src/kattis_cli/kattis_templates)
24
+ kattis_cli = [
25
+ "kattis_templates/*",
26
+ "kattis_templates/**",
22
27
  ]
23
- repository = "https://github.com/rambasnet/kattis-cli"
24
28
 
29
+ [tool.poetry]
25
30
  [project.urls]
26
31
  "Homepage" = "https://github.com/rambasnet/kattis-cli"
27
32
  "Bug Tracker" = "https://github.com/rambasnet/kattis-cli/issues"
28
33
 
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
36
+
29
37
  [tool.poetry.dependencies]
30
38
  python = "^3.10.0"
31
39
  requests = "^2.31.0"
@@ -39,4 +47,3 @@ trogon = "^0.6.0"
39
47
 
40
48
  [tool.poetry.scripts]
41
49
  kattis = 'kattis_cli.main:main'
42
-
@@ -0,0 +1,8 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+
4
+ int main() {
5
+ // Your solution here
6
+
7
+ return 0;
8
+ }
@@ -0,0 +1,15 @@
1
+ #include <iostream>
2
+ #include <vector>
3
+ #include <string>
4
+ #include <algorithm>
5
+
6
+ using namespace std;
7
+
8
+ int main() {
9
+ ios_base::sync_with_stdio(false);
10
+ cin.tie(NULL);
11
+
12
+ // Your solution here
13
+
14
+ return 0;
15
+ }
@@ -0,0 +1,14 @@
1
+ import java.util.Scanner;
2
+
3
+ public class {class_name} {
4
+ public static void main(String[] args) {
5
+ Scanner scanner = new Scanner(System.in);
6
+
7
+ // Your solution here
8
+ // if (scanner.hasNext()) {
9
+ // String line = scanner.next();
10
+ // }
11
+
12
+ scanner.close();
13
+ }
14
+ }
@@ -0,0 +1,21 @@
1
+ """Python template
2
+ """
3
+ import sys
4
+
5
+
6
+ def main() -> None:
7
+ """Main function
8
+ """
9
+ # Read all lines from stdin
10
+ input_data = sys.stdin.read().split()
11
+ if not input_data:
12
+ return
13
+
14
+ # Example: reading an integer
15
+ # n = int(input_data[0])
16
+
17
+ # Your solution here
18
+
19
+
20
+ if __name__ == "__main__":
21
+ main()
@@ -0,0 +1,22 @@
1
+ """Python template
2
+ """
3
+ import sys
4
+
5
+
6
+ def main() -> None:
7
+ """Main function
8
+ """
9
+ # Read all lines from stdin
10
+ input_data = sys.stdin.read().split()
11
+ if not input_data:
12
+ return
13
+
14
+ # Example: reading an integer
15
+ # n = int(input_data[0])
16
+
17
+ # Your solution here
18
+
19
+
20
+ if __name__ == "__main__":
21
+ name()
22
+
@@ -1,15 +1,11 @@
1
1
  """ Main module for the kattis_cli package.
2
- This is the main.py file for the kattis_cli package.
3
-
4
- Change the contents in dev.py instead of in main.py.
5
- build.sh script copies the contents of this file to main.py.
6
2
 
7
3
  Change the __version__ to match in pyproject.toml
8
- Has to be higher than the pypi version.
9
4
  """
10
- __version__ = '1.1.2'
5
+ __version__ = '1.2.0'
11
6
 
12
7
  from math import inf
8
+ import os
13
9
  from typing import Tuple
14
10
  from rich.console import Console
15
11
  import click
@@ -21,6 +17,7 @@ import kattis_cli.solution_tester as solution_tester
21
17
  import kattis_cli.kattis as kattis
22
18
  import kattis_cli.utils.languages as languages
23
19
  import kattis_cli.kattis_setup as kattis_setup
20
+ import kattis_cli.template as template
24
21
 
25
22
 
26
23
  @tui()
@@ -43,13 +40,16 @@ def get(problemid: str) -> None:
43
40
  f"Downloading samples: [bold blue]{problemid}[/bold blue]")
44
41
  try:
45
42
  download.download_sample_data(problemid)
43
+ console.print(
44
+ f"Downloading metadata: [bold blue]{problemid}[/bold blue]")
45
+ download.load_problem_metadata(problemid)
46
46
  except requests.exceptions.InvalidURL:
47
47
  console.print(
48
48
  f"Problem ID: [bold red]{problemid}[/bold red] not found.")
49
49
  else:
50
50
  console.print(
51
- f"Downloading metadata: [bold blue]{problemid}[/bold blue]")
52
- download.load_problem_metadata(problemid)
51
+ f"Downloaded samples and metadata: \
52
+ [bold blue]{problemid}[/bold blue]")
53
53
 
54
54
 
55
55
  @main.command(help='Show problem metadata.')
@@ -115,7 +115,6 @@ def submit(problemid: str, language: str,
115
115
  languages.update_args(
116
116
  problemid, language, mainclass, list(files))
117
117
  # Finally, submit the solution
118
- # print(f'{problemid=} {language=} {mainclass=} {tag=} {force=} {_files=}')
119
118
  if not mainclass:
120
119
  mainclass = languages.guess_mainfile(
121
120
  language, _files, problemid, lang_config)
@@ -132,5 +131,21 @@ def setup() -> None:
132
131
  kattis_setup.setup()
133
132
 
134
133
 
134
+ @main.command(help='Create a template file for a problem.')
135
+ @click.option('-l', '--language', default='python3',
136
+ help='Programming language (default: python3)')
137
+ @click.option('-p', '--problemid', default=None,
138
+ help='Problem ID (default: parent directory name)')
139
+ @click.option('-s', '--src', is_flag=True, default=False,
140
+ help='Create src layout structure')
141
+ def template_cmd(language: str, problemid: str, src: bool) -> None:
142
+ """Create a template file.
143
+ """
144
+ if not problemid:
145
+ problemid = os.path.basename(os.getcwd())
146
+
147
+ template.create_template(language, problemid, src)
148
+
149
+
135
150
  if __name__ == '__main__':
136
151
  main()
@@ -91,6 +91,10 @@ class SolutionTester:
91
91
  total = len(in_files)
92
92
  console.clear()
93
93
  title = f"[not italic bold blue]👷‍ Testing {mainclass} "
94
+ main_src_file = next((f for f in files if f.endswith(mainclass)), None)
95
+ if not main_src_file:
96
+ main_src_file = mainclass
97
+
94
98
  title += f" using {loc_language} 👷‍[/]"
95
99
  table.title = title
96
100
  with Live(table_centered, console=console,
@@ -145,7 +149,7 @@ class SolutionTester:
145
149
  expected = b"No .ans or .out file found!"
146
150
  code, ans, error = run_program.run(
147
151
  lang_config,
148
- mainclass,
152
+ main_src_file,
149
153
  in_file,
150
154
  )
151
155
  if code != 0:
@@ -159,7 +163,10 @@ class SolutionTester:
159
163
  result = "[bold red]❌[/bold red]"
160
164
 
161
165
  in_filename = Path(in_file).parts[-1]
162
- out_filename = Path(out_file).parts[-1]
166
+ if b"No .ans or .out file found!" == expected:
167
+ out_filename = "N/A"
168
+ else:
169
+ out_filename = Path(out_file).parts[-1]
163
170
  time.sleep(0.1)
164
171
  table.add_row(in_filename,
165
172
  input_content.decode('utf-8'),
@@ -0,0 +1,161 @@
1
+ """Module for generating project templates."""
2
+
3
+ import os
4
+ import shutil
5
+ from pathlib import Path
6
+ import importlib.resources as pkg_resources
7
+ from rich.console import Console
8
+
9
+
10
+ LANGUAGE_EXTENSIONS = {
11
+ 'c': '.c',
12
+ 'cpp': '.cpp',
13
+ 'csharp': '.cs',
14
+ 'cobol': '.cob',
15
+ 'fsharp': '.fs',
16
+ 'go': '.go',
17
+ 'haskell': '.hs',
18
+ 'java': '.java',
19
+ 'nodejs': '.js',
20
+ 'typescript': '.ts',
21
+ 'kotlin': '.kt',
22
+ 'lisp': '.lisp',
23
+ 'objective-c': '.m',
24
+ 'ocaml': '.ml',
25
+ 'pascal': '.pas',
26
+ 'php': '.php',
27
+ 'prolog': '.pl',
28
+ 'python': '.py',
29
+ 'python3': '.py',
30
+ 'ruby': '.rb',
31
+ 'rust': '.rs',
32
+ 'scala': '.scala',
33
+ 'fortran': '.f90',
34
+ 'bash': '.sh',
35
+ 'apl': '.apl',
36
+ 'gerbil': '.ss',
37
+ 'julia': '.jl',
38
+ 'vb': '.vb',
39
+ 'dart': '.dart',
40
+ 'zig': '.zig',
41
+ 'swift': '.swift',
42
+ 'nim': '.nim',
43
+ }
44
+
45
+
46
+ def create_template(
47
+ language: str,
48
+ problemid: str,
49
+ src_layout: bool = False) -> None:
50
+ """Create a template file for the specified language and problem ID.
51
+
52
+ Args:
53
+ language (str): The programming language (e.g., 'python3', 'cpp').
54
+ problemid (str): The problem ID, used for the filename.
55
+ src_layout (bool): If True, create a src/ directory structure.
56
+ """
57
+ language = language.lower()
58
+ home_templates = os.path.expanduser('~/kattis_templates')
59
+
60
+ def _check_kattis_templates() -> bool:
61
+ # Always use ~/kattis_templates as the user-facing template directory
62
+ # On first use, if not present, copy all default templates from
63
+ # package data
64
+ if not os.path.isdir(home_templates):
65
+ try:
66
+ # Use importlib.resources to access kattis_templates as a
67
+ # package resource
68
+ src = pkg_resources.files("kattis_cli") / "kattis_templates"
69
+ shutil.copytree(str(src), home_templates)
70
+ except Exception as e:
71
+ console.print(
72
+ f"[bold red]❌ Error:[/bold red] Could not \
73
+ copy templates: {e}")
74
+ return False
75
+ return True
76
+
77
+ def _get_main_template(language: str) -> str:
78
+ main_templates = Path(home_templates).joinpath('main')
79
+ for file in main_templates.iterdir():
80
+ # print(file.stem.lower(), language)
81
+ if file.is_file() and file.stem.lower() == language:
82
+ return str(file)
83
+ return ''
84
+
85
+ console = Console()
86
+ if not _check_kattis_templates():
87
+ console.print(
88
+ f"[bold red]❌ Error:[/bold red] Templates '{language}' \
89
+ not found in {home_templates}!")
90
+ return
91
+
92
+ def _copytree_with_problemid(src: str,
93
+ dst: str,
94
+ problemid: str) -> None:
95
+ for root, _, files in os.walk(src):
96
+ rel = os.path.relpath(root, src)
97
+ rel = rel.replace('problemid', problemid)
98
+ target_root = os.path.join(dst, rel) if rel != '.' else dst
99
+ os.makedirs(target_root, exist_ok=True)
100
+ for f in files:
101
+ src_file = os.path.join(root, f)
102
+ dst_file = os.path.join(
103
+ target_root, f.replace('problemid', problemid))
104
+ shutil.copy2(src_file, dst_file)
105
+
106
+ # If src_layout, copy the project structure for the language
107
+ if src_layout:
108
+ proj_struct_root = Path(home_templates).joinpath('project_structure')
109
+ lang_src_struct = proj_struct_root.joinpath(language)
110
+ if os.path.isdir(lang_src_struct):
111
+ _copytree_with_problemid(
112
+ str(lang_src_struct), os.getcwd(), problemid)
113
+ console.print(
114
+ f"[bold blue]✅ [/bold blue] Created project \
115
+ structure for {language}.")
116
+ target_dir = os.path.join("src", problemid)
117
+ else:
118
+ target_dir = "."
119
+
120
+ main_template = _get_main_template(language=language)
121
+ extension = LANGUAGE_EXTENSIONS.get(language, None)
122
+
123
+ try:
124
+ with open(str(main_template), 'r', encoding='utf-8') as tf:
125
+ template_content = tf.read()
126
+ except OSError:
127
+ console.print(
128
+ f"[bold red] ❌ [/bold red] Could not read \
129
+ template file: {main_template}")
130
+ return
131
+
132
+ if not main_template:
133
+ return
134
+ # Handle Java class naming convention (capitalize first letter)
135
+ if language == 'java':
136
+ class_name = problemid[0].upper(
137
+ ) + problemid[1:] if problemid else "Main"
138
+ filename = f"{class_name}{extension}"
139
+ content = template_content.replace("{class_name}", class_name)
140
+ else:
141
+ filename = f"{problemid}{extension}"
142
+ content = template_content
143
+
144
+ filepath = os.path.join(target_dir, filename)
145
+
146
+ if os.path.exists(filepath) and os.path.getsize(filepath) > 0:
147
+ console.print(
148
+ f"[bold yellow]Warning:[/bold yellow] File '{filepath}' \
149
+ exists with content. Skipping.")
150
+ return
151
+
152
+ try:
153
+ with open(filepath, 'w', encoding='utf-8') as f:
154
+ f.write(content)
155
+ console.print(
156
+ f"[bold green]✅ [/bold green] Created template \
157
+ '{filepath}' for {language}.")
158
+ except OSError as e:
159
+ console.print(
160
+ f"[bold red]❌ [/bold red] Failed to create template \
161
+ '{filepath}': {e}")
File without changes
@@ -11,7 +11,7 @@ import yaml
11
11
 
12
12
  from kattis_cli.utils.utility import find_problem_root_folder
13
13
 
14
- _DEFAULT_CONFIG = Path.home().joinpath('.kattisrc')
14
+ _KATTIS_RC = Path.home().joinpath('.kattisrc')
15
15
 
16
16
 
17
17
  class ConfigError(Exception):
@@ -42,8 +42,8 @@ def get_kattisrc() -> configparser.ConfigParser:
42
42
  """Returns a ConfigParser object for the .kattisrc file(s)
43
43
  """
44
44
  cfg = configparser.ConfigParser()
45
- if os.path.exists(_DEFAULT_CONFIG):
46
- cfg.read(_DEFAULT_CONFIG)
45
+ if os.path.exists(_KATTIS_RC):
46
+ cfg.read(_KATTIS_RC)
47
47
 
48
48
  if not cfg.read([os.path.join(os.path.expanduser("~"), '.kattisrc'),
49
49
  os.path.join(os.path.dirname(sys.argv[0]), '.kattisrc')]):
@@ -271,7 +271,7 @@ def update_args(problemid: str,
271
271
 
272
272
  console = Console()
273
273
  if not files:
274
- files = get_coding_files()
274
+ files = get_coding_files(Path.cwd())
275
275
  # check if problemid is given
276
276
  # if not problemid:
277
277
  cur_folder = Path.cwd()
@@ -318,13 +318,14 @@ filename extension "{ext}"''')
318
318
  return problemid, loc_language, mainclass, files, root_folder, lang_config
319
319
 
320
320
 
321
- def get_coding_files(base_path: Path = Path.cwd()) -> List[str]:
321
+ def get_coding_files(base_path: Path) -> List[str]:
322
322
  """Get coding files from current directory.
323
323
 
324
324
  Returns:
325
325
  List[str]: List of coding files.
326
326
  """
327
-
327
+ if not base_path:
328
+ base_path = Path.cwd()
328
329
  if Path(base_path / "src").is_dir():
329
330
  base_path = base_path / "src"
330
331
  console = Console()
File without changes