PyRel is RelationalAI’s Python package for building semantic models.
You’ll create and configure a project, then learn PyRel’s core concepts through a simple model.
Finally, you’ll query the model to answer a business question.
Estimated time
20–30 minutes
Prerequisites
A Bash, zsh, or PowerShell terminal.
Python 3.10–3.13 to run the project. If Python is not installed, the uv setup in this guide can download it automatically.
Network access to install Python packages and connect to your Snowflake account.
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:
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
uvpythoninstall3.13
uvsync
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.
Run these commands to check that PyRel and the rai command were installed:
Open a terminal and run these commands to extract the starter project, enter its folder, create a virtual environment, and install the required packages:
If you saved the ZIP file outside Downloads, update its path in the first command:
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. Activate the virtual environment again using the command from the previous step, then reinstall the packages:
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.
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
uvrunpythonfind_affected_products.py
pip
Terminal window
pythonfind_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.
Deploy the model
First, deploy the model from your project folder using the rai models deploy CLI command:
uv
Terminal window
uvrunraimodelsdeploy--pathmodel--wait
pip
Terminal window
raimodelsdeploy--pathmodel--wait
What this command does
--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.
Run the query
After deployment succeeds, run the query:
uv
Terminal window
uvrunpythonfind_affected_products.py
pip
Terminal window
pythonfind_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.
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
uvrunraimodelsteardown
pip
Terminal window
raimodelsteardown
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:
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.
No item selected.
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
Name
Type
supplier_id
String
Properties
Name
Type
name
String
Relationships
supplies
Supplier supplies Part
Example data: 3 Supplier entities
Source data suppliers.csv
Provides supplier identifiers and names.
data/suppliers.csv
Column
Maps to
supplier_id
Identity
supplier_name
name
supplier_id
supplier_name
S001
Northstar Components
S002
Harbor Metals
S003
Apex Plastics
Part
A component used to assemble or support a product.
Identity
Name
Type
part_id
String
Properties
Name
Type
name
String
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
Column
Maps to
part_id
Identity
part_name
name
part_id
part_name
P001
Control board
P002
Temperature sensor
P003
Aluminum enclosure
P004
Mounting bracket
Product
An item assembled from one or more required parts.
Identity
Name
Type
product_id
String
Properties
Name
Type
name
String
Relationships
requires
Product requires Part
Example data: 3 Product entities
Source data products.csv
Provides product identifiers and names.
data/products.csv
Column
Maps to
product_id
Identity
product_name
name
product_id
product_name
PR001
Cold-chain tracker
PR002
Factory gateway
PR003
Smart thermostat
supplies
Connects a supplier to a part that the supplier provides.
Reading
Supplier supplies Part
Fields
Name
Type
supplier
Supplier
part
Part
Example data: 4 supplies facts
Source data supplier_parts.csv
Records which supplier provides each part.
data/supplier_parts.csv
Column
Maps to
supplier_id
supplier
part_id
part
supplier_id
part_id
S001
P001
S001
P002
S002
P003
S003
P004
requires
Connects a product to a part needed by that product.
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.
1
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
2
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.
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.
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.
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}")
5
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.
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
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
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.
Each product that depends on a part supplied by Northstar Components.
The part supplied by Northstar that each product depends on.
What this result does not show
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.