In the middle of the desert you can say anything you want
# Create a new uv environment
uv init --name bbk-presentation --bare
# Add ipykernel
uv add --dev ipykernel
# Install the kernel in jupyterlab
uv run ipython kernel install --user --env VIRTUAL_ENV $(pwd)/.venv --name=bbk-paper
# Add whatever you need to the environment
uv add pandas seaborn
# Support "%pip" magic **and installing extensions through jupyterlab UI!**
uv venv --seed
# Start jupyterlab
uv run --with jupyter jupyter lab
uv venv --seed is advertised in uv’s help, it seems also to work for installing extensions through the UI, though not sure how official/supported that is. But it works for me.
Cool extensions as of 2026-02-12:
uv add jupyterlab-vim
uv run jupyter labextension list
uv run jupyter labextension enable jupyterlab_vim
uv run jupyter lab
apt install progress: Xfennec/progress: Linux tool to show progress for cp, mv, dd, … (formerly known as cv)progress -w gives status of running copy/mv operationsrsync -aP) pip install -U "huggingface_hub[cli]"
#either of
hf auth login
hf auth login --token $HF_TOKEN
# models
hf download adept/fuyu-8b --cache-dir ./path/to/cache
// TODO — vllm — will it be VLLM_CACHE_ROOT or HF_HOME?
Also: Troubleshooting - vLLM — they literally recommend getting it first via hf cli and passing the full path
Lost cumulatively hours on these things this months.
MODEL_CONFIG = ConfigDict(
serialize_by_alias=True, # why doesn't this, alone, work?
)
Guess why? Because I have pydantic 2.10, the config above was introduced in 2.11, and it just quietly allows me to set this config value.
(Configuration - Pydantic)
(Ty ty for picking up on this)
Next. Configuration - Pydantic
ConfigDict(
arbitrary_types_allowed=False, # disallow obj.invalid_field = "whatever"
)
For my own models as well. Setting obj.name='test' when you want obj.step_name is almost never a good idea.
And again about serialize_by_alias: will be default in pydantic v3, which I welcome, because if you forget to model_dump(by_alias=True) then the model will be dumped with unexpected names, which will then be quietly deleted when you try to initialize a new model from that dict through e.g. NewModel(**old_model.model_dump()).
(Should’ve validated anyway, but…)
~/.pdbrc gets read by both of them, and can import stuff and use aliases!
# ! makes it python code to be executed
!import rich
alias I rich.inspect(%1)
# # alternative if not !importing it above in one command
alias P !import rich; rich.print(%1)
print("Custom commands:")
print("\t I $thing — rich inspect $thing")
print("\t P $thing — rich pretty print $thing")
EDIT: the above works only if rich is already imported.
The above doesn’t do comprehensions well (+ needs imported rich in the running thing).
> [x for x in [2,4,5]]
[2, 4, 5]
> P [x for x in [2,4,5]]
*** SyntaxError: closing parenthesis ')' does not match opening parenthesis '['
Looking at:
self._getval(): https://github.com/python/cpython/blob/3.14/Lib/pdb.py#L2080Instead of doing alias ... which uses %1 which fails, we can use pdbpp’s pdb’s _getval() fn which does this in a smarter way.
THEN, in our ~/.pdbrc.py (NOT ~/.pdbrc!), adapting the code for pdbpp’s do_pp():
import pdb
import rich
import os, sys, traceback
class Config(pdb.DefaultConfig):
def setup(self, pdb):
Pdb = pdb.__class__
# "do_xxx" methods automagically get parsed into commands
# make 'l' an alias to 'longlist' -> existing method
Pdb.do_l = Pdb.do_longlist
# new methods
Pdb.do_P = _do_P
# defining a method with self outside a class feels so _wrong_...
def _do_P(self, arg):
try:
val = self._getval(arg)
except:
return
try:
rich.print(val)
except:
exc_info = sys.exc_info()[:2]
self.error(traceback.format_exception_only(*exc_info)[-1].strip())
# [x for x in [2,4,5]]
Then it works!
Even better:
import pdb
import os, sys, traceback
from pprint import pprint
try:
# from rich import print as rprint
from rich import inspect
from rich.pretty import pprint
except ImportError:
print("rich is not available, falling back to pprint")
pass
class Config(pdb.DefaultConfig):
prompt = "> "
sticky_by_default = True
def setup(self, pdb):
Pdb = pdb.__class__
Pdb.do_P = _do_P
Pdb.do_I = _do_I
def do_with_arg(self, arg, func):
try:
val = self._getval(arg)
except:
return
try:
func(val)
except:
exc_info = sys.exc_info()[:2]
self.error(traceback.format_exception_only(*exc_info)[-1].strip())
def _do_P(self, arg):
do_with_arg(self, arg, pprint)
def _do_I(self, arg):
try:
do_with_arg(self, arg, inspect)
except NameError:
print("rich is not available, falling back to pprint")
do_with_arg(self, arg, pprint)
I found out about uv self upgrade which took me from 0.5 to 0.8, read the CHANGELOGs etc. and many neat things exist.
upgrade --all · Issue #1419 · astral-sh/uvuv add -U pydantic one packageuv lock --upgrade all of them?uv build package you want to useuv add ../other/dist/package-2.4.0-py3-none-any.whl[tool.uv.sources]
coral-ucf = { path = "../other/dist/package-2.4.0-py3-none-any.whl" }
Copied from the old Semantic Wiki. Half of the old links are gone, yet another reminder of bit rot and memento mori.
Since forever I have some variations of this:
function lq
command jq . "$argv" -C | less -r
end
jless - A Command-Line JSON Viewer is this, but much better. Intuitive CLI viewer for json data, works seamlessly for large JSONs (which sometimes breaks my lq command, especially for large lines)
Now:
function lq
echo "not again, Serhii!!! Use jless/jl"
command jless -r -m line "$argv"
# command jq . "$argv" -C | less -r
end
m toggles the mode between line-mode (jq-like) and the (default) data mode-r does relative numbers! -N disables any line numbersh opens the help, the usual vim things do what I expect
H focuses the parentpX to just print the value)
yy !!! copy the value, including "yk copy the KEY under cursoryp copy the path from root to current objectIt does yaml as well!
EDIT: for CSVs theres YS-L/csvlens: Command line csv viewer , brew install csvlens
Long overdue, will update this page as I find better options.
torch_dtype=torch.float16 etc. to use half the memory*4? storing weights+gradient, better explanation at that link.*8 etc.Old langchain code for generating pairs of questions about feminitive usage, didn’t use it in my thesis but don’t want to lose it
from langchain.llms import OpenAI
from langchain.chat_models import ChatOpenAI
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain.pydantic_v1 import BaseModel, Field, validator
from langchain.schema import HumanMessage
from langchain.prompts import PromptTemplate
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser
from langchain.output_parsers.json import SimpleJsonOutputParser
from tqdm import tqdm
# from json import loads
from typing import List
from rich import print, inspect
b = breakpoint
# https://openai.com/pricing?ref=ghostcms.tenten.co
MODEL = "text-ada-001" # cheap, bad
MODEL = "text-davinci-003" # acceptable
MODEL = "gpt-4"
MODEL = "gpt-3.5-turbo-1106" # 'capable, cost-effective'
WOMEN_VARIANTS: str = "дівчина, моя сестра, моя жінка, колишня однокласниця, дочка маминої подруги, імена (Марія, Марія Петрівна, Кассандра, та ін.)"
COMPLETE_PROMPT: str = """Наведи будь-ласка {N_PROFS} однозначні короткі дефініції цій професії або слову, так, щоб по ним було однозначно очевидно про яку саме професію йде мова.
Зміни дефініції так, щоб вони стали фразами, де мова однозначно йде про жінку. Придумай різні варіанти жінок, про яких йде мова, умовно: {WOMEN_VARIANTS}. Але придумай і свої різноманітніші приклади.
Уникай використання самого слова чи поняття у визначеннях. Уникай слів 'фахівецька' чи 'спеціалістка'.
Наприклад:
Актор: "Моя жінка виконує ролі на сцені чи екрані"
Акушерка: "Марія Петрівна допомагає при пологах"
Автор: "Я знаю дівчину, яка пише твори та книжки".
Будь творчим. Але професія, про яку іде мова, має все рівно бути однозначно зрозумілою.
"""
FORMAT_INSTRUCTIONS = """
Формат виводу - JSON. Обʼєкт виглядати таким чином:
{
"profession": "",
"description_f": ["", ..., ""]
}
В полі description_f список всіх згенерованих дефініцій для цієї професії.
Виводь тільки код JSON, без ніяких додаткових даних до чи після.
"""
INSTRUCTIONS_GENDER_CHANGE = """Я писатиму речення про професію про жінку. Зміни
речення так, щоб мова йшла про чоловіка, а не жінку, не міняючи сам опис професії.
Імʼя чи опис жінки можеш міняти як завгодно, головне щоб на виході було речення
про чоловіка. """
def get_model(model_name = None):
model = OpenAI(model_name=model_name, temperature=0.0)
return model
def run_and_parse(model, profession: str, n_profs: int | str = 3, women: str = WOMEN_VARIANTS):
prompt = PromptTemplate(
template="{complete_prompt}\n{format_instructions}\n Професія, яку потрібно описати: {query}\n",
input_variables=["query"],
partial_variables={
"format_instructions": FORMAT_INSTRUCTIONS,
"complete_prompt": COMPLETE_PROMPT.format(
N_PROFS=n_profs, WOMEN_VARIANTS=women
),
},
)
json_parser = SimpleJsonOutputParser()
# prompt_and_model = prompt | model | json_parser
prompt_and_model = prompt | model
model_output = prompt_and_model.invoke({"query": profession})
output = json_parser.parse(model_output)
return output
def run_and_parse_gender_change(model, profession_description: str):
prompt = PromptTemplate(
template="{complete_prompt}\n Речення наступне: {query}\n",
input_variables=["query"],
partial_variables={
# "format_instructions": FORMAT_INSTRUCTIONS,
"complete_prompt": INSTRUCTIONS_GENDER_CHANGE
},
)
# json_parser = SimpleJsonOutputParser()
# prompt_and_model = prompt | model | json_parser
prompt_and_model = prompt | model
model_output = prompt_and_model.invoke({"query": profession_description})
output =model_output
# b()
# output = json_parser.parse(model_output)
return output
def generate_descriptions(model, profession: str, n_profs: int | str = 3, women: str = WOMEN_VARIANTS, do_male_version:bool = False):
desc = run_and_parse(model=model, profession=profession, n_profs =n_profs, women=women)
if do_male_version:
description_male = list()
for d in desc['description_f']:
changed = run_and_parse_gender_change(model=model, profession_description=d)
description_male.append(changed)
desc['description_m'] = description_male
return desc
def run():
professions_raw = """
абстракціоністка
автомобілістка
авторка
"""
"""
агрономка
адвокатка
анархіст
англієць
антрополог
асистентка
астронавт
аптекар
"""
profs = [x.strip() for x in professions_raw.splitlines()]
model=get_model(MODEL)
results = list()
for p in tqdm(profs):
r = generate_descriptions(model=model, profession=p, n_profs=2)
print(r)
results.append(r)
print(results)
if __name__ == "__main__":
run()
{
'profession': 'лікар',
'description_f': [
'Моя сестра працює в лікарні та лікує хворих',
'Дочка маминої подруги є лікарем та допомагає людям'
]
},
{
'profession': 'абстракціоністка',
'description_f': ['Моя сестра створює картини, які відображають абстрактні ідеї та почуття',
'Дівчина, яку я знаю, малює абстракціоністські полотна'
]
}, {
'profession': 'автомобілістка',
'description_f': [
'Моя сестра вміє водити автомобіль',
'Дочка маминої подруги працює водієм'
]
},
{
'profession': 'авторка',
'description_f': [
'Моя сестра пише книги та статті',
'Дочка маминої подруги є відомою письменницею'
]
},
{
'profession': 'Вчитель',
'description_f': [
'Моя сестра працює в школі та навчає дітей',
'Дочка маминої подруги викладає університетські предмети'
]
}
]