Metadata-Version: 2.4
Name: nexusflow-sdk
Version: 1.1.0
Summary: Python SDK for NexusFlow model editing and simulation workflows
Author: NexusFlow Team
License-Expression: LicenseRef-Proprietary
Keywords: nexusflow,pipeline-simulation,oil-gas,sdk,digital-twin
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.31.0
Requires-Dist: websocket-client>=1.8.0
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: twine>=5.1.1; extra == "dev"

# nexusflow-sdk

nexusflow-sdk is a Python SDK for NexusFlow model editing, simulation execution, streaming result retrieval, and runtime command control.

## Features

- Token-based authentication against the NexusFlow backend
- Create models for supported workspace types and open existing models
- Add, remove, connect, and configure components in the model graph
- Create and edit two-port linear components represented as component edges
- Create and manage multiple drawing sheets in one model
- Save model snapshots and start simulation jobs
- Poll or stream logs, plots, tables, inspect data, and container messages
- Send runtime commands to components during online or transient execution

## Requirements

- Python 3.10 or later
- A reachable NexusFlow service endpoint
- A NexusFlow account that can obtain access tokens

## Install

Install from a built wheel or from PyPI after publication:

```bash
pip install nexusflow-sdk
```

For local development in this repository:

```bash
pip install -e .
```

## Quick Start

```python
from nexusflow_sdk import NexusFlowClient

client = NexusFlowClient(
    base_url="http://localhost:8000",
    username="admin",
    password="your-password",
)

model = client.create_model(
    name="sdk-demo-model",
    workspace_type="lps_online",
    description="Created by nexusflow-sdk",
)

source = model.add_component("Source", position=(0, 0))
pipe = model.add_component("Pipe", position=(240, 0), mode="node")
load = model.add_component("Load", position=(480, 0))

model.connect(source, "0", pipe, "0")
model.connect(pipe, "1", load, "0")

model.save()
job = model.run(timeout=120, image="nexusflow")

for message in job.stream_results(timeout=2):
    print(message.get("type"), message.get("key"))
```

Parsed log results expose `LogMessage.format` as `"text"` or `"html"`;
missing and unknown values safely normalize to `"text"`. Table results retain
`html` columns through update and append merging. The SDK exposes
`LogFormat`, `TableColumnType`, and `TableColumnData` for type annotations, but
does not render or execute HTML.

## Multiple Sheets

Every new model contains `sheet_0`. Sheet IDs are allocated as `sheet_1`,
`sheet_2`, and so on for the lifetime of the model object.

```python
process = model.default_sheet
control = model.add_sheet("Control")

source = process.add_component("Source", position=(0, 0))
controller = control.add_component("Controller", position=(0, 0))

# Physical edges stay inside one sheet. Matching trimmed, case-sensitive pin
# labels create a logical connection across sheets.
source.set_pin_label("0", "pressure_signal")
controller.set_pin_label("0", "pressure_signal")

copied = model.copy_sheet(control)
print(copied.id)  # sheet_2
```

Legacy snapshots with top-level `nodes` and `edges` are loaded as `sheet_0`.
New saves always use snapshot schema version 2 with a top-level `sheets` array.

## Linear Components

A component definition with exactly two physical ports can use `mode="edge"`.
If its definition sets `linearization.defaultMode` to `edge`, the SDK uses the
linear form by default; pass `mode="node"` to override it.

```python
source = model.add_component("Source", position=(0, 0))
sink = model.add_component("Sink", position=(480, 0))
pipe = model.add_component("Pipe", position=(240, 40), mode="edge")

# portsDefinition[0] is the source end and portsDefinition[1] is the target end.
pipe.attach("source", source, "0")
pipe.attach("target", sink, "0")

# Either end may be detached at an explicit free canvas point.
pipe.detach("source", point=(120, 40))

# Conversion keeps the component id, label, parameters, and pin labels.
node_pipe = pipe.delinearize()
linear_pipe = node_pipe.linearize()
```

Ordinary `model.connect(...)` wires cannot connect to a `LinearComponent`.
Attach its source or target endpoint directly to a node port as shown above.
Linear components remain available through `model.components`; annotation
edges are kept separately in `model.annotations` and are excluded from physical
connections and simulation topology.

## Public API

The package currently exports these main entry points:

- `NexusFlowClient`
- `Model`
- `Component`
- `LinearComponent`
- `Connection`
- `AnnotationEdge`
- `Sheet`
- `Job`
- `MetaService`
- `ResultStream`
- `LogMessage`
- `LogFormat`
- `PlotMessage`
- `TableMessage`
- `TableColumnData`
- `TableColumnType`
- `InspectMessage`
- `ContainerMessage`
- `NexusFlowError`
- `AuthError`
- `APIError`
- `NotFoundError`
- `ValidationError`
- `ValidationIssue`
- `ValidationResult`

## Examples

- `examples/quickstart.py`: create, save, run, and fetch results
- `examples/transient_streaming.py`: stream transient online results and send commands during execution
- `examples/run_existing_model.py`: open an existing model by ID and run it

## Release Validation

Build and metadata check:

```bash
python -m build
python -m twine check dist/*
```

Minimal install smoke test with the built wheel:

```bash
python -m venv .smoke-venv
.smoke-venv\Scripts\python -m pip install dist\nexusflow_sdk-0.6.0-py3-none-any.whl
.smoke-venv\Scripts\python -c "from nexusflow_sdk import NexusFlowClient, Model, Job, ResultStream; print('smoke ok')"
```

## Release Workflow

If you want to publish a new version yourself, the repository now includes a reusable PowerShell script:

```powershell
.\scripts\release.ps1 -Repository pypi -Token "pypi-..."
```

Recommended process:

1. Update `version` in `pyproject.toml`.
2. Run the release script from the `nexusflow-sdk` directory.
3. Wait for PyPI index propagation if the published install smoke test fails on the first try.

The script performs these steps automatically:

- clean `dist/`
- `python -m build`
- `python -m twine check dist/*`
- `python -m unittest tests.test_public_api`
- install the built wheel into a temporary virtual environment for a local smoke test
- upload to PyPI or TestPyPI
- create a fresh temporary virtual environment and install the published package for a post-publish smoke test

Examples:

```powershell
# Full publish to PyPI
.\scripts\release.ps1 -Repository pypi -Token "pypi-..."

# Full publish to TestPyPI
.\scripts\release.ps1 -Repository testpypi -Token "pypi-..."

# Local validation only, without upload
.\scripts\release.ps1 -SkipUpload -SkipSmokeTest
```

You can also avoid passing tokens on the command line by using environment variables:

```powershell
$env:PYPI_TOKEN = "pypi-..."
.\scripts\release.ps1 -Repository pypi
```

## License

This package is currently distributed as proprietary software.
