Skip to content

Start building with PyRel

Start by downloading the starter project and installing the Python packages it needs. The project includes a simple model, a query, and CSV data that you’ll work through in this guide.

You can install the required Python packages with uv or pip. If you don’t have a preference, choose uv for fewer setup commands. Your selection applies to commands throughout this guide:

  1. If you haven’t already, download the starter project and save the ZIP file in your Downloads folder.

  2. If you don’t have uv installed, follow the installation instructions.

  3. Open a terminal and run these commands to extract the starter project, enter its folder, and install the required packages:

    If you saved the ZIP file outside Downloads, update its path in the first command:

    Terminal window
    unzip ~/Downloads/supplier-disruption.zip
    cd supplier-disruption
    uv sync
    • Installs PyRel from the relationalai package.
    • Installs pandas to read the starter project’s CSV files.
    • Stores the project’s packages in .venv, separate from other Python projects.

    Run the remaining commands in this guide from the supplier-disruption folder. You’ll configure the Snowflake connection in the next section.

    What if uv can’t find or download a supported Python version?

    uv normally downloads a compatible Python version when you run uv sync. If it does not, install Python 3.13 through uv, then try again:

    Terminal window
    uv python install 3.13
    uv sync

    If Python cannot be downloaded, check your network connection. Your organization may also disable Python downloads through uv. In that case, install Python 3.10 through 3.13 using your organization’s standard method.

    What if the terminal can’t find uv after installation?

    Close and reopen your terminal, then run:

    Terminal window
    uv --version

    If the terminal still cannot find uv, repeat the uv installation instructions for your operating system. Follow any message from the installer about updating your PATH, then open another terminal.

  4. Run these commands to check that PyRel and the rai command were installed:

    Terminal window
    uv run python -c "import relationalai; print('PyRel import OK')"
    uv run rai --version
    • The Python command prints PyRel import OK.
    • The rai command prints the installed CLI version.

    These results verify the installation only. You’ll test the Snowflake connection in the next section.

    What if one of these commands fails?

    Make sure your terminal is in the supplier-disruption folder, run uv sync, and try both commands again.

PyRel reads your connection settings from raiconfig.yaml in your project folder. If your administrator sent you an invitation link with all required settings, the configuration below is ready to save. Otherwise, the builder expands the fields you need to complete. You can always expand Review or edit configuration details to inspect or change settings. Then save the file, set any required credentials, and verify the connection.

  1. Add connection details

    Enter or review the account identifier and warehouse provided by your administrator. These settings tell PyRel which Snowflake account and warehouse to use.

    Identifies your Snowflake account, usually in the form organization-account.

    Enter the name of any Snowflake warehouse where you have the USAGE privilege. An X-Small warehouse is sufficient.

  2. Choose authentication

    Authentication verifies your identity when PyRel connects to Snowflake. Select the method your administrator configured for you.

  3. Enter your Snowflake username

    Enter or review the username PyRel will use to connect to Snowflake. Your administrator must grant this user the RAI_DEVELOPER role.

  4. Optional: Set up model deployment (Public Preview)

    Model deployment makes your model’s outputs available in Snowflake so other tools and applications can use them without running PyRel. Leave Set up model deployment unchecked to run this example without deployment.

  5. Save your configuration

    Copy or download the generated configuration and save it as raiconfig.yaml in your project folder, next to pyproject.toml.

    raiconfig.yaml
    default_connection: sf
    direct_access: true
    connections:
    sf:
    type: snowflake
    authenticator: oauth_authorization_code
    account: ""
    warehouse: ""
    user: ""
    role: RAI_DEVELOPER
    oauth_client_id: <oauth_client_id>
    oauth_redirect_uri: http://localhost:54321/snowflake/oauth-redirect

    Complete these fields to copy or download: Account identifier, Snowflake username, Warehouse, and OAuth client ID.

    If you downloaded the file to your Downloads folder, run the following command from your project folder to move it into place:

    Terminal window
    mv ~/Downloads/raiconfig.yaml .

    Check that raiconfig.yaml is beside pyproject.toml in your project folder. You’ll verify the connection after any required credential setup.

  6. Set your credentials

    No additional credentials are needed for browser sign-in. PyRel will open your browser when you test the connection in the next step.

    Set your Snowflake programmatic access token in the terminal you’ll use to run PyRel. The commands below store it in the SNOWFLAKE_PROGRAMMATIC_ACCESS_TOKEN environment variable, which PyRel reads when connecting to Snowflake.

    Keep this terminal open for the remaining steps. Don’t put the token in raiconfig.yaml or paste it into this page.

    Run this command to enter your token without displaying it:

    Terminal window
    printf 'Snowflake token: '
    IFS= read -r -s SNOWFLAKE_PROGRAMMATIC_ACCESS_TOKEN
    printf '\n'
    export SNOWFLAKE_PROGRAMMATIC_ACCESS_TOKEN

    Then check that the environment variable is set:

    Terminal window
    if [ -n "${SNOWFLAKE_PROGRAMMATIC_ACCESS_TOKEN:-}" ]; then
    printf 'credential set\n'
    else
    printf 'credential missing\n'
    fi

    You should see credential set. If you see credential missing, repeat the token-entry command and check again in the same terminal.

    This only confirms that the variable is set. You’ll test the connection in the next step.

    PyRel uses the private key file you specified in Choose authentication to sign in to Snowflake. If that file is not encrypted, remove private_key_passphrase from raiconfig.yaml and continue to Verify the connection.

    Otherwise, use the command below to store its passphrase in an environment variable. Run it in the terminal you’ll use for PyRel. Your input won’t be displayed:

    Terminal window
    printf 'Private key passphrase: '
    IFS= read -r -s SNOWFLAKE_PRIVATE_KEY_PASSPHRASE
    printf '\n'
    export SNOWFLAKE_PRIVATE_KEY_PASSPHRASE

    Then check that the environment variable is set:

    Terminal window
    if [ -n "${SNOWFLAKE_PRIVATE_KEY_PASSPHRASE:-}" ]; then
    printf 'credential set\n'
    else
    printf 'credential missing\n'
    fi

    You should see credential set. If you see credential missing, repeat the passphrase-entry command and check again in the same terminal.

    This only confirms that the variable is set. You’ll test the connection in the next step.

  7. Verify the connection

    Run the connection check from the supplier-disruption folder, where you saved raiconfig.yaml and pyproject.toml:

    uv
    Terminal window
    uv run rai connect
    pip
    Terminal window
    rai connect
    • PyRel can read raiconfig.yaml, authenticate, and connect to Snowflake.
    • The output shows the account, user, warehouse, and role so you can confirm each value.

    In the next step, you'll use PyRel to query the semantic model in the starter project.

    What if PyRel can’t read my configuration?

    If the error names a setting, correct it in the form and save the updated raiconfig.yaml in your project folder. Then rerun the connection check.

    If PyRel reports that no configuration file was found, make sure raiconfig.yaml is in your project folder beside pyproject.toml, then rerun the connection check. If PyRel loads the wrong configuration, run uv run rai config explain (pip: rai config explain) to see the active configuration and where each value came from.

    What if authentication fails?

    Check the OAuth client ID and redirect URI against the values from your administrator. Rerun the connection check and complete browser sign-in.

    Make sure you set your token in the same terminal where you run the connection check, then try again.

    In raiconfig.yaml, check the path to your private key file. If the key is encrypted, make sure you set its passphrase in the same terminal, then rerun the connection check.

    See Configure Snowflake authentication for method-specific detail.

    What if the connection times out or reports “Failed to connect to DB”?

    Check your network connection and connect to your organization’s VPN if required. If you use PrivateLink, confirm the zone with your administrator. If the connection still fails, ask your administrator to check firewall rules.

    These checks also apply to Snowflake error 250001.

    What if my user lacks the required permissions?

    Run uv run rai whoami (pip: rai whoami) and share the output with your administrator. Ask them to confirm that your user has the RAI_DEVELOPER role, and that this role has warehouse access and the RELATIONALAI.RAI_USER application role.

    After they update the permissions, rerun the connection check.

The starter project models a manufacturer that buys parts from several suppliers. Its completed semantic model connects suppliers to the parts they provide and the products that require those parts. You’ll use the included CSV data to answer a hypothetical question: If Northstar Components can’t deliver, which products depend on parts it supplies?

You’ve installed PyRel and verified that the project can connect to Snowflake. Next, you’ll use PyRel to query the semantic model and find which products depend on parts supplied by Northstar Components.

Use the same terminal where you ran rai connect in Verify the connection, make sure you’re in the supplier-disruption folder, and then run:

Without deployment

uv
Terminal window
uv run python find_affected_products.py
pip
Terminal window
python find_affected_products.py
Output
product part
0 Cold-chain tracker Control board
1 Cold-chain tracker Temperature sensor
2 Factory gateway Control board
3 Smart thermostat Temperature sensor

The rows may appear in a different order.

If you see this output, PyRel successfully connected to Snowflake, loaded the semantic model, ran the query, and returned results. You can pause here, or read on to learn how the starter project's semantic model works.

What if Python can’t find the model module?

If you see ModuleNotFoundError: No module named 'model', run the query command from your project folder. This is the folder containing pyproject.toml and the model folder.

What if authentication fails when I run the query?

Follow the troubleshooting guidance in Verify the connection. Once the connection check succeeds, retry the command.

What if my results don’t match the example output?

If you see different combinations of products and parts, compare your project files with the code in Understand the code, or download a fresh starter project.

With deployment

Your raiconfig.yaml includes deployment settings, so deploy the model, run the query, and clean up the deployment.

  1. Deploy the model

    First, deploy the model from your project folder using the rai models deploy CLI command:

    uv
    Terminal window
    uv run rai models deploy --path model --wait
    pip
    Terminal window
    rai models deploy --path model --wait
    • --path model loads the model from the model folder.
    • PyRel deploys the model to the schema set by deployment.schema in raiconfig.yaml.
    • PyRel creates output objects in Snowflake and fills them with the model's initial results.
    • Snowflake tasks refresh those outputs on configurable schedules to incorporate changes in your source data.
    • --wait keeps the command running until the initial data load finishes.
    What if deployment fails with a schema or permissions error?

    Run uv run rai config explain (pip: rai config explain) to check the names of the deployment and metadata schemas. Ask your administrator to confirm that your role has the required permissions on both schemas.

    What if authentication fails when I deploy the model?

    Follow the troubleshooting guidance in Verify the connection. Once the connection check succeeds, retry the command.

  2. Run the query

    After deployment succeeds, run the query:

    uv
    Terminal window
    uv run python find_affected_products.py
    pip
    Terminal window
    python find_affected_products.py
    Output
    product part
    0 Cold-chain tracker Control board
    1 Cold-chain tracker Temperature sensor
    2 Factory gateway Control board
    3 Smart thermostat Temperature sensor

    The rows may appear in a different order.

    If you see this output, PyRel successfully connected to Snowflake, loaded the semantic model, ran the query, and returned results. You can pause here, or read on to learn how the starter project's semantic model works.

    What if Python can’t find the model module?

    If you see ModuleNotFoundError: No module named 'model', run the query command from your project folder. This is the folder containing pyproject.toml and the model folder.

    What if authentication fails when I run the query?

    Follow the troubleshooting guidance in Verify the connection. Once the connection check succeeds, retry the command.

    What if my results don’t match the example output?

    If you see different combinations of products and parts, compare your project files with the code in Understand the code, or download a fresh starter project.

  3. Clean up the deployment

    When you’re done with the example, remove the deployed model from Snowflake. This deletes the objects RelationalAI created in your deployment and metadata schemas, but keeps both schemas.

    Preview the cleanup:

    uv
    Terminal window
    uv run rai models teardown
    pip
    Terminal window
    rai models teardown

    Review the preview and confirm that it names the deployment and metadata schemas you used for this example.

    Then run the following command to remove the model:

    uv
    Terminal window
    uv run rai models teardown --force
    pip
    Terminal window
    rai models teardown --force

Now that you’ve run the starter project, you can explore how PyRel builds the semantic model used to answer its question: Which products depend on parts supplied by Northstar Components?

With PyRel, you create a semantic model in Python. A semantic model adds business meaning to your source data by representing the things your business cares about and how they relate.

Three fundamental building blocks define the model’s structure:

  • Concepts represent kinds of things, such as suppliers, parts, and products.
  • Properties describe those things, such as a supplier’s name.
  • Relationships connect them. In this model, suppliers supply parts and products require parts.

Source mappings connect source rows to that structure, turning the CSV rows into entity and relationship facts. Together, the declarations and source mappings create a semantic model that PyRel can query.

The model explorer below shows concepts as labeled blocks and relationships as labeled paths. Select a block or path to see its details. At the bottom of the details pane, expand Source data to see the CSV file, how its columns map to the model, and the rows used in this example.

Supplier disruption

Three concepts describe the business objects. Two relationships connect them: a Supplier supplies a Part, and a Product requires a Part.

SupplierPartProductsuppliesrequires
SupplierPartProductsuppliesrequires
Supplier

A company that provides parts used by products.

Identity
NameType
supplier_idString
Properties
NameType
nameString
Relationships
supplies
Supplier supplies Part

Example data: 3 Supplier entities

Source data suppliers.csv

Provides supplier identifiers and names.

data/suppliers.csv

ColumnMaps to
supplier_idIdentity
supplier_namename
supplier_idsupplier_name
S001Northstar Components
S002Harbor Metals
S003Apex Plastics
Part

A component used to assemble or support a product.

Identity
NameType
part_idString
Properties
NameType
nameString
Relationships
supplies
Supplier supplies Part
requires
Product requires Part

Example data: 4 Part entities

Source data parts.csv

Provides part identifiers and names.

data/parts.csv

ColumnMaps to
part_idIdentity
part_namename
part_idpart_name
P001Control board
P002Temperature sensor
P003Aluminum enclosure
P004Mounting bracket
Product

An item assembled from one or more required parts.

Identity
NameType
product_idString
Properties
NameType
nameString
Relationships
requires
Product requires Part

Example data: 3 Product entities

Source data products.csv

Provides product identifiers and names.

data/products.csv

ColumnMaps to
product_idIdentity
product_namename
product_idproduct_name
PR001Cold-chain tracker
PR002Factory gateway
PR003Smart thermostat
supplies

Connects a supplier to a part that the supplier provides.

Reading

Supplier supplies Part

Fields
NameType
supplierSupplier
partPart

Example data: 4 supplies facts

Source data supplier_parts.csv

Records which supplier provides each part.

data/supplier_parts.csv

ColumnMaps to
supplier_idsupplier
part_idpart
supplier_idpart_id
S001P001
S001P002
S002P003
S003P004
requires

Connects a product to a part needed by that product.

Reading

Product requires Part

Fields
NameType
productProduct
partPart

Example data: 8 requires facts

Source data product_parts.csv

Records which parts each product needs.

data/product_parts.csv

ColumnMaps to
product_idproduct
part_idpart
product_idpart_id
PR001P001
PR001P002
PR001P003
PR002P001
PR002P003
PR002P004
PR003P002
PR003P004
suppliers.csv

Provides supplier identifiers and names.

Populates
Model item
Supplier
Source mapping
supplier_id
Supplier identity
supplier_name
Supplier.name
supplier_idsupplier_name
S001Northstar Components
S002Harbor Metals
S003Apex Plastics

Example data: 3 rows

parts.csv

Provides part identifiers and names.

Populates
Model item
Part
Source mapping
part_id
Part identity
part_name
Part.name
part_idpart_name
P001Control board
P002Temperature sensor
P003Aluminum enclosure
P004Mounting bracket

Example data: 4 rows

products.csv

Provides product identifiers and names.

Populates
Model item
Product
Source mapping
product_id
Product identity
product_name
Product.name
product_idproduct_name
PR001Cold-chain tracker
PR002Factory gateway
PR003Smart thermostat

Example data: 3 rows

supplier_parts.csv

Records which supplier provides each part.

Populates
Model item
supplies
Source mapping
supplier_id
supplier field
part_id
part field
supplier_idpart_id
S001P001
S001P002
S002P003
S003P004

Example data: 4 rows

product_parts.csv

Records which parts each product needs.

Populates
Model item
requires
Source mapping
product_id
product field
part_id
part field
product_idpart_id
PR001P001
PR001P002
PR001P003
PR002P001
PR002P003
PR002P004
PR003P002
PR003P004

Example data: 8 rows

This eight-step walkthrough connects the semantic model you just explored to the code that makes it all work. See how the project defines the model, turns CSV rows into facts, and builds the query. Hover over dotted-underlined text to highlight the corresponding code. You can also focus or tap it.

Explore the project structure

Each part of the project has one job:

  • data/ holds CSV facts about suppliers, parts, products, and their connections.
  • model/schema.py declares the model; model/source.py maps CSV rows to facts; model/__init__.py exposes the assembled model.
  • find_affected_products.py finds products that depend on parts supplied by Northstar Components.
  • pyproject.toml declares which Python version and packages the project requires.
  • raiconfig.yaml holds your local connection settings. You created it earlier; it is not included in the download.
  • Directorysupplier-disruption/
    • Directorymodel/
      • schema.py
      • source.py
      • __init__.py
    • Directorydata/
      • suppliers.csv
      • parts.csv
      • products.csv
      • supplier_parts.csv
      • product_parts.csv
    • find_affected_products.py
    • pyproject.toml
    • raiconfig.yaml local only, not included in the download

Create the model

Model("SupplierDisruption") creates a Model object named SupplierDisruption and stores it in model for the rest of the project to build and query.

model/schema.py
from relationalai.semantics import Model, String
model = Model("SupplierDisruption")
Supplier = model.Concept("Supplier", identify_by={"supplier_id": String})
Supplier.name = model.Property(f"{Supplier} has {String:name}")
Part = model.Concept("Part", identify_by={"part_id": String})
Part.name = model.Property(f"{Part} has {String:name}")
Product = model.Concept("Product", identify_by={"product_id": String})
Product.name = model.Property(f"{Product} has {String:name}")
Supplier.supplies = model.Relationship(f"{Supplier} supplies {Part}")
Product.requires = model.Relationship(f"{Product} requires {Part}")
model/schema.py (lines 1-3)
from relationalai.semantics import Model, String
model = Model("SupplierDisruption")

Define concepts and identities

Supplier, Part, and Product each represent one kind of thing. identify_by names the property that identifies each entity, so rows with the same supplier_id, for example, refer to the same supplier.

model/schema.py
from relationalai.semantics import Model, String
model = Model("SupplierDisruption")
Supplier = model.Concept("Supplier", identify_by={"supplier_id": String})
Supplier.name = model.Property(f"{Supplier} has {String:name}")
Part = model.Concept("Part", identify_by={"part_id": String})
Part.name = model.Property(f"{Part} has {String:name}")
Product = model.Concept("Product", identify_by={"product_id": String})
Product.name = model.Property(f"{Product} has {String:name}")
Supplier.supplies = model.Relationship(f"{Supplier} supplies {Part}")
Product.requires = model.Relationship(f"{Product} requires {Part}")
model/schema.py (lines 5)
Supplier = model.Concept("Supplier", identify_by={"supplier_id": String})
model/schema.py (lines 8)
Part = model.Concept("Part", identify_by={"part_id": String})
model/schema.py (lines 11)
Product = model.Concept("Product", identify_by={"product_id": String})

Add name properties

Each concept gets a name property so queries can return readable labels. model.Property() defines it from a reading, where f-string placeholders become typed PyRel fields: {Supplier} infers the field name supplier, while {String:name} explicitly names the string field name.

model/schema.py
from relationalai.semantics import Model, String
model = Model("SupplierDisruption")
Supplier = model.Concept("Supplier", identify_by={"supplier_id": String})
Supplier.name = model.Property(f"{Supplier} has {String:name}")
Part = model.Concept("Part", identify_by={"part_id": String})
Part.name = model.Property(f"{Part} has {String:name}")
Product = model.Concept("Product", identify_by={"product_id": String})
Product.name = model.Property(f"{Product} has {String:name}")
Supplier.supplies = model.Relationship(f"{Supplier} supplies {Part}")
Product.requires = model.Relationship(f"{Product} requires {Part}")
model/schema.py (lines 6)
Supplier.name = model.Property(f"{Supplier} has {String:name}")
model/schema.py (lines 9)
Part.name = model.Property(f"{Part} has {String:name}")
model/schema.py (lines 12)
Product.name = model.Property(f"{Product} has {String:name}")

Connect concepts with relationships

Supplier.supplies relates suppliers to parts, and Product.requires relates products to parts. Each relationship can connect one entity to many others, and its reading expresses the connection in natural language.

model/schema.py
from relationalai.semantics import Model, String
model = Model("SupplierDisruption")
Supplier = model.Concept("Supplier", identify_by={"supplier_id": String})
Supplier.name = model.Property(f"{Supplier} has {String:name}")
Part = model.Concept("Part", identify_by={"part_id": String})
Part.name = model.Property(f"{Part} has {String:name}")
Product = model.Concept("Product", identify_by={"product_id": String})
Product.name = model.Property(f"{Product} has {String:name}")
Supplier.supplies = model.Relationship(f"{Supplier} supplies {Part}")
Product.requires = model.Relationship(f"{Product} requires {Part}")
model/schema.py (lines 14)
Supplier.supplies = model.Relationship(f"{Supplier} supplies {Part}")
model/schema.py (lines 15)
Product.requires = model.Relationship(f"{Product} requires {Part}")

Map CSV rows to entities

read_csv() loads each entity file into a pandas DataFrame, and model.data() exposes its rows to PyRel. For each row, Supplier.new(), Part.new(), or Product.new() finds or creates the entity by ID; .name() assigns its readable name, and model.define() adds both facts to the model.

Use Snowflake data

For Snowflake tables, use Model.Table() instead. This starter uses model.data() so it can run from local CSV files.

model/source.py
8 collapsed lines
from pathlib import Path
from pandas import read_csv
from .schema import Part, Product, Supplier, model
DATA_DIR = Path(__file__).resolve().parent.parent / "data"
supplier_rows = model.data(read_csv(DATA_DIR / "suppliers.csv"))
model.define(
supplier := Supplier.new(supplier_id=supplier_rows["supplier_id"]),
supplier.name(supplier_rows["supplier_name"]),
)
part_rows = model.data(read_csv(DATA_DIR / "parts.csv"))
model.define(
part := Part.new(part_id=part_rows["part_id"]),
part.name(part_rows["part_name"]),
)
product_rows = model.data(read_csv(DATA_DIR / "products.csv"))
model.define(
product := Product.new(product_id=product_rows["product_id"]),
product.name(product_rows["product_name"]),
)
14 collapsed lines
supplier_part_rows = model.data(read_csv(DATA_DIR / "supplier_parts.csv"))
model.define(
Supplier.lookup(supplier_id=supplier_part_rows["supplier_id"]).supplies(
Part.lookup(part_id=supplier_part_rows["part_id"]),
)
)
product_part_rows = model.data(read_csv(DATA_DIR / "product_parts.csv"))
model.define(
Product.lookup(product_id=product_part_rows["product_id"]).requires(
Part.lookup(part_id=product_part_rows["part_id"]),
)
)
model/source.py (lines 9-13)
supplier_rows = model.data(read_csv(DATA_DIR / "suppliers.csv"))
model.define(
supplier := Supplier.new(supplier_id=supplier_rows["supplier_id"]),
supplier.name(supplier_rows["supplier_name"]),
)
model/source.py (lines 15-19)
part_rows = model.data(read_csv(DATA_DIR / "parts.csv"))
model.define(
part := Part.new(part_id=part_rows["part_id"]),
part.name(part_rows["part_name"]),
)
model/source.py (lines 21-25)
product_rows = model.data(read_csv(DATA_DIR / "products.csv"))
model.define(
product := Product.new(product_id=product_rows["product_id"]),
product.name(product_rows["product_name"]),
)

Map CSV rows to relationships

supplier_parts.csv and product_parts.csv store pairs of entity IDs. For each row, Supplier.lookup() or Product.lookup() finds one entity, Part.lookup() finds the other, and Supplier.supplies or Product.requires connects them. model.define() adds the relationship as a fact.

model/source.py
26 collapsed lines
from pathlib import Path
from pandas import read_csv
from .schema import Part, Product, Supplier, model
DATA_DIR = Path(__file__).resolve().parent.parent / "data"
supplier_rows = model.data(read_csv(DATA_DIR / "suppliers.csv"))
model.define(
supplier := Supplier.new(supplier_id=supplier_rows["supplier_id"]),
supplier.name(supplier_rows["supplier_name"]),
)
part_rows = model.data(read_csv(DATA_DIR / "parts.csv"))
model.define(
part := Part.new(part_id=part_rows["part_id"]),
part.name(part_rows["part_name"]),
)
product_rows = model.data(read_csv(DATA_DIR / "products.csv"))
model.define(
product := Product.new(product_id=product_rows["product_id"]),
product.name(product_rows["product_name"]),
)
supplier_part_rows = model.data(read_csv(DATA_DIR / "supplier_parts.csv"))
model.define(
Supplier.lookup(supplier_id=supplier_part_rows["supplier_id"]).supplies(
Part.lookup(part_id=supplier_part_rows["part_id"]),
)
)
product_part_rows = model.data(read_csv(DATA_DIR / "product_parts.csv"))
model.define(
Product.lookup(product_id=product_part_rows["product_id"]).requires(
Part.lookup(part_id=product_part_rows["part_id"]),
)
)
model/source.py (lines 27-32)
supplier_part_rows = model.data(read_csv(DATA_DIR / "supplier_parts.csv"))
model.define(
Supplier.lookup(supplier_id=supplier_part_rows["supplier_id"]).supplies(
Part.lookup(part_id=supplier_part_rows["part_id"]),
)
)
model/source.py (lines 34-39)
product_part_rows = model.data(read_csv(DATA_DIR / "product_parts.csv"))
model.define(
Product.lookup(product_id=product_part_rows["product_id"]).requires(
Part.lookup(part_id=product_part_rows["part_id"]),
)
)

Trace supplier exposure

The query starts with Northstar Components, follows Supplier.supplies to each part, then Product.requires to each product that uses it.

Each .ref() creates a variable that can match an entity. model.where() specifies how the supplier, parts, and products must be related. .select() chooses the names to return, and .inspect() runs the query and prints the matches.

find_affected_products.py
from model import Part, Product, Supplier, model
unavailable_supplier = Supplier.ref()
affected_part = Part.ref()
affected_product = Product.ref()
(
model.where(
unavailable_supplier.name == "Northstar Components",
unavailable_supplier.supplies(affected_part),
affected_product.requires(affected_part),
)
.select(
affected_product.name.alias("product"),
affected_part.name.alias("part"),
)
.inspect()
)
find_affected_products.py (lines 3-5)
unavailable_supplier = Supplier.ref()
affected_part = Part.ref()
affected_product = Product.ref()
find_affected_products.py (lines 7-18)
(
model.where(
unavailable_supplier.name == "Northstar Components",
unavailable_supplier.supplies(affected_part),
affected_product.requires(affected_part),
)
.select(
affected_product.name.alias("product"),
affected_part.name.alias("part"),
)
.inspect()
)
  • Each product that depends on a part supplied by Northstar Components.
  • The part supplied by Northstar that each product depends on.
  • Whether production will stop.
  • Which supplier should replace Northstar.
  • Answers to those questions, which RelationalAI can provide with a richer model that includes current inventory, lead times, and alternative suppliers, together with the appropriate reasoning.

Nice work!

You set up a PyRel project and used a semantic model to answer a business question. You’re ready to start building with your own data.

Choose a next step based on your goal: