Metadata-Version: 2.4
Name: primer3plus-core
Version: 0.1.0
Summary: Headless Primer3Plus logic — Boulder-IO parsing, subprocess runners, no Flask dependency
Author: Andreas Untergasser
License-Expression: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/primer3-org/primer3plus-core
Project-URL: Repository, https://github.com/primer3-org/primer3plus-core
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# primer3plus-core

Headless Python core for [Primer3Plus](https://github.com/primer3-org/primer3plus) —
Boulder-IO parsing, subprocess runners, and settings management. No Flask dependency.

This package provides the non-Web logic extracted from the Primer3Plus server.
It can be used as a standalone library to run Primer3 from Python without a browser.

## Requirements

- Python >= 3.9
- [`primer3_core`](https://github.com/primer3-org/primer3) must be installed and available on `PATH`

## Install

```bash
pip install primer3plus-core
```

Or from source:

```bash
git clone https://github.com/primer3-org/primer3plus-core.git
cd primer3plus-core
pip install .
```

## Quick start

### Prepare input and run Primer3

```python
from primer3plus_core.boulder import prepare_input
from primer3plus_core.runner import run_primer3
from primer3plus_core.files import new_uuid, work_dir

# Prepare Boulder-IO input (normalises newlines, injects mispriming libs)
raw = open("my_input.txt").read()
prepared = prepare_input(raw)

# Write to a work directory
uuidstr = new_uuid()
sf = work_dir("data", uuidstr)
infile = f"{sf}/p3p_{uuidstr}_input.txt"
with open(infile, "w") as f:
    f.write(prepared)

# Run primer3_core
outfile = f"{sf}/p3p_{uuidstr}_output.txt"
error = run_primer3(infile, outfile,
                    f"{sf}/p3p_{uuidstr}_error.txt",
                    f"{sf}/p3p_{uuidstr}.log")
if error:
    print("Error:", error)
else:
    print(open(outfile).read())
```

### Load default settings

```python
from primer3plus_core.settings import load_default_settings

settings_json = load_default_settings()
print(settings_json[:80])
```

### Parse prefold input (UNAFold)

```python
from primer3plus_core.boulder import parse_prefold_input

dat = parse_prefold_input(open("prefold_input.txt").read())
print("Sequence:", dat["seq"][:40], "...")
print("Temp:", dat["temp"])
```

## API modules

| Module | Purpose |
|--------|---------|
| `primer3plus_core.boulder` | Boulder-IO parsing, normalisation, tag injection, primer counting |
| `primer3plus_core.runner` | `run_primer3()`, `run_unafold()`, `run_amplicon3()` — subprocess with timeout |
| `primer3plus_core.files` | UUID helpers, work-directory creation, path builders |
| `primer3plus_core.settings` | Load settings JSON files shipped with the package |
| `primer3plus_core.logging` | Run-logging helper (IP/UA passed by caller) |
| `primer3plus_core.models` | `RunError` exception, result dataclasses |
| `primer3plus_core.config` | Paths and constants |

## Development

```bash
pip install -e ".[dev]"
python -m pytest tests/ -v
```

## License

GPL-3.0-or-later — same as [Primer3Plus](https://github.com/primer3-org/primer3plus).
