uvk 0.0.1__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.
uvk-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,49 @@
1
+ Metadata-Version: 2.4
2
+ Name: uvk
3
+ Version: 0.0.1
4
+ Summary: Fully isolated IPython kernels based on uv
5
+ Keywords: jupyter,kernel,ipython,ipykernel,uv
6
+ Author: Benoit Hamelin
7
+ Author-email: Benoit Hamelin <benoit.hamelin@gmail.com>
8
+ License-Expression: MIT
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Development Status :: 2 - Pre-Alpha
14
+ Classifier: Operating System :: OS Independent
15
+ Requires-Dist: ipykernel>=7.0.0
16
+ Requires-Dist: jupyter-core>=5.9.1
17
+ Requires-Dist: uv>=0.10.2
18
+ Maintainer: Benoit Hamelin
19
+ Maintainer-email: Benoit Hamelin <benoit.hamelin@gmail.com>
20
+ Requires-Python: >=3.10
21
+ Project-URL: Homepage, https://github.com/hamelin/uvk
22
+ Description-Content-Type: text/markdown
23
+
24
+ # uvk -- Fully isolated IPython kernels based on uv
25
+
26
+ Proper documentation TBD... In the meantime:
27
+
28
+ 1. Install `uvk` in an environment from which you run Jupyter Lab / Notebook.
29
+ 1. Invoke `uvk` from this environment to install the UVK kernel attached to the Python executable of your environment.
30
+ - Distinct icon TBD
31
+ 1. Use kernel `UVK (Python 3.xx)` in your notebooks
32
+
33
+ and 🎉 your Python kernel runs out of a temporary, isolated environment.
34
+ Check it out by running a notebook with a code cell going
35
+
36
+ ```python
37
+ import sys
38
+ sys.prefix
39
+ ```
40
+
41
+ and see how every time you restart the kernel, the prefix directory changes.
42
+
43
+ Feature wishlist:
44
+
45
+ - Python version validation against a constraint with a magic
46
+ - Magic for adding dependencies on the fly
47
+ - Magic for including [inline script metadata](https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata)
48
+ - Integration with uv project workflows
49
+ - Python version and executable management through duly-named alternate kernels
uvk-0.0.1/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # uvk -- Fully isolated IPython kernels based on uv
2
+
3
+ Proper documentation TBD... In the meantime:
4
+
5
+ 1. Install `uvk` in an environment from which you run Jupyter Lab / Notebook.
6
+ 1. Invoke `uvk` from this environment to install the UVK kernel attached to the Python executable of your environment.
7
+ - Distinct icon TBD
8
+ 1. Use kernel `UVK (Python 3.xx)` in your notebooks
9
+
10
+ and 🎉 your Python kernel runs out of a temporary, isolated environment.
11
+ Check it out by running a notebook with a code cell going
12
+
13
+ ```python
14
+ import sys
15
+ sys.prefix
16
+ ```
17
+
18
+ and see how every time you restart the kernel, the prefix directory changes.
19
+
20
+ Feature wishlist:
21
+
22
+ - Python version validation against a constraint with a magic
23
+ - Magic for adding dependencies on the fly
24
+ - Magic for including [inline script metadata](https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata)
25
+ - Integration with uv project workflows
26
+ - Python version and executable management through duly-named alternate kernels
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.10.2"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "uvk"
7
+ version = "0.0.1"
8
+ authors = [{name = "Benoit Hamelin", email = "benoit.hamelin@gmail.com"}]
9
+ maintainers = [{name = "Benoit Hamelin", email = "benoit.hamelin@gmail.com"}]
10
+ description = "Fully isolated IPython kernels based on uv"
11
+ readme = "README.md"
12
+ keywords = ["jupyter", "kernel", "ipython", "ipykernel", "uv"]
13
+ license = "MIT"
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3.10",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Programming Language :: Python :: 3.12",
18
+ "Programming Language :: Python :: 3.13",
19
+ "Development Status :: 2 - Pre-Alpha",
20
+ "Operating System :: OS Independent",
21
+ ]
22
+ requires-python = ">=3.10"
23
+ dependencies = [
24
+ "ipykernel>=7.0.0",
25
+ "jupyter-core>=5.9.1",
26
+ "uv>=0.10.2",
27
+ ]
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/hamelin/uvk"
31
+
32
+ [project.scripts]
33
+ uvk = "uvk.__main__:main"
34
+
35
+ [tool.setuptools]
36
+ zip-safe = true
37
+ include-package-data = true
38
+ packages = ["uvk"]
@@ -0,0 +1,47 @@
1
+ """
2
+ The uvk IPython extension provides magicks to manage the dependencies
3
+ of an isolated kernel. It also ensures that the uv executable is visible
4
+ by the IPython process, as shelling out to uv is how most of the kernel's
5
+ specific functionalities are delivered.
6
+ """
7
+
8
+
9
+ from IPython.core.magic import cell_magic, line_magic, line_cell_magic
10
+ import subprocess as sp
11
+ import warnings
12
+
13
+
14
+ class CannotFindUV(Exception):
15
+
16
+ def __init__(self, *args, **kwargs) -> None:
17
+ super().__init__(
18
+ (
19
+ "uv executable cannot be found; "
20
+ "it is critical for the features provided by "
21
+ f"extension {__name__}."
22
+ ),
23
+ *args,
24
+ **kwargs,
25
+ )
26
+
27
+
28
+ def load_ipython_extension(ipython) -> None:
29
+ try:
30
+ sp.run(["uv"], stdout=sp.DEVNULL, stderr=sp.DEVNULL)
31
+ except OSError:
32
+ raise CannotFindUV()
33
+
34
+
35
+ @cell_magic
36
+ def script_metadata(cell: str) -> None:
37
+ print("TBD")
38
+
39
+
40
+ @line_magic
41
+ def python_version(line: str) -> None:
42
+ print("TBD")
43
+
44
+
45
+ @line_cell_magic
46
+ def dependencies(line: str) -> None:
47
+ print("TBD")
@@ -0,0 +1,108 @@
1
+ from argparse import ArgumentParser
2
+ import json
3
+ import logging as lg
4
+ from pathlib import Path
5
+ import shutil
6
+ import subprocess as sp
7
+ import sys
8
+
9
+
10
+ LOG = lg.getLogger("uvk")
11
+
12
+
13
+ def main():
14
+ lg.basicConfig(level=lg.DEBUG, format="%(levelname)-10s %(message)s")
15
+
16
+ parser = ArgumentParser(
17
+ description="Deploys the UVK kernel",
18
+ )
19
+ parser.add_argument(
20
+ "--name",
21
+ help="Name of the kernelspec. Default is `uvk`.",
22
+ default="uvk",
23
+ )
24
+ displayname_default = f"UVK (Python {sys.version_info.major}.{sys.version_info.minor})"
25
+ parser.add_argument(
26
+ "--display-name",
27
+ help=(
28
+ "Pretty name for the kernelspec that will show in Jupyter "
29
+ f"interface. Default is `{displayname_default}`."
30
+ ),
31
+ default=displayname_default,
32
+ )
33
+ parser.add_argument(
34
+ "--tmp",
35
+ help="Location of the temporary directory. Default is the system's.",
36
+ default="",
37
+ )
38
+ args = parser.parse_args()
39
+
40
+ path_uv = shutil.which("uv")
41
+ if not path_uv:
42
+ LOG.error("Cannot find jupyter executable. Abort")
43
+ sys.exit(cp.returncode)
44
+
45
+ cp = sp.run(["jupyter", "--paths", "--json"], stdout=sp.PIPE)
46
+ paths_data = list(json.loads(cp.stdout).get("data") or [])
47
+ if not paths_data:
48
+ LOG.error("Cannot interpret the output of jupyter --paths. Abort")
49
+ sys.exit(1)
50
+ for p in paths_data:
51
+ dir = Path(p)
52
+ if dir.is_relative_to(Path.home() / ".local"):
53
+ dir_kernelspecs_user = dir / "kernels"
54
+ break
55
+ else:
56
+ LOG.error(
57
+ "Cannot find the user data path where Jupyter would find "
58
+ "user-specific kernelspecs. Abort"
59
+ )
60
+ sys.exit(2)
61
+
62
+ path_kernelspec_resources = Path(sys.prefix) / "share" / "jupyter" / "kernels" / "python3"
63
+ if not path_kernelspec_resources.is_dir():
64
+ LOG.error(
65
+ "The directory we expected to find kernelspec resources in does"
66
+ "not exist. Abort"
67
+ )
68
+ sys.exit(3)
69
+ dir_kernelspec_new = dir_kernelspecs_user / args.name
70
+ if dir_kernelspec_new.is_dir():
71
+ LOG.warn(
72
+ f"Kernel directory {dir_kernelspec_new} already exists. "
73
+ "Since carrying on would overwrite it, "
74
+ "we err on the side of caution and abort. "
75
+ "Delete it yourself and retry if you would rather overwrite."
76
+ )
77
+ sys.exit(4)
78
+ dir_kernelspec_new.mkdir(parents=True, exist_ok=False)
79
+ for p in path_kernelspec_resources.iterdir():
80
+ shutil.copy(p, dir_kernelspec_new / p.name, follow_symlinks=True)
81
+
82
+ path_kernel_json = dir_kernelspec_new / "kernel.json"
83
+ if not path_kernel_json.is_file():
84
+ LOG.error("Copying kernelspec resources failed somehow. Abort")
85
+ sys.exit(5)
86
+ kernel_json = json.loads(path_kernel_json.read_text(encoding="utf-8"))
87
+ kernel_json["argv"] = [
88
+ str(path_uv),
89
+ "run",
90
+ "--with",
91
+ "uvk",
92
+ "--isolated",
93
+ "--no-cache",
94
+ "python",
95
+ "-m",
96
+ "ipykernel_launcher",
97
+ "-f",
98
+ "{connection_file}",
99
+ ]
100
+ kernel_json["display_name"] = args.display_name
101
+ if args.tmp:
102
+ kernel_json["env"] = {"TMPDIR": args.tmp}
103
+ path_kernel_json.write_text(json.dumps(kernel_json, indent=2), encoding="utf-8")
104
+ LOG.info(f"UVK kernelspec added at {dir_kernelspec_new}")
105
+
106
+
107
+ if __name__ == "__main__":
108
+ main()