Coding python packages with AI
I tried using some new LLM tools to code 2 entire python packages (instead of editing a handful of lines at a time, which is what I did previously). It went well! These tools are not perfect, but they are useful!
Package 1: "actually exact GPyTorch" using cursor
The Gaussian Process package gpytorch
uses a bunch of linear algebra
approximations by default to run faster. I often write code to turn them off
and thought I should just offload this code into a standalone package.
I put the following prompt into cursor's AI tab, using the "Claude" model:
Please make a small python package called
gpytorch_safe_defaults
. The package should contain just one object calledsafe_defaults
.
- When called as a function (
safe_defaults
), it should import the packagelinear_operator
(throwing an error if it is not installed), and set the following attributes: inlinear_operator.settings
: _fast_covar_root_decomposition._default=False, _fast_log_prob._default=False, _fast_solves._default=False- When entered as a context (with safe_defaults: ...), it should enter the context
linear_operator.settings.fast_computations(False, False, False)
Please write a full package with documentation and a simple test with pytest where a basic gpytorch GP is initialized with and without safe_defaults.
I had never written a context manager in python before so I didn't know how to do this.
The results were ok.
- The overall structure of the repo was as intended, and the result is very close to the final product.
- The object coded didn't work out of the box. The model used the
@contextlib.contextmanager
but also defined an__enter__
method explicitly, which then requires defining an__exit__
method (which did - My email / GitHub were hallucinated so I needed to replace that
- Package version numbers and some pre-commit config names needed to be changed
After fixing and checking the package (and changing the name from
gpytorch_safe_defaults
to actually_exact_gpytorch
), it now lives here:
https://github.com/AustinT/actually_exact_gpytorch. At the time of writing of
this blog post, the latest commit hash is
483954ed86de6d701a6d1b8250ff9d87f18b8591
.
Package 2: "Tanimoto kernel for scikit-learn" using Gemini / Claude
This came from a request for a scikit-learn compatible version of the Tanimoto kernel. I fed the following prompt into both Gemini 2.5 pro and Claude 3.7:
Please write me a small python package. The package should contain two subclasses of sklearn.gaussian_processs.kernels.Kernel (see https://github.com/scikit-learn/scikit-learn/blob/98ed9dc73a86f5f11781a0e21f24c8f47979ec67/sklearn/gaussian_process/kernels.py#L153).
One class should be called MinMaxTanimoto and implement the function k(x,y) = (\sum_i \min(x_i, y_i)) / (\sum_j \max(x_j, y_j)) (where x_i is the ith component of vector input X). Remember that the inputs need to be batched.
A second class should be called DotProductTanimoto an implement the function k(x,y) = <x,y> / (|x|^2 + |y|^2 - <x,y>).
Finally, it should have an alias "Tanimoto" which is equal to MinMax.
The package name should be "sklearn_tanimoto_gp". MinMaxTanimoto, DotProductTanimoto, and Tanimoto should all be available as top-level imports.
The package should be set up with pre-commit, installed from a pyproject.toml file, and have some basic tests with pytest which test for the correct kernel values.
The package should be well-written, as if an experienced software engineer is writing it.
Both models designed a very similar package, but I liked Gemini's slightly
more. It reasoned to set k(0,0)=1 and used numpy.divide(A, B, out=...,
where=...)
to neatly avoid "divide by zero" errors. It wrote "# Replace with
XXX
" instead of hallucinating an output that it didn't know. Claude's package
was overall similar but included a "lengthscale" parameter which should not
have been there. I based the final package off of Gemini's.
Both models wrote a lot of comments (Gemini maybe had too many). This time I did not use the suggested pre-commit setup and just used my own python template.
This package lives at: https://github.com/AustinT/sklearn_tanimoto_gp. Commit
hash when this post was written: 526398804f5d7c035cd867495d42f99baca18ee4
.
Conclusions
The overall capability is impressive: although adjustments were necessary in both cases, they were relatively small and easy to debug. Writing tests together with code is extremely helpful (but of course you need to check the tests). Things like package version numbers always need to be checked carefully though.
Overall, I would recommend prompting LLMs to design small packages rather than writing them from scratch yourself.