<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: vincent-d-warmerdam</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/vincent-d-warmerdam.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-04-03T14:57:27+00:00</updated><author><name>Simon Willison</name></author><entry><title>smartfunc</title><link href="https://simonwillison.net/2025/Apr/3/smartfunc/#atom-tag" rel="alternate"/><published>2025-04-03T14:57:27+00:00</published><updated>2025-04-03T14:57:27+00:00</updated><id>https://simonwillison.net/2025/Apr/3/smartfunc/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/koaning/smartfunc"&gt;smartfunc&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Vincent D. Warmerdam built this ingenious wrapper around my &lt;a href="https://llm.datasette.io/en/stable/python-api.html"&gt;LLM Python library&lt;/a&gt; which lets you build LLM wrapper functions using a decorator and a docstring:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;smartfunc&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;backend&lt;/span&gt;

&lt;span class="pl-en"&gt;@&lt;span class="pl-en"&gt;backend&lt;/span&gt;(&lt;span class="pl-s"&gt;"gpt-4o"&lt;/span&gt;)&lt;/span&gt;
&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;generate_summary&lt;/span&gt;(&lt;span class="pl-s1"&gt;text&lt;/span&gt;: &lt;span class="pl-smi"&gt;str&lt;/span&gt;):
    &lt;span class="pl-s"&gt;"""Generate a summary of the following text: {{ text }}"""&lt;/span&gt;
    &lt;span class="pl-k"&gt;pass&lt;/span&gt;

&lt;span class="pl-s1"&gt;summary&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;generate_summary&lt;/span&gt;(&lt;span class="pl-s1"&gt;long_text&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;It works with &lt;a href="https://llm.datasette.io/en/stable/plugins/directory.html"&gt;LLM plugins&lt;/a&gt; so the same pattern should work against Gemini, Claude and hundreds of others, including local models.&lt;/p&gt;
&lt;p&gt;It integrates with more recent LLM features too, including &lt;a href="https://llm.datasette.io/en/stable/python-api.html#python-api-async"&gt;async support&lt;/a&gt; and &lt;a href="https://simonwillison.net/2025/Feb/28/llm-schemas/"&gt;schemas&lt;/a&gt;, by introspecting the function signature:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;class&lt;/span&gt; &lt;span class="pl-v"&gt;Summary&lt;/span&gt;(&lt;span class="pl-v"&gt;BaseModel&lt;/span&gt;):
    &lt;span class="pl-s1"&gt;summary&lt;/span&gt;: &lt;span class="pl-smi"&gt;str&lt;/span&gt;
    &lt;span class="pl-s1"&gt;pros&lt;/span&gt;: &lt;span class="pl-s1"&gt;list&lt;/span&gt;[&lt;span class="pl-smi"&gt;str&lt;/span&gt;]
    &lt;span class="pl-s1"&gt;cons&lt;/span&gt;: &lt;span class="pl-s1"&gt;list&lt;/span&gt;[&lt;span class="pl-smi"&gt;str&lt;/span&gt;]

&lt;span class="pl-en"&gt;@&lt;span class="pl-en"&gt;async_backend&lt;/span&gt;(&lt;span class="pl-s"&gt;"gpt-4o-mini"&lt;/span&gt;)&lt;/span&gt;
&lt;span class="pl-k"&gt;async&lt;/span&gt; &lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;generate_poke_desc&lt;/span&gt;(&lt;span class="pl-s1"&gt;text&lt;/span&gt;: &lt;span class="pl-smi"&gt;str&lt;/span&gt;) &lt;span class="pl-c1"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="pl-smi"&gt;Summary&lt;/span&gt;:
    &lt;span class="pl-s"&gt;"Describe the following pokemon: {{ text }}"&lt;/span&gt;
    &lt;span class="pl-k"&gt;pass&lt;/span&gt;

&lt;span class="pl-s1"&gt;pokemon&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-k"&gt;await&lt;/span&gt; &lt;span class="pl-en"&gt;generate_poke_desc&lt;/span&gt;(&lt;span class="pl-s"&gt;"pikachu"&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;Vincent also recorded &lt;a href="https://www.youtube.com/watch?v=j9jh46R0ryY"&gt;a 12 minute video&lt;/a&gt; walking through the implementation and showing how it uses &lt;a href="https://docs.pydantic.dev/"&gt;Pydantic&lt;/a&gt;, Python's &lt;a href="https://docs.python.org/3/library/inspect.html"&gt;inspect&lt;/a&gt; module and &lt;a href="https://docs.python.org/3/library/typing.html#typing.get_type_hints"&gt;typing.get_type_hints()&lt;/a&gt; function.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ai"&gt;ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/generative-ai"&gt;generative-ai&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llms"&gt;llms&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/llm"&gt;llm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vincent-d-warmerdam"&gt;vincent-d-warmerdam&lt;/a&gt;&lt;/p&gt;



</summary><category term="python"/><category term="ai"/><category term="generative-ai"/><category term="llms"/><category term="llm"/><category term="vincent-d-warmerdam"/></entry><entry><title>uvtrick</title><link href="https://simonwillison.net/2024/Sep/1/uvtrick/#atom-tag" rel="alternate"/><published>2024-09-01T05:03:23+00:00</published><updated>2024-09-01T05:03:23+00:00</updated><id>https://simonwillison.net/2024/Sep/1/uvtrick/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/koaning/uvtrick"&gt;uvtrick&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
This "fun party trick" by Vincent D. Warmerdam is absolutely brilliant and a little horrifying. The following code:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;uvtrick&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-v"&gt;Env&lt;/span&gt;

&lt;span class="pl-k"&gt;def&lt;/span&gt; &lt;span class="pl-en"&gt;uses_rich&lt;/span&gt;():
    &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s1"&gt;rich&lt;/span&gt; &lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-s1"&gt;print&lt;/span&gt;
    &lt;span class="pl-en"&gt;print&lt;/span&gt;(&lt;span class="pl-s"&gt;"hi :vampire:"&lt;/span&gt;)

&lt;span class="pl-v"&gt;Env&lt;/span&gt;(&lt;span class="pl-s"&gt;"rich"&lt;/span&gt;, &lt;span class="pl-s1"&gt;python&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;"3.12"&lt;/span&gt;).&lt;span class="pl-en"&gt;run&lt;/span&gt;(&lt;span class="pl-s1"&gt;uses_rich&lt;/span&gt;)&lt;/pre&gt;

&lt;p&gt;Executes that &lt;code&gt;uses_rich()&lt;/code&gt; function in a fresh virtual environment managed by &lt;a href="https://docs.astral.sh/uv/"&gt;uv&lt;/a&gt;, running the specified Python version (3.12) and ensuring the &lt;a href="https://github.com/Textualize/rich"&gt;rich&lt;/a&gt; package is available - even if it's not installed in the current environment.&lt;/p&gt;
&lt;p&gt;It's taking advantage of the fact that &lt;code&gt;uv&lt;/code&gt; is &lt;em&gt;so fast&lt;/em&gt; that the overhead of getting this to work is low enough for it to be worth at least playing with the idea.&lt;/p&gt;
&lt;p&gt;The real magic is in how &lt;code&gt;uvtrick&lt;/code&gt; works. It's &lt;a href="https://github.com/koaning/uvtrick/blob/9531006e77e099eada8847d1333087517469d26a/uvtrick/__init__.py"&gt;only 127 lines of code&lt;/a&gt; with some truly devious trickery going on.&lt;/p&gt;
&lt;p&gt;That &lt;code&gt;Env.run()&lt;/code&gt; method:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creates a temporary directory&lt;/li&gt;
&lt;li&gt;Pickles the &lt;code&gt;args&lt;/code&gt; and &lt;code&gt;kwargs&lt;/code&gt; and saves them to &lt;code&gt;pickled_inputs.pickle&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Uses &lt;code&gt;inspect.getsource()&lt;/code&gt; to retrieve the source code of the function passed to &lt;code&gt;run()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Writes &lt;em&gt;that&lt;/em&gt; to a &lt;code&gt;pytemp.py&lt;/code&gt; file, along with a generated &lt;code&gt;if __name__ == "__main__":&lt;/code&gt; block that calls the function with the pickled inputs and saves its output to another pickle file called &lt;code&gt;tmp.pickle&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Having created the temporary Python file it executes the program using a command something like this:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell"&gt;&lt;pre&gt;uv run --with rich --python 3.12 --quiet pytemp.py&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It reads the output from &lt;code&gt;tmp.pickle&lt;/code&gt; and returns it to the caller!

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/fishnets88/status/1829847133878432067"&gt;@fishnets88&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/uv"&gt;uv&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/vincent-d-warmerdam"&gt;vincent-d-warmerdam&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/rich"&gt;rich&lt;/a&gt;&lt;/p&gt;



</summary><category term="python"/><category term="uv"/><category term="vincent-d-warmerdam"/><category term="rich"/></entry></feed>