Terminal explorer for OData CSDL metadata
Project description
CSDL Explorer
A terminal explorer for OData CSDL metadata. Parse any $metadata XML and discover entities, properties, relationships, and field attributes — then query live OData services directly from the terminal.
Features:
- Interactive Rich REPL with colored tables and visual trees
- Full Textual TUI with tree navigation, tabbed views, and split panes
- Live OData queries with visual query builder (filter, select, expand, orderby)
- SAP SuccessFactors auth support (Bearer, Basic, OAuth2 SAML)
- Picklist exploration with impact analysis
- Headless mode for scripting and AI assistants
- Search across entity names, property names, labels, and picklist values
- Entity comparison, custom field discovery, navigation graphs
- Switchable color themes
The Problem
OData services expose their schema through $metadata but those XML documents can be enormous (10MB+, 700+ entities). This tool parses the CSDL and gives you fast, searchable access to every entity, property, navigation relationship, and annotation.
Particularly useful with SAP SuccessFactors, where documentation says "Worker Category" but the actual field is customString17.
Installation
pip install csdl-explore
For the full Textual TUI (tree navigation, split panes, query builder):
pip install csdl-explore[tui]
Or from source:
git clone https://github.com/guinetik/csdl-explore
cd csdl-explore
pip install -e . # Basic install
pip install -e ".[tui]" # With Textual TUI
Quick Start
# Point at any OData $metadata XML file
csdl-explore metadata.xml
# Search for fields
csdl-explore metadata.xml search contract
# Show entity details
csdl-explore metadata.xml entity EmpJob
# Launch full TUI with tree navigation
csdl-explore metadata.xml --tui
# Query a live OData service
csdl-explore metadata.xml query EmpJob --select "userId,company" --top 5
Usage
# Start interactive explorer (default)
csdl-explore metadata.xml
# Or with --file flag
csdl-explore --file metadata.xml entity EmpJob
# With connection settings
csdl-explore metadata.xml --base-url https://api.example.com --auth-type bearer --bearer-token TOKEN
Interactive Mode
$ csdl-explore metadata.xml
╭─────────────────────────────────────────╮
│ CSDL Explorer │
│ Loaded 735 entities │
╰─────────────────────────────────────────╯
csdl> search contract
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Search Results (4) ┃
┣━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━┫
┃ Type ┃ Entity ┃ Match ┃ Details ┃
┣━━━━━━━━╋━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━━━━━┫
┃ PROP ┃ EmpJob ┃ .contractType ┃ String ┃
┃ NAV ┃ EmpJob ┃ .contractTypeNav┃ ┃
┗━━━━━━━━┻━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━┛
csdl> tree EmpJob
EmpJob
├── Keys
│ ├── seqNumber Edm.Int64
│ ├── startDate Edm.DateTime
│ └── userId Edm.String
├── Properties (45)
│ ├── businessUnit Edm.String
│ ├── company Edm.String
│ └── ... and 42 more
├── Lookups (12)
│ ├── businessUnit -> FOBusinessUnit
│ └── ... and 9 more
├── Custom Fields (24)
│ ├── customString7 Edm.String
│ └── ... and 23 more
└── Navigation (8)
├── employmentNav -> EmpEmployment
└── ... and 7 more
Commands
Metadata Exploration
| Command | Aliases | Description |
|---|---|---|
entities |
List all entity types (multi-column on wide terminals) | |
entity <name> |
e |
Show all properties of an entity |
tree <name> |
t |
Show entity as visual tree with relationships |
model [entities] |
Show data model overview | |
search <term> |
s |
Search entities and properties |
custom <entity> |
c |
Show custom fields (customStringXX) |
nav <entity> |
Show navigation properties | |
diff <e1> <e2> |
Compare two entities | |
path <entity> |
paths |
Suggest JSON paths |
emp |
List Emp* entities (SAP SuccessFactors) | |
per |
List Per* entities (SAP SuccessFactors) |
Picklists
| Command | Aliases | Description |
|---|---|---|
picklists |
List all picklists used across entities (JSON) | |
picklist <name> |
pk |
Fetch picklist values from live API (JSON) |
batch-picklists <entity> |
Fetch all picklist values for an entity's fields |
OData Queries
| Command | Description |
|---|---|
query <entity> |
Execute an OData query against a live service |
Query flags:
| Flag | Description |
|---|---|
--select "<props>" |
Comma-separated properties to return |
--filter "<expr>" |
OData $filter expression |
--orderby "<prop>" |
Property to sort by |
--orderby-dir "asc|desc" |
Sort direction (default: asc) |
--top <n> |
Result limit (default: 20) |
--expand "<navs>" |
Navigation properties to expand |
--asof-date "<date>" |
Point-in-time query |
--from-date "<date>" |
Date range start |
--to-date "<date>" |
Date range end |
Example:
csdl-explore metadata.xml query EmpJob \
--select "userId,company,businessUnit" \
--filter "company eq 'ACME'" \
--top 10
Options
| Option | Description |
|---|---|
--file <file> |
Path to metadata XML file |
--tui |
Launch full Textual TUI |
--base-url <url> |
OData service base URL |
--auth-type <type> |
Auth type: none, bearer, basic, oauth2 |
--bearer-token <token> |
Bearer token for API access |
--username <user> |
Username for basic auth |
--password <pass> |
Password for basic auth |
--format <fmt> |
Output format: table (default), json, json-compact, csv |
--wide |
Show full column widths (no truncation) |
--filter <pattern> |
Filter properties by name glob pattern (e.g. "custom*") |
--json-only |
JSON output only, no banner (for agents/scripts) |
Connection settings can also be loaded from a .env file placed alongside the metadata XML, or from environment variables (SAP_BASE_URL, SAP_AUTH_TYPE, SAP_BEARER_TOKEN, etc.).
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
General error |
2 |
Invalid input (bad args, missing params) |
3 |
Network error (auth failure, HTTP error) |
4 |
Not found (entity/picklist doesn't exist) |
Full Textual TUI
For the best experience on large monitors, use the Textual TUI:
pip install csdl-explore[tui]
csdl-explore metadata.xml --tui
Features:
- Tree navigation - Browse entities by category (Emp*, Per*, alphabetical)
- Split pane view - Entity tree on left, tabbed details on right
- Global search - Search across all metadata from the sidebar
- Fuzzy filter - Type in any table to filter rows (fzf-style)
- Entity tabs - Details, Properties table, and Query sub-tabs per entity
- Picklist tabs - Overview, entity usage, impact analysis, and live value fetching
- Query builder - Visual form for OData queries with auth configuration
- Results viewer - Syntax-highlighted JSON/XML results with file export
- Navigation graph - Visualize entity relationships
- Switchable themes - Vercel dark, Classic, and more
Keyboard shortcuts:
| Key | Action |
|---|---|
/ |
Focus search |
Escape |
Clear search |
t |
Toggle tree sidebar |
Ctrl+T |
Cycle theme |
Ctrl+W |
Close current tab |
q |
Quit |
? |
Show help |
Headless Mode (for AI/Scripts)
All commands work without interactive mode, making it easy for AI assistants and scripts to discover fields:
csdl-explore metadata.xml search benefit
csdl-explore metadata.xml entity EmpJob
csdl-explore metadata.xml diff EmpCompensation EmpPayCompRecurring
csdl-explore metadata.xml tree EmpJob
csdl-explore metadata.xml picklists
csdl-explore metadata.xml query EmpJob --select "userId" --top 5
Python API
from csdl_explore import CSDLExplorer
from pathlib import Path
# Load from file
explorer = CSDLExplorer.from_file(Path("metadata.xml"))
# Search
results = explorer.search("worker")
for r in results:
print(f"{r.entity}.{r.property}: {r.prop_type}")
# Get entity details
entity = explorer.get_entity("EmpJob")
for prop in entity.properties.values():
print(f"{prop.name}: {prop.type} (label={prop.label})")
# Get custom fields
for prop in explorer.get_custom_fields("EmpJob"):
print(f"{prop.name}: {prop.label} picklist={prop.picklist}")
# Compare entities
comp = explorer.compare_entities("EmpCompensation", "EmpPayCompRecurring")
print(f"Only in first: {comp.only_in_entity1[:5]}")
# Picklist usage across all entities
usage = explorer.get_picklist_usage()
for picklist, entities in usage.items():
print(f"{picklist}: used by {entities}")
Supported OData Services
Any OData service that exposes CSDL $metadata should work. Tested with:
- SAP SuccessFactors (full annotation support: labels, picklists, CRUD flags)
- SAP S/4HANA OData
- Standard OData v2/v3 services
The parser auto-detects annotation namespaces, so vendor-specific attributes (like sap:label, sap:filterable) are extracted automatically.
Project Structure
csdl-explore/
├── pyproject.toml
├── README.md
└── src/
└── csdl_explore/
├── __init__.py # Package exports
├── cli.py # CLI entry point & command dispatch
├── parser.py # CSDL metadata parser
├── explorer.py # High-level exploration API
├── formatters.py # Pure data transforms (no UI imports)
├── themes.py # Textual themes + Rich color palettes
├── repl.py # Rich-based interactive REPL
├── sap_client.py # Async OData HTTP client & auth
├── app.py # Textual TUI application
└── widgets/
├── entity_pane.py # Entity tab container
├── details_tab.py # Entity details sub-tab
├── properties_tab.py # Filterable properties table
├── query_tab.py # OData query sub-tab
├── query_builder.py # Visual query form
├── connection_panel.py # Auth configuration panel
├── results_viewer.py # Query results + export
├── picklist_pane.py # Picklist tab container
├── entity_tree.py # Sidebar tree widget
├── global_search.py # Unified metadata search
├── filter_bar.py # fzf-style filter bar
├── filterable_table.py # Reusable filterable DataTable
├── auth_modal.py # Credential input modal
├── record_view_modal.py# Row detail viewer
├── nav_graph.py # Navigation graph visualization
└── welcome_tab.py # Welcome screen
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file csdl_explore-0.1.0.tar.gz.
File metadata
- Download URL: csdl_explore-0.1.0.tar.gz
- Upload date:
- Size: 117.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c9f8308e3e5cbb169f8222e1977a95aa3e67daf9da56d1f8defd0508d2bf1ebe
|
|
| MD5 |
367931aa0e79a0e0b588278d442c09a7
|
|
| BLAKE2b-256 |
c100b42a22a61f4616a506ac7618025e1a1769394d358104fb4f15c232b0bb64
|
File details
Details for the file csdl_explore-0.1.0-py3-none-any.whl.
File metadata
- Download URL: csdl_explore-0.1.0-py3-none-any.whl
- Upload date:
- Size: 81.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c6cfcd5178a1531bf5cd42494ccab455acaa6d16bf01a3266b0ae794011a6cf
|
|
| MD5 |
4f52f93ef6fa020a1ccbb68e4f569223
|
|
| BLAKE2b-256 |
d1e0db0dc3faff67a70cb5d61fc382e015190e0b2e9cc873a2067e1ba8966140
|