Skip to main content

PyRlang

R-style syntax, running on pure Python. No R runtime, no compilation, zero dependencies.

PyRlang lets you write R the way R programmers actually type it — x <- c(1, 2), 1:10, df$col, %>%, %in%, y ~ x — and runs it as ordinary Python underneath. It also ships the R-flavoured data types as a normal Python library, usable from plain .py files.

  • PyPI distribution name: pyr4py (PyPI compares names with -/_ stripped, so the whole family is blocked: pyr is a 2013 REPL, pyrlang is an actively developed BEAM runtime, and therefore pyr-lang/PyRlang are rejected on upload too. pyr4py — "PyR for Python" — is the distribution name)
  • Import name: PyRlang (import PyRlang, from PyRlang import *)
  • License: GPL-3.0-or-later
  • Python: >= 3.10

Install

pip install pyr4py

Two ways to use it

1. R-style scripts (.pyr) — full syntax

Write hello.pyr:

x <- c(2, 4.5, 8, 1, 3.3, NA)
mean(x, na.rm = TRUE)
summary(x)

v <- 1:5
v[1]              # one-based: the FIRST element
v[-1]             # drops the first element, R-style

df <- data.frame(
  name = c("ada", "bob"),
  age  = c(34, 47)
)
df$age
df[df$age > 35, ]
df$senior <- df$age > 40

df$age %>% mean() %>% round(2)
10 %in% c(4, 8, 10)
paste("R", "on", "Python", sep = "-") |> toupper()
f <- wage ~ age

Run it like an R script:

PyRlang hello.pyr          # or: python -m PyRlang hello.pyr

Top-level expressions echo their results exactly like the R console, vectors print as [1] 2 4.5 8 1 3.3 NA.

2. Interactive REPL

$ PyRlang
PyRlang 0.1.0 on Python 3.12 — R-style syntax, pure Python
Try: x <- c(1, 2, 3); mean(x).  exit() or Ctrl-D to quit.
>> x <- c(1, 2, 3)
>> mean(x)
[1] 2
>> 1:5 %>% sum()
[1] 15

3. As a Python library

from PyRlang import *

v = c(1, 2, 3)
v[1]  # 1 — one-based
mean(v)  # 2.0
f = Formula("y ~ x")
df = data_frame(age=c(34, 47), wage=c(21.5, 33.0))
summary(df)  # R-style six-number summaries

Syntax supported in transform mode

(.pyr files, the REPL, and PyRlang -e — plain .py files are never touched.)

R syntax becomes notes
x <- e x = e < and - must be adjacent, exactly like the real R parser
x < -e unchanged a space keeps it a Python comparison
<<- not supported clear error message
a:b seq(a, b) outside []/{}; not after lambda, not annotations, not slices
x ^ y x ** y
x %% y x % y
a && b a and b adjacent pair only, like R's scalar operators
a || b a or b
!x PyRlang.not_(x) element-wise negation — works on vectors
a %in% b PyRlang.isin(a, b) vectorised membership
a %>% f(b) PyRlang.pipe(a, f, b) magrittr; native R pipe a |> f(b) too
y ~ x + z Formula('y ~ x + z') including inside call arguments: lm(y ~ x, data = d) style
df$col df.col
data.frame(…) DataFrame(…) also read.csv, write.csv, which.max, which.min, na.rm=, length.out=

Semantics, by design

  • One-based indexing. v[1] is the first element; index 0 is an error with an R-style message. v[2:4] returns elements 2, 3, 4 (inclusive, like R), and out-of-range slices pad with NA.
  • Negative subscripts drop elements. v[-1] removes the first element. (This differs deliberately from Python's negative indexing.)
  • Recycling. c(1, 2) + c(1, 2, 3, 4) recycles the shorter vector, like R.
  • NA everywhere. A real NA sentinel: NA + 1 is NA, mean(c(1, NA)) is NA unless you write na.rm = TRUE, if (NA) raises R's error message.
  • R-flavoured printing. Vectors print as [1] 1 2 3, strings quoted, logicals as TRUE/FALSE, six-number summaries in R's column layout.
  • Division by zero is Inf/NaN, not an exception — like R.

What ships in the library

  • Constructors/inspection: c, seq, rep, length, unique, sort, rev, head, tail, which, which.max, which.min, table
  • Statistics: mean, median, sd, var, min, max, sum, prod, summary, sqrt, exp, log, all NA-aware
  • Strings: paste, paste0, sprintf, nchar, toupper, tolower, substr, substring, cat
  • Data: data.frame, $, R-style row/column subsetting, nrow, ncol, names, read.csv, write.csv
  • Logic: ifelse, %in%, element-wise &, |, !, vectorised comparisons

Honest limitations (v0.1)

  • No R block syntax (for (i in 1:10) { ... }) — keep Python blocks, use R expressions inside them.
  • -> (right assignment) is not yet transformed.
  • lm, glm, plot and the modelling/graphics stack do not exist yet; Formula is data only.
  • No packages/namespaces; Python modules are imported normally.
  • Type annotations in .pyr files are not supported (R mode treats n:m as a range).
  • Only Python >= 3.10 is supported.

Development

pip install -e ".[dev]"
pytest
ruff format . && ruff check .
python -m build
twine check dist/*

Run the examples:

python -m PyRlang examples/basics.pyr
python -m PyRlang examples/dataframe.pyr
PyRlang

Publishing to PyPI

The PyPI name for this project is pyr4py (taken-name note above).

python -m build
twine check dist/*
twine upload dist/pyr4py-0.1.0*

Use --repository testpypi to rehearse on TestPyPI, or configure an API token:

# ~/.pypirc
[pypi]
username = __token__
password = pypi-xxxxxxxx

License

GPL-3.0-or-later. See LICENSE.

Metadata

Release files for pyr4py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyr4py 0.1.0
File Size Uploaded Provenance
pyr4py-0.1.0.tar.gz 41.8 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pyr4py 0.1.0
File Interpreter ABI Platform
pyr4py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 83.3 kB

Release files / pyr4py-0.1.0.tar.gz

Download URL pyr4py-0.1.0.tar.gz
Size 41.8 kB
Tags Source
SHA-256 checksum
How to use checksums
af0d483db76ed3bcdaa5d03758384b666f75763209fbba144f52dbce834cbe13
BLAKE2b-256 checksum
How to use checksums
d3c0ac5f0c7043ef19adda5fb577bf978d4518d981be3867dfe0b1c838980538
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Release files / pyr4py-0.1.0-py3-none-any.whl

Download URL pyr4py-0.1.0-py3-none-any.whl
Size 41.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0450af5eed77399e562ade5e2288854b7835af2964d24a594f84f3a29f94d632
BLAKE2b-256 checksum
How to use checksums
a56e948539bc97243c42487c78d22d9b416bec019a660878a97d7a621da38a3a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.15

Security for pyr4py 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page