Metadata-Version: 2.4
Name: mgi_pathology
Version: 0.0.1
Summary: Python SDK for compiling protocols for the MGI Pathology workstation.
Author-email: Yang Meng <yangmeng1@mgi-tech.com>
Maintainer-email: Yang Meng <yangmeng1@mgi-tech.com>
License: Apache-2.0
Keywords: pipette,lab,automation,liquid handler,pathology,protocols,workstation,mgi
Classifier: Development Status :: 4 - Beta
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering
Classifier: Intended Audience :: Science/Research
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.7.1
Dynamic: license-file

# mgi_pathology

Python SDK for compiling protocols for the **MGI Pathology** moving-liquid workstation.

A protocol script defines a `metadata` dict and a `run(ctx)` function; the SDK
executes the function against a fresh `Context`, captures every command and
form-layer step, and emits a validated `ProtocolDefinition` JSON that the
workstation's runtime backend consumes.

## Install

```bash
pip install mgi_pathology
```

## Quick start

```python
metadata = {
    "protocolName": "minimal demo",
    "author": "you",
    "description": "",
}


def run(ctx):
    ctx.init(ingredients={"0": ("Sample", "#FF6B6B")})
    pipette = ctx.load_pipette("p1000_flex8")
    gripper = ctx.load_gripper("gripper")
    tiprack = gripper.load_labware_to(
        "mdk_96_filtertiprack_1000ul",
        "1-1",
        stackId="s-1",
    )
    pipette.pick_up_tip(tiprack["A1"])
    pipette.drop_tip()
```

Compile to JSON:

```bash
mgi_pathology_py demo.py -o demo.json
```

## Deck

The MGI Pathology deck has 7 lanes plus a fixed trash slot:

| Lane | Positions          |
|------|--------------------|
| 1    | 1-1, 1-2, 1-3, 1-4, 1-5 |
| 2    | 2-1, 2-2, 2-3, 2-4, 2-5 |
| 3    | 3-1, 3-2, 3-3, 3-4 |
| 4    | 4-1, 4-2, 4-3, 4-4 |
| 5    | 5-1, 5-2, 5-3, 5-4 |
| 6    | 6-1, 6-2, 6-3, 6-4 |
| 7    | 7-1, 7-2, 7-3, 7-4 |
| trash | trash             |

The trash slot is fixed and does not need to be configured.

## Hardware

- One pipette: `p1000_flex8` (8-channel, 1000 µL).
- One gripper: `gripper`.
- Optional temperature module: `pathologyTemperatureModuleV1`.
- Three side stacks reachable by the gripper: `s-1`, `s-2`, `s-3`.

## Documentation

See getting_started.md for a longer walkthrough.

---

# Getting started

## Protocol structure

Every protocol script is a regular Python file that defines two top-level objects:

- `metadata` — a dict with `protocolName`, `author`, `description`. Optional keys are
  passed through to the emitted JSON unchanged.
- `run(ctx)` — a function that receives a `mgi_pathology.Context` and uses it to
  describe the protocol.

The compiler executes `run(ctx)` against a fresh `Context`, captures every command
emitted, and produces a `ProtocolDefinition` JSON.

## Initialization

```python
ctx.init(ingredients={"0": ("Sample", "#FF6B6B"), "1": ("Buffer", "#4ECDC4")})
```

Unlike the prepall workstation, the pathology deck shape is fixed (7 lanes, 29 slots,
fixed trash bin), so `init` only takes optional `ingredients` — a registry of named
liquids, keyed by id, with `(displayName, displayColor)` values.

`init` must be called once before any other `Context` method.

## Loading hardware

```python
pipette = ctx.load_pipette("p1000_flex8")
gripper = ctx.load_gripper("gripper")
temp    = ctx.load_module("pathologyTemperatureModuleV1", "5-1")
adapter = ctx.load_labware("mgi_pathology_plate_carrier_adapter", "3-2")
```

Slots are referenced by string identifiers like `"3-2"` (lane 3, position 2).
See `LocationName` in `mgi_pathology.protocol_api.deck` for the full list.

## Feeding labware off side stacks

The gripper can pull labware off three side stacks `s-1`, `s-2`, `s-3` and drop it
on the deck:

```python
tiprack = gripper.load_labware_to(
    "mdk_96_filtertiprack_1000ul",
    "1-1",            # destination slot
    stackId="s-1",
    code="T1",        # optional operator-facing label
)
```

Each call materialises a fresh `Labware` and registers it on the context, so subsequent
pipette operations can target it by reference. The destination can be a slot string
(`"1-1"`), an existing `Labware` (stack on top), or a `Module`.

## Moving labware between deck locations

```python
gripper.move_labware(plate, "4-2")           # to a slot
gripper.move_labware(plate, temp_module)     # onto a module
gripper.move_labware(plate, base_adapter)    # stack on another labware
```

## Liquid handling

Liquid handling lives on `Pipette` and follows the Opentrons-style API:

```python
pipette.pick_up_tip(tiprack["A1"])
pipette.aspirate(100, source["A1"])
pipette.dispense(100, dest["A1"])
pipette.drop_tip()
```

For higher-level workflows, use `pipette.transfer(...)`, `pipette.distribute(...)`,
`pipette.consolidate(...)`, and `pipette.mix(...)`.

## Compiling

```bash
mgi_pathology_py path/to/protocol.py -o output.json
```

The CLI is also available as `python -m mgi_pathology path/to/protocol.py`.

## Trash

`pipette.drop_tip()` (no argument) drops the tip into the fixed trash bin. The
backing `loadLabware` for the trash slot is emitted lazily the first time
`drop_tip()` is called.
