Initializing help system before first use

# Getting Started with MoselPy

Topics covered in this chapter:

- Introduction
  - When to use MoselPy
  - Prerequisites
- Installation
- Your first model
  - The three-step workflow
  - Model parameters
- Stream redirection
  - Silencing output
  - Capturing output
  - Global vs per-model redirection
- Running a model from a string

## Introduction

MoselPy combines Python's ecosystem with Mosel's optimization capabilities, leveraging Mosel's performance, portability, and security characteristics while enabling Python-based data preparation, result analysis, and workflow integration.

### When to use MoselPy

Use MoselPy when you:

- have existing Mosel models and want to integrate them into Python applications
- prefer Mosel's algebraic modeling syntax, which closely mimics mathematical notation, for clarity and maintainability
- need pre-compiled models for performance optimization or intellectual property protection
- want to leverage Mosel's efficient integration with Xpress Solver while using Python for data preparation
- require seamless Pandas Series and DataFrames integration for input/output in data science workflows
- need iterative solving with Python-based logic between solves, combining Mosel's solving power with Python's flexibility
- are building data-driven optimization workflows that benefit from Mosel's efficiency and dynamic object support.

### Prerequisites

MoselPy requires:

- Python 3.10 to 3.14 (standard builds). Free-threaded Python (3.13t, 3.14t) is not currently supported.
- FICO Xpress installation (a solver license is only required to run optimization models; the Mosel runtime itself is license-free). The Xpress Solver libraries are only required when the Mosel model uses mmxprs or mmxnlp.
- Optional: Pandas (for Series and DataFrame integration)

## Installation

Install MoselPy via PyPI:

    pip install moselpy

Verify installation:

    import moselpy as mp
    print(f"MoselPy version: {mp.version}")
    print(f"Mosel version: {mp.mosel_version}")
    print(f"Xpress version: {mp.xpress_version}")

The package includes the Python bindings; the Mosel runtime and Xpress Optimizer libraries are provided by your Xpress installation (see the Xpress Installation Guide).

Runtime dependencies. MoselPy requires xprm_rt (Mosel runtime) and xprm_mc (Mosel compiler) from your Xpress installation. If a Mosel model loads Mosel libraries (BIM or DSO files) these also need to be present with their respective dependencies as indicated in the secrtdep.

### Environment variables

MoselPy uses the standard Xpress environment variables, which are automatically set up by the Xpress installers. The following are relevant when running MoselPy:

XPRESSDIR
  Path to the Xpress installation directory. Required if Xpress is not installed in the default location.
XPAUTH_PATH
  Path to the solver license file ( xpauth.xpr). Searched in standard locations if not specified. Only needed for solver-based models.

Note on Jupyter notebooks. Jupyter spawns a separate kernel process that may not inherit the full system environment. This causes solver modules such as mmxprs to be not found even when XPRESSDIR is correctly set. If you encounter this, add the following line at the top of your notebook setup cell, before importing moselpy:

    import os
    os.environ.setdefault('XPRESSDIR', '/path/to/xpressmp')

## Your first model

We start with a simple Mosel model that prints a message. Create a file hello.mos:

    model HelloWorld
      writeln("Hello from Mosel!")
    end-model

Execute it from Python:

    import moselpy as mp

    # One-step: compile, load, and run
    mp.execute_model("hello.mos")

Output: Hello from Mosel!

### The three-step workflow

For more control, use the three-step workflow: compile, load, run. The key functions are compile_model() to generate a compiled BIM file, load_model() to load it into memory, and run() to execute the model:

    import moselpy as mp

    # 1. Compile: .mos -> .bim
    mp.compile_model("hello.mos", "hello.bim")

    # 2. Load compiled model
    model = mp.load_model("hello.bim")

    # 3. Run
    model.run()

    print(f"Model '{model.name}' completed with status: {model.exec_status}")

Output:

    Hello from Mosel!
    Model 'HelloWorld' completed with status: ExecStatus.OK

The compiled .bim file is platform-independent and can be reused without recompilation, providing faster execution and intellectual property protection by hiding the model source code.

### Model parameters

Pass parameters to Mosel models at execution time using the exec_params argument in the run() method. Parameters defined in the Mosel parameters block can be overridden from Python. Create greeting.mos:

    model Greeting
      parameters
        NAME = "World"
      end-parameters

      writeln("Hello, ", NAME, "!")
    end-model

Run with different parameters:

    import moselpy as mp

    model = mp.load_model("greeting.bim")

    # Method 1: Dict (recommended)
    model.run(exec_params={"NAME": "Python"})

    # Method 2: String
    model.run(exec_params="NAME=MoselPy")

Output:

    Hello, Python!
    Hello, MoselPy!

The dict format handles special characters automatically and is the preferred option.

## Stream redirection

Control where Mosel output goes using set_default_stream(). See Chapter Model Class for the full API reference of Model.set_default_stream().

### Silencing output

Redirect output to the built-in null: driver to suppress it:

    import moselpy as mp

    model = mp.load_model("model.bim")
    model.set_default_stream(mp.StreamType.OUTPUT, "null:")
    model.set_default_stream(mp.StreamType.ERROR, "null:")
    model.run()

### Capturing output

Redirect output to a Python buffer using the moselpy: driver. Register a StringIO object in the model's symbol registry, then route the stream through it. The buffer must be set before calling run():

    import moselpy as mp
    from io import StringIO
    model = mp.load_model("model.bim")

    buf = StringIO()
    model.symbols["out"] = buf
    model.set_default_stream(mp.StreamType.OUTPUT, "moselpy:out")
    model.run()
    del model.symbols["out"]

    print(f"Captured: {buf.getvalue()}")

Output: Captured: Hello from Mosel!

### Global vs per-model redirection

Global stream settings affect all models that have not overridden their own streams. Per-model settings take precedence. Note that global settings via config.set_default_stream() must be set before the first load_model() call in the process. Once a model is loaded, only per-model set_default_stream() calls are possible:

    import moselpy as mp

    # Global: must be called BEFORE the first load_model()
    mp.config.set_default_stream(mp.StreamType.OUTPUT, "null:")

    # Per-model: can be called at any time, overrides global for this model only
    model = mp.load_model("model.bim")
    model.set_default_stream(mp.StreamType.OUTPUT, "output.txt")

Pass None as the file name to restore the default stream (sys.stdout, sys.stderr, or sys.stdin).

## Running a model from a string

For quick prototyping or generated models, you can define Mosel source directly as a Python string. Since compile_model() and execute_model() expect a file path, write the source to a temporary file, compile, run, then clean up:

    import moselpy as mp
    import tempfile, os

    src = """model SumToN
      declarations
        n: integer
        result: real
      end-declarations

      initializations from "moselpy:"
        n
      end-initializations

      result := n * (n + 1) / 2.0

      initializations to "moselpy:"
        result
      end-initializations
    end-model"""

    with tempfile.NamedTemporaryFile(mode="w", suffix=".mos", delete=False) as f:
        f.write(src)
        tmp_mos = f.name
    tmp_bim = tmp_mos[:-4] + ".bim"

    try:
        mp.compile_model(tmp_mos, tmp_bim)
        model = mp.load_model(tmp_bim)
        output = model.run(input_data={"n": 100})
        print(f"Sum 1..100 = {output['result']:.0f}")
    finally:
        for p in [tmp_mos, tmp_bim]:
            if os.path.exists(p):
                os.unlink(p)

Output:

    Sum 1..100 = 5050

This pattern is useful for testing small models interactively or for dynamically generating Mosel source from Python.

Parent Topic User Guide

© 2001-2026 Fair Isaac Corporation. All rights reserved. This documentation is the property of Fair Isaac Corporation (“FICO”). Receipt or possession of this documentation does not convey rights to disclose, reproduce, make derivative works, use, or allow others to use it except solely for internal evaluation purposes to determine whether to purchase a license to the software described in this documentation, or as otherwise set forth in a written software license agreement between you and FICO (or a FICO affiliate). Use of this documentation and the software described in it must conform strictly to the foregoing permitted uses, and no other use is permitted.