# frogml

> **Component**: frogml | **Owner**: Registry-Yoni | **Location**: N/A (client SDK) | **Lifecycle**: production

## Purpose

The `frogml` library is the core Python SDK for the JFrog ML platform. It provides objects and communication tools to define, build, deploy, and manage ML models, feature stores, automations, and versioned artifacts. It also includes an Artifactory-backed storage layer (`frogml.storage`) for uploading and downloading versioned models and datasets. Consumed by `frogml-cli`, `frogml-inference`, `frogml-runtime`, and `build-executor`.

## Key Capabilities

- **FrogMLClient** -- Central facade for all platform operations: builds, models, deployments, feature store, batch jobs, automations, analytics, file/data versioning, and auth.
- **BaseModel (FrogMlModel)** -- Abstract base class for user-defined ML models requiring `build()` and `predict(df)`.
- **Framework-specific model versions** -- CatBoost, HuggingFace, ONNX, PyTorch, scikit-learn, and generic file-based templates.
- **Input/output adapters** -- 10 input adapters (DataFrame, JSON, Numpy, Image, File, String, Proto, TfTensor, Multi) and 7 output adapters for inference serving.
- **Feature store** -- Batch and streaming feature set definitions, 13+ data sources, offline (`OfflineClientV2`) and online (`OnlineClient`) retrieval.
- **Automations** -- Scheduled/metric-based triggers, build-deploy and batch execution actions, autoscaling, notifications.
- **Artifact logging** -- `log_file`, `load_file`, `log_data`, `load_data`, `log_model`, `load_model` for versioned artifact management.
- **FrogMLStorage** -- Artifactory-backed upload/download of model and dataset versions with checksum verification.

## Architectural Decisions

1. **Dependency injection on import.** The top-level `frogml/__init__.py` calls `wire_dependencies()` on import, initializing the DI container via `dependency-injector`. This means any `import frogml` triggers full DI wiring.
2. **Star import for framework modules.** The top-level package does `from frogml.sdk.model_version import *` to surface framework-specific model version classes at the package root.
3. **Protobuf code is generated, never hand-edited.** The `frogml/_proto/` directory is regenerated via `./scripts/gen-proto.sh` (or `poetry run poe generate`).
4. **cloudpickle for model serialization.** Models are serialized with `cloudpickle==2.2.1` (pinned exact) for broad compatibility with user-defined classes and closures.
5. **`frogml.storage` is semi-independent.** It uses Pydantic models and its own auth layer (`AuthConfig`), and can conceptually operate without the full DI context, though the import side-effect currently makes this awkward.

## Traps and Known Issues

1. **Import side effects.** `import frogml` triggers DI wiring and `frogml/core/exceptions/__init__.py` overrides `sys.excepthook` globally. This slows startup and can interfere with other exception handlers, even when only `frogml.storage` is needed.
2. **No `__all__` on top-level package.** The public API boundary is unclear -- roughly 15 explicit exports plus everything from the `model_version` star import.
3. **Monolithic `FrogMLClient`** (863 lines, 30+ methods). Covers builds, models, deployments, feature store, analytics, batch jobs, and more in a single class.
4. **`retrying` library is unmaintained.** Pinned at 1.4.2. The maintained successor `tenacity` is already in dev dependencies but not used in production code.
5. **`orjson` not installable via extras.** Declared `optional = true` in `pyproject.toml` but not included in any extras group. Used in `frogml.feature_store.online.client` for a 6x JSON parsing speedup.
6. **Exact version pins are fragile.** `cloudpickle==2.2.1`, `retrying==1.4.2`, `chevron==0.14.0`, `dacite==1.9.2` can cause dependency conflicts downstream.
7. **`ClientResources` not in `__all__`.** Importable from `frogml.core.automations` but not listed in `__all__`, making its public status ambiguous.

## Development

```bash
# Install
cd sdk/python/frogml && poetry install          # base
cd sdk/python/frogml && poetry install --all-extras  # with all extras

# Protobuf generation
cd sdk/python/frogml && ./scripts/gen-proto.sh

# Format / lint / test
cd sdk/python/frogml && make format        # black
cd sdk/python/frogml && make lint          # black --check + flake8 + bandit
cd sdk/python/frogml && make unit-test     # unit tests (excludes integration)
cd sdk/python/frogml && make test          # all tests with coverage
```

## Consumers

- **frogml-cli** (`sdk/python/frogml-cli`) -- `frogml>=2,<3`
- **frogml-inference** (`sdk/python/frogml-inference`) -- `frogml>=1.2.7,<2` (optional, batch extra)
- **frogml-runtime** (`sdk/python/frogml-runtime`) -- `frogml>=2,<3`
- **build-executor** (`docker/build_executor`) -- `frogml>=1.2.42,<2`
