PRQL - Python Bindings

Python bindings for PRQL, the Pipelined Relational Query Language.

PRQL is a modern language for transforming data — a simple, powerful, pipelined SQL replacement. Like SQL, it’s readable, explicit and declarative. Unlike SQL, it forms a logical pipeline of transformations, and supports abstractions such as variables and functions. It can be used with any database that uses SQL, since it compiles to SQL.

PRQL can be as simple as:

  1. from tracks
  2. filter artist == "Bob Marley" # Each line transforms the previous result
  3. aggregate { # `aggregate` reduces each column to a value
  4. plays = sum plays,
  5. longest = max length,
  6. shortest = min length, # Trailing commas are allowed
  7. }

Installation

pip install prqlc

Usage

Basic usage:

  1. import prqlc
  2. prql_query = """
  3. from employees
  4. join salaries (==emp_id)
  5. group {employees.dept_id, employees.gender} (
  6. aggregate {
  7. avg_salary = average salaries.salary
  8. }
  9. )
  10. """
  11. options = prqlc.CompileOptions(
  12. format=True, signature_comment=True, target="sql.postgres"
  13. )
  14. sql = prqlc.compile(prql_query)
  15. sql_postgres = prqlc.compile(prql_query, options)

The following functions and classes are exposed:

  1. def compile(prql_query: str, options: Optional[CompileOptions] = None) -> str:
  2. """Compiles a PRQL query into SQL."""
  3. ...
  4. def prql_to_pl(prql_query: str) -> str:
  5. """Converts a PRQL query to PL AST in JSON format."""
  6. ...
  7. def pl_to_prql(pl_json: str) -> str:
  8. """Converts PL AST as a JSON string into a formatted PRQL string."""
  9. ...
  10. def pl_to_rq(pl_json: str) -> str:
  11. """Resolves and lowers PL AST (JSON) into RQ AST (JSON)."""
  12. ...
  13. def rq_to_sql(rq_json: str, options: Optional[CompileOptions] = None) -> str:
  14. """Converts RQ AST (JSON) into a SQL query."""
  15. ...
  16. class CompileOptions:
  17. def __init__(
  18. self,
  19. *,
  20. format: bool = True,
  21. target: str = "sql.any",
  22. signature_comment: bool = True,
  23. ) -> None:
  24. """Compilation options for SQL backend of the compiler.
  25. Args:
  26. format (bool): Pass generated SQL string through a formatter that splits
  27. it into multiple lines and prettifies indentation and spacing.
  28. Defaults to True.
  29. target (str): Target dialect to compile to. Defaults to "sql.any", which
  30. uses the 'target' argument from the query header to determine the
  31. SQL dialect. Other targets are available by calling the `get_targets`
  32. function.
  33. signature_comment (bool): Emits the compiler signature as a comment after
  34. the generated SQL. Defaults to True.
  35. """
  36. ...
  37. def get_targets() -> list[str]:
  38. """List available target dialects for compilation."""
  39. ...

Debugging functions

The following functions are available within the prqlc.debug module. They are for experimental purposes and may be unstable.

  1. def prql_lineage(prql_query: str) -> str:
  2. """Computes a column-level lineage graph from a PRQL query.
  3. Returns JSON-formatted string. See the docs for the `prqlc debug lineage`
  4. CLI command for more details.
  5. """
  6. ...
  7. def pl_to_lineage(pl_json: str) -> str:
  8. """Computes a column-level lineage graph from PL AST (JSON)."""
  9. ...

Notes

These bindings are in a crate named prqlc-python and published to a Python package on PyPI named prqlc, available at https://pypi.org/project/prqlc. This crate is not published to crates.io.

The package is consumed by pyprql & dbt-prql.

Relies on pyo3 for all the magic.