npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

python-random

v1.0.0

Published

CPython's random module in TypeScript, bit for bit: the same seed draws the same numbers as Python's random.Random.

Readme

python-random

CPython's random module in TypeScript, bit for bit. Seed it the way you seed Python and it draws the same numbers, in the same order, from every method.

>>> import random
>>> r = random.Random(42)
>>> r.random()
0.6394267984578837
import { Random } from "python-random";

const r = new Random(42);
console.log(r.random()); // 0.6394267984578837

Why

Math.random() cannot be seeded, and the seedable generators on npm are not the one Python uses. When a Python service and a JavaScript one must agree on a seeded draw, such as the same shuffle, the same sample or the same simulated identity, both sides need the same generator and the same methods on top of it. This package is a port of both: the Mersenne Twister (MT19937) core of CPython's Modules/_randommodule.c, seeded exactly as CPython seeds it, and the methods of Lib/random.py, with the same rejection loops, branch points and floating-point evaluation order.

Install

npm install python-random

Node 20 or newer. ESM only, with TypeScript types included. No runtime dependencies.

Usage

import { Random } from "python-random";

const r = new Random(42);
console.log(r.random()); // 0.6394267984578837
console.log(r.randint(1, 6)); // 1
console.log(r.choice(["rock", "paper", "scissors"])); // scissors
console.log(r.sample(Array.from({ length: 100 }, (_, i) => i), 5)); // [ 35, 31, 28, 17, 94 ]

const deck = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
r.shuffle(deck);
console.log(deck); // [ 7, 2, 5, 6, 0, 3, 4, 9, 8, 1 ]
console.log(r.choices(["a", "b", "c"], { weights: [5, 1, 1], k: 6 })); // [ 'a', 'a', 'a', 'b', 'a', 'a' ]

The same calls in Python print the same values:

r = random.Random(42)
r.random(); r.randint(1, 6); r.choice(["rock", "paper", "scissors"])
r.sample(range(100), 5)
deck = list(range(10)); r.shuffle(deck)
r.choices(["a", "b", "c"], [5, 1, 1], k=6)

The module-level functions share one hidden generator, as Python's do:

import * as random from "python-random";

random.seed("hello");
console.log(random.random()); // 0.3537754404730722
console.log(random.randrange(0, 100, 5)); // 85

Python ints have no size limit and JavaScript numbers stop being exact at 253, so integers past that are bigints. getrandbits() always returns one; randrange() and randint() return whichever type they are given:

import { Random } from "python-random";

const r = new Random(2n ** 100n);
console.log(r.getrandbits(100)); // 97103624483852547665086082069n
console.log(r.randrange(10n ** 30n)); // 881832314501477294104966971409n
console.log(r.randbytes(4)); // Uint8Array(4) [ 50, 9, 107, 212 ]

A number that is not a safe integer is rejected with a RangeError rather than rounded, since a rounded number is a different seed or range from the one Python would see.

API

Everything is a method of Random, and each method is also exported as a module-level function bound to one shared instance.

| JavaScript | Python | |---|---| | new Random(a?) | random.Random(a=None) | | seed(a?) | seed(a=None) (version 2) | | random() | random() | | getrandbits(k), a bigint | getrandbits(k) | | randbytes(n), a Uint8Array | randbytes(n) | | randrange(start, stop?, step?) | randrange(start, stop=None, step=1) | | randint(a, b) | randint(a, b) | | choice(seq) | choice(seq) | | choices(population, { weights, cumWeights, k }) | choices(population, weights=None, *, cum_weights=None, k=1) | | sample(population, k, { counts }) | sample(population, k, *, counts=None) | | shuffle(x), in place | shuffle(x) | | uniform(a, b) | uniform(a, b) | | triangular(low?, high?, mode?) | triangular(low=0.0, high=1.0, mode=None) |

A seed is a number (a safe integer), a bigint, a string, a Uint8Array (for Python bytes), or null/undefined for OS entropy. Like Python, an int seed uses its absolute value, and a string or bytes seed is hashed with SHA-512 (seed version 2).

A Python ValueError or IndexError is a RangeError here, and a TypeError is a TypeError.

Not included

The distributions built on log, exp, sin, cos or pow (gauss, normalvariate, lognormvariate, expovariate, vonmisesvariate, gammavariate, betavariate, paretovariate, weibullvariate and binomialvariate) are left out. V8 computes those functions with different code from the C library CPython calls, so their results can differ in the last bit, and this package only ships what it can match exactly. Also left out are getstate()/setstate(), SystemRandom, seed version 1, and float seeds, which Python hashes.

Guarantees

Every method above is checked against CPython 3.10, 3.11, 3.12, 3.13 and 3.14 on Node 20, 22 and 24. The tests run scripts/golden.py under a real interpreter on every run, replay its calls over 22 seeds of every kind, and compare each result exactly, along with which calls raise.

The versions agree on every result, with one exception in error handling: sample(population, 0, { counts }) with counts that sum to zero returns [] here, as in Python 3.12 and later. Python 3.10 and 3.11 raise.

Development

pnpm install
pnpm check       # biome
pnpm typecheck
pnpm build
pnpm test        # needs CPython 3.10+: $PYTHON, else python3

The tests regenerate test/fixtures/ from CPython on every run, and fail when no interpreter is found. Matching CPython beats improving on it: a change that alters which words are drawn, or in what order, is a bug even when it looks like a cleanup.

Licence

PSF-2.0 AND BSD-3-Clause. The methods are derived from CPython's Lib/random.py (Python Software Foundation License Version 2) and the generator from the MT19937 code in Modules/_randommodule.c (© Makoto Matsumoto and Takuji Nishimura, BSD 3-clause). The port itself is © Jake Writer under BSD 3-clause. LICENSE holds all three texts, and NOTICE summarises the changes from CPython.