# NumPy: Meson builds, CPython only, and a licence that shifts by artifact

> NumPy is the array package that scientific Python sits on, built by mesonpy with a Cython floor, restricted to Python 3.12 and newer on CPython. The most useful thing in its pyproject.toml is a comment explaining why the licence you read in the source is not the licence of the wheel you install.

**numpy/numpy** — GitHub describes it as The fundamental package for scientific computing with Python.. The repository metadata lists Python as its primary language. The metadata lists the NOASSERTION license. This article stays within the project description and details documented in the GitHub repository README.

- Repository: https://github.com/numpy/numpy
- Website: https://numpy.org
- Stars: 32,893 · Forks: 12,861
- Language: Python
- License: NOASSERTION
- Published: 2026-08-13 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/numpy-numpy

## The build backend is mesonpy, and the Cython floor is written down twice

pyproject.toml names mesonpy as the build backend and requires meson-python>=0.20.0 and Cython>=3.1.0 to build. That second line carries an inline comment, keep in sync with version check in meson.build, which says the floor lives in two files and someone has to move both when it changes.

The layout backs this up. There is a meson.build at the root, a meson.options, a meson_cpu/ directory, a vendored-meson/ directory, and a document called building_with_meson.md. INSTALL.rst sits next to them. A vendored copy of the build system is a deliberate choice to pin the tool, and it means a source build uses the Meson in the repository rather than whatever version happens to be on the machine.

Around that sit .circleci/ for continuous integration, a .devcontainer/ directory, and .spin/ for the C and C++ edit-build loop. The Python tooling is a smaller perimeter: .clang-format, ruff.toml, .codecov.yml and .coveragerc.

What the readme does not give you is a build command. There is no pip install line and no meson invocation in it. The one build command in the repository appears inside a comment in pyproject.toml, and it names the case it is describing precisely.

## requires-python is 3.12, and CPython is the only interpreter listed

Two lines in pyproject.toml decide who can install this at all. `requires-python = ">=3.12"`, and a classifier list that names CPython and nothing else, alongside `Python :: 3 :: Only`. No other implementation appears anywhere in the metadata.

The Python floor is a moving constraint rather than a historical note. Recent release tags are v2.5.3 on 2026-09-06, v2.5.2 on 2026-08-09 and v2.5.1 on 2026-07-04, close to one release a month, and every one of those will refuse to install on 3.11. The classifiers list three interpreters, 3.12, 3.13 and 3.14, and the operating systems named are Windows, POSIX, Unix and MacOS.

For a reader planning a deployment the first check is short. Verify the Python version on the target before anything else, because a NumPy that resolves for a 3.11 interpreter is an older NumPy, and running that alongside a 3.12 environment in one fleet is how version-dependent bugs arrive.

The interpreter line is the harder one to reason about. Naming CPython as the sole implementation says nothing about other runtimes except that this project does not classify them, so an alternative interpreter is not a path the metadata endorses. Check that against the platform you actually run before building a plan on it.

## pyproject.toml carries 2.6.0.dev0 while the newest tag is v2.5.3

The version field reads 2.6.0.dev0. The recent release tags are v2.5.3, v2.5.2 and v2.5.1, the default branch is main, and the last push was on 2026-09-22.

So the tree already sits one minor version ahead of anything released, with a development marker in the string. That is ordinary for a project shipping from tags, and it has one consequence worth stating plainly: installing from a checkout of main gives you something identified as 2.6.0.dev0, not a release, and comparing that version number against 2.5.3 tells you nothing about what changed. Diff the checkout against the tag you mean to run.

The classifier calls the project Production/Stable, which describes the released line rather than the development line. The gap matters when a dependency resolver is in the picture, because a dev version on main is a different resolution target from the release everyone else has pinned.

Some parts of the metadata do not move. Authors are Travis E. Oliphant et al., maintainers are the NumPy Developers at numpy-discussion@python.org, and CITATION.bib sits in the root for anyone who needs a citation. That part you can rely on. The version number in a working tree, you cannot.

## The SPDX expression describes a source build, not the wheel you install

The licence comment in pyproject.toml is the most carefully written thing in this repository, and it says something the one-line answer does not. The main NumPy project licence is BSD-3-Clause, and the SPDX expression below that comment reflects installed packages only when built from source with no vendoring. The command the comment uses to define that case is in the file.

```bash
python -m build --wheel
```

Having named that case, the comment says the expression is incomplete in two others. The first is sdists, which carry further licences recorded under the `license-files` key. The second is wheels on PyPI, where most wheels include vendored libraries under additional terms, and the one it names is libopenblas under BSD-3-Clause AND BSD-3-Clause-Attribution, with a platform exception the text cuts off before finishing.

This matters beyond licensing trivia, because automated compliance does not read comments. A scanner pointed at an installed wheel from PyPI can report more than BSD-3-Clause and still be right, while the SPDX string in the source is the wrong reference point for that artifact. A policy check has to run against the file you ship, not the tree you built from.

The licence field recorded for this repository is NOASSERTION, and the tree carries LICENSE.txt. Where those two disagree, the file in the tree and the vendored licences inside the wheel are what a reviewer should read.

## pytest covers the Python layer, and the C API has its own test path

Testing is the one place the readme hands you a runnable command, and it runs everything rather than a selection.

```bash
python -c "import numpy, sys; sys.exit(numpy.test() is False)"
```

That needs pytest, which the documentation names as a requirement. Past it sit optional test dependencies chosen by what you are testing: Meson for testing the NumPy C API, Cython for testing the NumPy Cython API, and Hypothesis for property-based tests. Three surfaces, three tools, and a green run on a base install says nothing about the other two. If your change touches the C API or the Cython API, the base command does not test your change.

The supporting files match that structure. A pytest.ini, a .coveragerc and a .codecov.yml handle the Python layer, a .ctags.d generates tags across the C sources, and a .gitmodules pulls in submodules the tree needs.

Worth being blunt about the first-run experience: there is no smoke-test command. The documentation offers the full suite invocation and nothing shorter, so anyone wanting to confirm an install is working ends up running the whole test run, or reading the installation instructions elsewhere.

## Four capabilities are promised, and none of them is input or output

The readme lists what NumPy provides in four lines: an N-dimensional array object, broadcasting functions, tools for integrating C/C++ and Fortran code, and linear algebra, Fourier transform and random number capabilities. Read that list for what is missing as well as what is there.

No file format appears in it, no plotting, no labelled table, no distributed execution. Nothing in the project documentation claims otherwise, and for a reader deciding whether this is a whole data stack, the answer is that it is not one. Reading data and drawing results are somebody else's layer.

The third line is the one that gets skipped over, and it is the one that carries the most build and test surface. Tools for integrating C and C++ and Fortran code is what makes the package useful to a codebase that is not Python. It is also the line that depends on Cython and Meson being present to verify, rather than pytest alone.

The list is short enough to recall after one reading, which is the point of a substrate rather than a toolkit. Knowing where the boundary sits saves you the round trip later.

## Large source changes are expected to start on a public mailing list

Contributions come with a process rather than just a pull request box. Anyone considering a larger contribution to the source code is asked to contact the project through the mailing list first, at mail.python.org/mailman/listinfo/numpy-discussion. Smaller improvements and fixes are welcomed without that step.

For an engineer with a substantial patch, that is the first real friction point. A large change is expected to be discussed before it is written, so a company trying to upstream an internal refactor has to plan for a public thread before it plans for the diff. That is a deliberate choice about how a foundational library changes, and it costs calendar time.

The rest of the process is well signposted. Preferred channels are public, including GitHub issues and comments, while private contact runs through the community coordinators at numpy-team@googlegroups.com or on Slack using the same address for an invitation. There is a biweekly community call announced on the mailing list, a Code of Conduct, CONTRIBUTING.rst in the root, THANKS.txt, and a getting-started guide linked for people new to open source.

One asymmetry to keep in mind. Reviewing pull requests, working through old and new issues, tutorials, website maintenance, brand design, translation and grant writing are all named as contributions that do not involve code. Those routes have the least gatekeeping, and for a first contribution they cost the least.

## Where the N-dimensional array stops and a labelled table starts

Comparison with a dataframe library is a common search, and the difference comes down to the shape of the data. NumPy's object is the N-dimensional array with broadcasting functions over it, and the extra capabilities named are linear algebra, Fourier transforms and random numbers. None of those is a table concern.

pandas builds on arrays of this kind and organises them as labelled rows and columns, which is why the two get described as different levels of one stack. Pick the array when the work is numeric and shape-based, since the transform, algebra and random number capabilities are the parts a dataframe library does not aim at. Pick the labelled table when the work is per-column and per-row over fields that do not share a shape.

The other axis is the metadata from earlier, and it applies to whatever you layer on top. NumPy's constraints arrive in your environment as a compiled extension whether or not you import it directly: Python 3.12 or newer, CPython as the only listed implementation, and a mesonpy build with a Cython floor if you compile it yourself rather than installing a wheel. Planning for a dataframe library and planning for the array underneath it are not the same task, and the second one constrains the first.

## Conclusion

Adopt NumPy when you need the N-dimensional array, broadcasting, linear algebra, Fourier transforms and random numbers on CPython 3.12 or newer, and take it from PyPI or the conda-forge channel rather than building it. Skip it if your runtime is not CPython or your Python predates 3.12, because pyproject.toml sets requires-python to >=3.12 and names no interpreter besides CPython. Two things to check before you trust a compliance report: the SPDX expression in pyproject.toml is written for a wheel built with nothing vendored, and the comment under it says PyPI wheels ship vendored libraries under additional terms, so scan the artifact you actually deploy. And if you must build from source, remember the backend is mesonpy with a Cython floor of 3.1.0 that meson.build checks again.

## FAQ

### What is NumPy in Python used for?

The readme lists what it provides: an N-dimensional array object, broadcasting functions, tools for integrating C/C++ and Fortran code, and linear algebra, Fourier transform and random number capabilities. The project describes itself as the fundamental package for scientific computing with Python.

### Is NumPy written in C or C++?

The source is both. The classifiers in pyproject.toml list Programming Language :: C alongside Programming Language :: Python, the build backend is mesonpy with Cython>=3.1.0, and the readme names tools for integrating C/C++ and Fortran code.

### Can I pip install NumPy?

The readme gives no install command at all. It points to the PyPI project page and to the conda-forge channel as the distribution points, so which installer you use is a choice the documentation leaves open.

### how to use numpy arrays

The N-dimensional array object is the first of the four things the readme says NumPy provides, with broadcasting functions listed alongside it. No usage example is given in the readme itself; examples live in the documentation at numpy.org/doc.

### how to install numpy

Installation from source is not a one-line instruction in the readme. Building means the mesonpy backend, meson-python>=0.20.0 and Cython>=3.1.0, with the procedure in building_with_meson.md or INSTALL.rst, and the project also links PyPI and the conda-forge channel for prebuilt packages.

## Sources

- [Official documentation](https://numpy.org)
- [Official README](https://github.com/numpy/numpy#readme)
- [Project repository](https://github.com/numpy/numpy)
- [Release notes](https://github.com/numpy/numpy/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/numpy-numpy
