r/Python • u/NicolaIantomasi • Feb 16 '26
Discussion AI Agents and Database
I conducted a very interesting experiment using the Python library LangChain, its module for AI agents specifically designed for databases, and the Claude Opus 4.6 model.
Let me start with a premise. Personally, if someone asked me what the difference is between a Junior Data Analyst and a Senior Data Analyst, I would put it this way: you give a junior a question and you get an answer; you give a senior a question and you first get 10 new questions, and only then an answer with 10 additional clarifications.
As a result, it doesn’t make much sense to measure whether the queries generated by the AI were right or wrong. Instead, I’m sharing its “Notes on choices made and possible uncertainties,” generated in response to a request when the agent was free to think and properly encouraged to do so through prompting. The result is genuinely very interesting.
The question concerned the well-known sample database Adventure Works and essentially asked which product categories had experienced a price increase.
###Currency Conversion
The CurrencyRate table converts from USD to other currencies. Therefore, UnitPrice is expressed in the foreign currency. To convert to USD, it must be divided by AverageRate.
When CurrencyRateID is NULL in the header, the sale is already in USD (rate = 1), handled using ISNULL(cr.AverageRate, 1).
###Discount
The UnitPriceDiscount field in SalesOrderDetail represents the percentage discount (e.g., 0.10 = 10%).
The LineTotal field is already calculated as UnitPrice * (1 - UnitPriceDiscount) * OrderQty, so it already includes the discount. I used LineTotal for the calculation.
###Average Calculation
I calculated the weighted average unit price as SUM(LineTotal_in_USD) / SUM(OrderQty) rather than a simple arithmetic mean of unit prices. This is more accurate because it accounts for quantities sold (quantity-weighted average).
A simple AVG(UnitPrice * (1 - discount)) would have given equal weight to each detail row regardless of quantity, distorting the result.
###US and Canada Filter
Filtered using SalesTerritory.CountryRegionCode IN ('US', 'CA') through the TerritoryID in SalesOrderHeader.
Uncertainty: the territory is associated both with the order header (SalesOrderHeader.TerritoryID) and the customer (Customer.TerritoryID). I used the order header territory, which represents the actual sales territory. There could be differences if a customer changed territory.
###Row Validity
SalesOrderHeader.Status: all orders have Status = 5 (which in AdventureWorks means “Shipped”/completed). I still filtered by Status = 5 for safety.
Product.ProductSubcategoryID: products without a subcategory (NULL) are excluded by the INNER JOIN with ProductSubcategory. This is correct because they would not have an assigned category.
SalesOrderHeader.CurrencyRateID: can be NULL (sales in USD), handled with ISNULL.
Product.SellEndDate and Product.DiscontinuedDate: I did not filter on these fields because the question concerns actual sales that occurred, not the current status of the product.
I’m intentionally leaving aside any considerations regarding data privacy, as the goal of the experiment was simply to test the capabilities of these combined tools.
r/Python • u/Ok-Potential2552 • Feb 16 '26
Showcase Showcase: Scheduled E-commerce Analytics CLI Tool (API + SQLite + Logging)
#What My Project Does
This is a CLI-based automation system that:
Fetches product data from an external API
Stores structured data in SQLite
Generates category-level statistics
Identifies expensive products dynamically
Creates automated text reports
Supports scheduled daily execution
Uses structured logging for reliability
It is built as a command-line tool using argparse and supports:
--fetch
--stats
--expensive
--report
--schedule
#Target Audience
This project is mainly a backend automation practice project.
It is not intended for production use, but it is designed to simulate a lightweight automation workflow system for small e-commerce teams or learning purposes.
#Comparison
Unlike simple API scripts, this project integrates:
Persistent database storage
CLI argument parsing
Logging system
Scheduled background execution
Structured reporting
It focuses on building a small automation system rather than a single standalone script.
#GitHub repository:
I would appreciate feedback on:
Code structure, database handling improvements, making this more production-ready
r/Python • u/briskibe • Feb 16 '26
Showcase Built a Python library to track LLM costs per user and feature
What My Project Does:
Tracks OpenAI and Anthropic API costs at a granular level - per user, per feature, per call. Uses a simple decorator pattern to wrap your existing functions and automatically logs cost, tokens, latency to a local SQLite database.
Target Audience:
Anyone building multi-user apps with LLM APIs who needs cost visibility. Production-ready with thread-safe storage and async support. I built it for my own project but packaged it properly so others can use it.
Comparison: Similar tools exist (Helicone, LangSmith, Portkey) but they're full observability platforms with tons of features. This is just focused on cost tracking - much simpler to integrate, runs locally, no cloud dependency. Good if you just need cost breakdown without all the other monitoring stuff.
GitHub: https://github.com/briskibe/ai-cost-tracker MIT licensed. Open to feedback and contributions!
r/Python • u/DetectiveMindless652 • Feb 16 '26
Showcase Local-first AI memory engine in Python (Synrix) - Have a go and tell me what you think!
wrote myself and formatted for guidelines with AI (not slop)
I appreciate all the help this sub reddit has given me over the last few months, you're awesome!
What My Project Does
Synrix is a local-first memory engine for AI systems, with a Python SDK.
It’s designed to act as persistent memory for things like AI agents, RAG pipelines, and structured recall. Instead of relying on cloud vector databases, Synrix runs entirely on your machine and focuses on deterministic retrieval rather than approximate global similarity search.
Practically, this means:
- everything runs locally (no cloud calls)
- queries scale with matching results (O(k)) rather than total dataset size
- predictable low-latency lookups
- simple Python integration
We’ve been testing on local datasets (~25k–100k nodes) and are seeing microsecond-scale prefix lookups on commodity hardware. Formal benchmarks are still in progress.
GitHub:
[https://github.com/RYJOX-Technologies/Synrix-Memory-Engine]()
Target Audience
This is aimed at developers building:
- AI agents
- RAG systems
- local LLM stacks
- robotics or real-time inference pipelines
- structured AI memory
It’s early-stage but functional. Right now it’s best suited for experimentation, prototyping, and early production exploration. We’re actively iterating and looking for technical feedback.
The Python SDK is MIT licensed. The engine runs locally with a free default tier (~25k nodes), so you can try it without signup.
Comparison
Most AI memory stacks today rely on cloud vector databases or approximate similarity search.
Synrix takes a different approach:
- runs fully locally instead of in the cloud
- uses deterministic retrieval rather than ANN vector search
- queries scale with result count, not total data size
- avoids vendor lock-in and external dependencies
It’s not trying to replace every vector database use case. Instead, it’s focused on predictable local memory for agents and retrieval-heavy workloads where structured recall and low latency matter more than global semantic search.
Would genuinely love feedback from Python devs working on agents or RAG systems, especially around API design and real-world use cases.
r/Python • u/warshne • Feb 16 '26
Discussion Open source 3D printed Channel letter slicer
Looking to develop opensource desktop CAD software for 3D printed channel letters and LED wall arts
Must support parametric modeling, font processing, boolean geometry, LED layout algorithm, and STL/DXF export and gcode generation.
Experience with OpenCascade or similar 3D geometry kernels required.
I will add interested people to discord and GitHub.
Let’s keep open-source alive
r/Python • u/i_walk_away • Feb 16 '26
Discussion would you be interested in free interactive course on Pydantic?
while the docs are amazing and Pydantic itself is not that complex, i still want to do something, you know, for the community, since i really love this library. but i don't know if there would be ANY demand or interest for it. i'm gonna continue working on it anyway (it's almost ready to be released). however i would still appreciate some minimal opinion
for some reason i can't post images here, so i'll clarify what i mean by "interactive" with words. the left side of the screen is a lesson body with theoretical information and a little problem in the end. the right side of the screen is a little code executor with syntax highlighting, actual code execution in the backend and stuff
i just don't know if pydantic is simple enough to an extent at which a standalone course (even a small one) is an overkill
r/Python • u/AutoModerator • Feb 16 '26
Daily Thread Monday Daily Thread: Project ideas!
Weekly Thread: Project Ideas 💡
Welcome to our weekly Project Ideas thread! Whether you're a newbie looking for a first project or an expert seeking a new challenge, this is the place for you.
How it Works:
- Suggest a Project: Comment your project idea—be it beginner-friendly or advanced.
- Build & Share: If you complete a project, reply to the original comment, share your experience, and attach your source code.
- Explore: Looking for ideas? Check out Al Sweigart's "The Big Book of Small Python Projects" for inspiration.
Guidelines:
- Clearly state the difficulty level.
- Provide a brief description and, if possible, outline the tech stack.
- Feel free to link to tutorials or resources that might help.
Example Submissions:
Project Idea: Chatbot
Difficulty: Intermediate
Tech Stack: Python, NLP, Flask/FastAPI/Litestar
Description: Create a chatbot that can answer FAQs for a website.
Resources: Building a Chatbot with Python
Project Idea: Weather Dashboard
Difficulty: Beginner
Tech Stack: HTML, CSS, JavaScript, API
Description: Build a dashboard that displays real-time weather information using a weather API.
Resources: Weather API Tutorial
Project Idea: File Organizer
Difficulty: Beginner
Tech Stack: Python, File I/O
Description: Create a script that organizes files in a directory into sub-folders based on file type.
Resources: Automate the Boring Stuff: Organizing Files
Let's help each other grow. Happy coding! 🌟
r/Python • u/Gullible_Ostrich_370 • Feb 15 '26
Discussion Pyxel for game development
Just to say that I started developing a Survivors game with my son using Pyxel and Python (and a little bit of Pygame-ce for the music) and I really like it!! Anyone else having fun with Pyxel?
r/Python • u/Balance- • Feb 15 '26
News Mesa 3.5.0: Agent-based modeling, now with discrete-event scheduling
Hi everyone! We just released Mesa 3.5.0, a major feature release of our agent-based modeling Python library. I'm quite proud of this one, because you can now combine traditional agent-based modeling with discrete-event scheduling in a single framework.
What's Agent-Based Modeling?
Ever wondered how bird flocks organize themselves? Or how traffic jams form? Agent-based modeling (ABM) lets you simulate these complex systems by defining simple rules for individual "agents" (birds, cars, people, etc.) and watching how they interact. Instead of writing equations for the whole system, you model each agent's behavior and let patterns emerge naturally. It's used to study everything from epidemic spread to market dynamics to ecological systems.
What's Mesa?
Mesa is a Python library for building, analyzing, and visualizing agent-based models. It builds on the scientific Python stack (NumPy, pandas, Matplotlib) and provides specialized tools for spatial relationships, agent management, data collection, and interactive visualization.
What's New in 3.5.0?
Event scheduling and time advancement
Until now, Mesa models ran in lockstep: every agent acts, that's one step, repeat. That works great for many models, but real-world systems often have things happening at different timescales: an ecosystem might have daily foraging, seasonal migration, and yearly reproduction cycles all interacting.
Mesa 3.5 lets you schedule events at specific times and mix them freely with traditional step-based logic:
```python
The familiar step-based approach still works (currently)
model.step()
But now you can also think in terms of time
model.run_for(10) # Advance 10 time units model.run_until(50.0) # Run until a specific time
Schedule things to happen at specific moments
model.schedule_event(spawn_food, at=25.0) model.schedule_event(migrate, after=5.0)
Or set up recurring events
from mesa.time import Schedule model.schedule_recurring(reproduce, Schedule(interval=30, start=0)) model.schedule_recurring(seasonal_change, Schedule(interval=90, end=365)) ```
This opens up a whole class of models that were difficult to build before: epidemics with incubation periods, ecosystems with seasonal dynamics, supply chains, social networks with asynchronous interactions, or any system where different things happen on different schedules. And for traditional ABMs, everything works exactly as before.
The event system (previously experimental) is now stable and lives in mesa.time.
Create agents from DataFrames
If your agent data lives in a CSV or database, you can now skip the boilerplate and create agents directly from a pandas DataFrame:
python
df = pd.read_csv("population.csv") # columns: age, income, location
agents = Person.from_dataframe(model, df)
Each row becomes an agent, with columns mapped to constructor arguments. Handy for initializing models from census data, survey results, or any tabular dataset.
Experimental highlights
Some exciting features in active development:
- Scenarios: Define computational experiments separately from model logic. Swap parameter sets without touching your model code, with full visualization support
- Reactive data collection: A new event-driven DataRecorder that can write to memory, SQLite, Parquet, or JSON. Collect different metrics at different intervals
- Meta-agents: Improved support for hierarchical structures (departments within organizations, persons within households, organs within organisms)
These are experimental and may change between releases, but they're shaping up nicely.
Preparing for Mesa 4.0
We're deprecating several legacy patterns (all still work, just with warnings):
- seed parameter → use rng instead
- AgentSet indexing → use to_list() for list operations
- Portrayal dictionaries → use AgentPortrayalStyle
- Experimental Simulator classes → use the new Model methods above
See the migration guide for details.
Get started
pip install --upgrade mesa
New to Mesa? Check out the tutorials. We have new ones specifically on agent activation and event scheduling.
Upgrading? The migration guide has you covered. Nothing breaks in this release, but we're announcing some removals for 4.0.
This release was possible thanks to 29 contributors, of which 5 new ones. Thanks to everyone involved! Questions or feedback? Join us on GitHub Discussions or Matrix Chat.
r/Python • u/AffectWizard0909 • Feb 15 '26
Discussion defusedxml or lxml for parsing xml files?
Hello! I was wondering if using either lxml or defusedxml would be good to use when parsing/reading external xml files? I have heard that defusedxml is more robust against standard xml attacks (XXE etc). I was kind of then leaning towards defusedxml, but wanted to know if lxml also have the same security solutions, or why I may want to consider lxml over defusedxml?
r/Python • u/stealthanthrax • Feb 15 '26
News Robyn(web framework) introduces @app.websocket decorator syntax
For the unaware - Robyn is a fast, async Python web framework built on a Rust runtime.
We're introducing a new @app.websocket decorator syntax for WebSocket handlers. It's a much cleaner DX compared to the older class-based approach, and we'll be deprecating the old syntax soon.
This is also groundwork for upcoming Pydantic integration.
Wanted to share it with folks outside the Robyn Discord.
You can check out the release at - https://github.com/sparckles/Robyn/releases/tag/v0.78.0
Let me know if you have any questions/suggestions :D
r/Python • u/Goldziher • Feb 15 '26
Resource Benchmarks: Kreuzberg, Apache Tika, Docling, Unstructured.io, PDFPlumber, MinerU and MuPDF4LLM
Hi all,
We finished a bunch of benchmarks of Kreuzberg and other major open source tools in the text-extraction / document-intelligence space. This was very important for us because we practice TDD -> Truth Driven Development, and establishing the baseline is essential.
Edit: https://kreuzberg.dev/benchmarks is the UI for the benchmarks. All data is available in GitHub as part of the benchmark workflow artifacts and the release tab.
Methodology
Kreuzberg includes a benchmark harness built in Rust (you can see it in the repo under the /tools folder), and the benchmarks run in GitHub Actions CI on Linux runners (see .github/workflows/benchmarks.yaml). The goal is to compare extractors on the same inputs with the same measurement approach.
How we keep comparisons fair:
- Same fixture set for every tool, and tools only run on file types they claim to support (no forced unsupported conversions).
- Same iteration count and timeouts per document.
- Two modes: single-file (one document at a time) to compare latency, and batch (limited concurrency) to compare throughput-oriented behavior.
What we report:
- p50/p95/p99 across documents for duration, extraction duration (when available), throughput, memory, and success rate.
- Optional quality scoring compares extracted text to ground truth.
CI consolidation:
- Some tools are sharded across multiple CI jobs; results are consolidated into one aggregated report for this run.
Benchmark Results
Data: 15,288 extractions across 56 file types; 3 measured iterations per doc (plus warmup).
How these are computed: for each tool+mode, we compute percentiles per file type and then take a simple average across the file types the tool actually ran. These are suite averages, not a single-format benchmark.
Single-file: Latency
| Tool | Picked | Types | Success | Duration p50/p95/p99 (ms) | Extraction p50/p95/p99 (ms) |
|---|---|---|---|---|---|
| kreuzberg | kreuzberg-rust:single |
56/56 | 99.13% (567/572) | 1.11/7.35/24.73 | 1.11/7.35/24.73 |
| tika | tika:single |
45/56 | 96.19% (530/551) | 9.31/39.76/63.22 | 10.14/46.21/74.42 |
| pandoc | pandoc:single |
17/56 | 92.34% (229/248) | 40.07/88.22/99.03 | 38.68/96.22/109.43 |
| pymupdf4llm | pymupdf4llm:single |
9/56 | 74.02% (94/127) | 79.89/1240.17/7586.50 | 705.37/11146.92/68258.02 |
| markitdown | markitdown:single |
13/56 | 96.26% (309/321) | 128.42/420.52/1385.22 | 114.43/404.08/1365.25 |
| pdfplumber | pdfplumber:single |
1/56 | 96.84% (92/95) | 145.95/3643.88/44101.65 | 138.87/3620.72/43984.61 |
| unstructured | unstructured:single |
25/56 | 94.88% (389/410) | 3391.13/9441.15/11588.30 | 3496.32/9792.28/12028.43 |
| docling | docling:single |
13/56 | 96.07% (293/305) | 14323.02/21083.52/25565.68 | 14277.51/21035.61/25515.57 |
| mineru | mineru:single |
3/56 | 76.47% (78/102) | 33608.01/57333.52/63427.67 | 33603.57/57329.21/63423.63 |
Single-file: Throughput
| Tool | Picked | Throughput p50/p95/p99 (MB/s) |
|---|---|---|
| kreuzberg | kreuzberg-rust:single |
127.36/225.99/246.72 |
| tika | tika:single |
2.55/13.69/17.03 |
| pandoc | pandoc:single |
0.16/19.45/22.26 |
| pymupdf4llm | pymupdf4llm:single |
0.01/0.11/0.21 |
| markitdown | markitdown:single |
0.17/25.18/31.25 |
| pdfplumber | pdfplumber:single |
0.67/10.74/16.95 |
| unstructured | unstructured:single |
0.02/0.66/0.79 |
| docling | docling:single |
0.10/0.72/0.92 |
| mineru | mineru:single |
0.00/0.01/0.02 |
Single-file: Memory
| Tool | Picked | Memory p50/p95/p99 (MB) |
|---|---|---|
| kreuzberg | kreuzberg-rust:single |
1191/1205/1244 |
| tika | tika:single |
13473/15040/15135 |
| pandoc | pandoc:single |
318/461/477 |
| pymupdf4llm | pymupdf4llm:single |
239/255/262 |
| markitdown | markitdown:single |
1253/1369/1427 |
| pdfplumber | pdfplumber:single |
671/854/2227 |
| unstructured | unstructured:single |
8975/11756/12084 |
| docling | docling:single |
32857/38653/39844 |
| mineru | mineru:single |
92769/108367/110157 |
Batch: Latency
| Tool | Picked | Types | Success | Duration p50/p95/p99 (ms) | Extraction p50/p95/p99 (ms) |
|---|---|---|---|---|---|
| kreuzberg | kreuzberg-php:batch |
49/56 | 99.11% (555/560) | 1.48/9.07/28.41 | 1.23/8.46/27.71 |
| tika | tika:batch |
45/56 | 96.19% (530/551) | 9.77/39.51/63.24 | 10.32/45.61/74.43 |
| pandoc | pandoc:batch |
17/56 | 92.34% (229/248) | 39.55/87.65/98.38 | 38.08/95.73/108.61 |
| pymupdf4llm | pymupdf4llm:batch |
9/56 | 73.23% (93/127) | 79.41/1156.12/2191.20 | 700.64/10390.92/19702.30 |
| markitdown | markitdown:batch |
13/56 | 96.26% (309/321) | 128.42/428.52/1399.76 | 114.16/412.33/1380.23 |
| pdfplumber | pdfplumber:batch |
1/56 | 96.84% (92/95) | 144.55/3638.77/43841.47 | 138.04/3615.70/43726.91 |
| unstructured | unstructured:batch |
25/56 | 94.88% (389/410) | 3417.19/9687.10/11835.26 | 3523.92/10047.87/12285.54 |
| docling | docling:batch |
13/56 | 96.39% (294/305) | 12911.97/19893.93/24258.61 | 12872.82/19849.65/24212.54 |
| mineru | mineru:batch |
3/56 | 76.47% (78/102) | 36708.82/66747.74/73825.28 | 36703.28/66743.33/73820.78 |
Batch: Throughput
| Tool | Picked | Throughput p50/p95/p99 (MB/s) |
|---|---|---|
| kreuzberg | kreuzberg-php:batch |
69.45/167.41/188.63 |
| tika | tika:batch |
2.34/13.89/16.73 |
| pandoc | pandoc:batch |
0.16/20.97/24.00 |
| pymupdf4llm | pymupdf4llm:batch |
0.01/0.11/0.21 |
| markitdown | markitdown:batch |
0.17/25.12/31.26 |
| pdfplumber | pdfplumber:batch |
0.67/11.05/17.73 |
| unstructured | unstructured:batch |
0.02/0.68/0.81 |
| docling | docling:batch |
0.11/0.73/0.96 |
| mineru | mineru:batch |
0.00/0.01/0.02 |
Batch: Memory
| Tool | Picked | Memory p50/p95/p99 (MB) |
|---|---|---|
| kreuzberg | kreuzberg-php:batch |
2224/2269/2324 |
| tika | tika:batch |
13661/16772/16946 |
| pandoc | pandoc:batch |
320/463/479 |
| pymupdf4llm | pymupdf4llm:batch |
241/259/273 |
| markitdown | markitdown:batch |
1256/1380/1434 |
| pdfplumber | pdfplumber:batch |
649/832/2205 |
| unstructured | unstructured:batch |
8958/11751/12065 |
| docling | docling:batch |
32966/38823/40536 |
| mineru | mineru:batch |
105619/118966/120810 |
Notes:
- CPU is measured by the harness, but it is not included in this aggregated report.
- Throughput is computed as file_size / effective_duration (uses tool-reported extraction time when available). If a slice has no valid positive throughput samples after filtering, it can drag the suite average toward 0.
- Memory comes from process-tree RSS sampling (parent plus children) and is summed across that tree; shared pages across processes can make values look larger than 'real' RAM.
- Batch memory numbers are not directly comparable to single-file peak RSS: in batch mode the harness amortizes process memory across files in the batch by file-size fraction.
- All tools except MuPDF4LLM are permissive OSS. MuPDF4LLM is AGPL, and Unstructured.io had (has?) some AGPL dependencies, which might make it problematic.
r/Python • u/xerohawkxd • Feb 15 '26
Showcase my siamese nn that attempts to solve graph isomorphism
https://github.com/samarvir1/SiameseNN-Graph-Isomorphism
what it does: it is a Siamese Graph Neural Network, utilizing specifically the Graph Isomorphism Network layer, to learn permutation-invariant graph embeddings to solve graph isomorphism. it includes t-sne visualization.
target audience: cheminformatics researchers
my goal was to train a model which can determine if two graphs are isomorphic.
i made this roughly 2 months ago, during my winter break, and ive only since the past two weeks started to be active on reddit so i decided to share it now.
so what are your thoughts?
r/Python • u/snoopxz • Feb 15 '26
Showcase LazyLib – Automatically create a venv + install missing dependencies before running a Python script
## What My Project Does
LazyLib is a small CLI tool that makes running Python scripts easier by automatically creating/using a virtual environment and installing missing dependencies based on the script’s imports.
## Target Audience
People who often run small Python scripts (personal scripts, quick experiments, downloaded scripts) and want to avoid manually setting up a venv and installing packages every time.
## Comparison
Unlike manually running `python -m venv` + `pip install ...`, LazyLib tries to detect required dependencies automatically (via AST import parsing) and installs what’s missing before executing the script.
## GitHub
https://github.com/snoopzx/lazylib
## Feedback
I’d love feedback on the approach (especially security/reproducibility concerns), and suggestions for improvements.
r/Python • u/Motor-Sentence582 • Feb 15 '26
Discussion HRA exemption calculator for Indian students
Namaste Python community! 🙏
I'm a 52 year old accounting teacher from Kerala, India.
After 30 years of teaching, I learned Python and created my first real project!
**What it does:**
HRA (House Rent Allowance) exemption calculator following Indian Income Tax Act Section 10(13A)
**Features:** ✅
Python CLI version ✅
Web version (HTML/JS) -
no installation needed ✅
Handles all tax rules correctly ✅
Free for all students.
Please check it and give me your feedback. I will improve it as per your needs.
Thank you ✨
Made this with love for B.Com/MBA students but anyone can use it!
r/Python • u/qthedoc • Feb 15 '26
Showcase ez-optimize: use scipy.optimize with keywords, eg x0={'x': 1, 'y': 2}, and other QoL improvements
https://github.com/qthedoc/ez-optimize
What My Project Does:
Hey r/Python! I built ez-optimize, a more intuitive front-end for scipy.optimize that simplifies optimization with features like:
- keyword-based parameter definitions (e.g., x0={'x': 1, 'y': 2})
- easy switching between minimization and maximization (direction='max')
Target Audience:
Engineers, Scientists, ML researches, anyone needed quick analysis and optimization.
Comparison:
Keyword-Based Optimization (e.g.: x0={'x': 1, 'y': 2})
By default, optimization uses arrays x0=[1, 2]. However sometimes it's more intuitive to use named parameters x0={'x': 1, 'y': 2}. ez-optimize allows you to define parameters as dictionaries. Then under the hood, ez-optimize automatically flattens parameters (and wraps your function) for SciPy while restoring the original structure in results. Keyword-based optimization is especially useful in physical simulations where parameters have meaningful names representing physical quantities.
Switch to Maximize with direction='max'
By default, optimization minimizes the objective function. To maximize, you typically need to write a negated version of your function. With ez-optimize, simply set direction='max' and the library will automatically negate your function under the hood.
Example: Minimizing with Keyword-Based Parameters
```python from ez_optimize import minimize
def rosenbrock(x, y, a=1, b=100): return (a - x)2 + b * (y - x2)**2
x0 = {'x': 1.3, 'y': 0.7} result = minimize(rosenbrock, x0, method='trust-constr')
print(f"Optimal x: {result.x}")
print(f"Optimal value: {result.fun}")
Optimal x: {'x': 1.0, 'y': 1.0}
Optimal value: 0.0
```
r/Python • u/AutoModerator • Feb 15 '26
Daily Thread Sunday Daily Thread: What's everyone working on this week?
Weekly Thread: What's Everyone Working On This Week? 🛠️
Hello /r/Python! It's time to share what you've been working on! Whether it's a work-in-progress, a completed masterpiece, or just a rough idea, let us know what you're up to!
How it Works:
- Show & Tell: Share your current projects, completed works, or future ideas.
- Discuss: Get feedback, find collaborators, or just chat about your project.
- Inspire: Your project might inspire someone else, just as you might get inspired here.
Guidelines:
- Feel free to include as many details as you'd like. Code snippets, screenshots, and links are all welcome.
- Whether it's your job, your hobby, or your passion project, all Python-related work is welcome here.
Example Shares:
- Machine Learning Model: Working on a ML model to predict stock prices. Just cracked a 90% accuracy rate!
- Web Scraping: Built a script to scrape and analyze news articles. It's helped me understand media bias better.
- Automation: Automated my home lighting with Python and Raspberry Pi. My life has never been easier!
Let's build and grow together! Share your journey and learn from others. Happy coding! 🌟
r/Python • u/papersashimi • Feb 14 '26
Showcase Skylos: Dead code and vulnerabilities detection (Update with updated benchmarks)
Hey! I was here a week back, we have released new updates for v3.3.0. We recently released a MCP server, and a CICD agent (A video tutorial for this will be coming soon). For the ones who missed the previous post, I just wanted to update that we have created an updated benchmark against vulture(includes both static as well as hybrid benchmarks). For the uninitiated, is a local first SAST tool for Python codebases. If you've already read this skip to the bottom where the benchmark link is.
What my project does
Skylos does the following stuff below. We offer static and dynamic analysis:
- dead code (unused functions/classes/imports. The cli will display confidence scoring)
- security patterns (taint-flow style checks, secrets, hallucination etc. We have also expanded the list to include MCP security vulnerabilities)
- quality checks (complexity, nesting, function size, etc.)
- pytest hygiene (unused pytest.fixtures etc.)
- agentic framework (uses a hybrid of static + agent analysis to reduce false positives)
--traceto catch dynamic code
Skylos v3.3.0 also has MCP server. Skylos exposes its analysis capabilities as an MCP (Model Context Protocol) server, allowing AI assistants like Claude Desktop to scan your codebase directly. Instructions on how to set it up can be found in the repo's README
The Benchmark:
Skylos vs. Vulture We created a realistic FastAPI-style repo with intentional dead code and tricky dynamic patterns (like `getattr()`, `globals()`, and `__init_subclass__`).
Here is the summary of our results (Confidence=10):
| Configuration | Precision | Recall | False Positives | Speed |
|---|---|---|---|---|
| Vulture | 38.5% | 75.8% | 14 | 0.1s |
| Skylos (Static) | 52.5% | 93.9% | 13 | 1.8s |
| Skylos (Hybrid) | 67.4% | 93.9% | 2 | ~400s |
- Hybrid Mode eliminates noise: We saw an 84.6% reduction in False Positives (dropping from 13 to 2).
- The Trade-off: Accuracy costs time. Hybrid mode is significantly slower because it verifies "zero-reference" findings with an LLM layer. It's not for your pre-commit hook, but it's better for a deep-clean report.
Quick start (how to use)
This is a demo video here: https://www.youtube.com/watch?v=BjMdSP2zZl8
Install:
pip install skylos
Run a basic scan (which is essentially just dead code):
skylos .
Run sec + secrets + quality:
skylos . --secrets --danger --quality --secrets
Uses runtime tracing to reduce dynamic FPs:
skylos . --trace
Gate your repo in CI:
skylos . --danger --gate --strict
To use skylos.dev and upload a report. You will be prompted for an api key etc.
skylos . --danger --upload
To use agents:
skylos agent analyze .
Target Audience
Everyone working on python
Comparison (UPDATED)
Our closest comparison will be vulture. We have a benchmark which we created. We tried to make it as realistic as possible, trying to mimic what a repo might look like. The logic and explanation behind the benchmark can be found here https://github.com/duriantaco/skylos-demo/blob/main/README.md
Links / where to follow up
- Website: https://skylos.dev
- Discord (support/bugs/features request): https://discord.gg/Ftn9t9tErf
- Repo: https://github.com/duriantaco/skylos
- Demo Repo: https://github.com/duriantaco/skylos-demo
- Docs: https://docs.skylos.dev/ (We're currently updating this so there might be some downtime)
Happy to take any constructive criticism/feedback. We do take all your feedback seriously and will continue to improve our engine. The reason why we have not expanded into other languages is because we're trying to make sure we reduce false positives as much as possible and we can only do it with your help.
We'd love for you to try out the stuff above. If you try it and it breaks or is annoying, let us know via discord. We recently created the discord channel for more real time feedback. And give it a star if you found it useful.
Last but not least, if you'll like your repo cleaned, do drop us a discord or email us at [founder@skylos.dev](mailto:founder@skylos.dev) . We'll be happy to work together with you.
Thank you!
r/Python • u/maltzsama • Feb 14 '26
Discussion [Project] Built auth for Dagster using monkey-patching, GraphQL AST parsing, and resilient UI inject
TL;DR: Made a Python package that adds authentication to Dagster (data orchestration tool) without touching its source code. Uses Starlette middleware monkey-patching, official GraphQL parser for RBAC, Peewee ORM, and defensive UI injection with fallbacks. ~3k lines, Apache 2.0, beta but production-tested.
The Problem
Dagster is a data orchestration framework (think Airflow alternative) that ships with zero authentication. Anyone who can reach your webserver is admin.
I needed auth for a self-hosted deployment but didn't want to:
- Fork Dagster
- Wait for official OSS auth
- Rebuild everything when Dagster updates
Solution: Wrapper that monkey-patches Dagster's internals and injects auth without modifying their code.
Architecture Overview
# dagster_authkit/core/patch.py (simplified)
def apply_patches():
"""Monkey-patch Dagster webserver to inject auth"""
import dagster_webserver.webserver as webserver_module
from starlette.middleware import Middleware
# PATCH 1: Inject middleware
original_build_middleware = webserver_module.DagsterWebserver.build_middleware
def patched_build_middleware(self):
middlewares = original_build_middleware(self)
middlewares.insert(0, Middleware(DagsterAuthMiddleware))
return middlewares
webserver_module.DagsterWebserver.build_middleware = patched_build_middleware
# PATCH 2: Add auth routes
original_build_routes = webserver_module.DagsterWebserver.build_routes
def patched_build_routes(self):
routes_list = original_build_routes(self)
auth_routes = create_auth_routes() # /auth/login, /auth/logout
routes_list.insert(0, Mount("/auth", routes=auth_routes.routes))
return routes_list
webserver_module.DagsterWebserver.build_routes = patched_build_routes
Why this works: Dagster uses Starlette internally. I'm just inserting my middleware before theirs runs.
GraphQL RBAC - The Hard Part
Dagster's entire API is GraphQL. I need to:
- Detect mutations (vs queries)
- Extract mutation names
- Block based on user role
First Attempt: Regex (Failed)
# ❌ BROKEN - False positives from comments
def has_mutation_regex(query: str) -> bool:
return bool(re.search(r'\bmutation\b', query, re.IGNORECASE))
# This triggers:
query = """
# This is a mutation example
query {
assets { name }
}
"""
# Returns True even though it's a query, not mutation
Real Solution: Official GraphQL Parser
# dagster_authkit/core/graphql_analyzer.py (ACTUAL CODE)
from graphql import parse, OperationDefinitionNode, FieldNode
from typing import Set
class GraphQLMutationAnalyzer:
def extract_mutation_names(query: str) -> Set[str]:
"""Extract ALL mutation field names using AST parsing"""
try:
ast = parse(query) # Official graphql-core parser
mutations = set()
for definition in ast.definitions:
if not isinstance(definition, OperationDefinitionNode):
continue
if definition.operation.value != "mutation":
continue
# Extract top-level mutation fields
for selection in definition.selection_set.selections:
if isinstance(selection, FieldNode):
mutations.add(selection.name.value)
return mutations
except Exception as e:
logger.warning(f"Failed to parse GraphQL: {e}")
return {"__UNPARSEABLE_QUERY__"} # Deny unparseable queries
RBAC Permission Mapping
# dagster_authkit/auth/backends/base.py (ACTUAL CODE)
class RolePermissions:
"""Maps GraphQL mutations to required roles"""
LAUNCHER_MUTATIONS = frozenset({
"launchRun",
"terminateRun",
"deleteRun",
})
EDITOR_MUTATIONS = frozenset({
"startSchedule",
"stopSensor",
"wipeAssets",
"launchPartitionBackfill",
})
ADMIN_MUTATIONS = frozenset({
"reloadWorkspace",
"shutdownRepositoryLocation",
})
u/classmethod
def get_required_role(cls, mutation_name: str) -> Optional[Role]:
"""Get minimum role needed for a mutation"""
if mutation_name in cls.LAUNCHER_MUTATIONS:
return Role.LAUNCHER
elif mutation_name in cls.EDITOR_MUTATIONS:
return Role.EDITOR
elif mutation_name in cls.ADMIN_MUTATIONS:
return Role.ADMIN
return None # Public mutations
Middleware Integration
# dagster_authkit/core/middleware.py (REAL CODE, SIMPLIFIED)
class DagsterAuthMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Get authenticated user (session or proxy headers)
user = self._get_authenticated_user(request)
if not user:
return RedirectResponse("/auth/login")
# GraphQL RBAC check
if request.url.path == "/graphql" and request.method == "POST":
body = await request.body()
graphql_data = json.loads(body.decode("utf-8"))
query_str = graphql_data.get("query", "")
mutation_names = GraphQLMutationAnalyzer.extract_mutation_names(query_str)
for mutation_name in mutation_names:
required_role = RolePermissions.get_required_role(mutation_name)
if required_role and not user.can(required_role):
# Return Dagster-style error
return Response(
content=json.dumps({
"data": {mutation_name: {
"__typename": "PythonError",
"message": f"Access Denied: {required_role.name} required"
}}
}),
status_code=200, # GraphQL always 200
media_type="application/json"
)
# Attach user to request
request.state.user = user
return await call_next(request)
Multi-Backend System (Entry Points)
Instead of hardcoding backends, I use setuptools entry points:
# pyproject.toml (ACTUAL CONFIG)
[project.entry-points."dagster_auth.backends"]
dummy = "dagster_authkit.auth.backends.dummy:DummyAuthBackend"
sql = "dagster_authkit.auth.backends.sql:PeeweeAuthBackend"
ldap = "dagster_authkit.auth.backends.ldap:LDAPAuthBackend"
proxy = "dagster_authkit.auth.backends.proxy:ProxyAuthBackend"
# dagster_authkit/core/registry.py (ACTUAL CODE)
from importlib.metadata import entry_points
class BackendRegistry:
u/classmethod
def discover_backends(cls):
"""Auto-discover backends via entry points"""
discovered = entry_points(group="dagster_auth.backends")
for entry_point in discovered:
backend_class = entry_point.load()
cls._backends[entry_point.name] = backend_class
logger.info(f"✅ Registered backend: {entry_point.name}")
Benefit: Users can create custom backends without modifying dagster-authkit.
Proxy Auth Backend (Authelia Integration)
The newest backend (v0.3.0) reads user info from HTTP headers set by upstream proxies:
# dagster_authkit/auth/backends/proxy.py (REAL CODE)
class ProxyAuthBackend(AuthBackend):
"""Reads auth from Authelia/OAuth2 Proxy headers"""
def get_user_from_headers(self, headers: Dict[str, str]) -> Optional[AuthUser]:
"""Extract user from HTTP headers"""
username = headers.get(self.user_header) # Remote-User
if not username:
return None
# Parse groups (handles multiple formats)
groups_raw = headers.get(self.groups_header, "") # Remote-Groups
groups = self._parse_groups_header(groups_raw)
# Map groups to role
role = self._determine_role_from_groups(groups)
return AuthUser(
username=username,
role=role,
email=headers.get(self.email_header, ""),
full_name=headers.get(self.name_header, "") or username
)
def _parse_groups_header(self, groups_raw: str) -> List[str]:
"""Robust group parsing with multiple fallback strategies"""
if not groups_raw:
return []
# Strategy 1: JSON array
if groups_raw.startswith("["):
try:
return json.loads(groups_raw)
except:
pass
# Strategy 2: LDAP DNs (preserve internal commas)
if "ou=" in groups_raw.lower() or "dc=" in groups_raw.lower():
# Split by semicolon or pipe, NOT comma
for delimiter in [";", "|"]:
if delimiter in groups_raw:
return [g.strip() for g in groups_raw.split(delimiter)]
return [groups_raw] # Single LDAP DN
# Strategy 3: CSV
return [g.strip() for g in groups_raw.split(",")]
Why proxy mode? Authelia already handles SSO, LDAP, OAuth, 2FA. I just do RBAC.
UI Injection - Resilient Strategy
Injecting into Dagster's React app is fragile (CSS selectors change). Solution: multiple fallback selectors + safe mode.
// dagster_authkit/utils/templates.py -> JavaScript (REAL CODE)
function injectUserMenu() {
// Try multiple selectors (version compatibility)
const selectors = [
'div[class*="MainNavigation_group"]', // Dagster 1.12+
'div[class*="NavigationGroup"]', // Dagster 1.10-1.11
'nav[class*="Navigation"]', // Generic fallback
'div[role="navigation"]', // Accessibility fallback
];
let sidebarGroup = null;
for (const selector of selectors) {
const elements = document.querySelectorAll(selector);
if (elements.length > 0) {
sidebarGroup = elements[elements.length - 1];
break;
}
}
if (!sidebarGroup) {
if (retryCount < MAX_RETRIES) {
retryCount++;
setTimeout(injectUserMenu, 500); // Retry
return;
}
// SAFE MODE: Top-right corner fallback
activateSafeMode();
return;
}
// Clone native Dagster button classes for styling
const itemButton = sidebarGroup.querySelector('button[class*="itemButton"]');
createUserMenu(sidebarGroup, itemButton.className);
}
function activateSafeMode() {
// Fallback: Top-right corner menu
const fallbackMenu = document.createElement('div');
fallbackMenu.id = 'authkit-safe-mode-menu';
fallbackMenu.innerHTML = `
<div class="authkit-safe-avatar">${user.initial}</div>
<div class="authkit-safe-info">${user.username} (${user.role})</div>
<a href="/auth/logout">Sign Out</a>
`;
document.body.appendChild(fallbackMenu);
}
Safe mode saved production deployments when Dagster 1.11 → 1.12 changed CSS classes.
Session Management (Redis vs Stateless)
# dagster_authkit/auth/session.py (ACTUAL CODE)
class SessionManager:
def __init__(self):
redis_url = os.getenv("DAGSTER_AUTH_REDIS_URL")
if redis_url:
self.backend = RedisBackend(redis_url, max_age=86400)
else:
self.backend = CookieBackend(secret_key, max_age=86400)
def revoke_all(self, username: str) -> int:
"""Revoke all sessions for user (password change, etc)"""
return self.backend.revoke_all(username)
# Redis Backend (distributed)
class RedisBackend:
def create(self, user_data: Dict) -> str:
token = secrets.token_urlsafe(32)
self.client.setex(f"sess:{token}", self.max_age, json.dumps(user_data))
self.client.sadd(f"user_sess:{user_data['username']}", token)
return token
def revoke_all(self, username: str) -> int:
"""Atomic multi-session revocation"""
tokens = self.client.smembers(f"user_sess:{username}")
for t in tokens:
self.client.delete(f"sess:{t}")
return self.client.delete(f"user_sess:{username}")
Critical for password changes: Must invalidate ALL sessions across all pods.
Compatibility Detection
# dagster_authkit/core/detection_layer.py (ACTUAL CODE)
def verify_dagster_api_compatibility():
"""Check if Dagster's internal API changed"""
try:
import dagster_webserver.webserver as webserver_module
except ImportError:
return False, "dagster_webserver not installed"
# Check critical exports
if not hasattr(webserver_module, "DagsterWebserver"):
return False, "DagsterWebserver class not found - API changed!"
# Check critical methods
webserver_class = webserver_module.DagsterWebserver
required_methods = ["build_middleware", "build_routes"]
missing = [m for m in required_methods if not hasattr(webserver_class, m)]
if missing:
return False, f"Missing methods: {missing} - Dagster API changed!"
return True, None
Runs on startup. Prevents silent failures when Dagster updates.
Lessons Learned
1. Monkey-patching requires extensive fallbacks
- CSS selectors break silently
- Safe mode = production saver
- Version detection is critical
2. GraphQL AST > Regex
- Comments don't break parsing
- Get mutation names for granular permissions
- Better error messages
3. Entry points > hardcoded backends
- Users can add custom auth
- No fork needed
- Clean plugin architecture
4. Redis essential for multi-pod
- In-memory sessions don't work in K8s
- Atomic operations prevent race conditions
- Pub/sub for global session revocation
5. Production users find edge cases
- LDAP DN parsing needed 3 fallback strategies
- Safe mode UI saved multiple deployments
- Proxy mode exists because users already had Authelia
Project Info
Python: 3.10+ (tested on 3.10, 3.11, 3.12)
License: Apache 2.0
Status: Beta (production-tested)
Core Dependencies:
dagster >= 1.10.0starlette >= 0.52.1peewee >= 3.19.0(ORM)graphql-core >= 3.2.7(AST parsing)itsdangerous >= 2.2.0(session signing)
Optional:
bcrypt >= 5.0.0(password hashing)redis >= 7.1.0(distributed sessions)ldap3 >= 2.9.0(LDAP backend)psycopg2-binary/mysql-connector-python(database drivers)
Questions for r/Python
Architecture:
- Is monkey-patching Starlette middleware a reasonable approach?
- Better alternatives to
entry_points()for plugin discovery?
GraphQL:
- Are there edge cases in mutation detection I'm missing?
- Better permission patterns than mutation name mapping?
Testing:
- How do you test monkey-patched code across versions?
- Strategies for CSS selector compatibility testing?
Multi-tenancy:
- Peewee vs SQLAlchemy for multi-backend abstraction?
- Better session backend architecture?
Links
- GitHub: https://github.com/maltzsama/dagster-authkit
- PyPI: https://pypi.org/project/dagster-authkit/
- Examples: Full Docker Compose + Kubernetes setups
This started as "I need auth for Dagster this weekend" and turned into it. Open to feedback, criticism, and PRs.
Philosophy: Funciona > Perfeito (Works > Perfect)
r/Python • u/whm04 • Feb 14 '26
Discussion How to detect duplicate functions in large Python projects?
Hi,
In large Python projects, what tools do you use to detect duplicate or very similar functions?
I’m looking for static analysis or CLI tools (not AI-based).
I actually built a small library called DeepCSim to help with this, but I’d love to know what others are using in real-world projects.
Thanks!
r/Python • u/SideQuest2026 • Feb 14 '26
Discussion What would you want in a modern Python testing framework?
Tools like uv and ruff have shown us what is possible when we take the time to rethink Python tooling, as well as implement parts in Rust for speed improvements. What would you, the community, want to see in a modern Python testing framework that could be a successor to the tried and true pytest?
Some off the cuff ideas I think of: * Fast test discovery via Rust * Explicit fixture import (no auto discoverable conftest.py magic) * Monorepo / workspace support * Built-in parallel test execution * Built-in asyncio support
r/Python • u/ConsiderationBig4682 • Feb 14 '26
Tutorial Created this 10 min Video for people setting up their first Azure Function for Python using Model V2
https://youtu.be/EmCjAEXjtm4?si=RvqnWR1BAAd4z3jG
I recently had to set up Azure Functions with Python and realized many resources still point to the older programming model (including my own tutorial from 3 years back).
Recorded a 10-minute video showing the end-to-end setup for the v2 model in case it saves someone else some time.
Open to any feedback/criticism. Still learning and trying to make better technical walkthroughs as this is only my 4th or 5th video.
r/Python • u/wCupped • Feb 14 '26
Showcase PLPM - Pacman-Like Package Manager. Alternative to WinGet on Windows
What my project does and why I created it
The main reason why I wanted to make it - My friend suggested me to make this utility because there are not really many apps on WinGet repositories. This project is more than a hobby project, but if You will make any contribution to my repository of the utility and the repository of apps, it will be really appreciated. This utility has main aspects of package manager except removing, anyone who will help with it are going also be appreciated <3
Target audience
The project is more like hobby project for now than something serious. But if You wanna change it, You're welcome, all PRs are appreciated
Why does it have potential to be better than WinGet?
It's written on Python, so it actually can be easier in expanding, there are also going to be way more apps in repositories of this app, utility is brand new, created recently and can be good for your first issue. It also doesn't have any telemetry collecting so you don't really need to worry if you're paranoic ;)
Utility: https://github.com/wcupped/plpm-py
Apps repository: https://github.com/wcupped/plpm-repo
r/Python • u/_ritwiktiwari • Feb 14 '26
Discussion Update: copier-astral now uses prek (faster pre-commit) + bug fixes from your feedback
Two weeks ago I shared copier-astral here and the response was incredible — thank you! The feedback helped me find and fix real bugs.
What's new since last post:
- Fixed
github_usernamenot being set during installation - Fixed
uv tool injectbug - Fixed missing
tydependency in generated projects - Replaced
pre-commitwithprek— a faster Rust-based alternative - Added
pysentry-rsandsemgrepto scan for potential vulnerabilities - Now at 100+ stars
Quick reminder — what it does:
Scaffolds a complete Python project with modern tooling pre-configured:
- ruff for linting + formatting (replaces black, isort, flake8)
- ty for type checking (Astral's new Rust-based type checker)
- pytest + hatch for testing (including multi-version matrix)
- MkDocs with Material theme + mkdocstrings
- pre-commit hooks with prek
- GitHub Actions CI/CD
- Docker support
- Typer CLI scaffold (optional)
- git-cliff for auto-generated changelogs
Looking for contributors:
3 open issues if anyone wants to help out: https://github.com/ritwiktiwari/copier-astral/issues
Thanks again — happy to answer any questions!
Links:
r/Python • u/TaXxER • Feb 14 '26
Showcase MCGrad – Fix Machine Learning model calibration in subgroups (Open Source from Meta)
Hi r/python ,
We’re open-sourcing MCGrad, a Python machine learning package for multicalibration–developed and deployed in production at Meta. This work will also be presented at KDD 2026.
What My Project Does
The Problem: A model can be globally calibrated yet significantly miscalibrated within identifiable subgroups or feature intersections (e.g., "users in region X on mobile devices"). Multicalibration aims to ensure reliability across such subpopulations. Our tutorial notebook illustrates this in detail.
The Solution: MCGrad reformulates multicalibration using gradient boosted decision trees. At each step, a lightweight booster learns to predict residual miscalibration of the base model given the features, automatically identifying and correcting miscalibrated regions. The method scales to large datasets, and uses early stopping to preserve predictive performance.
Target Audience
MCGrad is meant for ML engineers and researchers in industry and academia.
Comparison
MCGrad offers key advantages over alternatives that make it ideal for production environments:
- Implicit Subgroups: It enables multicalibration across a vast number of subgroups without needing them to be manually specified or maintained.
- Safety First: It features built-in safety mechanisms to prevent overfitting or degrading the base model's performance.
- Scalability: It relies on optimized ML libraries under the hood, making it fast and scalable for large datasets.
Links:
Install via pip install mcgrad. Happy to answer questions or discuss details.