code-battles-cli 1.2.2__tar.gz → 1.2.5__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 (21) hide show
  1. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/PKG-INFO +6 -11
  2. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/README.md +2 -7
  3. code_battles_cli-1.2.5/pyproject.toml +33 -0
  4. code_battles_cli-1.2.2/pyproject.toml → code_battles_cli-1.2.5/pyproject.toml.orig +9 -10
  5. code_battles_cli-1.2.5/src/code_battles_cli/__init__.py +1 -0
  6. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/__main__.py +2 -1
  7. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/api.py +92 -58
  8. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/cli.py +3 -5
  9. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/commands/download.py +8 -7
  10. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/commands/run.py +13 -12
  11. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/commands/upload.py +7 -6
  12. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/log.py +3 -3
  13. code_battles_cli-1.2.2/.github/workflows/test.yml +0 -21
  14. code_battles_cli-1.2.2/.gitignore +0 -13
  15. code_battles_cli-1.2.2/.python-version +0 -1
  16. code_battles_cli-1.2.2/LICENSE.md +0 -7
  17. code_battles_cli-1.2.2/requirements-dev.lock +0 -84
  18. code_battles_cli-1.2.2/requirements.lock +0 -72
  19. code_battles_cli-1.2.2/src/code_battles_cli/__init__.py +0 -1
  20. code_battles_cli-1.2.2/tests/test_cli.py +0 -2
  21. {code_battles_cli-1.2.2 → code_battles_cli-1.2.5}/src/code_battles_cli/commands/__init__.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: code-battles-cli
3
- Version: 1.2.2
3
+ Version: 1.2.5
4
4
  Summary: A CLI for competitors in any Code Battles event!
5
- Requires-Python: >=3.8
6
- Requires-Dist: click>=8.1.7
7
- Requires-Dist: google-cloud-firestore>=2.19.0
8
5
  Requires-Dist: requests>=2.32.3
6
+ Requires-Dist: google-cloud-firestore>=2.19.0
9
7
  Requires-Dist: rich>=13.9.3
8
+ Requires-Dist: click>=8.1.7
9
+ Requires-Python: >=3.8
10
10
  Description-Content-Type: text/markdown
11
11
 
12
12
  <p align="center">
@@ -27,8 +27,6 @@ Description-Content-Type: text/markdown
27
27
  🏃 <a href="#getting-started">Getting Started</a>
28
28
  &nbsp;&middot&nbsp;
29
29
  💡 <a href="#features">Features</a>
30
- &nbsp;&middot&nbsp;
31
- 🚗 <a href="#roadmap">Roadmap</a>
32
30
  </p>
33
31
 
34
32
  # Getting Started
@@ -72,9 +70,6 @@ print(client.get_bots())
72
70
  print(client.run_simulation("NYC", ["bots/example.py", "bots/another_example.py"]))
73
71
  ```
74
72
 
75
- # Roadmap
73
+ # Development
76
74
 
77
- - [x] Download bots.
78
- - [x] Upload bots.
79
- - [x] Run no-UI simulations locally.
80
- - [x] Be usable in scripts.
75
+ For development, you should set up the pre-commit hooks with `uv run pre-commit install`.
@@ -16,8 +16,6 @@
16
16
  🏃 <a href="#getting-started">Getting Started</a>
17
17
  &nbsp;&middot&nbsp;
18
18
  💡 <a href="#features">Features</a>
19
- &nbsp;&middot&nbsp;
20
- 🚗 <a href="#roadmap">Roadmap</a>
21
19
  </p>
22
20
 
23
21
  # Getting Started
@@ -61,9 +59,6 @@ print(client.get_bots())
61
59
  print(client.run_simulation("NYC", ["bots/example.py", "bots/another_example.py"]))
62
60
  ```
63
61
 
64
- # Roadmap
62
+ # Development
65
63
 
66
- - [x] Download bots.
67
- - [x] Upload bots.
68
- - [x] Run no-UI simulations locally.
69
- - [x] Be usable in scripts.
64
+ For development, you should set up the pre-commit hooks with `uv run pre-commit install`.
@@ -0,0 +1,33 @@
1
+ [project]
2
+ name = "code-battles-cli"
3
+ version = "1.2.5"
4
+ description = "A CLI for competitors in any Code Battles event!"
5
+ dependencies = [
6
+ "requests>=2.32.3",
7
+ "google-cloud-firestore>=2.19.0",
8
+ "rich>=13.9.3",
9
+ "click>=8.1.7",
10
+ ]
11
+ readme = "README.md"
12
+ requires-python = ">= 3.8"
13
+
14
+ [project.scripts]
15
+ code-battles = "code_battles_cli:main"
16
+
17
+ [build-system]
18
+ requires = ["uv_build>=0.10,<0.13"]
19
+ build-backend = "uv_build"
20
+
21
+ [dependency-groups]
22
+ dev = [
23
+ "mypy>=1.14.1",
24
+ "pre-commit>=3.5.0",
25
+ "pytest>=8.3.5",
26
+ "ruff>=0.16.10",
27
+ ]
28
+
29
+ [tool.mypy]
30
+ untyped_calls_exclude = "google"
31
+
32
+ [tool.ruff.lint]
33
+ ignore = ["LOG015"]
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "code-battles-cli"
3
- version = "1.2.2"
3
+ version = "1.2.5"
4
4
  description = "A CLI for competitors in any Code Battles event!"
5
5
  dependencies = [
6
6
  "requests>=2.32.3",
@@ -15,15 +15,14 @@ requires-python = ">= 3.8"
15
15
  "code-battles" = "code_battles_cli:main"
16
16
 
17
17
  [build-system]
18
- requires = ["hatchling==1.26.3"]
19
- build-backend = "hatchling.build"
18
+ requires = ["uv_build>=0.10,<0.13"]
19
+ build-backend = "uv_build"
20
20
 
21
- [tool.rye]
22
- managed = true
23
- dev-dependencies = ["pytest>=8.3.5"]
21
+ [dependency-groups]
22
+ dev = ["mypy>=1.14.1", "pre-commit>=3.5.0", "pytest>=8.3.5", "ruff>=0.16.10"]
24
23
 
25
- [tool.hatch.metadata]
26
- allow-direct-references = true
24
+ [tool.mypy]
25
+ untyped_calls_exclude = "google"
27
26
 
28
- [tool.hatch.build.targets.wheel]
29
- packages = ["src/code_battles_cli"]
27
+ [tool.ruff]
28
+ lint.ignore = ["LOG015"]
@@ -0,0 +1 @@
1
+ from code_battles_cli.cli import main as main
@@ -1,4 +1,5 @@
1
- from code_battles_cli.cli import main
2
1
  import sys
3
2
 
3
+ from code_battles_cli.cli import main
4
+
4
5
  sys.exit(main())
@@ -4,6 +4,8 @@ Code Battles Python Client API
4
4
  Firestore client implementation inspired by https://medium.com/@bobthomas295/client-side-authentication-with-python-firestore-and-firebase-352e484a2634
5
5
  """
6
6
 
7
+ from __future__ import annotations
8
+
7
9
  import base64
8
10
  import datetime
9
11
  import gzip
@@ -15,12 +17,13 @@ import subprocess
15
17
  import sys
16
18
  from dataclasses import dataclass
17
19
  from pathlib import Path
18
- from typing import Any, Callable, Dict, List, Optional, Union
20
+ from typing import Any, Callable, Literal
19
21
 
20
22
  import requests
21
23
  from google.cloud.firestore import Client as FirestoreClient
22
24
  from google.oauth2.credentials import Credentials
23
25
  from rich.prompt import Prompt
26
+ from typing_extensions import overload
24
27
 
25
28
  from code_battles_cli.log import console, log
26
29
 
@@ -28,7 +31,7 @@ SIMULATION_FINISHED_MARK = b"--- SIMULATION FINISHED ---"
28
31
  SIMULATION_STEP_MARK = b"__CODE_BATTLES_ADVANCE_STEP"
29
32
 
30
33
 
31
- def normalize(url: str):
34
+ def normalize(url: str) -> str:
32
35
  if url.startswith("https"):
33
36
  url = url[5:]
34
37
 
@@ -45,7 +48,7 @@ class SimulationException(Exception):
45
48
  self.stderr = stderr
46
49
  self.exit_code = exit_code
47
50
 
48
- def __str__(self):
51
+ def __str__(self) -> str:
49
52
  return (
50
53
  f"Simulation failed with exit code {self.exit_code}. Output:\n"
51
54
  + self.stderr.decode()
@@ -57,7 +60,7 @@ class LogEntry:
57
60
  step: int
58
61
  text: str
59
62
  color: str
60
- player_index: Optional[int]
63
+ player_index: int | None
61
64
 
62
65
 
63
66
  @dataclass
@@ -65,22 +68,23 @@ class SimulationResults:
65
68
  winner_index: int
66
69
  winner: str
67
70
  steps: int
68
- logs: List[LogEntry]
71
+ logs: list[LogEntry]
69
72
 
70
73
 
71
74
  @dataclass
72
75
  class Simulation:
73
- parameters: Dict[str, str]
76
+ parameters: dict[str, str]
77
+ statistics: dict[str, float]
74
78
  player_names: str
75
79
  game: str
76
80
  version: str
77
81
  timestamp: datetime.datetime
78
- logs: list
79
- alerts: list
80
- decisions: List[bytes]
82
+ logs: list[Any]
83
+ alerts: list[Any]
84
+ decisions: list[bytes]
81
85
  seed: int
82
86
 
83
- def dump(self):
87
+ def dump(self) -> str:
84
88
  return base64.b64encode(
85
89
  gzip.compress(
86
90
  json.dumps(
@@ -97,18 +101,20 @@ class Simulation:
97
101
  for decision in self.decisions
98
102
  ],
99
103
  "seed": self.seed,
104
+ "statistics": self.statistics,
100
105
  }
101
106
  ).encode()
102
107
  )
103
108
  ).decode()
104
109
 
105
110
  @staticmethod
106
- def load(file: str):
107
- contents: Dict[str, Any] = json.loads(gzip.decompress(base64.b64decode(file)))
111
+ def load(file: str) -> Simulation:
112
+ contents: dict[str, Any] = json.loads(gzip.decompress(base64.b64decode(file)))
108
113
  return Simulation(
109
114
  contents["parameters"]
110
115
  if "parameters" in contents
111
116
  else {"map": contents["map"]},
117
+ contents.get("statistics", {}),
112
118
  contents["playerNames"],
113
119
  contents["game"],
114
120
  contents["version"],
@@ -123,10 +129,10 @@ class Simulation:
123
129
  class Client:
124
130
  def __init__(
125
131
  self,
126
- url: Optional[str] = None,
127
- username: Optional[str] = None,
128
- password: Optional[str] = None,
129
- dump_credentials=True,
132
+ url: str | None = None,
133
+ username: str | None = None,
134
+ password: str | None = None,
135
+ dump_credentials: bool = True,
130
136
  ):
131
137
  """
132
138
  Creates a client for getting and setting the bots for a Code Battles hosted at `url`
@@ -146,16 +152,13 @@ class Client:
146
152
  if dump_credentials:
147
153
  self._dump_credentials()
148
154
 
149
- def _get_credentials(self):
155
+ def _get_credentials(self) -> None:
150
156
  if os.path.exists("code-battles.json"):
151
- try:
152
- with open("code-battles.json", "r") as f:
153
- configuration = json.load(f)
154
- self.url: str = configuration["url"]
155
- self.username: str = configuration["username"]
156
- self.password: str = configuration["password"]
157
- except Exception:
158
- pass
157
+ with open("code-battles.json", "r") as f:
158
+ configuration = json.load(f)
159
+ self.url = configuration["url"]
160
+ self.username = configuration["username"]
161
+ self.password = configuration["password"]
159
162
 
160
163
  if (
161
164
  not hasattr(self, "url")
@@ -171,14 +174,14 @@ class Client:
171
174
 
172
175
  self.username = Prompt.ask("Enter your team's username", console=console)
173
176
 
174
- if not self.username == self.username.lower():
177
+ if self.username != self.username.lower():
175
178
  log.warning("Your username should most likely be lowercased.")
176
179
 
177
180
  self.password = Prompt.ask(
178
181
  "Enter your team's password", console=console, password=True
179
182
  )
180
183
 
181
- def _dump_credentials(self):
184
+ def _dump_credentials(self) -> None:
182
185
  with open("code-battles.json", "w") as f:
183
186
  json.dump(
184
187
  {"url": self.url, "username": self.username, "password": self.password},
@@ -188,12 +191,12 @@ class Client:
188
191
  "Credentials were dumped to `code-battles.json`. Make sure other teams don't have access to this file!"
189
192
  )
190
193
 
191
- def _get_firebase_data(self):
194
+ def _get_firebase_data(self) -> None:
192
195
  configuration = requests.get(self.url + "/firebase-configuration.json").json()
193
196
  self.firebase_api_key: str = configuration["apiKey"]
194
197
  self.firebase_project_id: str = configuration["projectId"]
195
198
 
196
- def _sign_in(self, email_domain="gmail.com"):
199
+ def _sign_in(self, email_domain: str = "gmail.com") -> None:
197
200
  try:
198
201
  response = requests.post(
199
202
  f"https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key={self.firebase_api_key}",
@@ -203,27 +206,29 @@ class Client:
203
206
  "returnSecureToken": True,
204
207
  },
205
208
  ).json()
206
- except Exception:
207
- raise Exception(
209
+ except Exception as e:
210
+ raise RuntimeError(
208
211
  "Sign in failed! Make sure the username and password are correct."
209
- )
212
+ ) from e
210
213
 
211
214
  self.credentials = Credentials(response["idToken"], response["refreshToken"])
212
215
  self.client = FirestoreClient(self.firebase_project_id, self.credentials)
213
216
  self.document = self.client.document(f"bots/{self.username}")
214
217
 
215
- def get_bots(self) -> Dict[str, str]:
218
+ def get_bots(self) -> dict[str, str]:
216
219
  """Returns a mapping from a bot's name to their Python code."""
217
- return self.document.get().to_dict()
220
+ result = self.document.get().to_dict()
221
+ assert result is not None
222
+ return result
218
223
 
219
- def set_bots(self, bots: Dict[str, str], merge=True) -> None:
224
+ def set_bots(self, bots: dict[str, str], merge: bool = True) -> None:
220
225
  """
221
226
  Sets the bots in the website to the specified bots.
222
227
  Doesn't remove any bot unless ``merge`` is ``False``, in which case only bots specified in ``bots`` will remain.
223
228
  """
224
229
  self.document.set(bots, merge)
225
230
 
226
- def _possibly_download(self, force_download=False):
231
+ def _possibly_download(self, force_download: bool = False) -> str:
227
232
  directory_name = "".join(
228
233
  [c for c in normalize(self.url) if c.isalnum() or c == "-"]
229
234
  )
@@ -245,14 +250,16 @@ class Client:
245
250
 
246
251
  def _get_simulation_output(
247
252
  self,
248
- p: subprocess.Popen,
249
- json_output=False,
250
- on_step: Optional[Callable[[], None]] = None,
251
- ) -> Union[SimulationResults, str]:
253
+ p: subprocess.Popen[bytes],
254
+ json_output: bool = False,
255
+ on_step: Callable[[], None] | None = None,
256
+ ) -> SimulationResults | str:
252
257
  while True:
253
258
  if p.poll() is not None and p.returncode != 0:
259
+ assert p.stderr is not None
254
260
  raise SimulationException(p.stderr.read(), p.returncode)
255
261
 
262
+ assert p.stdout is not None
256
263
  line: bytes = p.stdout.readline()
257
264
  line = line.strip()
258
265
  if line == SIMULATION_FINISHED_MARK:
@@ -267,19 +274,20 @@ class Client:
267
274
  if json_output:
268
275
  return output.decode()
269
276
 
270
- output = json.loads(output)
277
+ output_json = json.loads(output)
271
278
  result = SimulationResults(
272
- output["winner_index"],
273
- output["winner"],
274
- output["steps"],
279
+ output_json["winner_index"],
280
+ output_json["winner"],
281
+ output_json["steps"],
275
282
  [
276
283
  LogEntry(
277
284
  entry["step"], entry["text"], entry["color"], entry["player_index"]
278
285
  )
279
- for entry in output["logs"]
286
+ for entry in output_json["logs"]
280
287
  ],
281
288
  )
282
289
 
290
+ assert p.stderr is not None
283
291
  error: bytes = p.stderr.read()
284
292
  exit_code = p.wait()
285
293
  if exit_code != 0:
@@ -287,17 +295,43 @@ class Client:
287
295
 
288
296
  return result
289
297
 
298
+ @overload
299
+ def run_simulation(
300
+ self,
301
+ parameters: dict[str, str],
302
+ bot_filenames: list[str],
303
+ bot_names: list[str] | None = None,
304
+ seed: int | None = None,
305
+ force_download: bool = False,
306
+ json_output: Literal[False] = False,
307
+ on_step: Callable[[], None] | None = None,
308
+ output_file: str | None = None,
309
+ ) -> SimulationResults: ...
310
+
311
+ @overload
312
+ def run_simulation(
313
+ self,
314
+ parameters: dict[str, str],
315
+ bot_filenames: list[str],
316
+ bot_names: list[str] | None = None,
317
+ seed: int | None = None,
318
+ force_download: bool = False,
319
+ json_output: Literal[True] = True,
320
+ on_step: Callable[[], None] | None = None,
321
+ output_file: str | None = None,
322
+ ) -> str: ...
323
+
290
324
  def run_simulation(
291
325
  self,
292
- parameters: Dict[str, str],
293
- bot_filenames: List[str],
294
- bot_names: Optional[List[str]] = None,
295
- seed: Optional[int] = None,
296
- force_download=False,
297
- json_output=False,
298
- on_step: Optional[Callable[[], None]] = None,
299
- output_file: Optional[str] = None,
300
- ) -> Union[SimulationResults, str]:
326
+ parameters: dict[str, str],
327
+ bot_filenames: list[str],
328
+ bot_names: list[str] | None = None,
329
+ seed: int | None = None,
330
+ force_download: bool = False,
331
+ json_output: bool = False,
332
+ on_step: Callable[[], None] | None = None,
333
+ output_file: str | None = None,
334
+ ) -> SimulationResults | str:
301
335
  """
302
336
  Runs the given simulation without UI locally.
303
337
  If ``bot_names`` is not specified, they will be the filenames without the extension.
@@ -340,10 +374,10 @@ class Client:
340
374
  def run_simulation_from_file(
341
375
  self,
342
376
  simulation_file: str,
343
- force_download=False,
344
- json_output=False,
345
- on_step: Optional[Callable[[], None]] = None,
346
- ) -> Union[SimulationResults, str]:
377
+ force_download: bool = False,
378
+ json_output: bool = False,
379
+ on_step: Callable[[], None] | None = None,
380
+ ) -> SimulationResults | str:
347
381
  """
348
382
  Runs the given simulation without UI locally from the given simulation file.
349
383
 
@@ -1,22 +1,20 @@
1
- import datetime
2
-
3
1
  import click
4
2
 
5
3
 
6
4
  @click.group()
7
5
  @click.version_option(message="%(prog)s %(version)s")
8
- def cli():
6
+ def cli() -> None:
9
7
  pass
10
8
 
11
9
 
12
10
  def main() -> int:
13
- from code_battles_cli.log import setup_logging, log
11
+ from code_battles_cli.log import setup_logging
14
12
 
15
13
  setup_logging()
16
14
 
17
15
  from code_battles_cli.commands.download import download
18
- from code_battles_cli.commands.upload import upload
19
16
  from code_battles_cli.commands.run import run
17
+ from code_battles_cli.commands.upload import upload
20
18
 
21
19
  cli.add_command(download)
22
20
  cli.add_command(upload)
@@ -1,5 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
- from typing import Optional
3
4
 
4
5
  import click
5
6
 
@@ -35,18 +36,18 @@ from code_battles_cli.log import log
35
36
  help="The directory to download the bots into",
36
37
  )
37
38
  def download(
38
- url: Optional[str],
39
- username: Optional[str],
40
- password: Optional[str],
39
+ url: str | None,
40
+ username: str | None,
41
+ password: str | None,
41
42
  dump_credentials: bool,
42
- bot: Optional[str],
43
+ bot: str | None,
43
44
  d: str,
44
- ):
45
+ ) -> None:
45
46
  client = Client(url, username, password, dump_credentials)
46
47
  bots = client.get_bots()
47
48
  if bot is not None:
48
49
  if bot not in bots:
49
- raise Exception(f"The specified bot '{bot}' does not exist!")
50
+ raise KeyError(bot)
50
51
  bots = {bot: bots[bot]}
51
52
 
52
53
  if not os.path.exists(d):
@@ -1,8 +1,8 @@
1
+ from __future__ import annotations
2
+
1
3
  import json
2
4
  import logging
3
- import sys
4
5
  import time
5
- from typing import List, Optional, Tuple
6
6
 
7
7
  import click
8
8
 
@@ -50,17 +50,17 @@ from code_battles_cli.log import log, progress
50
50
  help="Output file to dump the simulation into",
51
51
  )
52
52
  def run(
53
- url: Optional[str],
54
- username: Optional[str],
55
- password: Optional[str],
53
+ url: str | None,
54
+ username: str | None,
55
+ password: str | None,
56
56
  dump_credentials: bool,
57
- parameters: Optional[str],
58
- bots: Tuple[str],
57
+ parameters: str | None,
58
+ bots: tuple[str],
59
59
  force_download: bool,
60
- seed: Optional[int],
61
- simulation_file: Optional[str],
62
- output_file: Optional[str],
63
- ):
60
+ seed: int | None,
61
+ simulation_file: str | None,
62
+ output_file: str | None,
63
+ ) -> None:
64
64
  logging.getLogger("rich").setLevel(logging.WARNING)
65
65
  client = Client(url, username, password, dump_credentials)
66
66
  client._possibly_download(force_download)
@@ -69,7 +69,7 @@ def run(
69
69
  with progress:
70
70
  progress_id = progress.add_task("[green]Simulating...", total=None)
71
71
 
72
- def on_step():
72
+ def on_step() -> None:
73
73
  progress.update(progress_id, advance=1)
74
74
 
75
75
  if simulation_file is not None:
@@ -103,6 +103,7 @@ def run(
103
103
  else:
104
104
  assert map is not None, "Map is required for simulation!"
105
105
  assert len(bots) > 0, "Bots are required for simulation!"
106
+ assert parameters is not None, "Parameters are required for simulation!"
106
107
 
107
108
  results = client.run_simulation(
108
109
  json.loads(parameters),
@@ -1,5 +1,6 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
- from typing import Optional
3
4
 
4
5
  import click
5
6
 
@@ -33,12 +34,12 @@ from code_battles_cli.log import log
33
34
  )
34
35
  def upload(
35
36
  file: str,
36
- name: Optional[str],
37
- url: Optional[str],
38
- username: Optional[str],
39
- password: Optional[str],
37
+ name: str | None,
38
+ url: str | None,
39
+ username: str | None,
40
+ password: str | None,
40
41
  dump_credentials: bool,
41
- ):
42
+ ) -> None:
42
43
  bot_name = name if name is not None else os.path.splitext(os.path.basename(file))[0]
43
44
  with open(file, "r") as f:
44
45
  bot_code = f.read()
@@ -1,11 +1,11 @@
1
- import os
2
1
  import logging
2
+ import os
3
3
 
4
4
  from rich.console import Console
5
+ from rich.logging import RichHandler
5
6
  from rich.progress import BarColumn, MofNCompleteColumn, Progress, TextColumn
6
7
  from rich.table import Column
7
8
  from rich.traceback import install
8
- from rich.logging import RichHandler
9
9
 
10
10
  log = logging.getLogger("rich")
11
11
  console = Console()
@@ -22,7 +22,7 @@ progress = Progress(
22
22
  )
23
23
 
24
24
 
25
- def setup_logging():
25
+ def setup_logging() -> None:
26
26
  FORMAT = "%(message)s"
27
27
 
28
28
  logging.basicConfig(
@@ -1,21 +0,0 @@
1
- name: Test
2
- on: [push]
3
- jobs:
4
- test:
5
- name: Test
6
- strategy:
7
- matrix:
8
- version: ["3.8", "3.12"]
9
- os: [ubuntu-latest, windows-latest, macos-latest]
10
- runs-on: ${{ matrix.os }}
11
- steps:
12
- - name: Clone the repository
13
- uses: actions/checkout@v4
14
- - name: Install the latest version of rye
15
- uses: eifinger/setup-rye@v4
16
- - name: Pin Python version
17
- run: rye pin ${{ matrix.version }}
18
- - name: Sync rye
19
- run: rye sync
20
- - name: Run tests
21
- run: rye test
@@ -1,13 +0,0 @@
1
- # python generated files
2
- __pycache__/
3
- *.py[oc]
4
- build/
5
- dist/
6
- wheels/
7
- *.egg-info
8
-
9
- # venv
10
- .venv
11
-
12
- bots
13
- code-battles.json
@@ -1 +0,0 @@
1
- 3.8
@@ -1,7 +0,0 @@
1
- Copyright 2024 Noam Zaks and Code Battles Contributors
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
-
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
-
7
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,84 +0,0 @@
1
- # generated by rye
2
- # use `rye lock` or `rye sync` to update this lockfile
3
- #
4
- # last locked with the following flags:
5
- # pre: false
6
- # features: []
7
- # all-features: false
8
- # with-sources: false
9
- # generate-hashes: false
10
- # universal: false
11
-
12
- -e file:.
13
- cachetools==5.5.0
14
- # via google-auth
15
- certifi==2024.8.30
16
- # via requests
17
- charset-normalizer==3.4.0
18
- # via requests
19
- click==8.1.7
20
- # via code-battles-cli
21
- exceptiongroup==1.3.0
22
- # via pytest
23
- google-api-core==2.21.0
24
- # via google-cloud-core
25
- # via google-cloud-firestore
26
- google-auth==2.35.0
27
- # via google-api-core
28
- # via google-cloud-core
29
- # via google-cloud-firestore
30
- google-cloud-core==2.4.1
31
- # via google-cloud-firestore
32
- google-cloud-firestore==2.19.0
33
- # via code-battles-cli
34
- googleapis-common-protos==1.65.0
35
- # via google-api-core
36
- # via grpcio-status
37
- grpcio==1.67.0
38
- # via google-api-core
39
- # via grpcio-status
40
- grpcio-status==1.67.0
41
- # via google-api-core
42
- idna==3.10
43
- # via requests
44
- iniconfig==2.1.0
45
- # via pytest
46
- markdown-it-py==3.0.0
47
- # via rich
48
- mdurl==0.1.2
49
- # via markdown-it-py
50
- packaging==25.0
51
- # via pytest
52
- pluggy==1.5.0
53
- # via pytest
54
- proto-plus==1.24.0
55
- # via google-api-core
56
- # via google-cloud-firestore
57
- protobuf==5.28.2
58
- # via google-api-core
59
- # via google-cloud-firestore
60
- # via googleapis-common-protos
61
- # via grpcio-status
62
- # via proto-plus
63
- pyasn1==0.6.1
64
- # via pyasn1-modules
65
- # via rsa
66
- pyasn1-modules==0.4.1
67
- # via google-auth
68
- pygments==2.18.0
69
- # via rich
70
- pytest==8.3.5
71
- requests==2.32.3
72
- # via code-battles-cli
73
- # via google-api-core
74
- rich==13.9.3
75
- # via code-battles-cli
76
- rsa==4.9
77
- # via google-auth
78
- tomli==2.2.1
79
- # via pytest
80
- typing-extensions==4.13.2
81
- # via exceptiongroup
82
- # via rich
83
- urllib3==2.2.3
84
- # via requests
@@ -1,72 +0,0 @@
1
- # generated by rye
2
- # use `rye lock` or `rye sync` to update this lockfile
3
- #
4
- # last locked with the following flags:
5
- # pre: false
6
- # features: []
7
- # all-features: false
8
- # with-sources: false
9
- # generate-hashes: false
10
- # universal: false
11
-
12
- -e file:.
13
- cachetools==5.5.0
14
- # via google-auth
15
- certifi==2024.8.30
16
- # via requests
17
- charset-normalizer==3.4.0
18
- # via requests
19
- click==8.1.7
20
- # via code-battles-cli
21
- google-api-core==2.21.0
22
- # via google-cloud-core
23
- # via google-cloud-firestore
24
- google-auth==2.35.0
25
- # via google-api-core
26
- # via google-cloud-core
27
- # via google-cloud-firestore
28
- google-cloud-core==2.4.1
29
- # via google-cloud-firestore
30
- google-cloud-firestore==2.19.0
31
- # via code-battles-cli
32
- googleapis-common-protos==1.65.0
33
- # via google-api-core
34
- # via grpcio-status
35
- grpcio==1.67.0
36
- # via google-api-core
37
- # via grpcio-status
38
- grpcio-status==1.67.0
39
- # via google-api-core
40
- idna==3.10
41
- # via requests
42
- markdown-it-py==3.0.0
43
- # via rich
44
- mdurl==0.1.2
45
- # via markdown-it-py
46
- proto-plus==1.24.0
47
- # via google-api-core
48
- # via google-cloud-firestore
49
- protobuf==5.28.2
50
- # via google-api-core
51
- # via google-cloud-firestore
52
- # via googleapis-common-protos
53
- # via grpcio-status
54
- # via proto-plus
55
- pyasn1==0.6.1
56
- # via pyasn1-modules
57
- # via rsa
58
- pyasn1-modules==0.4.1
59
- # via google-auth
60
- pygments==2.18.0
61
- # via rich
62
- requests==2.32.3
63
- # via code-battles-cli
64
- # via google-api-core
65
- rich==13.9.3
66
- # via code-battles-cli
67
- rsa==4.9
68
- # via google-auth
69
- typing-extensions==4.13.2
70
- # via rich
71
- urllib3==2.2.3
72
- # via requests
@@ -1 +0,0 @@
1
- from code_battles_cli.cli import main
@@ -1,2 +0,0 @@
1
- def test_client():
2
- from code_battles_cli.api import Client