# API and ABI Versioning

## Build-time version constants

CPython exposes its version number in the following macros. Note that these correspond to the version code is **built** with. See `Py_Version` for the version used at **run time**.

See `stable` for a discussion of API and ABI stability across versions.

> The `3` in `3.4.1a2`.

> The `4` in `3.4.1a2`.

> The `1` in `3.4.1a2`.

> The `a` in `3.4.1a2`. This can be `0xA` for alpha, `0xB` for beta, `0xC` for release candidate or `0xF` for final.
>
> For completeness, the values are available as macros: `!PY_RELEASE_LEVEL_ALPHA` (`0xA`), `!PY_RELEASE_LEVEL_BETA` (`0xB`), `!PY_RELEASE_LEVEL_GAMMA` (`0xC`), and `!PY_RELEASE_LEVEL_FINAL` (`0xF`).

> The `2` in `3.4.1a2`. Zero for final releases.

> The Python version number encoded in a single integer. See `Py_PACK_FULL_VERSION` for the encoding details.
>
> Use this for numeric comparisons, for example, `#if PY_VERSION_HEX >= ...`.

> The Python version as a string, for example, `"3.4.1a2"`.

These macros are defined in `Include/patchlevel.h`.

## Run-time version

> The Python runtime version number encoded in a single constant integer. See `Py_PACK_FULL_VERSION` for the encoding details. This contains the Python version used at run time.
>
> Use this for numeric comparisons, for example, `if (Py_Version >= ...)`.
>
> <div class="versionadded">
>
> 3.11
>
> </div>

## Bit-packing macros

> Return the given version, encoded as a single 32-bit integer with the following structure:
>
> <table style="width:95%;">
> <colgroup>
> <col style="width: 21%" />
> <col style="width: 9%" />
> <col style="width: 19%" />
> <col style="width: 13%" />
> <col style="width: 16%" />
> <col style="width: 14%" />
> </colgroup>
> <thead>
> <tr>
> <th rowspan="2"><p>Argument</p></th>
> <th rowspan="2"><p>No. of bits</p></th>
> <th rowspan="2"><p>Bit mask</p></th>
> <th rowspan="2"><p>Bit shift</p></th>
> <th colspan="2"><p>Example values</p></th>
> </tr>
> <tr>
> <th><p><code>3.4.1a2</code></p></th>
> <th><p><code>3.10.0</code></p></th>
> </tr>
> </thead>
> <tbody>
> <tr>
> <td><p><em>major</em></p></td>
> <td><blockquote>
> <p>8</p>
> </blockquote></td>
> <td><p><code>0xFF000000</code></p></td>
> <td><p>24</p></td>
> <td><p><code>0x03</code></p></td>
> <td><p><code>0x03</code></p></td>
> </tr>
> <tr>
> <td><p><em>minor</em></p></td>
> <td><blockquote>
> <p>8</p>
> </blockquote></td>
> <td><p><code>0x00FF0000</code></p></td>
> <td><p>16</p></td>
> <td><p><code>0x04</code></p></td>
> <td><p><code>0x0A</code></p></td>
> </tr>
> <tr>
> <td><p><em>micro</em></p></td>
> <td><blockquote>
> <p>8</p>
> </blockquote></td>
> <td><p><code>0x0000FF00</code></p></td>
> <td><p>8</p></td>
> <td><p><code>0x01</code></p></td>
> <td><p><code>0x00</code></p></td>
> </tr>
> <tr>
> <td><p><em>release_level</em></p></td>
> <td><blockquote>
> <p>4</p>
> </blockquote></td>
> <td><p><code>0x000000F0</code></p></td>
> <td><p>4</p></td>
> <td><p><code>0xA</code></p></td>
> <td><p><code>0xF</code></p></td>
> </tr>
> <tr>
> <td><p><em>release_serial</em></p></td>
> <td><blockquote>
> <p>4</p>
> </blockquote></td>
> <td><p><code>0x0000000F</code></p></td>
> <td><p>0</p></td>
> <td><p><code>0x2</code></p></td>
> <td><p><code>0x0</code></p></td>
> </tr>
> </tbody>
> </table>
>
> For example:
>
> | Version   | `Py_PACK_FULL_VERSION` arguments | Encoded version |
> |-----------|----------------------------------|-----------------|
> | `3.4.1a2` | `(3, 4, 1, 0xA, 2)`              | `0x030401a2`    |
> | `3.10.0`  | `(3, 10, 0, 0xF, 0)`             | `0x030a00f0`    |
>
> Out-of range bits in the arguments are ignored. That is, the macro can be defined as:
>
> ``` c
> #ifndef Py_PACK_FULL_VERSION
> #define Py_PACK_FULL_VERSION(X, Y, Z, LEVEL, SERIAL) ( \
>    (((X) & 0xff) << 24) |                              \
>    (((Y) & 0xff) << 16) |                              \
>    (((Z) & 0xff) << 8) |                               \
>    (((LEVEL) & 0xf) << 4) |                            \
>    (((SERIAL) & 0xf) << 0))
> #endif
> ```
>
> `Py_PACK_FULL_VERSION` is primarily a macro, intended for use in `#if` directives, but it is also available as an exported function.
>
> <div class="versionadded">
>
> 3.14
>
> </div>

> Equivalent to `Py_PACK_FULL_VERSION(major, minor, 0, 0, 0)`. The result does not correspond to any Python release, but is useful in numeric comparisons.
>
> <div class="versionadded">
>
> 3.14
>
> </div>