Skip to content

codingame_tools.language.languages.python3

python3

CgPython3Language: the concrete CgLanguage implementation for CodinGame's "Python3"--see codingame_tools.language.registry for the discovery contract (LANGUAGE below) that finds it.

CgPython3Language

CgPython3Language()

Bases: CgLanguage

Python3 (CodinGame's cg_id "Python3"), the only language with a full implementation today. See CgLanguage for what each capability means.

Source code in codingame_tools/language/languages/python3.py
43
44
def __init__(self) -> None:
    super().__init__("Python3")

toolchain_fragment property

toolchain_fragment

Depends on the python311 subsystem and adds nothing of its own.

Python has no container backend yet -- run_streaming still uses the host interpreter -- so nothing drives this today. It is here because an image is described by what it should contain, not by what happens to be wired up: a dev container needs CodinGame's interpreter present whether or not cg is currently routing through it.

build_vscode_provisioning async

build_vscode_provisioning(request)

A single debugpy launch configuration that runs the solution the active editor tab belongs to, against that working directory's selected test case.

Nothing in it is specific to a working directory, so it is written once and never regenerated--not after an import, not after a language change, not for the next puzzle. The two questions a debug launch has to answer are both deferred to launch time:

  • which working directory, from VS Code's ${file} macro, resolved by codingame_tools.debug; and
  • which test case, from that directory's .meta/selected-test.json, defaulting to the first test case.

What it replaces was the opposite: a pickString of every test case on disk plus, for contributions, a local/validator picker, all baked in and all stale the moment the test cases changed.

Passing ${file} rather than an absolute path also keeps breakpoints bound to the exact file the user has open--including when that's the solution.py symlink rather than its data/solution.src target. Same no-realpath invariant codingame_tools.test_runner.debug_stdin documents.

No build, so no preLaunchTask; no container, so no extra files.

Source code in codingame_tools/language/languages/python3.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
async def build_vscode_provisioning(self, request: CgVsCodeRequest) -> CgVsCodeProvisioning:
    """A single `debugpy` launch configuration that runs the solution the active editor tab
       belongs to, against that working directory's selected test case.

       **Nothing in it is specific to a working directory**, so it is written once and never
       regenerated--not after an import, not after a language change, not for the next puzzle.
       The two questions a debug launch has to answer are both deferred to launch time:

       - *which working directory*, from VS Code's `${file}` macro, resolved by
         `codingame_tools.debug`; and
       - *which test case*, from that directory's `.meta/selected-test.json`, defaulting to the
         first test case.

       What it replaces was the opposite: a `pickString` of every test case on disk plus, for
       contributions, a local/validator picker, all baked in and all stale the moment the test
       cases changed.

       Passing `${file}` rather than an absolute path also keeps breakpoints bound to the exact
       file the user has open--including when that's the `solution.py` symlink rather than its
       `data/solution.src` target. Same no-realpath invariant
       `codingame_tools.test_runner.debug_stdin` documents.

       No build, so no `preLaunchTask`; no container, so no extra files."""
    return CgVsCodeProvisioning(
            configurations=[
                    {
                        "name": entry_name(self.cg_id, ACTION_DEBUG),
                        "presentation": PRESENTATION,
                        "type": "debugpy",
                        "request": "launch",
                        "module": _DEBUG_MODULE,
                        "args": ["${file}"],
                        "console": "integratedTerminal",
                        "justMyCode": True,
                        # debugpy writes its own protocol log to a file rather than the console.
                        **({"logToFile": True} if request.debug_adapter_logging else {}),
                    },
                ],
            recommended_extensions=["ms-python.python"],
        )

run_streaming async

run_streaming(ctx, input_text, *, timeout=DEFAULT_RUN_TIMEOUT_SECONDS)

Runs ctx.solution_file with the same Python interpreter this client itself runs under (sys.executable), rather than hoping a "python3" on PATH matches. Forces unbuffered stdout (-u + PYTHONUNBUFFERED=1)--Python fully block-buffers stdout by default when it isn't attached to a TTY (true of a subprocess pipe), which would otherwise defeat progressive real-time streaming entirely.

Python3 needs no build step, so it inherits CgLanguage.build's no-op.

Source code in codingame_tools/language/languages/python3.py
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
async def run_streaming(
            self,
            ctx: CgLanguageContext,
            input_text: str,
            *,
            timeout: float = DEFAULT_RUN_TIMEOUT_SECONDS,
        ) -> AsyncGenerator[CgRunEvent, None]:
    """Runs `ctx.solution_file` with the *same* Python interpreter this client itself runs under
       (`sys.executable`), rather than hoping a "python3" on PATH matches. Forces unbuffered
       stdout (`-u` + `PYTHONUNBUFFERED=1`)--Python fully block-buffers stdout by default when
       it isn't attached to a TTY (true of a subprocess pipe), which would otherwise defeat
       progressive real-time streaming entirely.

       Python3 needs no build step, so it inherits `CgLanguage.build`'s no-op."""
    env = {**os.environ, "PYTHONUNBUFFERED": "1"}
    argv = [sys.executable, "-u", str(ctx.solution_file)]
    async for event in run_argv_streaming(argv, input_text, timeout=timeout, env=env):
        yield event