Open Source · Python

Python Library for Obsidian Databases

upstream-edge lets you read and write wells, production, forecasts, and economic assumptions directly from your Obsidian .obsdb files.

pip install upstream-edge

Python 3.11+  ·  Apache-2.0  ·  pandas optional

Quick start

See it in action

from upstream_edge.obsidian_db import Database, RsvCat

with Database.open("reserves.obsdb") as db:
    # Cumulative oil for every producing well — no SQL required.
    pdp_wells = [w for w in db.wells() if w.rsv_cat is RsvCat.PDP]
    for w in pdp_wells:
        monthly = db.production_monthly(w.prop_id)
        cum_oil = sum(m.oil_bbl for m in monthly)
        print(f"{w.prop_id}  {w.well_name}:  {cum_oil:,.0f} bbl")
What's inside

One Python interface to the whole database

Wells

Add, update, delete, and query wells.

Production

Import and export monthly and daily production records.

Forecasts

Export or build multi-segment Arps decline curves programmatically.

Economic models

Define prices, expenses, and other economic assumptions.

Scenarios

Organize model assignments by named scenarios.

Subsurface

Manage surveys, reservoirs, completions, and perforations.

Custom attributes

Add user-defined text, numeric, and date columns to wells.

pandas export

Optional [pandas] extra adds a _df variant to every reader.

Scripted, repeatable, reviewable

Automate database updates

Build an Arps decline forecast

from datetime import date
from upstream_edge.obsidian_db import Database, ForecastSegment, Phase

with Database.open("reserves.obsdb") as db:
    with db.transaction():
        db.set_forecast("PROP_001", model="BASE", phase=Phase.OIL, segments=[
            ForecastSegment(start=date(2026, 6, 1), rate_init=450.0,
                            decline_init=0.65, b_factor=1.1, decline_min=0.06),
        ])

Batch-update a price deck

from datetime import date
from upstream_edge.obsidian_db import Database, PriceModelSegment

with Database.open("reserves.obsdb") as db:
    with db.transaction():
        db.set_price_model("STRIP_2026", [
            PriceModelSegment(date(2026, 1, 1), oil=72.50, gas=3.40, ngl=24.10),
            PriceModelSegment(date(2027, 1, 1), oil=70.00, gas=3.20, ngl=23.00),
        ])
Who it's for

Built for engineers and data teams

Reservoir and production engineers, data analysts, and developers who need programmatic access to reserve and production data—teams integrating into broader pipelines, and anyone using AI coding assistants to automate data operations with their Obsidian files.

Don't have Obsidian yet?

See the product →