Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/notebooks/custom_kernel.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"assert uv_path.exists()\n",
"\n",
"write_kernel_spec(\n",
" kernel_name=\"async_3.15\",\n",
" name=\"async_3.15\",\n",
" display_name=\"Python 3.15 (async)\",\n",
" env={\"UV_PROJECT_ENVIRONMENT\": str(uv_path)},\n",
" executable=(\"uv\", \"run\", \"--no-sync\", \"python\", \"-m\", \"async_kernel\"),\n",
Expand Down
4 changes: 2 additions & 2 deletions docs/usage/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The kernel spec looks like this:
"-f",
"{connection_file}",
"--start_interface=async_kernel.interface.start_kernel_zmq_interface",
"--kernel_name=async",
"--name=async",
"--backend=trio",
"--host=tk"
],
Expand Down Expand Up @@ -258,7 +258,7 @@ async-kernel -f .
Additional settings can be passed as arguments.

```bash
async-kernel -f . --kernel_name=async-trio-custom --display_name='My custom kernel' --quiet=False
async-kernel -f . --name=async-trio-custom --display_name='My custom kernel' --quiet=False
```

The call above will start a new kernel with a 'trio' backend. The quiet setting is
Expand Down
4 changes: 2 additions & 2 deletions src/async_kernel/asyncshell.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class AsyncInteractiveShell(InteractiveShell):

@override
def __repr__(self) -> str:
return f"<{self.__class__.__name__} kernel_name: {self.kernel.kernel_name!r} subshell_id: {self.subshell_id}>"
return f"<{self.__class__.__name__} name: {self.kernel.name!r} subshell_id: {self.subshell_id}>"

def __new__(cls) -> Self:
if issubclass(cls, AsyncInteractiveSubshell):
Expand Down Expand Up @@ -718,7 +718,7 @@ def __init_subclass__(cls) -> None:

@override
def __repr__(self) -> str:
return f"<{self.__class__.__name__} kernel_name: {self.kernel.kernel_name!r} subshell_id: {self.subshell_id}{' stopped' if self.stopped else ''}>"
return f"<{self.__class__.__name__} name: {self.kernel.name!r} subshell_id: {self.subshell_id}{' stopped' if self.stopped else ''}>"

@property
@override
Expand Down
4 changes: 2 additions & 2 deletions src/async_kernel/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ def command_line() -> None:

# Add kernel spec
if args.add:
if not hasattr(args, "kernel_name"):
args.kernel_name = args.add
if not hasattr(args, "name"):
args.name = args.add
for name in cl_names:
delattr(args, name)
path = write_kernel_spec(**vars(args))
Expand Down
2 changes: 1 addition & 1 deletion src/async_kernel/interface/zmq.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ def _write_connection_file(
ip=self.ip,
key=self.session.key,
signature_scheme=self.session.signature_scheme,
kernel_name=self.kernel.kernel_name,
kernel_name=self.kernel.name,
**{f"{channel}_port": self.ports[channel] for channel in Channel},
)
ip_files: list[pathlib.Path] = []
Expand Down
12 changes: 6 additions & 6 deletions src/async_kernel/kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class Kernel(traitlets.HasTraits):
of the current profile, but can be specified by absolute path.
"""

kernel_name = traitlets.CUnicode()
name = traitlets.CUnicode()
"The kernels name - if it contains 'trio' a trio backend will be used instead of an asyncio backend."

help_links = traitlets.List(trait=traitlets.Dict())
Expand Down Expand Up @@ -162,8 +162,8 @@ def __repr__(self) -> str:
def _default_log(self) -> LoggerAdapter[Logger]:
return logging.LoggerAdapter(logging.getLogger(self.__class__.__name__))

@traitlets.default("kernel_name")
def _default_kernel_name(self) -> Literal["async-trio", "async"]:
@traitlets.default("name")
def _default_name(self) -> Literal["async-trio", "async"]:
return "async-trio" if current_async_library(failsafe=True) == "trio" else "async"

@traitlets.default("interface")
Expand Down Expand Up @@ -234,14 +234,14 @@ def kernel_info(self) -> dict[str, Any]:
"banner": self.banner,
"help_links": self.help_links,
"debugger": bool(self.interface.debugger),
"kernel_name": self.kernel_name,
"name": self.name,
"supported_features": self.supported_features,
}

@property
def settings(self) -> dict[str, Any]:
"Settings that have been set to customise the behaviour of the kernel."
return {k: getattr(self, k) for k in ("kernel_name", "connection_file")} | self._settings
return {k: getattr(self, k) for k in ("name", "connection_file")} | self._settings

@property
def shell(self) -> AsyncInteractiveShell | AsyncInteractiveSubshell:
Expand Down Expand Up @@ -272,7 +272,7 @@ def load_settings(self, settings: dict[str, Any]) -> None:
if self.event_started:
msg = "It is too late to load settings!"
raise RuntimeError(msg)
settings_ = self._settings or {"kernel_name": self.kernel_name}
settings_ = self._settings or {"name": self.name}
for k, v in settings.items():
settings_ |= utils.setattr_nested(self, k, v)
self._settings.update(settings_)
Expand Down
26 changes: 13 additions & 13 deletions src/async_kernel/kernelspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
def make_argv(
*,
connection_file: str = "{connection_file}",
kernel_name: str = "async",
name: str = "async",
start_interface: str | InterfaceStartType = DEFAULT_START_INTERFACE,
executable: tuple[str, ...] = DEFAULT_EXECUTABLE,
**kwargs: dict[str, Any],
Expand All @@ -43,23 +43,23 @@ def make_argv(
connection_file: The path to the connection file.
start_interface: Either the kernel factory object itself, or the string import path to a
callable that returns a non-started kernel.
kernel_name: The name of the kernel to use.
name: The name to use for the kernel.
executable: The command line executable to call.
**kwargs: Additional settings to pass when creating the kernel passed to `start_interface`.

Returns:
list: A list of command-line arguments to launch the kernel module.
"""
argv = [*executable, "-f", connection_file]
for k, v in ({"start_interface": start_interface, "kernel_name": kernel_name} | kwargs).items():
for k, v in ({"start_interface": start_interface, "name": name} | kwargs).items():
argv.append(f"--{k}={v}")
return argv


def write_kernel_spec(
path: Path | str | None = None,
*,
kernel_name: str = "async",
name: str = "async",
display_name: str = "",
executable: tuple[str, ...] = DEFAULT_EXECUTABLE,
prefix: str = "",
Expand All @@ -77,8 +77,8 @@ def write_kernel_spec(

Args:
path: The path where to write the spec.
kernel_name: The name of the kernel to use.
display_name: The display name for Jupyter to use for the kernel. The default is `"Python ({kernel_name})"`.
name: The name of the kernel to use.
display_name: The display name for Jupyter to use for the kernel. The default is `"Python ({name})"`.
executable: The first part of 'argv' to use.
prefix: given, the kernelspec will be installed to PREFIX/share/jupyter/kernels/KERNEL_NAME.
This can be sys.prefix for installation inside virtual or conda envs.
Expand Down Expand Up @@ -114,16 +114,16 @@ async def execute_request(self, job):


async_kernel.kernelspec.write_kernel_spec(
kernel_name="async-print-job", start_interface=start_interface
name="async-print-job", start_interface=start_interface
)
```

Warning:
Moving the spec folder will break the import which is stored as an absolute path.
"""

assert re.match(re.compile(r"^[a-z0-9._\-]+$", re.IGNORECASE), kernel_name)
path = Path(path).expanduser() if path else (get_kernel_dir(folder=folder, prefix=prefix) / kernel_name)
assert re.match(re.compile(r"^[a-z0-9._\-]+$", re.IGNORECASE), name)
path = Path(path).expanduser() if path else (get_kernel_dir(folder=folder, prefix=prefix) / name)
# stage resources
try:
path.mkdir(parents=True, exist_ok=True)
Expand All @@ -138,14 +138,14 @@ async def execute_request(self, job):
argv = make_argv(
start_interface=start_interface,
connection_file=connection_file,
kernel_name=kernel_name,
name=name,
executable=executable,
**kwargs,
)
spec: dict[str, list[Any] | Any | dict[Any, Any] | str | dict[str, bool]] = {
"argv": argv,
"env": env or {},
"display_name": display_name or f"Python {sys.version_info.major}.{sys.version_info.minor} ({kernel_name})",
"display_name": display_name or f"Python {sys.version_info.major}.{sys.version_info.minor} ({name})",
"language": language,
"interrupt_mode": "message",
"metadata": metadata if metadata is not None else {"debugger": True, "concurrent": True},
Expand All @@ -160,9 +160,9 @@ async def execute_request(self, job):
return path


def remove_kernel_spec(kernel_name: str, *, folder: str = "", prefix: str = "") -> bool:
def remove_kernel_spec(name: str, *, folder: str = "", prefix: str = "") -> bool:
"Remove a kernelspec returning True if it was removed."
if (path := get_kernel_dir(folder=folder, prefix=prefix).joinpath(kernel_name)).exists():
if (path := get_kernel_dir(folder=folder, prefix=prefix).joinpath(name)).exists():
shutil.rmtree(path, ignore_errors=True)
return True
return False
Expand Down
8 changes: 4 additions & 4 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,20 +111,20 @@ async def client(kernel: Kernel) -> AsyncGenerator[AsyncKernelClient, Any]:


@pytest.fixture(scope="module", params=["async", "async-trio"])
def kernel_name(request):
def name(request):
return request.param


@pytest.fixture(scope="module")
async def subprocess_kernels_client(anyio_backend, tmp_path_factory, kernel_name, transport: str):
async def subprocess_kernels_client(anyio_backend, tmp_path_factory, name, transport: str):
"""
Starts a kernel in a subprocess and returns an AsyncKernelCient that is connected to it.
"""
assert anyio_backend[0] == "asyncio", "Asyncio is required for the client"
connection_file = tmp_path_factory.mktemp("async_kernel") / "temp_connection.json"
backend = Backend.trio if "trio" in kernel_name else Backend.asyncio
backend = Backend.trio if "trio" in name else Backend.asyncio
kwgs = {"interface.transport": transport, "interface.backend": backend}
command = make_argv(connection_file=connection_file, kernel_name=kernel_name, **kwgs) # pyright: ignore[reportArgumentType]
command = make_argv(connection_file=connection_file, name=name, **kwgs) # pyright: ignore[reportArgumentType]
process = await anyio.open_process([*command, "--no-print_kernel_messages"])
async with process:
while not connection_file.exists() or not connection_file.stat().st_size:
Expand Down
28 changes: 14 additions & 14 deletions tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def test_add_kernel(monkeypatch, fake_kernel_dir: pathlib.Path, capsys):
"-f",
"{connection_file}",
"--start_interface=async_kernel.kernel.Kernel",
"--kernel_name=async-trio",
"--name=async-trio",
],
"env": {},
"display_name": "my kernel",
Expand All @@ -82,23 +82,23 @@ def test_add_kernel(monkeypatch, fake_kernel_dir: pathlib.Path, capsys):

@pytest.mark.parametrize("mode", ["folder", "prefix", "default"])
def test_remove_existing_kernel(monkeypatch, fake_kernel_dir, capsys, mode: Literal["folder", "prefix", "default"]):
kernel_name = "asyncio"
(fake_kernel_dir / kernel_name).mkdir()
name = "asyncio"
(fake_kernel_dir / name).mkdir()
if mode == "folder":
monkeypatch.setattr(sys, "argv", ["prog", "-r", kernel_name, f"--folder={fake_kernel_dir}"])
monkeypatch.setattr(sys, "argv", ["prog", "-r", name, f"--folder={fake_kernel_dir}"])
elif mode == "prefix":
monkeypatch.setattr(sys, "argv", ["prog", "-r", kernel_name, f"--prefix={sys.prefix}"])
monkeypatch.setattr(sys, "argv", ["prog", "-r", name, f"--prefix={sys.prefix}"])
else:
monkeypatch.setattr(sys, "argv", ["prog", "-r", kernel_name])
monkeypatch.setattr(sys, "argv", ["prog", "-r", name])
command_line()
out = capsys.readouterr().out
assert "removed" in out
assert not (fake_kernel_dir / kernel_name).exists()
assert not (fake_kernel_dir / name).exists()


def test_remove_nonexistent_kernel(monkeypatch, fake_kernel_dir, capsys):
kernel_name = "not a kernel"
monkeypatch.setattr(sys, "argv", ["prog", "-r", kernel_name])
name = "not a kernel"
monkeypatch.setattr(sys, "argv", ["prog", "-r", name])
command_line()
out = capsys.readouterr().out
assert "not found!" in out
Expand Down Expand Up @@ -142,7 +142,7 @@ def test_command_start_kernel_enable_matplotlib(monkeypatch, backend, host):
"prog",
"-f",
".",
f"--kernel_name=async-{host}",
f"--name=async-{host}",
f"--interface.host={host}",
f"--interface.backend={backend}",
"--no-print_kernel_messages",
Expand All @@ -159,20 +159,20 @@ def test_command_start_kernel_enable_matplotlib(monkeypatch, backend, host):
async_kernel.Kernel._instance = None # pyright: ignore[reportPrivateUsage]


async def test_subprocess_kernels_client(subprocess_kernels_client: AsyncKernelClient, kernel_name, transport):
async def test_subprocess_kernels_client(subprocess_kernels_client: AsyncKernelClient, name, transport):
# Start & Stop a kernel
backend = Backend.trio if "trio" in kernel_name.lower() else Backend.asyncio
backend = Backend.trio if "trio" in name.lower() else Backend.asyncio
_, reply = await utils.execute(
subprocess_kernels_client,
"kernel = get_ipython().kernel",
user_expressions={
"kernel_name": "kernel.kernel_name",
"name": "kernel.name",
"host": "kernel.interface.host",
"backend": "kernel.interface.backend",
"transport": "kernel.interface.transport",
},
)
assert kernel_name in reply["user_expressions"]["kernel_name"]["data"]["text/plain"]
assert name in reply["user_expressions"]["name"]["data"]["text/plain"]
assert backend in reply["user_expressions"]["backend"]["data"]["text/plain"]
assert transport in reply["user_expressions"]["transport"]["data"]["text/plain"]

Expand Down
2 changes: 1 addition & 1 deletion tests/test_enter_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@pytest.mark.parametrize("anyio_backend", argvalues=["asyncio", "trio"])
async def test_start_kernel_in_context(anyio_backend):
async with Kernel({"print_kernel_messages": False}).interface as kernel:
assert kernel.kernel_name == {"asyncio": "async", "trio": "async-trio"}[anyio_backend]
assert kernel.name == {"asyncio": "async", "trio": "async-trio"}[anyio_backend]
connection_file = kernel.connection_file
# Test prohibit nested async context.
with pytest.raises(RuntimeError, match="has already been entered"):
Expand Down
4 changes: 2 additions & 2 deletions tests/test_kernel.py
Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,8 @@ async def test_subshell(client: AsyncKernelClient, kernel: Kernel):
subshell_id = kernel.subshell_manager.create_subshell(protected=True).subshell_id
subshell = kernel.subshell_manager.subshells[subshell_id]

assert repr(kernel.main_shell) == "<IPythonAsyncInteractiveShell kernel_name: 'async' subshell_id: None>"
assert repr(subshell) == f"<IPythonInteractiveSubshell kernel_name: 'async' subshell_id: {subshell_id}>"
assert repr(kernel.main_shell) == "<IPythonAsyncInteractiveShell name: 'async' subshell_id: None>"
assert repr(subshell) == f"<IPythonInteractiveSubshell name: 'async' subshell_id: {subshell_id}>"

assert kernel.main_shell.user_ns is kernel.main_shell.user_global_ns
assert subshell.user_ns is not kernel.main_shell.user_ns
Expand Down
8 changes: 4 additions & 4 deletions tests/test_kernelspec.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,21 @@


@pytest.mark.parametrize(
("kernel_name", "start_interface"),
("name", "start_interface"),
[
("trio", DEFAULT_START_INTERFACE),
("function_factory", "custom"),
],
)
def test_write_kernel_spec(kernel_name, start_interface, tmp_path, monkeypatch):
def test_write_kernel_spec(name, start_interface, tmp_path, monkeypatch):
if start_interface == "custom":

def my_start_interface(settings: dict | None):
return "custom"

start_interface = my_start_interface

path = write_kernel_spec(tmp_path, kernel_name=kernel_name, start_interface=start_interface)
path = write_kernel_spec(tmp_path, name=name, start_interface=start_interface)
kernel_json = path.joinpath("kernel.json")
assert kernel_json.exists()
data = json.loads(kernel_json.read_bytes())
Expand All @@ -45,4 +45,4 @@ def my_start_interface(settings: dict | None):

def test_write_kernel_spec_fails():
with pytest.raises(ValueError, match="not enough values to unpack"):
write_kernel_spec(kernel_name="never-works", start_interface="not a factory")
write_kernel_spec(name="never-works", start_interface="not a factory")
2 changes: 1 addition & 1 deletion tests/test_message_spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ async def test_kernel_info_request(client: AsyncKernelClient):
"banner",
"help_links",
"debugger",
"kernel_name",
"name",
"supported_features",
"status",
]
Expand Down
Loading