{
  "version": "1",
  "pip_version": "24.0",
  "install": [
    {
      "download_info": {
        "url": "https://github.com/roboflow/rf-detr.git",
        "vcs_info": {
          "vcs": "git",
          "requested_revision": "3f7748b1783533bc2e62804ca5975fe9b9cfc041",
          "commit_id": "3f7748b1783533bc2e62804ca5975fe9b9cfc041"
        }
      },
      "is_direct": true,
      "is_yanked": false,
      "requested": true,
      "metadata": {
        "metadata_version": "2.4",
        "name": "rfdetr",
        "version": "1.9.3",
        "dynamic": [
          "license-file"
        ],
        "summary": "RF-DETR",
        "description": "# RF-DETR: Real-Time SOTA Object Detection, Instance Segmentation, and Keypoint Detection\n\n<div align=\"center\">\n\n[![version](https://badge.fury.io/py/rfdetr.svg)](https://badge.fury.io/py/rfdetr) [![downloads](https://img.shields.io/pypi/dm/rfdetr)](https://pypistats.org/packages/rfdetr) [![codecov](https://codecov.io/gh/roboflow/rf-detr/graph/badge.svg?token=K8V4ARR3XV)](https://codecov.io/gh/roboflow/rf-detr) [![python-version](https://img.shields.io/pypi/pyversions/rfdetr)](https://badge.fury.io/py/rfdetr) [![license](https://img.shields.io/badge/license-Apache%202.0-blue)](https://github.com/roboflow/rf-detr/blob/main/LICENSE)\n\n[![arXiv](https://img.shields.io/badge/arXiv-2511.09554-b31b1b.svg)](https://arxiv.org/abs/2511.09554) [![hf space](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/SkalskiP/RF-DETR) [![colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-finetune-rf-detr-on-detection-dataset.ipynb) [![roboflow](https://raw.githubusercontent.com/roboflow-ai/notebooks/main/assets/badges/roboflow-blogpost.svg)](https://blog.roboflow.com/rf-detr) [![discord](https://img.shields.io/discord/1159501506232451173?logo=discord&label=discord&labelColor=fff&color=5865f2&link=https%3A%2F%2Fdiscord.gg%2FGbfgXGJ8Bk)](https://discord.gg/GbfgXGJ8Bk)\n\n<a href=\"https://trendshift.io/repositories/14379?utm_source=repository-badge&amp;utm_medium=badge&amp;utm_campaign=badge-repository-14379\" target=\"_blank\" rel=\"noopener noreferrer\">\n<img src=\"https://trendshift.io/api/badge/repositories/14379\" alt=\"roboflow%2Frf-detr | Trendshift\" width=\"250\" height=\"55\"/>\n</a>\n\n</div>\n\n---\n\nRF-DETR is a real-time transformer architecture for object detection, instance segmentation, and keypoint detection (preview) developed by Roboflow. Built on a DINOv2 vision transformer backbone, RF-DETR delivers state-of-the-art accuracy and latency trade-offs on [Microsoft COCO](https://cocodataset.org/#home) and [RF100-VL](https://github.com/roboflow/rf100-vl).\n\nRF-DETR uses a DINOv2 vision transformer backbone and supports object detection, instance segmentation, and keypoint detection (preview) in a single, consistent API. The open-source `rfdetr` package and Apache-designated models are released under Apache 2.0, while Plus components (`rfdetr_plus`, including RF-DETR-XL/2XL detection models) are licensed under PML 1.0.\n\nThe published RF-DETR sizes were created with neural architecture search (NAS) — and the same NAS method is now available on the [Roboflow platform](https://app.roboflow.com/), so you can discover the best architecture for your own dataset. Learn more in the [NAS docs](https://docs.roboflow.com/train/neural-architecture-search).\n\nhttps://github.com/user-attachments/assets/add23fd1-266f-4538-8809-d7dd5767e8e6\n\n## Install\n\nTo install RF-DETR, install the `rfdetr` package in a [**Python>=3.10**](https://www.python.org/) environment with `pip`.\n\n```bash\npip install rfdetr\n```\n\n<details>\n<summary>Install from source</summary>\n\n<br>\n\nBy installing RF-DETR from source, you can explore the most recent features and enhancements that have not yet been officially released. **Please note that these updates are still in development and may not be as stable as the latest published release.**\n\n```bash\npip install https://github.com/roboflow/rf-detr/archive/refs/heads/develop.zip\n```\n\n</details>\n\n## Benchmarks\n\nRF-DETR achieves state-of-the-art results in both object detection and instance segmentation, with benchmarks reported on Microsoft COCO and RF100-VL (RF100-VL for detection only). The charts and tables below compare RF-DETR against other top real-time models across accuracy and latency for detection and segmentation. All COCO accuracy numbers are measured in-house for every model shown, computed with pycocotools in SAB over the full 5,000-image `val2017` split, so every row is directly comparable and may differ from vendor-reported figures. The sole exception is rows marked †, which are quoted from the original authors' paper and were not measured in SAB. All latency numbers were measured on an NVIDIA T4 using TensorRT, FP16, and batch size 1. Parameter counts are deployment (fused) `nn.Module` parameter counts (`model.parameters()`, not the raw tensor count of the saved checkpoint), except rows marked †, which are the authors' reported counts. For full benchmarking methodology and reproducibility details, see [roboflow/sab](https://github.com/roboflow/single_artifact_benchmarking).\n\n### Detection\n\n<img alt=\"rf_detr_1-4_latency_accuracy_object_detection\" src=\"https://storage.googleapis.com/com-roboflow-marketing/rf-detr/rf_detr_1-4_latency_accuracy_object_detection.png\" />\n\n<details>\n<summary>See object detection benchmark numbers</summary>\n\n<br>\n\n| Architecture  | COCO AP<sub>50</sub> | COCO AP<sub>50:95</sub> | RF100VL AP<sub>50</sub> | RF100VL AP<sub>50:95</sub> | Latency (ms) | Params (M) | Resolution |  License   |\n| :-----------: | :------------------: | :---------------------: | :---------------------: | :------------------------: | :----------: | :--------: | :--------: | :--------: |\n|   RF-DETR-N   |         67.6         |          48.4           |          85.0           |            57.7            |     2.3      |    30.5    |  384x384   | Apache 2.0 |\n|   RF-DETR-S   |         72.1         |          53.0           |          86.7           |            60.2            |     3.5      |    32.1    |  512x512   | Apache 2.0 |\n|   RF-DETR-M   |         73.6         |          54.7           |          87.4           |            61.2            |     4.4      |    33.7    |  576x576   | Apache 2.0 |\n|   RF-DETR-L   |         75.1         |          56.5           |          88.2           |            62.2            |     6.8      |    33.9    |  704x704   | Apache 2.0 |\n| RF-DETR-XL △  |         77.4         |          58.6           |          88.5           |            62.9            |     11.5     |   126.4    |  700x700   |  PML 1.0   |\n| RF-DETR-2XL △ |         78.5         |          60.1           |          89.0           |            63.2            |     17.2     |   126.9    |  880x880   |  PML 1.0   |\n|   YOLO11-N    |         52.0         |          37.4           |          81.4           |            55.3            |     2.5      |    2.6     |  640x640   |  AGPL-3.0  |\n|   YOLO11-S    |         59.7         |          44.4           |          82.3           |            56.2            |     3.2      |    9.4     |  640x640   |  AGPL-3.0  |\n|   YOLO11-M    |         64.1         |          48.6           |          82.5           |            56.5            |     5.1      |    20.1    |  640x640   |  AGPL-3.0  |\n|   YOLO11-L    |         64.9         |          49.9           |          82.2           |            56.5            |     6.5      |    25.3    |  640x640   |  AGPL-3.0  |\n|   YOLO11-X    |         66.1         |          50.9           |          81.7           |            56.2            |     10.5     |    56.9    |  640x640   |  AGPL-3.0  |\n|   YOLO26-N    |         55.8         |          40.3           |          76.7           |            52.0            |     1.7      |    2.6     |  640x640   |  AGPL-3.0  |\n|   YOLO26-S    |         64.3         |          47.7           |          82.7           |            57.0            |     2.6      |    9.4     |  640x640   |  AGPL-3.0  |\n|   YOLO26-M    |         69.7         |          52.5           |          84.4           |            58.7            |     4.4      |    20.1    |  640x640   |  AGPL-3.0  |\n|   YOLO26-L    |         71.1         |          54.1           |          85.0           |            59.3            |     5.7      |    25.3    |  640x640   |  AGPL-3.0  |\n|   YOLO26-X    |         74.0         |          56.9           |          85.6           |            60.0            |     9.6      |    56.9    |  640x640   |  AGPL-3.0  |\n|   LW-DETR-T   |         60.7         |          42.9           |          84.7           |            57.1            |     1.9      |    12.1    |  640x640   | Apache 2.0 |\n|   LW-DETR-S   |         66.8         |          48.0           |          85.0           |            57.4            |     2.6      |    14.6    |  640x640   | Apache 2.0 |\n|   LW-DETR-M   |         72.0         |          52.6           |          86.8           |            59.8            |     4.4      |    28.2    |  640x640   | Apache 2.0 |\n|   LW-DETR-L   |         74.6         |          56.1           |          87.4           |            61.5            |     6.9      |    46.8    |  640x640   | Apache 2.0 |\n|   LW-DETR-X   |         76.9         |          58.3           |          87.9           |            62.1            |     13.0     |   118.0    |  640x640   | Apache 2.0 |\n|   D-FINE-N    |         60.2         |          42.7           |          84.4           |            58.2            |     2.1      |    3.8     |  640x640   | Apache 2.0 |\n|   D-FINE-S    |         67.6         |          50.6           |          85.3           |            60.3            |     3.5      |    10.2    |  640x640   | Apache 2.0 |\n|   D-FINE-M    |         72.6         |          55.0           |          85.5           |            60.6            |     5.4      |    19.2    |  640x640   | Apache 2.0 |\n|   D-FINE-L    |         74.9         |          57.2           |          86.4           |            61.6            |     7.5      |    31.0    |  640x640   | Apache 2.0 |\n|   D-FINE-X    |         76.8         |          59.3           |          86.9           |            62.2            |     11.5     |    62.0    |  640x640   | Apache 2.0 |\n|    SAM 3 †    |          —           |            —            |            —            |            61.6            |      —       |    ~850    | 1008x1008  |    N/A     |\n\n> † Reported by the SAM 3 authors ([arXiv:2511.16719](https://arxiv.org/abs/2511.16719), Table 36), **not** measured by us in SAB. The value is SAM 3 fine-tuned on the full RF100-VL training set, which is the same setting as the RF100VL columns above — SAM 3's paper reports LW-DETR-m at 59.8 on this benchmark, matching our own measurement, so the numbers line up. Dashes mark results SAM 3 does not report under this protocol. Parameter count is the paper's stated ~850 M (~450 M vision + ~300 M text encoders + ~100 M detector/tracker).\n\n</details>\n\n### Segmentation\n\n<img alt=\"rf_detr_1-4_latency_accuracy_instance_segmentation\" src=\"https://storage.googleapis.com/com-roboflow-marketing/rf-detr/rf_detr_1-4_latency_accuracy_instance_segmentation.png\" />\n\n<details>\n<summary>See instance segmentation benchmark numbers</summary>\n\n<br>\n\n|  Architecture   | COCO AP<sub>50</sub> | COCO AP<sub>50:95</sub> | Latency (ms) | Params (M) | Resolution |  License   |\n| :-------------: | :------------------: | :---------------------: | :----------: | :--------: | :--------: | :--------: |\n|  RF-DETR-Seg-N  |         63.0         |          40.3           |     3.4      |    33.6    |  312x312   | Apache 2.0 |\n|  RF-DETR-Seg-S  |         66.2         |          43.1           |     4.4      |    33.7    |  384x384   | Apache 2.0 |\n|  RF-DETR-Seg-M  |         68.4         |          45.3           |     5.9      |    35.7    |  432x432   | Apache 2.0 |\n|  RF-DETR-Seg-L  |         70.5         |          47.1           |     8.8      |    36.2    |  504x504   | Apache 2.0 |\n| RF-DETR-Seg-XL  |         72.2         |          48.8           |     13.5     |    38.1    |  624x624   | Apache 2.0 |\n| RF-DETR-Seg-2XL |         73.1         |          49.9           |     21.8     |    38.6    |  768x768   | Apache 2.0 |\n|  YOLOv8-N-Seg   |         45.6         |          28.3           |     3.5      |    3.4     |  640x640   |  AGPL-3.0  |\n|  YOLOv8-S-Seg   |         53.8         |          34.0           |     4.2      |    11.8    |  640x640   |  AGPL-3.0  |\n|  YOLOv8-M-Seg   |         58.2         |          37.3           |     7.0      |    27.3    |  640x640   |  AGPL-3.0  |\n|  YOLOv8-L-Seg   |         60.5         |          39.0           |     9.7      |    46.0    |  640x640   |  AGPL-3.0  |\n|  YOLOv8-XL-Seg  |         61.3         |          39.5           |     14.0     |    71.8    |  640x640   |  AGPL-3.0  |\n|  YOLOv11-N-Seg  |         47.8         |          30.0           |     3.6      |    2.9     |  640x640   |  AGPL-3.0  |\n|  YOLOv11-S-Seg  |         55.4         |          35.0           |     4.6      |    10.1    |  640x640   |  AGPL-3.0  |\n|  YOLOv11-M-Seg  |         60.0         |          38.5           |     6.9      |    22.4    |  640x640   |  AGPL-3.0  |\n|  YOLOv11-L-Seg  |         61.5         |          39.5           |     8.3      |    27.6    |  640x640   |  AGPL-3.0  |\n| YOLOv11-XL-Seg  |         62.4         |          40.1           |     13.7     |    62.1    |  640x640   |  AGPL-3.0  |\n|  YOLO26-N-Seg   |         54.3         |          34.7           |     2.31     |    2.7     |  640x640   |  AGPL-3.0  |\n|  YOLO26-S-Seg   |         62.4         |          40.2           |     3.47     |    10.4    |  640x640   |  AGPL-3.0  |\n|  YOLO26-M-Seg   |         67.8         |          44.0           |     6.32     |    23.6    |  640x640   |  AGPL-3.0  |\n|  YOLO26-L-Seg   |         69.8         |          45.5           |     7.58     |    28.0    |  640x640   |  AGPL-3.0  |\n|  YOLO26-X-Seg   |         71.6         |          46.8           |    12.92     |    62.8    |  640x640   |  AGPL-3.0  |\n\n</details>\n\n### Keypoints\n\n<img alt=\"RF-DETR Keypoint mAP vs latency chart comparing against YOLO26-pose and YOLO11-pose on MS COCO\" src=\"https://raw.githubusercontent.com/roboflow/rf-detr/develop/docs/assets/keypoints/kp-map-latency.png\" />\n\n<details>\n<summary>See keypoint detection benchmark numbers</summary>\n\n<br>\n\n|        Architecture        | COCO AP<sub>50:95</sub> | Latency (ms) | Params (M) |  License   |\n| :------------------------: | :---------------------: | :----------: | :--------: | :--------: |\n| RF-DETR Keypoint (Preview) |          71.8           |     9.7      |    40.7    | Apache 2.0 |\n|       YOLO11-pose N        |          48.9           |     3.2      |    2.9     |  AGPL-3.0  |\n|       YOLO11-pose S        |          57.5           |     3.4      |    9.9     |  AGPL-3.0  |\n|       YOLO11-pose M        |          64.2           |     5.2      |    20.9    |  AGPL-3.0  |\n|       YOLO11-pose L        |          65.2           |     6.6      |    26.2    |  AGPL-3.0  |\n|       YOLO11-pose X        |          68.6           |     10.6     |    58.8    |  AGPL-3.0  |\n|       YOLO26-pose N        |          55.9           |     1.9      |    2.9     |  AGPL-3.0  |\n|       YOLO26-pose S        |          62.0           |     2.7      |    10.4    |  AGPL-3.0  |\n|       YOLO26-pose M        |          68.0           |     4.6      |    21.5    |  AGPL-3.0  |\n|       YOLO26-pose L        |          69.2           |     5.9      |    25.9    |  AGPL-3.0  |\n|       YOLO26-pose X        |          71.0           |     9.8      |    57.6    |  AGPL-3.0  |\n\n</details>\n\n> Keypoint benchmarks report AP<sub>50:95</sub> (OKS-based); this is the standard COCO keypoint comparison metric.\n\n### NAS on the Roboflow Platform\n\n<img alt=\"RF100-VL accuracy-latency Pareto chart showing RF-DETR NAS trained on the Roboflow platform outperforming the paper NAS and named configs\" src=\"https://raw.githubusercontent.com/roboflow/rf-detr/develop/docs/assets/nas_two_source_comparison_100_test_only.svg\" />\n\nSince the paper release, we have improved RF-DETR NAS training on the Roboflow platform even further. A single training run gives you every model size, with results that beat not only the open-source checkpoints but also our own paper NAS results. [Try it now!](https://roboflow.com/)\n\n## Run Models\n\n### Detection\n\nRF-DETR provides multiple model sizes, ranging from Nano to 2XLarge. To use a different model size, replace the class name in the code snippet below with another class from the table.\n\n```python\nimport supervision as sv\nfrom rfdetr import RFDETRMedium\nfrom rfdetr.assets.coco_classes import COCO_CLASSES\n\nmodel = RFDETRMedium()\n\ndetections = model.predict(\"https://media.roboflow.com/dog.jpg\", threshold=0.5)\n\nlabels = [f\"{COCO_CLASSES[class_id]}\" for class_id in detections.class_id]\n\nannotated_image = sv.BoxAnnotator().annotate(detections.metadata[\"source_image\"], detections)\nannotated_image = sv.LabelAnnotator().annotate(annotated_image, detections, labels)\n```\n\n> **Note:** `COCO_CLASSES` works for COCO-pretrained models. For fine-tuned models, use `detections.data[\"class_name\"]` instead — it resolves class names from the checkpoint and works for both COCO and custom datasets.\n\n<details>\n<summary>Run RF-DETR with Inference</summary>\n\n<br>\n\nYou can also run RF-DETR models using the Inference library. To switch model size, select the appropriate inference package alias from the table below.\n\n```python\nimport requests\nimport supervision as sv\nfrom PIL import Image\nfrom inference import get_model\n\nmodel = get_model(\"rfdetr-medium\")\n\nimage = Image.open(requests.get(\"https://media.roboflow.com/dog.jpg\", stream=True).raw)\npredictions = model.infer(image, confidence=0.5)[0]\ndetections = sv.Detections.from_inference(predictions)\n\nannotated_image = sv.BoxAnnotator().annotate(image, detections)\nannotated_image = sv.LabelAnnotator().annotate(annotated_image, detections)\n```\n\n</details>\n\n| Size | RF-DETR package class | Inference package alias | COCO AP<sub>50</sub> | COCO AP<sub>50:95</sub> | Latency (ms) | Params (M) | Resolution |  License   |\n| :--: | :-------------------: | :---------------------- | :------------------: | :---------------------: | :----------: | :--------: | :--------: | :--------: |\n|  N   |     `RFDETRNano`      | `rfdetr-nano`           |         67.6         |          48.4           |     2.3      |    30.5    |  384x384   | Apache 2.0 |\n|  S   |     `RFDETRSmall`     | `rfdetr-small`          |         72.1         |          53.0           |     3.5      |    32.1    |  512x512   | Apache 2.0 |\n|  M   |    `RFDETRMedium`     | `rfdetr-medium`         |         73.6         |          54.7           |     4.4      |    33.7    |  576x576   | Apache 2.0 |\n|  L   |     `RFDETRLarge`     | `rfdetr-large`          |         75.1         |          56.5           |     6.8      |    33.9    |  704x704   | Apache 2.0 |\n|  XL  |   `RFDETRXLarge` △    | `rfdetr-xlarge`         |         77.4         |          58.6           |     11.5     |   126.4    |  700x700   |  PML 1.0   |\n| 2XL  |   `RFDETR2XLarge` △   | `rfdetr-2xlarge`        |         78.5         |          60.1           |     17.2     |   126.9    |  880x880   |  PML 1.0   |\n\n> △ Requires the `rfdetr_plus` extension: `pip install rfdetr[plus]`. See [License](#license) for details.\n\n### Segmentation\n\nRF-DETR supports instance segmentation with model sizes from Nano to 2XLarge. To use a different model size, replace the class name in the code snippet below with another class from the table.\n\n```python\nimport supervision as sv\nfrom rfdetr import RFDETRSegMedium\nfrom rfdetr.assets.coco_classes import COCO_CLASSES\n\nmodel = RFDETRSegMedium()\n\ndetections = model.predict(\"https://media.roboflow.com/dog.jpg\", threshold=0.5)\n\nlabels = [f\"{COCO_CLASSES[class_id]}\" for class_id in detections.class_id]\n\nannotated_image = sv.MaskAnnotator().annotate(detections.metadata[\"source_image\"], detections)\nannotated_image = sv.LabelAnnotator().annotate(annotated_image, detections, labels)\n```\n\n<details>\n<summary>Run RF-DETR-Seg with Inference</summary>\n\n<br>\n\nYou can also run RF-DETR-Seg models using the Inference library. To switch model size, select the appropriate inference package alias from the table below.\n\n```python\nimport requests\nimport supervision as sv\nfrom PIL import Image\nfrom inference import get_model\n\nmodel = get_model(\"rfdetr-seg-medium\")\n\nimage = Image.open(requests.get(\"https://media.roboflow.com/dog.jpg\", stream=True).raw)\npredictions = model.infer(image, confidence=0.5)[0]\ndetections = sv.Detections.from_inference(predictions)\n\nannotated_image = sv.MaskAnnotator().annotate(image, detections)\nannotated_image = sv.LabelAnnotator().annotate(annotated_image, detections)\n```\n\n</details>\n\n| Size | RF-DETR package class | Inference package alias | COCO AP<sub>50</sub> | COCO AP<sub>50:95</sub> | Latency (ms) | Params (M) | Resolution |  License   |\n| :--: | :-------------------: | :---------------------- | :------------------: | :---------------------: | :----------: | :--------: | :--------: | :--------: |\n|  N   |    `RFDETRSegNano`    | `rfdetr-seg-nano`       |         63.0         |          40.3           |     3.4      |    33.6    |  312x312   | Apache 2.0 |\n|  S   |   `RFDETRSegSmall`    | `rfdetr-seg-small`      |         66.2         |          43.1           |     4.4      |    33.7    |  384x384   | Apache 2.0 |\n|  M   |   `RFDETRSegMedium`   | `rfdetr-seg-medium`     |         68.4         |          45.3           |     5.9      |    35.7    |  432x432   | Apache 2.0 |\n|  L   |   `RFDETRSegLarge`    | `rfdetr-seg-large`      |         70.5         |          47.1           |     8.8      |    36.2    |  504x504   | Apache 2.0 |\n|  XL  |   `RFDETRSegXLarge`   | `rfdetr-seg-xlarge`     |         72.2         |          48.8           |     13.5     |    38.1    |  624x624   | Apache 2.0 |\n| 2XL  |  `RFDETRSeg2XLarge`   | `rfdetr-seg-2xlarge`    |         73.1         |          49.9           |     21.8     |    38.6    |  768x768   | Apache 2.0 |\n\n### Keypoints\n\nRF-DETR supports keypoint detection (preview) with `RFDETRKeypointPreview`, pretrained on COCO person keypoints.\n\n```python\nfrom rfdetr import RFDETRKeypointPreview\n\nmodel = RFDETRKeypointPreview()\nkey_points = model.predict(\"image.jpg\", threshold=0.5)\n```\n\n|        Size        |  RF-DETR package class  | COCO AP<sub>50:95</sub> | Latency (ms) | Params (M) | Resolution |  License   |\n| :----------------: | :---------------------: | :---------------------: | :----------: | :--------: | :--------: | :--------: |\n| Keypoint (Preview) | `RFDETRKeypointPreview` |          71.8           |     9.7      |    40.7    |  576x576   | Apache 2.0 |\n\n### Train Models\n\nRF-DETR supports training for object detection, instance segmentation, and keypoint detection (preview). You can train models in [Google Colab](https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/how-to-finetune-rf-detr-on-detection-dataset.ipynb) or directly on the Roboflow platform. Below you will find a step-by-step video fine-tuning tutorial.\n\n[![rf-detr-tutorial-banner](https://github.com/user-attachments/assets/555a45c3-96e8-4d8a-ad29-f23403c8edfd)](https://youtu.be/-OvpdLAElFA)\n\n## Documentation\n\nVisit our [documentation website](https://rfdetr.roboflow.com) to learn more about how to use RF-DETR.\n\n## License\n\nLicensing is split by component:\n\n- The open-source `rfdetr` package and Apache-designated model weights are licensed under Apache License 2.0. See [`LICENSE`](LICENSE).\n- Plus components, including the `rfdetr_plus` extension and RF-DETR-XL / RF-DETR-2XL detection models, are licensed under PML 1.0.\n\n## Acknowledgements\n\nOur work is built upon [LW-DETR](https://arxiv.org/pdf/2406.03459), [DINOv2](https://arxiv.org/pdf/2304.07193), and [Deformable DETR](https://arxiv.org/pdf/2010.04159). Thanks to their authors for their excellent work!\n\n## Citation\n\nIf you find our work helpful for your research, please consider citing the following BibTeX entry.\n\n```bibtex\n@inproceedings{robinson2026rfdetr,\n  title     = {RF-DETR: Real-Time Detection Transformer},\n  author    = {Robinson, Isaac and Robicheaux, Peter and Popov, Matvei and Ramanan, Deva and Peri, Neehar},\n  booktitle = {International Conference on Learning Representations (ICLR)},\n  year      = {2026},\n  url       = {https://arxiv.org/abs/2511.09554}\n}\n```\n\n## Contribute\n\nWe welcome and appreciate all contributions! If you notice any issues or bugs, have questions, or would like to suggest new features, please [open an issue](https://github.com/roboflow/rf-detr/issues/new) or pull request. By sharing your ideas and improvements, you help make RF-DETR better for everyone.\n\n<p align=\"center\">\n    <a href=\"https://youtube.com/roboflow\"><img src=\"https://media.roboflow.com/notebooks/template/icons/purple/youtube.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949634652\" width=\"3%\"/></a>\n    <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n    <a href=\"https://roboflow.com\"><img src=\"https://media.roboflow.com/notebooks/template/icons/purple/roboflow-app.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949746649\" width=\"3%\"/></a>\n    <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n    <a href=\"https://www.linkedin.com/company/roboflow-ai/\"><img src=\"https://media.roboflow.com/notebooks/template/icons/purple/linkedin.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633691\" width=\"3%\"/></a>\n    <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n    <a href=\"https://docs.roboflow.com\"><img src=\"https://media.roboflow.com/notebooks/template/icons/purple/knowledge.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949634511\" width=\"3%\"/></a>\n    <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n    <a href=\"https://discuss.roboflow.com\"><img src=\"https://media.roboflow.com/notebooks/template/icons/purple/forum.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633584\" width=\"3%\"/></a>\n    <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n    <a href=\"https://blog.roboflow.com\"><img src=\"https://media.roboflow.com/notebooks/template/icons/purple/blog.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633605\" width=\"3%\"/></a>\n</p>\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "machine-learning",
          "deep-learning",
          "vision",
          "ML",
          "DL",
          "AI",
          "DETR",
          "RF-DETR",
          "Roboflow"
        ],
        "author_email": "\"Roboflow, Inc\" <develop@roboflow.com>",
        "license": "Apache License 2.0",
        "classifier": [
          "Development Status :: 4 - Beta",
          "Intended Audience :: Developers",
          "Intended Audience :: Education",
          "Intended Audience :: Science/Research",
          "License :: OSI Approved :: Apache Software License",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3 :: Only",
          "Topic :: Software Development",
          "Topic :: Scientific/Engineering",
          "Topic :: Scientific/Engineering :: Artificial Intelligence",
          "Typing :: Typed",
          "Operating System :: POSIX",
          "Operating System :: Unix",
          "Operating System :: MacOS"
        ],
        "requires_dist": [
          "requests",
          "numpy",
          "torch>=2.2.0",
          "torchvision>=0.17.0",
          "tqdm",
          "transformers<6.0.0,>=5.1.0",
          "pydantic<3,>=2.0",
          "supervision>=0.29.0",
          "pyDeprecate<0.10,>=0.9",
          "peft; extra == \"lora\"",
          "peft; extra == \"train\"",
          "pytorch_lightning!=2.6.2,!=2.6.3,<3,>=2.6; extra == \"train\"",
          "torchmetrics[detection]>=1.2; extra == \"train\"",
          "faster-coco-eval>=1.7.2; extra == \"train\"",
          "pycocotools; extra == \"train\"",
          "scipy; extra == \"train\"",
          "roboflow; extra == \"train\"",
          "rf100vl; extra == \"train\"",
          "albumentations<3.0.0,>=1.4.24; extra == \"augment\"",
          "kornia<1,>=0.7; extra == \"augment\"",
          "onnx<2.0,>=1.16.0; extra == \"onnx\"",
          "onnxsim>=0.7.0; extra == \"onnx\"",
          "onnx_graphsurgeon; extra == \"onnx\"",
          "onnxruntime<1.24; python_version < \"3.11\" and extra == \"onnx\"",
          "onnxruntime; python_version >= \"3.11\" and extra == \"onnx\"",
          "polygraphy; extra == \"onnx\"",
          "onnxruntime-gpu; extra == \"tensorrt\"",
          "tensorrt>=8.6.1; extra == \"tensorrt\"",
          "polygraphy; extra == \"tensorrt\"",
          "pycuda>=2024.1; extra == \"tensorrt-bench\"",
          "onnx<2.0,>=1.20.0; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "onnxsim>=0.7.0; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "onnx_graphsurgeon; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "polygraphy; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "onnx2tf<3.0.0,>=2.4.0; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "flatbuffers>=23.5.26; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "tf-keras>=2.16.0; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "tensorflow>=2.16.0; (python_version >= \"3.12\" and python_version < \"3.13\") and extra == \"tflite\"",
          "executorch<2.0,>=1.3; python_version < \"3.14\" and extra == \"executorch\"",
          "coremltools<10.0,>=8.0; extra == \"coreml\"",
          "torch<2.12; extra == \"coreml\"",
          "tensorboard>=2.13.0; extra == \"loggers\"",
          "protobuf>=3.20.0; extra == \"loggers\"",
          "wandb; extra == \"loggers\"",
          "mlflow; extra == \"loggers\"",
          "clearml; extra == \"loggers\"",
          "matplotlib; extra == \"visual\"",
          "pandas; extra == \"visual\"",
          "seaborn; extra == \"visual\"",
          "jsonargparse[signatures]>=4.27.7; extra == \"cli\"",
          "rfdetr_plus<2.0.0,>=1.0.1; extra == \"plus\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/roboflow/rf-detr"
        ],
        "provides_extra": [
          "lora",
          "train",
          "augment",
          "onnx",
          "tensorrt",
          "tensorrt-bench",
          "tflite",
          "executorch",
          "coreml",
          "loggers",
          "visual",
          "cli",
          "plus"
        ]
      },
      "requested_extras": [
        "onnx"
      ]
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce",
          "hashes": {
            "sha256": "d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": true,
      "metadata": {
        "metadata_version": "2.4",
        "name": "jsonschema",
        "version": "4.26.0",
        "summary": "An implementation of JSON Schema validation for Python",
        "description": "==========\njsonschema\n==========\n\n|PyPI| |Pythons| |CI| |ReadTheDocs| |Precommit| |Zenodo|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema.svg\n   :alt: PyPI version\n   :target: https://pypi.org/project/jsonschema/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema.svg\n   :alt: Supported Python versions\n   :target: https://pypi.org/project/jsonschema/\n\n.. |CI| image:: https://github.com/python-jsonschema/jsonschema/workflows/CI/badge.svg\n  :alt: Build status\n  :target: https://github.com/python-jsonschema/jsonschema/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/python-jsonschema/badge/?version=stable&style=flat\n   :alt: ReadTheDocs status\n   :target: https://python-jsonschema.readthedocs.io/en/stable/\n\n.. |Precommit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/jsonschema/main.svg\n   :alt: pre-commit.ci status\n   :target: https://results.pre-commit.ci/latest/github/python-jsonschema/jsonschema/main\n\n.. |Zenodo| image:: https://zenodo.org/badge/3072629.svg\n   :alt: Zenodo DOI\n   :target: https://zenodo.org/badge/latestdoi/3072629\n\n\n``jsonschema`` is an implementation of the `JSON Schema <https://json-schema.org>`_ specification for Python.\n\n.. code:: python\n\n    >>> from jsonschema import validate\n\n    >>> # A sample schema, like what we'd get from json.load()\n    >>> schema = {\n    ...     \"type\" : \"object\",\n    ...     \"properties\" : {\n    ...         \"price\" : {\"type\" : \"number\"},\n    ...         \"name\" : {\"type\" : \"string\"},\n    ...     },\n    ... }\n\n    >>> # If no exception is raised by validate(), the instance is valid.\n    >>> validate(instance={\"name\" : \"Eggs\", \"price\" : 34.99}, schema=schema)\n\n    >>> validate(\n    ...     instance={\"name\" : \"Eggs\", \"price\" : \"Invalid\"}, schema=schema,\n    ... )                                   # doctest: +IGNORE_EXCEPTION_DETAIL\n    Traceback (most recent call last):\n        ...\n    ValidationError: 'Invalid' is not of type 'number'\n\nIt can also be used from the command line by installing `check-jsonschema <https://github.com/python-jsonschema/check-jsonschema>`_.\n\nFeatures\n--------\n\n* Full support for `Draft 2020-12 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft202012Validator>`_, `Draft 2019-09 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft201909Validator>`_, `Draft 7 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft7Validator>`_, `Draft 6 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft6Validator>`_, `Draft 4 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft4Validator>`_ and `Draft 3 <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/validators/#jsonschema.validators.Draft3Validator>`_\n\n* `Lazy validation <https://python-jsonschema.readthedocs.io/en/latest/api/jsonschema/protocols/#jsonschema.protocols.Validator.iter_errors>`_ that can iteratively report *all* validation errors.\n\n* `Programmatic querying <https://python-jsonschema.readthedocs.io/en/latest/errors/>`_ of which properties or items failed validation.\n\n\nInstallation\n------------\n\n``jsonschema`` is available on `PyPI <https://pypi.org/project/jsonschema/>`_. You can install using `pip <https://pip.pypa.io/en/stable/>`_:\n\n.. code:: bash\n\n    $ pip install jsonschema\n\n\nExtras\n======\n\nTwo extras are available when installing the package, both currently related to ``format`` validation:\n\n    * ``format``\n    * ``format-nongpl``\n\nThey can be used when installing in order to include additional dependencies, e.g.:\n\n.. code:: bash\n\n    $ pip install jsonschema'[format]'\n\nBe aware that the mere presence of these dependencies – or even the specification of ``format`` checks in a schema – do *not* activate format checks (as per the specification).\nPlease read the `format validation documentation <https://python-jsonschema.readthedocs.io/en/latest/validate/#validating-formats>`_ for further details.\n\nAbout\n-----\n\nI'm Julian Berman.\n\n``jsonschema`` is on `GitHub <https://github.com/python-jsonschema/jsonschema>`_.\n\nGet in touch, via GitHub or otherwise, if you've got something to contribute, it'd be most welcome!\n\nIf you feel overwhelmingly grateful, you can also `sponsor me <https://github.com/sponsors/Julian/>`_.\n\nAnd for companies who appreciate ``jsonschema`` and its continued support and growth, ``jsonschema`` is also now supportable via `TideLift <https://tidelift.com/subscription/pkg/pypi-jsonschema?utm_source=pypi-jsonschema&utm_medium=referral&utm_campaign=readme>`_.\n\n\nRelease Information\n-------------------\n\nv4.26.0\n=======\n\n* Decrease import time by delaying importing of ``urllib.request`` (#1416).\n",
        "description_content_type": "text/x-rst",
        "keywords": [
          "data validation",
          "json",
          "json schema",
          "jsonschema",
          "validation"
        ],
        "author_email": "Julian Berman <Julian+jsonschema@GrayVines.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Operating System :: OS Independent",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Topic :: File Formats :: JSON",
          "Topic :: File Formats :: JSON :: JSON Schema"
        ],
        "requires_dist": [
          "attrs>=22.2.0",
          "jsonschema-specifications>=2023.03.6",
          "referencing>=0.28.4",
          "rpds-py>=0.25.0",
          "fqdn; extra == 'format'",
          "idna; extra == 'format'",
          "isoduration; extra == 'format'",
          "jsonpointer>1.13; extra == 'format'",
          "rfc3339-validator; extra == 'format'",
          "rfc3987; extra == 'format'",
          "uri-template; extra == 'format'",
          "webcolors>=1.11; extra == 'format'",
          "fqdn; extra == 'format-nongpl'",
          "idna; extra == 'format-nongpl'",
          "isoduration; extra == 'format-nongpl'",
          "jsonpointer>1.13; extra == 'format-nongpl'",
          "rfc3339-validator; extra == 'format-nongpl'",
          "rfc3986-validator>0.1.0; extra == 'format-nongpl'",
          "rfc3987-syntax>=1.1.0; extra == 'format-nongpl'",
          "uri-template; extra == 'format-nongpl'",
          "webcolors>=24.6.0; extra == 'format-nongpl'"
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/python-jsonschema/jsonschema",
          "Documentation, https://python-jsonschema.readthedocs.io/",
          "Issues, https://github.com/python-jsonschema/jsonschema/issues/",
          "Funding, https://github.com/sponsors/Julian",
          "Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema?utm_source=pypi-jsonschema&utm_medium=referral&utm_campaign=pypi-link",
          "Changelog, https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst",
          "Source, https://github.com/python-jsonschema/jsonschema"
        ],
        "provides_extra": [
          "format",
          "format-nongpl"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309",
          "hashes": {
            "sha256": "c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "attrs",
        "version": "26.1.0",
        "summary": "Classes Without Boilerplate",
        "description": "<p align=\"center\">\n  <a href=\"https://www.attrs.org/\">\n    <img src=\"https://raw.githubusercontent.com/python-attrs/attrs/main/docs/_static/attrs_logo.svg\" width=\"35%\" alt=\"attrs\" />\n  </a>\n</p>\n\n\n*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)).\nTrusted by NASA for [Mars missions since 2020](https://github.com/readme/featured/nasa-ingenuity-helicopter)!\n\nIts main goal is to help you to write **concise** and **correct** software without slowing down your code.\n\n\n## Sponsors\n\n*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek).\nEspecially those generously supporting us at the *The Organization* tier and higher:\n\n<!-- sponsor-break-begin -->\n\n<p align=\"center\">\n\n<!-- [[[cog\nimport pathlib, tomllib\n\nfor sponsor in tomllib.loads(pathlib.Path(\"pyproject.toml\").read_text())[\"tool\"][\"sponcon\"][\"sponsors\"]:\n      print(f'<a href=\"{sponsor[\"url\"]}\"><img title=\"{sponsor[\"title\"]}\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/{sponsor[\"img\"]}\" width=\"190\" /></a>')\n]]] -->\n<a href=\"https://www.variomedia.de/\"><img title=\"Variomedia AG\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/Variomedia.svg\" width=\"190\" /></a>\n<a href=\"https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek\"><img title=\"Tidelift\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/Tidelift.svg\" width=\"190\" /></a>\n<a href=\"https://kraken.tech/\"><img title=\"Kraken Tech\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/Kraken.svg\" width=\"190\" /></a>\n<a href=\"https://privacy-solutions.org/\"><img title=\"Privacy Solutions\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/Privacy-Solutions.svg\" width=\"190\" /></a>\n<a href=\"https://filepreviews.io/\"><img title=\"FilePreviews\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/FilePreviews.svg\" width=\"190\" /></a>\n<a href=\"https://www.testmuai.com/?utm_medium=sponsor&utm_source=structlog\"><img title=\"TestMu AI\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/TestMu-AI.svg\" width=\"190\" /></a>\n<a href=\"https://polar.sh/\"><img title=\"Polar\" src=\"https://www.attrs.org/en/26.1.0/_static/sponsors/Polar.svg\" width=\"190\" /></a>\n<!-- [[[end]]] -->\n\n</p>\n\n<!-- sponsor-break-end -->\n\n<p align=\"center\">\n   <strong>Please consider <a href=\"https://github.com/sponsors/hynek\">joining them</a> to help make <em>attrs</em>’s maintenance more sustainable!</strong>\n</p>\n\n<!-- teaser-end -->\n\n## Example\n\n*attrs* gives you a class decorator and a way to declaratively define the attributes on that class:\n\n<!-- code-begin -->\n\n```pycon\n>>> from attrs import asdict, define, make_class, Factory\n\n>>> @define\n... class SomeClass:\n...     a_number: int = 42\n...     list_of_numbers: list[int] = Factory(list)\n...\n...     def hard_math(self, another_number):\n...         return self.a_number + sum(self.list_of_numbers) * another_number\n\n\n>>> sc = SomeClass(1, [1, 2, 3])\n>>> sc\nSomeClass(a_number=1, list_of_numbers=[1, 2, 3])\n\n>>> sc.hard_math(3)\n19\n>>> sc == SomeClass(1, [1, 2, 3])\nTrue\n>>> sc != SomeClass(2, [3, 2, 1])\nTrue\n\n>>> asdict(sc)\n{'a_number': 1, 'list_of_numbers': [1, 2, 3]}\n\n>>> SomeClass()\nSomeClass(a_number=42, list_of_numbers=[])\n\n>>> C = make_class(\"C\", [\"a\", \"b\"])\n>>> C(\"foo\", \"bar\")\nC(a='foo', b='bar')\n```\n\nAfter *declaring* your attributes, *attrs* gives you:\n\n- a concise and explicit overview of the class's attributes,\n- a nice human-readable `__repr__`,\n- equality-checking methods,\n- an initializer,\n- and much more,\n\n*without* writing dull boilerplate code again and again and *without* runtime performance penalties.\n\n---\n\nThis example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0.\nThe classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**.\n\nCheck out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation!\n\n\n### Hate Type Annotations!?\n\nNo problem!\nTypes are entirely **optional** with *attrs*.\nSimply assign `attrs.field()` to the attributes instead of annotating them with types:\n\n```python\nfrom attrs import define, field\n\n@define\nclass SomeClass:\n    a_number = field(default=42)\n    list_of_numbers = field(factory=list)\n```\n\n\n## Data Classes\n\nOn the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*).\nIn practice it does a lot more and is more flexible.\nFor instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger.\n\nFor more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice.\n\n\n## Project Information\n\n- [**Changelog**](https://www.attrs.org/en/stable/changelog.html)\n- [**Documentation**](https://www.attrs.org/)\n- [**PyPI**](https://pypi.org/project/attrs/)\n- [**Source Code**](https://github.com/python-attrs/attrs)\n- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md)\n- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs)\n- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs)\n\n\n### *attrs* for Enterprise\n\nAvailable as part of the [Tidelift Subscription](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek).\n\nThe maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications.\nSave time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.\n\n## Release Information\n\n### Backwards-incompatible Changes\n\n- Field aliases are now resolved *before* calling `field_transformer`, so transformers receive fully populated `Attribute` objects with usable `alias` values instead of `None`.\n  The new `Attribute.alias_is_default` flag indicates whether the alias was auto-generated (`True`) or explicitly set by the user (`False`).\n  [#1509](https://github.com/python-attrs/attrs/issues/1509)\n\n\n### Changes\n\n- Fix type annotations for `attrs.validators.optional()`, so it no longer rejects tuples with more than one validator.\n  [#1496](https://github.com/python-attrs/attrs/issues/1496)\n- The `attrs.validators.disabled()` contextmanager can now be nested.\n  [#1513](https://github.com/python-attrs/attrs/issues/1513)\n- Frozen classes can set `on_setattr=attrs.setters.NO_OP` in addition to `None`.\n  [#1515](https://github.com/python-attrs/attrs/issues/1515)\n- It's now possible to pass *attrs* **instances** in addition to *attrs* **classes** to `attrs.fields()`.\n  [#1529](https://github.com/python-attrs/attrs/issues/1529)\n\n\n\n---\n\n[Full changelog →](https://www.attrs.org/en/stable/changelog.html)\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "attribute",
          "boilerplate",
          "class"
        ],
        "author_email": "Hynek Schlawack <hs@ox.cx>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Typing :: Typed"
        ],
        "requires_python": ">=3.9",
        "project_url": [
          "Documentation, https://www.attrs.org/",
          "Changelog, https://www.attrs.org/en/stable/changelog.html",
          "GitHub, https://github.com/python-attrs/attrs",
          "Funding, https://github.com/sponsors/hynek",
          "Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe",
          "hashes": {
            "sha256": "98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "jsonschema-specifications",
        "version": "2025.9.1",
        "summary": "The JSON Schema meta-schemas and vocabularies, exposed as a Registry",
        "description": "=============================\n``jsonschema-specifications``\n=============================\n\n|PyPI| |Pythons| |CI| |ReadTheDocs|\n\nJSON support files from the `JSON Schema Specifications <https://json-schema.org/specification.html>`_ (metaschemas, vocabularies, etc.), packaged for runtime access from Python as a `referencing-based Schema Registry <https://referencing.readthedocs.io/en/stable/api/#referencing.Registry>`_.\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/jsonschema-specifications.svg\n  :alt: PyPI version\n  :target: https://pypi.org/project/jsonschema-specifications/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/jsonschema-specifications.svg\n  :alt: Supported Python versions\n  :target: https://pypi.org/project/jsonschema-specifications/\n\n.. |CI| image:: https://github.com/python-jsonschema/jsonschema-specifications/workflows/CI/badge.svg\n  :alt: Build status\n  :target: https://github.com/python-jsonschema/jsonschema-specifications/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/jsonschema-specifications/badge/?version=stable&style=flat\n  :alt: ReadTheDocs status\n  :target: https://jsonschema-specifications.readthedocs.io/en/stable/\n",
        "description_content_type": "text/x-rst",
        "keywords": [
          "data validation",
          "json",
          "json schema",
          "jsonschema",
          "validation"
        ],
        "author_email": "Julian Berman <Julian+jsonschema-specifications@GrayVines.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Operating System :: OS Independent",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Topic :: File Formats :: JSON",
          "Topic :: File Formats :: JSON :: JSON Schema"
        ],
        "requires_dist": [
          "referencing>=0.31.0"
        ],
        "requires_python": ">=3.9",
        "project_url": [
          "Documentation, https://jsonschema-specifications.readthedocs.io/",
          "Homepage, https://github.com/python-jsonschema/jsonschema-specifications",
          "Issues, https://github.com/python-jsonschema/jsonschema-specifications/issues/",
          "Funding, https://github.com/sponsors/Julian",
          "Tidelift, https://tidelift.com/subscription/pkg/pypi-jsonschema-specifications?utm_source=pypi-jsonschema-specifications&utm_medium=referral&utm_campaign=pypi-link",
          "Source, https://github.com/python-jsonschema/jsonschema-specifications"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/09/a6/bd32357e6cc1ecb473afd78193d7231724f284435d2db25696ecfaaa1503/onnx-1.22.0-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=955e02e1f6d385b53d52f9cd7b9cdf5caf417c300bcfe3c64c6d542be763845b",
          "hashes": {
            "sha256": "955e02e1f6d385b53d52f9cd7b9cdf5caf417c300bcfe3c64c6d542be763845b"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "onnx",
        "version": "1.22.0",
        "summary": "Open Neural Network Exchange",
        "description": "<!--\nCopyright (c) ONNX Project Contributors\n\nSPDX-License-Identifier: Apache-2.0\n-->\n\n<p align=\"center\"><img width=\"40%\" src=\"https://github.com/onnx/onnx/raw/main/docs/onnx-horizontal-color.png\" /></p>\n\n[![PyPI - Version](https://img.shields.io/pypi/v/onnx.svg)](https://pypi.org/project/onnx)\n[![CI](https://github.com/onnx/onnx/actions/workflows/main.yml/badge.svg)](https://github.com/onnx/onnx/actions/workflows/main.yml)\n[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3313/badge)](https://bestpractices.coreinfrastructure.org/projects/3313)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/onnx/onnx/badge)](https://api.securityscorecards.dev/projects/github.com/onnx/onnx)\n[![SLSA 2](https://slsa.dev/images/gh-badge-level2.svg)](https://slsa.dev)\n[![REUSE compliant](https://api.reuse.software/badge/github.com/onnx/onnx)](https://api.reuse.software/info/github.com/onnx/onnx)\n[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)\n[![abi3 compatible](https://img.shields.io/badge/abi3-compatible-brightgreen)](https://docs.python.org/3/c-api/stable.html)\n\n[Open Neural Network Exchange (ONNX)](https://onnx.ai) is an open ecosystem that empowers AI developers\nto choose the right tools as their project evolves. ONNX provides an open source format for AI models, both deep learning and traditional ML. It defines an extensible computation graph model, as well as definitions of built-in operators and standard\ndata types. Currently we focus on the capabilities needed for inferencing (scoring).\n\nONNX is [widely supported](http://onnx.ai/supported-tools) and can be found in many frameworks, tools, and hardware. Enabling interoperability between different frameworks and streamlining the path from research to production helps increase the speed of innovation in the AI community. We invite the community to join us and further evolve ONNX.\n\n\n# Use ONNX\n\n* [Documentation of ONNX Python Package](https://onnx.ai/onnx/)\n* [Tutorials for creating ONNX models](https://github.com/onnx/tutorials)\n* [Pre-trained ONNX models](https://github.com/onnx/models)\n\n# Learn about the ONNX spec\n\n* [Overview](https://github.com/onnx/onnx/blob/main/docs/Overview.md)\n* [ONNX intermediate representation spec](https://github.com/onnx/onnx/blob/main/docs/IR.md)\n* [Versioning principles of the spec](https://github.com/onnx/onnx/blob/main/docs/Versioning.md)\n* [Operators documentation](https://github.com/onnx/onnx/blob/main/docs/Operators.md)\n* [Operators documentation](https://onnx.ai/onnx/operators/index.html) (latest release)\n* [Python API Overview](https://github.com/onnx/onnx/blob/main/docs/PythonAPIOverview.md)\n\n# Programming utilities for working with ONNX Graphs\n\n* [Shape and Type Inference](https://github.com/onnx/onnx/blob/main/docs/ShapeInference.md)\n* [Graph Optimization](https://github.com/onnx/optimizer)\n* [Opset Version Conversion](https://github.com/onnx/onnx/blob/main/docs/docsgen/source/api/version_converter.md)\n\n# Contribute\n\nONNX is a community project and the open governance model is described [here](https://github.com/onnx/onnx/blob/main/community/readme.md). We encourage you to join the effort and contribute feedback, ideas, and code. You can participate in the [Special Interest Groups](https://github.com/onnx/onnx/blob/main/community/sigs.md) and [Working Groups](https://github.com/onnx/onnx/blob/main/community/working-groups.md) to shape the future of ONNX.\n\nCheck out our [contribution guide](https://github.com/onnx/onnx/blob/main/CONTRIBUTING.md) to get started.\n\nIf you think some operator should be added to ONNX specification, please read\n[this document](https://github.com/onnx/onnx/blob/main/docs/AddNewOp.md).\n\n# Community meetings\n\nThe schedules of the regular meetings of the Steering Committee, the working groups and the SIGs can be found [here](https://onnx.ai/calendar)\n\nCommunity Meetups are held at least once a year. Content from previous community meetups are at:\n\n* 2020.04.09 <https://lf-aidata.atlassian.net/wiki/spaces/DL/pages/14091402/LF+AI+Day+-ONNX+Community+Virtual+Meetup+-+Silicon+Valley+-+2020+April+9>\n* 2020.10.14 <https://lf-aidata.atlassian.net/wiki/spaces/DL/pages/14092138/LF+AI+Day+-+ONNX+Community+Workshop+-+2020+October+14>\n* 2021.03.24 <https://lf-aidata.atlassian.net/wiki/spaces/DL/pages/14092424/Instructions+for+Event+Hosts+-+LF+AI+Data+Day+-+ONNX+Virtual+Community+Meetup+-+March+2021>\n* 2021.10.21 <https://lf-aidata.atlassian.net/wiki/spaces/DL/pages/14093194/LF+AI+Data+Day+ONNX+Community+Virtual+Meetup+-+October+2021>\n* 2022.06.24 <https://lf-aidata.atlassian.net/wiki/spaces/DL/pages/14093969/ONNX+Community+Day+-+2022+June+24>\n* 2023.06.28 <https://lf-aidata.atlassian.net/wiki/spaces/DL/pages/14094507/ONNX+Community+Day+2023+-+June+28>\n\n# Discuss\n\nWe encourage you to open [Issues](https://github.com/onnx/onnx/issues), or use [Slack](https://lfaifoundation.slack.com/) (If you have not joined yet, please use this [link](https://join.slack.com/t/lfaifoundation/shared_invite/zt-3wx5vohc3-MeSYi3_dscb~u~cqs7zlPg) to join the group) for more real-time discussion.\n\n# Follow Us\n\nStay up to date with the latest ONNX news. [[Facebook](https://www.facebook.com/onnxai/)] [[Twitter/X](https://twitter.com/onnxai)]\n\n# Roadmap\n\nA roadmap process takes place every year. More details can be found [here](https://github.com/onnx/steering-committee/tree/main/roadmap)\n\n# Installation\n\nONNX released packages are published in PyPi.\n\n```sh\npip install onnx # or pip install onnx[reference] for optional reference implementation dependencies\n```\n\n[ONNX weekly packages](https://pypi.org/project/onnx-weekly/) are published in PyPI to enable experimentation and early testing.\n\nDetailed install instructions, including Common Build Options and Common Errors can be found [here](https://github.com/onnx/onnx/blob/main/INSTALL.md)\n\n# Python ABI3 Compatibility\n\nThis package provides [abi3](https://docs.python.org/3/c-api/stable.html)-compatible wheels, allowing a single binary wheel to work across multiple Python versions (from 3.12 onwards).\n\n\n# Testing\n\nONNX uses [pytest](https://docs.pytest.org) as test driver. In order to run tests, you will first need to install `pytest`:\n\n```sh\npip install pytest\n```\n\nAfter installing pytest, use the following command to run tests.\n\n```sh\npytest\n```\n\n# Development\n\nCheck out the [contributor guide](https://github.com/onnx/onnx/blob/main/CONTRIBUTING.md) for instructions.\n\n# Reproducible Builds (Linux)\n\nThis project provides reproducible builds for Linux.\n\nA *reproducible build* means that the same source code will always produce identical binary outputs, no matter who builds it or where it is built.\n\nTo achieve this, we use the [`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/docs/source-date-epoch/) standard. This ensures that build timestamps and other time-dependent information are fixed, making the output bit-for-bit identical across different environments.\n\n### Why this matters\n- **Transparency**: Anyone can verify that the distributed binaries were created from the published source code.\n- **Security**: Prevents tampering or hidden changes in the build process.\n- **Trust**: Users can be confident that the binaries they download are exactly what the maintainers intended.\n\nIf you prefer, you can use the prebuilt reproducible binaries instead of building from source yourself.\n\n# License\n\n[Apache License v2.0](LICENSE)\n\n# Trademark\nCheckout [https://trademarks.justia.com](https://trademarks.justia.com/877/25/onnx-87725026.html) for the trademark.\n\n[General rules of the Linux Foundation on Trademark usage](https://www.linuxfoundation.org/legal/trademark-usage)\n\n# Code of Conduct\n\n[ONNX Open Source Code of Conduct](https://onnx.ai/codeofconduct.html)\n",
        "description_content_type": "text/markdown",
        "author_email": "ONNX Contributors <onnx-technical-discuss@lists.lfaidata.foundation>",
        "classifier": [
          "Programming Language :: Python :: 3"
        ],
        "requires_dist": [
          "numpy>=1.23.2",
          "protobuf>=4.25.1",
          "typing_extensions>=4.15.0",
          "ml_dtypes>=0.5.4",
          "Pillow; extra == \"reference\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://onnx.ai/",
          "Repository, https://github.com/onnx/onnx"
        ],
        "provides_extra": [
          "reference"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/12/ce/3bd161619ba6829d8059af3a99e2ca5f2feb2684415b91be72d825e86969/onnxsim-0.7.3-cp312-abi3-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=88f40b0d3f434c19bf0629c17eb5aa3c8f788085b201c6ae8cda9d41b83ed7e3",
          "hashes": {
            "sha256": "88f40b0d3f434c19bf0629c17eb5aa3c8f788085b201c6ae8cda9d41b83ed7e3"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "onnxsim",
        "version": "0.7.3",
        "dynamic": [
          "license-file"
        ],
        "summary": "Simplify your ONNX model",
        "description": "# ONNX Simplifier\n\n[![PyPI version](https://img.shields.io/pypi/v/onnxsim.svg)](https://pypi.python.org/pypi/onnxsim/)\n[![PyPI pyversions](https://img.shields.io/pypi/pyversions/onnxsim.svg)](https://pypi.python.org/pypi/onnxsim/)\n[![PyPI license](https://img.shields.io/pypi/l/onnxsim.svg)](https://pypi.python.org/pypi/onnxsim/)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/onnxsim/onnxsim/pulls)\n[![Discord](https://img.shields.io/discord/1475920534847099121?logo=discord)](https://discord.gg/W3ht33v4)\n\n_ONNX is great, but sometimes too complicated._\n\n## Background\n\nOne day I wanted to export the following simple reshape operation to ONNX:\n\n```python\nimport torch\n\n\nclass JustReshape(torch.nn.Module):\n    def __init__(self):\n        super(JustReshape, self).__init__()\n\n    def forward(self, x):\n        return x.view((x.shape[0], x.shape[1], x.shape[3], x.shape[2]))\n\n\nnet = JustReshape()\nmodel_name = 'just_reshape.onnx'\ndummy_input = torch.randn(2, 3, 4, 5)\ntorch.onnx.export(net, dummy_input, model_name, input_names=['input'], output_names=['output'])\n```\n\nThe input shape in this model is static, so what I expected is\n\n![simple_reshape](imgs/simple_reshape.png)\n\nHowever, I got the following complicated model instead:\n\n![complicated_reshape](imgs/complicated_reshape.png)\n\n## Our solution\n\nONNX Simplifier is presented to simplify the ONNX model. It infers the whole computation graph\nand then replaces the redundant operators with their constant outputs (a.k.a. constant folding).\n\n## Features\n\nAt its core onnxsim runs a fixed point of shape inference, graph optimization and\nconstant folding until the model stops changing. Around that it offers:\n\n- **Constant folding.** Evaluates the constant parts of the graph and replaces\n  redundant operators with their computed outputs. By default initializers count\n  as constants; pass `--initializers-as-non-constants` (Python:\n  `initializers_as_constants=False`) to keep weights as tunable tensors so nodes\n  rooted only at initializers — and value-baking fusions such as fuse BatchNorm\n  into Conv — are left untouched.\n- **Graph optimization passes.** Runs onnx-optimizer's fusions and eliminations\n  (e.g. fuse BatchNorm into Conv). List them with\n  `onnxsim --list-default-optimizers`; skip all or some with\n  `--skip-optimization [pass ...]`.\n- **Shape inference.** Propagates tensor shapes through the graph — including\n  partial shape evaluation via ONNX data propagation — to unlock more folding.\n- **Correctness checking.** Optionally validates the simplified model against the\n  original on `N` random inputs (the positional `check_n` argument, with\n  configurable `--check-rtol`/`--check-atol`). Choose how the generated inputs are\n  filled with `--input-fill` (Python: `input_fill=`): `random` (uniform `[0, 1)`,\n  the default), `ones`, `zeros` or `arange`.\n- **Fixed and dynamic input shapes.** Pin a dynamic model's shapes for\n  simplification/checking with `--overwrite-input-shape` and `--test-input-shape`.\n- **[Custom operators](#custom-operators).** Keeps custom ops (TensorRT plugins,\n  vendor domains, or custom ops in the default ONNX domain) unchanged and picks\n  up schemas registered via `onnx.defs.register_schema` automatically.\n- **[Opset conversion](#changing-the-opset-version).** Upgrade or downgrade the\n  model's opset while simplifying with `--target-opset`.\n- **Function inlining.** Flatten the model's local (model-defined) functions into\n  the main graph before simplifying with `--inline-functions` (Python:\n  `inline_functions=True`), so the optimizer, shape inference and constant folding\n  can see through function calls. Schema-defined (built-in) functions are left\n  alone.\n- **[Custom rewriters](#custom-rewriters).** Plug your own rewriting logic into\n  the fixed point with `custom_rewriter`, or express data-only `FunctionProto`\n  rules that also run from the C and Rust bindings.\n- **Subgraph simplification.** Simplify `If`/`Loop`/`Scan` subgraph bodies too\n  with `--include-subgraph`.\n- **Large-model handling.** Guard against blow-up from ops like `Tile`/\n  `ConstantOfShape` (`--no-large-tensor`), read and write external-data models,\n  and eliminate unused outputs (`--unused-output`).\n- **Many ways to run it.** A zero-install [web version](#web-version), a Python\n  package and `onnxsim` CLI, a C API, and a Rust wrapper — all sharing the same\n  C++ core. onnxruntime is optional; onnxsim falls back to the onnx reference\n  evaluator when it isn't installed.\n\n## Getting started\n\n### Web version\n\nWe have published ONNX Simplifier on [GitHub pages](https://onnxsim.github.io/onnxsim/). It works out of the box and **doesn't need any installation**. Note that it runs in the browser locally and your model is completely safe.\n\n### Python version\n\n\n```\npip3 install -U pip && pip3 install onnxsim\n```\n\nThen\n\n```\nonnxsim input_onnx_model output_onnx_model\n```\n\nFor more advanced features, try the following command for help message\n\n```\nonnxsim -h\n```\n\n### Node.js version\n\nThe same WebAssembly build backing the web version above is also published as\nan npm package, for JavaScript tooling that wants ONNX simplification without\na native build step or a Python runtime. See\n[`npm/onnxsim/README.md`](npm/onnxsim/README.md) for usage.\n\n```\nnpm install onnxsim\n```\n\n## Demonstration\n\nAn overall comparison between\n[a complicated model](https://github.com/JDAI-CV/DNNLibrary/issues/17#issuecomment-455934190)\nand its simplified version:\n\n![Comparison between old model and new model](imgs/comparison.png)\n\n## In-script workflow\n\nIf you would like to embed ONNX simplifier python package in another script, it is just that simple.\n\n```python\nimport onnx\nfrom onnxsim import simplify\n\n# load your predefined ONNX model\nmodel = onnx.load(filename)\n\n# convert model\nmodel_simp, check = simplify(model)\n\nassert check, \"Simplified ONNX model could not be validated\"\n\n# use model_simp as a standard ONNX model object\n```\n\nYou can see more details of the API in [onnxsim/onnx_simplifier.py](onnxsim/onnx_simplifier.py)\n\n## Custom operators\n\nModels that contain custom operators, such as TensorRT plugins\n(`BatchedNMS_TRT`, `EfficientNMS_TRT`, ...), are supported. onnxsim keeps these\nops unchanged and simplifies the rest of the graph around them. This works\nwhether the custom op lives in a vendor-specific domain (e.g. `TRT`) or in the\ndefault ONNX domain, so you no longer need to manually move it into a custom\ndomain to get past validation (issues\n[#107](https://github.com/onnxsim/onnxsim/issues/107) and\n[#220](https://github.com/onnxsim/onnxsim/issues/220)).\n\nIf you describe your custom operator to ONNX with\n[`onnx.defs.register_schema`](https://onnx.ai/onnx/api/defs.html), onnxsim\npicks that schema up automatically: onnxsim links its own copy of ONNX, so its\noperator registry is separate from the `onnx` Python module's, and every\n`simplify` call imports the schemas you registered into onnxsim's registry\nbefore validating the model (issue\n[#326](https://github.com/onnxsim/onnxsim/issues/326)). You can also trigger the\nimport explicitly with `onnxsim.import_onnx_schemas()`, or turn the automatic\nimport off with `onnxsim.simplify(model, import_custom_schemas=False)` (CLI:\n`--skip-schema-import`).\n\n```python\nimport onnx\nimport onnxsim\n\n# Teach ONNX about your custom operator.\nonnx.defs.register_schema(my_op_schema)\n\n# simplify() imports the schema into onnxsim automatically.\nmodel_simp, check_ok = onnxsim.simplify(model)\n```\n\nIf a registered schema also has a type/shape-inference function (set via\n`onnx.defs.OpSchema.set_type_and_shape_inference_function`), onnxsim registers a\ntrampoline that calls it back through `onnx.shape_inference.infer_node_outputs`\nduring simplification, so the custom operator's output shapes are inferred too.\nCustom operators without an inference function are still imported; shape\ninference simply flows past them.\n\n## Changing the opset version\n\nYou can upgrade (or downgrade) the model's opset version while simplifying. Pass\n`target_opset_version` to `simplify` (CLI: `--target-opset`) and onnxsim converts\nthe default ONNX domain to that opset — using onnx's own version converter —\nbefore running the simplification, so any redundant nodes the conversion\nintroduces get cleaned up too.\n\n```python\nimport onnx\nimport onnxsim\n\nmodel = onnx.load(filename)\n\n# Convert the model to opset 18 and simplify it.\nmodel_simp, check = onnxsim.simplify(model, target_opset_version=18)\n```\n\nOn the command line:\n\n```\nonnxsim input_onnx_model output_onnx_model --target-opset 18\n```\n\nWhen `target_opset_version` is left unset (the default), the model's opset\nversion is preserved.\n\nThe conversion runs inside onnxsim's C++ core, so every binding shares it —\nthe Python package, the C API and its Rust wrapper (`Options::target_opset_version`),\nthe standalone `onnxsim` binary (`--target-opset`), and the\n[web version](https://onnxsim.github.io/onnxsim/) (the \"target opset version\"\nfield).\n\n## Constant folding on the GPU (CUDA execution provider)\n\nonnxsim constant-folds by running the foldable sub-graphs through ONNX Runtime.\nBy default it uses the CPU execution provider, which is always available and\ngives deterministic results. For large models it can be much faster to fold on\nan NVIDIA GPU. Pass `providers` to `simplify` to choose the ONNX Runtime\n[execution providers](https://onnxruntime.ai/docs/execution-providers/), in\npriority order:\n\n```python\nimport onnx\nimport onnxsim\n\nmodel = onnx.load(filename)\n\n# Fold on the GPU, falling back to CPU for ops CUDA cannot run.\nmodel_simp, check = onnxsim.simplify(\n    model, providers=[\"CUDAExecutionProvider\", \"CPUExecutionProvider\"]\n)\n```\n\nOn the command line:\n\n```\n# Explicit provider list (priority order):\nonnxsim input_onnx_model output_onnx_model \\\n    --providers CUDAExecutionProvider CPUExecutionProvider\n\n# Or the shortcut, equivalent to the line above:\nonnxsim input_onnx_model output_onnx_model --cuda\n```\n\nKeeping `CPUExecutionProvider` last is recommended: ONNX Runtime falls back to\nit for any operator the GPU provider cannot run. Each provider entry may also be\na `(name, options)` tuple, exactly as\n[`onnxruntime.InferenceSession`](https://onnxruntime.ai/docs/api/python/api_summary.html)\naccepts it, for example to pin a specific `device_id`:\n\n```python\nmodel_simp, check = onnxsim.simplify(\n    model,\n    providers=[(\"CUDAExecutionProvider\", {\"device_id\": 1}), \"CPUExecutionProvider\"],\n)\n```\n\nThe CUDA execution provider requires the GPU build of ONNX Runtime\n(`pip install onnxruntime-gpu`). If you request a provider the installed ONNX\nRuntime does not offer, onnxsim raises a `ValueError` listing the available\nproviders instead of silently folding on the CPU. When `providers` is left\nunset (the default), folding runs on the CPU.\n\n## Profiling the optimization\n\nSimplification alternates a handful of transforms -- shape inference, the\nonnx-optimizer passes, constant folding and any custom rewriter -- to a joint\nfixed point. To see where the time and memory go, pass `profile` to `simplify`\n(or `--profile` on the command line). onnxsim then measures each fixed-point\nfunction's wall-clock and CPU duration and the peak resident memory reached while\nit runs, prints a per-function summary, and writes a\n[Chrome Trace Event Format](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview)\nJSON. Open that file in `chrome://tracing` or at\n[ui.perfetto.dev](https://ui.perfetto.dev) to view it as a **flame graph**: the\nnested fixed points appear as parent spans and the individual transforms as their\nchildren, one box per invocation, annotated with peak RSS and CPU time.\n\nConstant folding's actual work is running the model through ONNX Runtime, so\nthose session runs are profiled too. Each fold group appears under `FoldConstant`\nas an `OrtSession` span, which times running that group's sub-model through the\ninference executor. This works for every binding, since it wraps the one call\nsite common to both the built-in ONNX Runtime executor and the Python executor\nthat `simplify()` uses. When the built-in executor runs, the `OrtSession` span is\nsplit further into `OrtSessionInit` (building the session, where ONNX Runtime\nloads the graph and usually the dominant cost) and `OrtSessionRun` (the\ninference). This makes it easy to see how much of simplification time is spent\ninside ONNX Runtime versus in shape inference and the optimizer passes.\n\n```python\nimport onnx\nimport onnxsim\n\nmodel = onnx.load(filename)\n\n# Write the trace to profile.json (open it in chrome://tracing or ui.perfetto.dev).\nmodel_simp, check = onnxsim.simplify(model, profile=\"profile.json\")\n```\n\nOn the command line:\n\n```\n# Give a path, or omit it to use onnxsim_profile.json in the current directory.\nonnxsim input_onnx_model output_onnx_model --profile profile.json\n```\n\nThe printed summary looks like:\n\n```\nonnxsim profiling summary (per fixed-point function)\n-------------------------------------------------------------------------------------\nfunction                calls     wall(ms)      cpu(ms) max wall(ms)    peak(MiB)\n-------------------------------------------------------------------------------------\nSimplify                    1       260.59       270.93       260.59       112.95\n  Pipeline                  3       259.75       269.67       100.76       112.94\n    OptAndShape             3       158.63       165.13        53.20       101.43\n    FoldConstant            3       100.36       103.78        47.69       112.93\n      Optimize              3       112.56       116.99        37.77       101.42\n      InferShapes           3        45.46        47.10        15.22        78.68\n      OrtSession           12        71.44        74.02        18.31       112.93\n        OrtSessionInit     12        58.02        60.11        15.90       112.93\n        OrtSessionRun      12         9.85        10.42         2.71       109.10\n-------------------------------------------------------------------------------------\n```\n\n(`OrtSessionInit`/`OrtSessionRun` show only when the built-in ONNX Runtime\nexecutor runs the fold; the Python `simplify()` path shows just `OrtSession`.)\n\n`calls` is how many times a function ran across all fixed-point rounds, `cpu(ms)`\nis process CPU time (it can exceed wall time when constant folding runs multiple\nONNX Runtime threads), and `peak(MiB)` is the highest process RSS observed while\nthat function was on the stack (sampled by a lightweight background thread; tune\nthe interval with `ONNXSIM_PROFILE_INTERVAL_MS`, default 5ms).\n\nProfiling is implemented in onnxsim's C++ core and is driven by the\n`ONNXSIM_PROFILE` environment variable (the Python `profile` argument and the\n`--profile` flag just set it), so it also works from the C ABI and the Rust\nwrapper without any code change:\n\n```\nONNXSIM_PROFILE=profile.json onnxsim input_onnx_model output_onnx_model\n```\n\n### ONNX Runtime's own session profiler\n\nThe `OrtSession` span above times each folding session as a whole. For a\nfiner, per-operator breakdown *inside* those sessions, turn on ONNX Runtime's\nown [session profiler](https://onnxruntime.ai/docs/performance/tune-performance/profiling-tools.html)\nwith `ort_profile` (or `--ort-profile`). This flips on\n`SessionOptions.enable_profiling` for the ONNX Runtime sessions onnxsim runs\nwhile simplifying (the constant-folding sessions, plus the correctness-check\nruns when `check_n > 0`), so each one writes ONNX Runtime's detailed per-kernel\nChrome trace:\n\n```python\n# Write onnxruntime session traces with the given file prefix.\nmodel_simp, check = onnxsim.simplify(model, ort_profile=\"ort_profile\")\n```\n\n```\nonnxsim input_onnx_model output_onnx_model --ort-profile ort_profile\n```\n\nThe value is a file **prefix**: ONNX Runtime writes one\n`<prefix>_<timestamp>.json` per session, so a run that folds in several batches\nproduces several files (open each in `chrome://tracing` or\n[ui.perfetto.dev](https://ui.perfetto.dev)). It is independent of `profile` --\nuse either, or both together (`profile` for onnxsim's pipeline, `ort_profile`\nfor what ONNX Runtime does inside each fold). Like `profile`, it is driven by an\nenvironment variable (`ONNXSIM_ORT_PROFILE`), so it works from every binding:\n\n```\nONNXSIM_ORT_PROFILE=ort_profile onnxsim input_onnx_model output_onnx_model\n```\n\n#### Merging it into onnxsim's trace\n\nRather than juggling separate files, `merge_ort_profile` (or `--merge-ort-profile`)\nsplices ONNX Runtime's per-operator events straight into onnxsim's `profile`\ntrace, so each `OrtSession` span gets ONNX Runtime's operator-level detail lined\nup beneath it on its own **onnxruntime** track -- one unified flame graph. It\nimplies `profile` (defaulting to `onnxsim_profile.json`), and ONNX Runtime's\nintermediate traces are captured to a temporary directory and removed after\nmerging, so nothing is left behind. This works for every executor, including the\nPython one `simplify()` uses:\n\n```python\nmodel_simp, check = onnxsim.simplify(model, profile=\"profile.json\", merge_ort_profile=True)\n```\n\n```\nonnxsim input_onnx_model output_onnx_model --profile profile.json --merge-ort-profile\n```\n\nThe merge is also available from the **C ABI, Rust and WASM bindings** (which\nfold through the built-in ONNX Runtime executor): set the `ONNXSIM_MERGE_ORT_PROFILE`\nenvironment variable and it is done entirely in onnxsim's C++ core -- no Python\nneeded. It implies `ONNXSIM_PROFILE` (defaulting to `onnxsim_profile.json`):\n\n```\nONNXSIM_MERGE_ORT_PROFILE=1 onnxsim input_onnx_model output_onnx_model\n```\n\n## Custom rewriters\n\nBeyond the built-in optimizer passes, you can plug your own graph rewriting\nlogic into simplification with the `custom_rewriter` parameter of `simplify()`.\nIt accepts a callable\n\n```python\nCallable[[onnx.ModelProto], Optional[onnx.ModelProto]]\n```\n\nthat either returns a rewritten model or mutates the model in place and returns\n`None`. The callable runs **inside** onnxsim's simplification fixed point,\ninterleaved with shape inference, the built-in optimizer and constant folding —\nso a rewrite can expose new optimization/folding opportunities and vice versa,\nand the whole pipeline iterates until it converges. onnxsim itself takes no\ndependency on any particular rewriting library; you bring your own.\n\n### Using onnx-rewriter (`onnxscript.rewriter`)\n\n[onnx-rewriter](https://github.com/microsoft/onnxscript) lets you express a\nsubgraph pattern and its replacement as plain Python and have it matched and\nrewritten anywhere in the model. Install it alongside onnxsim:\n\n```\npip3 install onnxscript\n```\n\nThen define a rule set and hand it to `simplify` via `custom_rewriter`. This\nexample fuses `MatMul` + `Add` into a single `Gemm`:\n\n```python\nimport onnx\nimport onnxsim\nfrom onnxscript.rewriter import pattern, rewrite\n\n# The subgraph to match: y = MatMul(x, w) + b\ndef matmul_add_pattern(op, x, w, b):\n    return op.Add(op.MatMul(x, w), b)\n\n# What to replace it with: y = Gemm(x, w, b)\ndef gemm_replacement(op, x, w, b):\n    return op.Gemm(x, w, b)\n\nrules = pattern.RewriteRuleSet(\n    [pattern.RewriteRule(matmul_add_pattern, gemm_replacement)]\n)\n\nmodel = onnx.load(\"model.onnx\")\nmodel_simp, check = onnxsim.simplify(\n    model,\n    custom_rewriter=lambda m: rewrite(m, pattern_rewrite_rules=rules),\n)\nassert check, \"Simplified ONNX model could not be validated\"\n```\n\nBecause the rewriter runs every round of the fixed point, the fused `Gemm`\nabove (and anything it unlocks) is folded and re-optimized together with the\nrest of the graph.\n\n### Skipping the copy when nothing is rewritten\n\nThe rewriter runs on every fixed-point round, including the final one where it\nhas nothing left to do — and the fixed point always ends with at least one\nsuch no-op round to detect convergence. onnxsim hands the model to your\ncallable as protobuf bytes and parses whatever comes back into a fresh\n`ModelProto`, so a rewriter that reports a rewritten model each round pays for\nthat copy even when it changed nothing.\n\nReturn `False` to tell onnxsim that this round rewrote nothing; onnxsim then\nkeeps the model it already has and skips the round-trip. Run the rules through\nonnx-ir's `PassManager` — `onnxscript.rewriter.RewritePass` wraps a rule set as\nan IR pass — and read the `modified` flag of the `PassResult` it returns. That\nflag is the reliable signal: an IR round-trip can reorder the serialized bytes\neven when no rule fires, so a byte comparison would falsely report a change.\n\n```python\nfrom onnxscript import ir\nfrom onnxscript.rewriter import RewritePass, pattern\n\nrules = pattern.RewriteRuleSet(\n    [pattern.RewriteRule(matmul_add_pattern, gemm_replacement)]\n)\nrewrite_pass = ir.passes.PassManager([RewritePass(rules)])\n\ndef apply_rules(model: onnx.ModelProto):\n    model_ir = ir.serde.deserialize_model(model)\n    result = rewrite_pass(model_ir)  # ir.passes.PassResult\n    if not result.modified:\n        return False  # no rule fired this round: skip the copy\n    return ir.serde.serialize_model(result.model)\n\nmodel_simp, check = onnxsim.simplify(model, custom_rewriter=apply_rules)\n```\n\nThe plain `lambda m: rewrite(m, pattern_rewrite_rules=rules)` form still works —\nit just always returns a model, so onnxsim copies it back every round.\n\nA few things to keep in mind:\n\n- **Keep the model schema-valid.** After each rewrite onnxsim validates the\n  model, so any op you introduce must be registered at the model's opset (for\n  example `Gelu` only exists from opset 20). Custom-domain ops are fine — see\n  [Custom operators](#custom-operators) for registering their schemas.\n- **Match the opset your rules target.** Convert the model to the opset your\n  patterns expect (e.g. with `onnx.version_converter`) before simplifying if\n  needed.\n- **You are not limited to onnx-rewriter.** Any callable works — a hand-written\n  pass over `model.graph`, an [onnx-graphsurgeon](https://github.com/NVIDIA/TensorRT/tree/main/tools/onnx-graphsurgeon)\n  edit, etc. — as long as it takes and returns a `ModelProto`.\n\n### From the C API and Rust\n\nThe custom rewriter lives in onnxsim's C++ core, so the C API and its Rust\nwrapper expose it too — the model is exchanged as serialized `ModelProto` bytes\nacross the boundary instead of as an `onnx.ModelProto` object. In Rust, use\n[`simplify_with_rewriter`](rust/onnxsim) (or `simplify_path_with_rewriter`) and\npass a closure `FnMut(&[u8]) -> Result<Option<Vec<u8>>, E>`: return `Ok(None)`\nwhen a round rewrote nothing (onnxsim skips the copy, matching the Python\n`False` sentinel), `Ok(Some(bytes))` for the rewritten model, or `Err(..)` to\nabort.\n\n```rust\nlet simplified = onnxsim::simplify_with_rewriter(\n    &model_bytes,\n    &onnxsim::Options::new(),\n    |bytes: &[u8]| {\n        // Decode `bytes`, rewrite, and return the new bytes — or Ok(None).\n        let _ = bytes;\n        Ok::<_, onnxsim::Error>(None)\n    },\n)?;\n```\n\nIn C, pass an `OnnxsimRewriteFn` callback (and an optional matching free\ncallback) to `onnxsim_simplify` / `onnxsim_simplify_path`; see\n[`onnxsim/capi/onnxsim_c_api.h`](onnxsim/capi/onnxsim_c_api.h) for the contract.\nThe only binding without it is the standalone CLI, which has no way to carry a\nuser callback.\n\n### FunctionProto rules (works in every binding)\n\n`custom_rewriter` takes a Python **callable**, so it only works from the Python\nbinding. If instead you express a rule as **pure data** — a `(pattern,\nreplacement)` pair of `onnx.FunctionProto` — onnxsim matches and applies it in\nits C++ core, so the *same* rule set also works from the C and Rust bindings\nwith no dependency on onnxscript. The pattern's inputs are wildcards that bind\nto graph values, its body is the subgraph to match, and its outputs are rewired\nto the replacement's outputs. Build the FunctionProtos with\n`onnx.parser.parse_function`:\n\n```python\nimport onnx\nimport onnxsim\nfrom onnx import parser\n\npattern = parser.parse_function(\"\"\"\n<domain: \"com.example\", opset_import: [\"\" : 18]>\nmatmul_add_pattern (x, w, b) => (y)\n{\n    t = MatMul(x, w)\n    y = Add(t, b)\n}\n\"\"\")\nreplacement = parser.parse_function(\"\"\"\n<domain: \"com.example\", opset_import: [\"\" : 18]>\ngemm_replacement (x, w, b) => (y)\n{\n    y = Gemm(x, w, b)\n}\n\"\"\")\n\nmodel = onnx.load(\"model.onnx\")\nmodel_simp, check = onnxsim.simplify(\n    model, function_rewrite_rules=[(pattern, replacement)]\n)\n```\n\nThis is enough to stand in for a hand-written onnxoptimizer pass: the rule above\nreproduces the built-in `fuse_matmul_add_bias_into_gemm` fusion. Skip the\nbuilt-in pass and let the rule do it:\n\n```python\nmodel_simp, check = onnxsim.simplify(\n    model,\n    skipped_optimizers=[\"fuse_matmul_add_bias_into_gemm\"],\n    function_rewrite_rules=[(pattern, replacement)],\n)\n```\n\nA node attribute written `@name` (an ONNX-text *ref attribute*) is an attribute\nwildcard: it binds the matched node's attribute and is substituted into the\nreplacement. `function_rewrite_rules` is mutually exclusive with\n`custom_rewriter`.\n\nMany of onnxscript's ready-made\n[common rewrite rules](https://github.com/microsoft/onnxscript/tree/main/onnxscript/rewriter/rules/common)\n(e.g. `matmul_add_to_gemm_rule`, `reshape_reshape_rule`) are simple structural\npattern→replacement rules that translate directly into a FunctionProto pair like\nthe one above; see `tests/test_function_rewriter_common_rules.py` for worked\nexamples that check parity against the onnxscript rule itself.\n\nInstead of writing the ONNX text by hand you can author each side as an\n`onnxscript.script` function and call `.to_function_proto()` — a Python-typed\nattribute parameter (`alpha: float`) even compiles to the `@name` wildcard form:\n\n```python\nfrom onnxscript import script\nfrom onnxscript import opset18 as op\n\n@script()\ndef matmul_add(a, b, c):\n    return op.Add(op.MatMul(a, b), c)\n\n@script()\ndef gemm(a, b, c):\n    return op.Gemm(a, b, c)\n\nmodel_simp, check = onnxsim.simplify(\n    model,\n    function_rewrite_rules=[(matmul_add.to_function_proto(), gemm.to_function_proto())],\n)\n```\n\nSee `tests/test_function_rewriter_onnxscript_script.py` for the `@script`\napproach, including the attribute-wildcard case. To reuse an *existing*\n`onnxscript` rule, its structural `pattern` method can be compiled to a\nFunctionProto through the same `@script` converter —\n`tests/test_function_rewriter_compile_rule.py` shows a small helper that does\nthis (paired with a simple replacement), noting the boundary where a rewrite\nthat derives attributes from the match can't be compiled that way.\n\nFrom C, call `onnxsim_simplify_with_rules` with the serialized FunctionProto\npairs (see `onnxsim/capi/onnxsim_c_api.h`); from Rust, use\n`Options::function_rewrite_rule(pattern_bytes, replacement_bytes)`.\n\n**Capabilities and limits of the built-in matcher.** It matches arbitrary\nconnected DAG patterns with one or more outputs, tries both operand orders for\nthe commutative binary ops (`Add`, `Mul`, …), matches attributes exactly or as\n`@name` wildcards, matches a pattern `Constant` against a byte-equal\ninitializer, and refuses a rewrite that would break a value consumed outside the\nmatch. It does **not** (in this version) traverse `If`/`Loop`/`Scan` subgraph\nbodies, handle variadic/optional-input arity mismatches, match >2-operand\ncommutative permutations, or evaluate attribute *predicates* — for those, the\nPython-only `onnxscript.rewriter` via `custom_rewriter` remains the richer\noption.\n\n## Projects Using ONNX Simplifier\n\nONNX Simplifier is most often used as a post-export cleanup step, run on a\nfreshly exported ONNX graph before it is handed to a mobile / edge / accelerator\nruntime converter. Projects that actively use it in their current export or\nconversion tooling include:\n\n* [YOLOX](https://github.com/Megvii-BaseDetection/YOLOX) (Megvii) — the ONNX export runs onnxsim by default (`--no-onnxsim` to disable)\n* [PaddleDetection](https://github.com/PaddlePaddle/PaddleDetection) (PaddlePaddle) — simplifies exported detectors (PP-YOLOE, PicoDet, RT-DETR, …) with onnxsim before deployment\n* [X2Paddle](https://github.com/PaddlePaddle/X2Paddle) (PaddlePaddle) — runs `onnxsim.simplify` in its ONNX → Paddle conversion optimizer\n* [ncnn](https://github.com/Tencent/ncnn) (Tencent) — recommends simplifying with onnxsim before `onnx2ncnn`\n* [RKNN Model Zoo](https://github.com/airockchip/rknn_model_zoo) (Rockchip) — runs onnxsim in its ONNX export scripts before RKNN conversion\n\n## Chat\n\nWe created a Chinese QQ group for ONNX!\n\nONNX QQ Group (Chinese): 1021964010, verification code: nndab. Welcome to join!\n\nFor English users, I'm active on the [ONNX Slack](https://github.com/onnx/onnx#discuss). You can find and chat with me (daquexian) there.\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "deep-learning",
          "ONNX"
        ],
        "author_email": "ONNX Simplifier Authors <daquexian566@gmail.com>",
        "classifier": [
          "Development Status :: 4 - Beta",
          "Intended Audience :: Developers",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Topic :: Scientific/Engineering",
          "Topic :: Software Development"
        ],
        "requires_dist": [
          "onnx",
          "rich",
          "onnxruntime>=1.6.0; extra == \"onnxruntime\"",
          "sympy; extra == \"symbolic\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/onnxsim/onnxsim"
        ],
        "provides_extra": [
          "onnxruntime",
          "symbolic"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/47/87/a155f16c1c17adccaa2ed2256484fe1c6ad37b925e8e39695ed8860bc0b5/pydeprecate-0.9.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=c9501dae1a2567a3c7f7b04221ad5a97d1ad972a02ddb729a04299b435fedd7c",
          "hashes": {
            "sha256": "c9501dae1a2567a3c7f7b04221ad5a97d1ad972a02ddb729a04299b435fedd7c"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "pyDeprecate",
        "version": "0.9.0",
        "dynamic": [
          "author",
          "author-email",
          "classifier",
          "description",
          "description-content-type",
          "home-page",
          "keywords",
          "license",
          "license-file",
          "project-url",
          "provides-extra",
          "requires-python",
          "summary"
        ],
        "summary": "Python deprecation decorator: call forwarding, argument mapping, class proxying, CI audit. Zero deps.",
        "description": "# pyDeprecate\n\n**Simple tooling for marking deprecated functions or classes and re-routing to their successors.**\n\n> **Summary**: pyDeprecate is a lightweight Python library for managing function and class deprecations with zero dependencies. It provides automatic call forwarding to replacement functions, argument mapping between old and new APIs, and configurable warning controls to prevent log spam. Perfect for library maintainers evolving APIs while maintaining backward compatibility.\n\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pyDeprecate)](https://pypi.org/project/pyDeprecate/)\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/Borda/pyDeprecate/blob/main/LICENSE)\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2FBorda%2FpyDeprecate.svg?type=shield&issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2FBorda%2FpyDeprecate?ref=badge_shield&issueType=license)\n\n[![PyPI Status](https://badge.fury.io/py/pyDeprecate.svg)](https://badge.fury.io/py/pyDeprecate)\n[![PyPI Status](https://pepy.tech/badge/pyDeprecate)](https://pepy.tech/project/pyDeprecate)\n[![Conda](https://img.shields.io/conda/v/conda-forge/pyDeprecate?label=conda&color=success)](https://anaconda.org/conda-forge/pyDeprecate)\n![Conda](https://img.shields.io/conda/dn/conda-forge/pyDeprecate?color=blue)\n[![CodeFactor](https://www.codefactor.io/repository/github/borda/pydeprecate/badge)](https://www.codefactor.io/repository/github/borda/pydeprecate)\n[![Documentation](https://img.shields.io/badge/docs-borda.github.io-blue)](https://borda.github.io/pyDeprecate/)\n\n[![CI testing](https://github.com/Borda/pyDeprecate/actions/workflows/ci_testing.yml/badge.svg?tag=v0.9.0)](https://github.com/Borda/pyDeprecate/actions/workflows/ci_testing.yml)\n[![Install pkg](https://github.com/Borda/pyDeprecate/actions/workflows/ci_install-pkg.yml/badge.svg?tag=v0.9.0)](https://github.com/Borda/pyDeprecate/actions/workflows/ci_install-pkg.yml)\n[![codecov](https://codecov.io/gh/Borda/pyDeprecate/release/v0.9.0/graph/badge.svg?token=BG7RQ86UJA)](https://codecov.io/gh/Borda/pyDeprecate)\n[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/Borda/pyDeprecate/main.svg)](https://results.pre-commit.ci/latest/github/Borda/pyDeprecate/main)\n\n> **Author:** [Jiri Borovec](https://github.com/Borda) · **License:** Apache 2.0 · **Python:** 3.9+ · **Install:** `pip install pyDeprecate` · **Import:** `from deprecate import deprecated, deprecated_class` · **Docs:** https://borda.github.io/pyDeprecate/\n\n______________________________________________________________________\n\n## 📋 Table of Contents\n\n- [📖 Overview](#overview)\n- [✨ Features](#features)\n  - [Comparison with Other Tools](#comparison-with-other-tools)\n- [💾 Installation](#installation)\n- [🚀 Quick Start](#quick-start)\n- [🗺 API at a Glance](#api-at-a-glance)\n- [📚 Use-cases and Applications](#use-cases-and-applications)\n  - [Simple function forwarding](#simple-function-forwarding)\n  - [Advanced target argument mapping](#advanced-target-argument-mapping)\n  - [Deprecation warning only](#deprecation-warning-only)\n  - [Self argument mapping](#self-argument-mapping)\n  - [Stacked deprecation decorators](#stacked-deprecation-decorators)\n  - [Conditional skip](#conditional-skip)\n  - [Class deprecation](#class-deprecation)\n  - [Deprecating constants and instances](#deprecating-constants-and-instances)\n  - [Deprecating Enums and dataclasses](#deprecating-enums-and-dataclasses)\n  - [Automatic docstring updates](#automatic-docstring-updates)\n  - [Injecting new required arguments](#injecting-new-required-arguments)\n  - [Async functions](#-async-functions)\n- [🔇 Understanding the void() Helper](#understanding-the-void-helper)\n- [🔍 Audit](#audit)\n  - [Validating Wrapper Configuration](#validating-wrapper-configuration)\n  - [Generating Deprecation Tables](#generating-deprecation-tables)\n  - [Enforcing Deprecation Removal Deadlines](#enforcing-deprecation-removal-deadlines)\n  - [Detecting Deprecation Chains](#detecting-deprecation-chains)\n- [🧪 Testing Deprecated Code](#testing-deprecated-code)\n- [🔧 Troubleshooting](#troubleshooting)\n- [🤝 Contributing](#contributing)\n\n## 📖 Overview\n\nThe common use-case is moving your functions across a codebase or outsourcing some functionalities to new packages.\nFor most of these cases, you want to maintain some compatibility, so you cannot simply remove the past function. You also want to warn users for some time that the functionality they have been using has moved and is now deprecated in favor of another function (which should be used instead) and will soon be removed completely.\n\nAnother good aspect is not overwhelming users with too many warnings, so per function/class, this warning is raised only N times in the preferred stream (warning, logger, etc.).\n\n> **Read:** [Mastering API Deprecation in Python — the pain points and how pyDeprecate can help](https://medium.com/codex/mastering-api-deprecation-in-python-the-pain-points-and-how-pydeprecate-can-help-1dbfd90e2b62) — CodeX / Medium\n\n## ✨ Features\n\n- ⚠️ Deprecation warnings are shown once per function by default (prevents log spam)\n- 🔄 Arguments are automatically mapped to the target function\n- 🚫 The deprecated function body is never executed when using `target`\n- ⚡ Minimal runtime overhead with zero dependencies (Python standard library only)\n- 🛠️ Supports deprecating callables: functions, methods, class constructors, **generator functions** (`def gen(): yield` — warning fires eagerly at call time, before iteration begins), and **`async def` coroutine functions** (wrapper is `async def`, `inspect.iscoroutinefunction(wrapper)` returns `True`; warning fires when the coroutine is awaited)\n- 📦 Supports deprecating classes, Enums, dataclasses, and module-level constants/objects via transparent proxies (`deprecated_class` for types; `deprecated_instance` for objects, with optional read-only enforcement — blocks standard collection mutators: `append`, `pop`, `update`, `clear`, etc.; custom mutator names bypass this guard)\n- 📝 Optionally, docstrings can be updated automatically in RST/Sphinx or MkDocs/Markdown format (auto-detected); ships bundled Griffe and Sphinx doc-engine extensions\n- 🔍 Preserves original function signature, annotations and metadata for introspection\n- ⚙️ Configurable warning message template and output stream (logging, warnings, custom callable)\n- 🎯 Fine‑grained control: per‑argument deprecation/mapping, `args_extra` for injecting fixed forwarded kwargs, and conditional `skip_if` behavior\n- 🧪 Includes testing helpers (e.g., `assert_no_warnings`, formerly `no_warning_call`) for deterministic tests\n- 🔎 Audit tools for CI pipelines: validate wrapper config, enforce removal deadlines, and detect deprecated-to-deprecated chains\n\n### 📊 Comparison with Other Tools\n\n> 💬 _How does pyDeprecate compare to other Python deprecation solutions?_\n\nWhile `pyDeprecate` focuses on comprehensive forwarding and argument mapping, other tools might fit different needs:\n\n- [`warnings.warn`](https://docs.python.org/3/library/warnings.html) (stdlib): The standard library's built-in function, perfect for simple cases requiring no dependencies.\n- [`deprecation`](https://pypi.org/project/deprecation/) (Lib): A widely used library by Brian Curtin, excellent for version-based deprecations.\n- [`Deprecated`](https://pypi.org/project/Deprecated/) (wrapt): A robust decorator-based library by Laurent Laporte with `wrapt` integration.\n\n<details>\n  <summary><strong>Key Advantages & Feature Breakdown</strong></summary>\n\n- **Simple Warnings**: Emits standard Python warnings, compatible with default error handling tools.\n- **Auto-Forward Calls**: Automatically redirects calls to the new function, ensuring the deprecated code is *never* executed.\n- **Generator / Async**: Works natively with generator functions (`def fn(): yield`), `async def` coroutines, and async generators (`async def fn(): yield`) — the deprecation warning fires at call time regardless of callable type, and the wrapper preserves the correct introspection flags (`iscoroutinefunction`, etc.).\n- **Argument Mapping**: Seamlessly translates old API arguments to new ones, handling complex renames and restructuring.\n- **Argument Deprecation**: Warns when specific arguments are used, even if the function itself isn't deprecated.\n- **Docstring Updates**: Automatically appends deprecation notices to the function's docstring.\n- **Version Tracking**: Clearly specifies `deprecated_in` and `remove_in` versions for better lifecycle management.\n- **Prevent Log Spam**: Prevents log spam by showing warnings only once per function (or N times) by default.\n- **Zero Extra Depend.**: Lightweight and easy to install, relying solely on the Python standard library.\n- **Custom Streams**: Route warnings to `logging`, standard `warnings`, or any custom callable to fit your monitoring stack.\n- **Testing Helpers**: Built-in tools like `assert_no_warnings()` ensure your deprecations are testable and deterministic.\n- **Class/Instance Proxy**: Deprecate entire classes, Enums, dataclasses, and module-level objects with transparent proxy wrappers (`deprecated_class`, `deprecated_instance`).\n- **CI/Audit Tools**: Validate wrapper configuration, and—when installed with the `pyDeprecate[audit]` extra—enforce removal deadlines (PEP 440) and detect deprecated-to-deprecated chains — designed for CI pipelines and test suites.\n- **Static Type-Checker Signals**: Native PEP 702 static diagnostics come from `warnings.deprecated`. For projects that need both static-checker hints and runtime call-forwarding, `warnings.deprecated` (for the static signal) and pyDeprecate's `@deprecated` (for forwarding) can be applied separately to the same function.\n- **Decorator Stacking**: Stack `@deprecated` decorators for multi-version migrations — rename arguments across releases (`ARGS_REMAP + ARGS_REMAP`), then deprecate the whole function when a complete replacement arrives (`ARGS_REMAP + NOTIFY`). Unsupported combinations warn at decoration time.\n- **Sphinx Plugin**: Ships a Sphinx autodoc extension (`deprecate.docstring.sphinx_ext`) so `_DeprecatedProxy` objects are documented with their injected deprecation notice instead of rendering as opaque aliases.\n- **MkDocs Plugin**: Ships a Griffe extension (`deprecate.docstring.griffe_ext`) for mkdocstrings so runtime-injected `!!! warning` admonitions are visible in MkDocs-generated API docs.\n\n</details>\n\n> **When to prefer `warnings.deprecated` (PEP 702):** If your project targets Python 3.13+ and you only need simple call-site warnings visible to static type-checkers (mypy, pyright, IDEs), the stdlib decorator is the right choice — zero extra dependency. `warnings.warn` tells users what is deprecated; pyDeprecate tells users what to use instead and does the forwarding for them. Choose `pyDeprecate` when you need call-forwarding, argument remapping, proxy wrapping of module-level constants, or CI audit tools — none of those exist in PEP 702. On Python < 3.13, `typing_extensions.deprecated` requires `typing_extensions` (marked ✍️ for that reason).\n\n<br>\n\n| _Feature_                 | `pyDeprecate` | `warnings.warn` (stdlib) | `deprecation` (Lib) | `Deprecated` (wrapt) | `warnings.deprecated`† (py3.13+) |\n| ------------------------- | :-----------: | :----------------------: | :-----------------: | :------------------: | :------------------------------: |\n| **Simple Warnings**       |      ✅       |            ✅            |         ✅          |          ✅          |                ✅                |\n| **Auto-Forward Calls**    |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **Generator / Async**     |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **Argument Mapping**      |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **Argument Deprecation**  |      ✅       |            ✍️            |         ❌          |          ❌          |                ❌                |\n| **Class/Instance Proxy**  |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **Docstring Updates**     |      ✅       |            ❌            |         ✅          |          ✅          |                ❌                |\n| **Version Tracking**      |      ✅       |            ✍️            |         ✅          |          ✅          |                ❌                |\n| **Prevent Log Spam**      |      ✅       |            ✍️            |         ❌          |          ❌          |                ❌                |\n| **Zero Extra Depend.**    |      ✅       |            ✅            |         ❌          |          ❌          |                †                 |\n| **Custom Streams**        |      ✅       |            ✍️            |         ❌          |          ❌          |                ❌                |\n| **Testing Helpers**       |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **CI/Audit Tools**        |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **Static Checker Signal** |      ✍️       |            ❌            |         ❌          |          ❌          |                ✅                |\n| **Decorator Stacking**    |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **Sphinx Plugin**         |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n| **MkDocs Plugin**         |      ✅       |            ❌            |         ❌          |          ❌          |                ❌                |\n\n✍️ = possible but requires manual implementation\n</br>\n† `warnings.deprecated` in the stdlib on Python 3.13+ (PEP 702); also available as `typing_extensions.deprecated` for Python < 3.13\n\n_Comparison as of v0.8, May 2026. [Open an issue](https://github.com/Borda/pyDeprecate/issues) if you spot an inaccuracy._\n\n**Fair strengths in alternative tools worth considering:**\n\n- `warnings.deprecated` is the best option when your top priority is IDE/type-checker diagnostics with no runtime behavior changes; it also adds no per-call runtime overhead when the warning category is suppressed.\n- `deprecation` includes `@fail_if_not_removed`, a focused test helper for direct test-failure enforcement when removal deadlines are reached.\n- `Deprecated` — `deprecated.sphinx` includes `@versionadded` and `@versionchanged` decorators that inject Sphinx directives into docstrings for lifecycle annotation in Sphinx-built API docs.\n- `warnings.warn` stays the lowest-friction option for one-off internal warnings where compatibility shims are unnecessary.\n\n> [!NOTE]\n> This comparison is compiled to the best of our knowledge and we're happy to make any justified corrections. If you spot an inaccuracy, please [open an issue](https://github.com/Borda/pyDeprecate/issues) or submit a PR.\n\n> [!TIP]\n> Every deprecation variant writes the same `DeprecationConfig` — `@deprecated`, `deprecated_class`, `deprecated_instance`, and the audit tools all read from a single source of truth. This means your CI pipeline (`pydeprecate check src/`) catches misconfigured wrappers across all three variants with one scan.\n\n## 💾 Installation\n\nRequires **Python 3.9 or later**.\n\nSimple installation from PyPI:\n\n```bash\npip install pyDeprecate\n```\n\n<details>\n  <summary>Other installations</summary>\n\nSimply install with pip from source:\n\n```bash\npip install https://github.com/Borda/pyDeprecate/archive/main.zip\n```\n\n</details>\n\n<br>\n\n## 🚀 Quick Start\n\nHere's the simplest way to get started with deprecating a function:\n\n```python\nfrom deprecate import deprecated\n\n\n# NEW/FUTURE API — renamed to be more explicit about what it computes\ndef compute_sum(a: int = 0, b: int = 3) -> int:\n    return a + b\n\n\n# DEPRECATED API — `addition` was the original name before the rename\n@deprecated(target=compute_sum, deprecated_in=\"1.0\", remove_in=\"2.0\")\ndef addition(a: int, b: int = 5) -> int:\n    pass  # body is not needed — calls are forwarded to compute_sum\n\n\n# Using the original name still works but shows a warning\nresult = addition(1, 2)  # Returns 3\n# Warning: The `addition` was deprecated since v1.0 in favor of `__main__.compute_sum`.\n#          It will be removed in v2.0.\nprint(result)\n```\n\n<details>\n  <summary>Output: <code>addition(1, 2)</code></summary>\n\n```\n3\n```\n\n</details>\n\nThat's it! All calls to `addition()` are automatically forwarded to `compute_sum()` with a deprecation warning.\n\n> [!IMPORTANT]\n> When `target=<callable>` is set, pyDeprecate intercepts the call **before** the body executes — the body is dead code under normal forwarding. **Exception**: if `skip_if` evaluates `True` at call time, the source body runs as the fallback, so keep a working implementation when combining `target=<callable>` with `skip_if`.\n\n## 🗺 API at a Glance\n\nNot sure which API to reach for? Start here.\n\n**Pick the right decorator:**\n\n| Scenario                                      | API to use                                                               |\n| --------------------------------------------- | ------------------------------------------------------------------------ |\n| Renaming a function or method                 | `@deprecated(target=new_func)`                                           |\n| Renaming an argument within the same function | `@deprecated(target=TargetMode.ARGS_REMAP, args_mapping={\"old\": \"new\"})` |\n| Warn only — original body still runs          | `@deprecated(deprecated_in=\"1.0\", remove_in=\"2.0\")`                      |\n| Deprecating a class, Enum, or dataclass name  | `@deprecated_class(target=NewClass)`                                     |\n| Deprecating a module-level constant or object | `deprecated_instance(obj, ...)`                                          |\n\n> **Note:** Legacy `target=None` and `target=True` emit `FutureWarning` at decoration time in v0.8 and become `TypeError` in v1.0. Use `TargetMode.NOTIFY` and `TargetMode.ARGS_REMAP` respectively.\n\n<details>\n  <summary><strong>All `@deprecated` parameters at a glance:</strong></summary>\n\n| Param              | Default                     | Purpose                                                                                                    |\n| ------------------ | --------------------------- | ---------------------------------------------------------------------------------------------------------- |\n| `target`           | `TargetMode.NOTIFY`         | `Callable` to forward to · `TargetMode.ARGS_REMAP` to remap args · `TargetMode.NOTIFY` (default) warn-only |\n| `deprecated_in`    | `\"\"`                        | Version when deprecated (e.g. `\"1.0\"`)                                                                     |\n| `remove_in`        | `\"\"`                        | Version when removed (e.g. `\"2.0\"`)                                                                        |\n|                    | **Advanced: ~10% of cases** |                                                                                                            |\n| `stream`           | `deprecation_warning`       | Warning sink callable (set `None` to silence warnings)                                                     |\n| `num_warns`        | `1`                         | `1` once · `-1` always · `N` exactly N times                                                               |\n| `args_mapping`     | `None`                      | `{\"old\": \"new\"}` rename · `{\"old\": None}` drop                                                             |\n| `template_mgs`     | `None`                      | Custom warning message template (`%`-style placeholders)                                                   |\n| `args_extra`       | `None`                      | Fixed kwargs injected into the target call                                                                 |\n| `skip_if`          | `False`                     | `bool` or `Callable → bool`; skip deprecation when true                                                    |\n| `update_docstring` | `False`                     | Append Sphinx `.. deprecated::` notice to docstring                                                        |\n\n> [!TIP]\n> `@deprecated_class()` shares `target`, `deprecated_in`, `remove_in`, `num_warns`, `stream`, `args_mapping`, `args_extra`, `template_mgs`, `update_docstring`, and `docstring_style`.\n> `deprecated_instance()` shares `deprecated_in`, `remove_in`, `num_warns`, `stream`, `args_extra`, and `template_mgs`; it requires `obj` and adds `name` (display name) and `read_only`.\n\n</details>\n\n## 📚 Use-cases and Applications\n\nThe functionality is kept simple and all defaults should be reasonable, but you can still do extra customization such as:\n\n- 💬 define user warning message and preferred stream\n- 🔀 extended argument mapping to target function/method\n- 🎯 define deprecation logic for self arguments\n- 📊 specify warning count per:\n  - called function (for func deprecation)\n  - used arguments (for argument deprecation)\n- ⚙️ define conditional skip (e.g. depending on some package version)\n\nIn particular the target values (cases):\n\n| `target` value          | Use case                                      | `args_mapping`                     | Warning trigger                    |\n| ----------------------- | --------------------------------------------- | ---------------------------------- | ---------------------------------- |\n| `TargetMode.NOTIFY`     | Whole callable going away; no replacement yet | Ignored (warns; TypeError in v1.0) | Every call                         |\n| `TargetMode.ARGS_REMAP` | Callable stays; argument names are renamed    | Required                           | Only when old arg names are passed |\n| `<callable>`            | Callable replaced by another; calls forwarded | Optional                           | Every call                         |\n\n> [!TIP]\n> `TargetMode.NOTIFY` replaces the old `target=None` sentinel and `TargetMode.ARGS_REMAP` replaces the old `target=True` sentinel. The old forms still work but emit a `FutureWarning` at decoration time.\n\n> [!NOTE]\n> `@deprecated` is designed for functions and methods. To deprecate a class, Enum, or dataclass, use `@deprecated_class()` instead (see [Deprecating Enums and dataclasses](#deprecating-enums-and-dataclasses)).\n\n### ➡ Simple function forwarding\n\nIt is very straightforward: you forward your function call to a new function and all arguments are mapped:\n\n```python\n# NEW/FUTURE API — renamed to be more explicit about what it computes\ndef compute(a: int = 0, b: int = 3) -> int:\n    \"\"\"New function anywhere in the codebase or even other package.\"\"\"\n    return a + b\n\n\n# ---------------------------\n\nfrom deprecate import deprecated\n\n\n# What this module looked like before the rename:\n# def calculate(a: int, b: int = 5) -> int:\n#     return a + b\n\n\n# DEPRECATED API — `calculate` was the original name before the rename\n@deprecated(target=compute, deprecated_in=\"0.1\", remove_in=\"0.5\")\ndef calculate(a: int, b: int = 5) -> int:\n    \"\"\"\n    My deprecated function which now has an empty body\n     as all calls are routed to the new function.\n    \"\"\"\n    pass  # or you can just place docstring as one above\n\n\n# calling this function will raise a deprecation warning:\n#   The `calculate` was deprecated since v0.1 in favor of `__main__.compute`.\n#   It will be removed in v0.5.\nprint(calculate(1, 2))\n```\n\n<details>\n  <summary>Output: <code>calculate(1, 2)</code></summary>\n\n```\n3\n```\n\n</details>\n\n<br>\n\n<details>\n<summary>Wrapper form: applying <code>@deprecated</code> without the decorator syntax</summary>\n\nWhen the deprecated name already exists as a callable (for example, imported from another package), you can apply `deprecated()` directly without redefining the function:\n\n```python\nfrom deprecate import deprecated\n\n\n# NEW/FUTURE API — in real usage this would be imported from another module\ndef compute_sum(a: int, b: int = 0) -> int:\n    return a + b\n\n\n# LEGACY — already-existing callable that is being deprecated\ndef addition(a: int, b: int = 0) -> int:\n    return a + b\n\n\n# DEPRECATED API — `calculate` was the original name in this package;\n# wrap it without redefining a function body\ncalculate = deprecated(\n    target=compute_sum,\n    deprecated_in=\"0.5\",\n    remove_in=\"1.0\",\n)(addition)\nprint(calculate(1, 2))\n```\n\n<details>\n  <summary>Output: <code>calculate(1, 2)</code></summary>\n\n```\n3\n```\n\n</details>\n\nThis is an equivalent to the `@deprecated(...)` decorator form but applied to an already-existing callable — useful when the deprecated function lives in a dependency you don't control.\n\n</details>\n\n<br>\n\n### 🔀 Advanced target argument mapping\n\nAnother more complex example is using argument mapping is:\n\n<details>\n  <summary>Example: mapping deprecated args to <code>sklearn.metrics.accuracy_score</code></summary>\n\n```python\nimport logging\nfrom sklearn.metrics import accuracy_score\nfrom deprecate import deprecated, void\n\n\n@deprecated(\n    # use standard sklearn accuracy implementation\n    target=accuracy_score,\n    # custom warning stream\n    stream=logging.warning,\n    # number of warnings per lifetime (with -1 for always)\n    num_warns=5,\n    # custom message template\n    template_mgs=\"`%(source_name)s` was deprecated, use `%(target_path)s`\",\n    # as target args are different, define mapping from source to target func\n    args_mapping={\"preds\": \"y_pred\", \"target\": \"y_true\", \"blabla\": None},\n)\ndef depr_accuracy(preds: list, target: list, blabla: float) -> float:\n    \"\"\"My deprecated function which is mapping to sklearn accuracy.\"\"\"\n    # to stop complain your IDE about unused argument you can use void/empty function\n    return void(preds, target, blabla)\n\n\n# calling this function will raise a deprecation warning:\n#   WARNING:root:`depr_accuracy` was deprecated, use `sklearn.metrics.accuracy_score`\nprint(depr_accuracy([1, 0, 1, 2], [0, 1, 1, 2], 1.23))\n```\n\nsample output:\n\n```\n0.5\n```\n\n</details>\n\n<br>\n\n### ⚠ Deprecation warning only\n\nBase use-case with no forwarding and just raising a warning:\n\n```python\nfrom deprecate import deprecated\n\n\n@deprecated(deprecated_in=\"0.1\", remove_in=\"0.5\")\ndef my_sum(a: int, b: int = 5) -> int:\n    \"\"\"My deprecated function which still has to have implementation.\"\"\"\n    return a + b\n\n\n# calling this function will raise a deprecation warning:\n#   The `my_sum` was deprecated since v0.1. It will be removed in v0.5.\nprint(my_sum(1, 2))\n```\n\n<details>\n  <summary>Output: <code>my_sum(1, 2)</code></summary>\n\n```\n3\n```\n\n</details>\n\n<br>\n\n> [!NOTE]\n> When using `TargetMode.NOTIFY`, the deprecated function's implementation must be preserved and will be executed. The deprecation decorator only adds a warning without forwarding.\n\n### 🔄 Self argument mapping\n\nWe also support deprecation and argument mapping for the function itself:\n\n```python\nfrom deprecate import TargetMode, deprecated\n\n\n@deprecated(\n    # define as deprecation some self argument - mapping\n    target=TargetMode.ARGS_REMAP,\n    args_mapping={\"coef\": \"new_coef\"},\n    # common version info\n    deprecated_in=\"0.2\",\n    remove_in=\"0.4\",\n)\ndef any_pow(base: float, coef: float = 0, new_coef: float = 0) -> float:\n    \"\"\"My function with deprecated argument `coef` mapped to `new_coef`.\"\"\"\n    return base**new_coef\n\n\n# calling this function will raise a deprecation warning:\n#   The `any_pow` uses deprecated arguments: `coef` -> `new_coef`.\n#   They were deprecated since v0.2 and will be removed in v0.4.\nprint(any_pow(2, 3))\n```\n\n<details>\n  <summary>Output: <code>any_pow(2, 3)</code></summary>\n\n```\n8\n```\n\n</details>\n\n<br>\n\nTo **drop** an argument entirely (warn when it's passed, then discard it), map it to `None`:\n\n```python\nfrom deprecate import TargetMode, deprecated\nfrom typing import Optional\n\n\n@deprecated(\n    target=TargetMode.ARGS_REMAP,\n    args_mapping={\"legacy_param\": None},\n    deprecated_in=\"1.8\",\n    remove_in=\"1.9\",\n)\ndef my_func(value: int, legacy_param: Optional[str] = None) -> int:\n    \"\"\"legacy_param is no longer used; pass None or omit it.\"\"\"\n    return value * 2\n\n\n# Passing the removed argument triggers a warning and the argument is silently discarded:\n#   The `my_func` uses deprecated arguments: `legacy_param` -> `None`.\n#   They were deprecated since v1.8 and will be removed in v1.9.\nprint(my_func(value=42, legacy_param=\"old\"))\n```\n\n<details>\n  <summary>Output: <code>my_func(value=42, legacy_param=\"old\")</code></summary>\n\n```\n84\n```\n\n</details>\n\n> [!WARNING]\n> `TargetMode.ARGS_REMAP` without `args_mapping` is a misconfiguration; using it emits a construction-time `UserWarning`. This will become a `TypeError` in v1.0. If you only want to warn callers with no forwarding or remapping, use `TargetMode.NOTIFY` instead.\n\n### 🔗 Stacked deprecation decorators\n\nStack `@deprecated` decorators to handle multi-version deprecation migrations. Each layer tracks its own version range and warning count independently.\n\n<details>\n  <summary>Pattern 1: multi-step argument renames (ARGS_REMAP + ARGS_REMAP)</summary>\n\n```python\nfrom deprecate import TargetMode, deprecated\n\n\n@deprecated(\n    target=TargetMode.ARGS_REMAP,\n    deprecated_in=\"0.3\",\n    remove_in=\"0.6\",\n    args_mapping=dict(c1=\"nc1\"),\n    template_mgs=\"Depr: v%(deprecated_in)s rm v%(remove_in)s for args: %(argument_map)s.\",\n)\n@deprecated(\n    target=TargetMode.ARGS_REMAP,\n    deprecated_in=\"0.4\",\n    remove_in=\"0.7\",\n    args_mapping=dict(nc1=\"nc2\"),\n    template_mgs=\"Depr: v%(deprecated_in)s rm v%(remove_in)s for args: %(argument_map)s.\",\n)\ndef any_pow(base, c1: float = 0, nc1: float = 0, nc2: float = 2) -> float:\n    return base**nc2\n\n\n# calling this function will raise deprecation warnings:\n#   FutureWarning('Depr: v0.3 rm v0.6 for args: `c1` -> `nc1`.')\n#   FutureWarning('Depr: v0.4 rm v0.7 for args: `nc1` -> `nc2`.')\nprint(any_pow(2, 3))\n```\n\ncode output:\n\n```\n8\n```\n\n</details>\n\n<details>\n  <summary>Pattern 2: lifecycle migration (ARGS_REMAP + NOTIFY)</summary>\n\nRename an argument in v1.0, then deprecate the whole function in v2.0 when a complete replacement exists. `ARGS_REMAP` must be the outermost (top) decorator; `NOTIFY` goes below it.\n\n```python\nfrom deprecate import TargetMode, deprecated\n\n\n@deprecated(TargetMode.ARGS_REMAP, deprecated_in=\"1.0\", remove_in=\"2.0\", args_mapping={\"factor\": \"scale\"})\n@deprecated(TargetMode.NOTIFY, deprecated_in=\"2.0\", remove_in=\"3.0\")\ndef compute_power(base: float, factor: float = 1, scale: float = 1) -> float:\n    return base**scale\n\n\nprint(compute_power(2, factor=3))  # → 2 warnings (arg rename + function deprecated)\nprint(compute_power(2, scale=3))  # → 1 warning  (function deprecated only)\n```\n\n</details>\n\n<details>\n  <summary>Output: <code>compute_power(2, factor=3); compute_power(2, scale=3)</code></summary>\n\n```\n8\n8\n```\n\n</details>\n\n| Outer (top)  | Inner (bottom) | Status                             | Notes                                                                   |\n| ------------ | -------------- | ---------------------------------- | ----------------------------------------------------------------------- |\n| `ARGS_REMAP` | `ARGS_REMAP`   | ✓ Supported                        | Multi-step argument renames across versions                             |\n| `ARGS_REMAP` | `NOTIFY`       | ✓ Supported                        | Lifecycle: rename args first, then deprecate the whole function         |\n| `NOTIFY`     | `callable`     | ✓ Supported                        | Outer NOTIFY warns callers; inner callable handles forwarding           |\n| `callable`   | `callable`     | ✗ `UserWarning` at decoration time | Use a single `@deprecated(target=<callable>)` instead                   |\n| `callable`   | `ARGS_REMAP`   | ✗ `UserWarning` at decoration time | Collapse to `@deprecated(target=fn, args_mapping={...})`                |\n| `callable`   | `NOTIFY`       | ✗ `UserWarning` at decoration time | Collapse to a single `@deprecated(target=<callable>)`                   |\n| `ARGS_REMAP` | `callable`     | ✗ `UserWarning` at decoration time | Update the inner decorator to include `target=` and `args_mapping=`     |\n| `NOTIFY`     | `NOTIFY`       | ✗ `UserWarning` at decoration time | Update the existing decorator's versions instead of adding a second one |\n| `NOTIFY`     | `ARGS_REMAP`   | ✗ `UserWarning` at decoration time | Wrong order — swap: `ARGS_REMAP` on top, `NOTIFY` below                 |\n\n<br>\n\n### ⚙ Conditional skip\n\nConditional skip of which can be used for mapping between different target functions depending on additional input such as package version\n\n<details>\n<summary>Example: <code>skip_if</code> based on a runtime condition</summary>\n\n```python\nfrom deprecate import TargetMode, deprecated\n\nFAKE_VERSION = 1\n\n\ndef version_greater_1():\n    return FAKE_VERSION > 1\n\n\n@deprecated(\n    target=TargetMode.ARGS_REMAP,\n    deprecated_in=\"0.3\",\n    remove_in=\"0.6\",\n    args_mapping=dict(c1=\"nc1\"),\n    skip_if=version_greater_1,\n)\ndef skip_pow(base, c1: float = 1, nc1: float = 1) -> float:\n    return base ** (c1 - nc1)\n\n\n# calling this function will raise a deprecation warning\nprint(skip_pow(2, 3))\n\n# change the fake versions\nFAKE_VERSION = 2\n\n# will not raise any warning\nprint(skip_pow(2, 3))\n```\n\n</details>\n\n<br>\n\n<details>\n  <summary>Output: <code>skip_pow(2, 3); skip_pow(2, 3)</code></summary>\n\n```\n0.25\n4\n```\n\n</details>\n\n<br>\n\nThis can be beneficial with multiple deprecation levels shown above...\n\n### 🏗 Class deprecation\n\nTwo common patterns: deprecating a single method (rename within the same class) or deprecating the whole class by forwarding `__init__` to a successor.\n\n<details>\n<summary>Example: renaming a method within the same class</summary>\n\n```python\nfrom deprecate import deprecated, void\n\n\nclass MyService:\n    # NEW/FUTURE API — renamed from run() for clarity\n    def execute(self, x: int) -> int:\n        \"\"\"Current method.\"\"\"\n        return x * 2\n\n    # DEPRECATED API — `run` was the original name before the rename\n    @deprecated(target=execute, deprecated_in=\"1.0\", remove_in=\"2.0\")\n    def run(self, x: int) -> int:\n        \"\"\"Deprecated — renamed to execute().\"\"\"\n        return void(x)\n\n\nsvc = MyService()\n# calling this method will raise a deprecation warning:\n#   The `run` was deprecated since v1.0 in favor of `__main__.execute`.\n#   It will be removed in v2.0.\nprint(svc.run(5))\n```\n\n</details>\n\n<br>\n\n<details>\n  <summary>Output: <code>svc.run(5)</code></summary>\n\n```\n10\n```\n\n</details>\n\n<br>\n\n<details>\n<summary>Example: forwarding <code>__init__</code> to a successor class</summary>\n\n```python\n# NEW/FUTURE API — renamed to be more descriptive\nclass HttpClient:\n    \"\"\"My new class anywhere in the codebase or other package.\"\"\"\n\n    def __init__(self, c: float, d: str = \"abc\"):\n        self.my_c = c\n        self.my_d = d\n\n\n# ---------------------------\n\nfrom deprecate import deprecated, void\n\n\n# DEPRECATED API — `Client` was the original name before it was renamed to HttpClient\nclass Client(HttpClient):\n    \"\"\"\n    The deprecated class should be inherited from the successor class\n     to hold all methods and properties.\n    \"\"\"\n\n    @deprecated(target=HttpClient, deprecated_in=\"0.2\", remove_in=\"0.4\")\n    def __init__(self, c: int, d: str = \"efg\"):\n        \"\"\"\n        You place the decorator around __init__ as you want\n         to warn user just at the time of creating object.\n\n        Decorating __init__ warns at instantiation time and optionally\n        forwards to another class. For deprecating the class itself\n        (name change, Enum, dataclass), use @deprecated_class() instead.\n        \"\"\"\n        void(c, d)\n\n\n# calling this function will raise a deprecation warning:\n#   The `Client` was deprecated since v0.2 in favor of `__main__.HttpClient`.\n#   It will be removed in v0.4.\ninst = Client(7)\nprint(inst.my_c)  # returns: 7\nprint(inst.my_d)  # returns: \"efg\"\n```\n\n</details>\n\n<br>\n\n<details>\n  <summary>Output: <code>inst.my_c; inst.my_d</code></summary>\n\n```\n7\nefg\n```\n\n</details>\n\n<br>\n\n### 📦 Deprecating constants and instances\n\nUse `deprecated_instance` to wrap objects accessed via attribute/item/call operations (for example, dicts,\nlists, or custom objects) with transparent deprecation warnings. Primitive protocol methods (such as numeric\narithmetic on `float` or concatenation on `str`) are not proxied. For primitive constants like floats or\nstrings, prefer wrapping them in a container (such as a dict or configuration object) or updating call sites\ndirectly, since arithmetic and other primitive protocol operations are not intercepted by the wrapper. The\n`name` parameter is optional; when omitted it defaults to the type name of the wrapped object.\n\nThe proxy passes `isinstance(obj, OriginalClass)` and `issubclass(SubClass, OriginalClass)` checks transparently — zero changes needed in type-guard code.\n\n```python\nfrom deprecate import deprecated_instance\n\n# NEW/FUTURE API — renamed to be more explicit about its scope\nTRAINING_CONFIG = {\"lr\": 0.001, \"batch_size\": 32, \"epochs\": 10}\n\n# What it looked like before the rename:\n# DEFAULTS = {\"lr\": 0.001, \"batch_size\": 32, \"epochs\": 10}\n\n# DEPRECATED API — `DEFAULTS` was the original name; read-only so\n# callers cannot mutate shared state through the deprecated alias\nDEFAULTS = deprecated_instance(\n    TRAINING_CONFIG,\n    deprecated_in=\"1.2\",\n    remove_in=\"2.0\",\n    read_only=True,\n)\n\n# Reading still works but emits a FutureWarning once:\n#   The `dict` was deprecated since v1.2. It will be removed in v2.0.\nprint(DEFAULTS[\"lr\"])  # 0.001\n```\n\n<details>\n  <summary>Output: <code>DEFAULTS[\"lr\"]</code></summary>\n\n```\n0.001\n```\n\n</details>\n\n<br>\n\n### 🗂 Deprecating Enums and dataclasses\n\n<details>\n<summary>Example: <code>deprecated_class()</code> for Enum and dataclass</summary>\n\n`deprecated_class()` wraps an entire Enum or dataclass in a transparent proxy that warns on every\naccess and forwards attribute, item, and call operations to the replacement class.\nUse `args_mapping` to rename or drop kwargs when the deprecated class is called.\n\n> [!NOTE]\n> Type checks with `isinstance()` and `issubclass()` work transparently with `deprecated_class()` proxies and do not emit deprecation warnings, as these are structural checks rather than actual usage of the deprecated API.\n\n```python\nfrom enum import Enum\nfrom dataclasses import dataclass\nfrom deprecate import deprecated_class\n\n# mypackage/theme.py — what it looked like before the rename:\n#\n# class Color(Enum):\n#     RED = 1\n#     BLUE = 2\n\n\n# NEW/FUTURE API — renamed to be more descriptive\nclass ThemeColor(Enum):\n    RED = 1\n    BLUE = 2\n\n\n# DEPRECATED API — `Color` was the original name; no class body needed,\n# the proxy forwards all access to ThemeColor\nColor = deprecated_class(target=ThemeColor, deprecated_in=\"1.0\", remove_in=\"2.0\")(ThemeColor)\n\n# All access is forwarded to ThemeColor — a FutureWarning is emitted once:\n#   The `Color` was deprecated since v1.0. It will be removed in v2.0.\nprint(Color.RED is ThemeColor.RED)  # True\nprint(Color(1) is ThemeColor.RED)  # True\nprint(Color[\"RED\"] is ThemeColor.RED)  # True\n\n\n# Precision migration story:\n# - PointV1 used integer pixel coordinates.\n# - PointV2 supports float coordinates for sub-pixel precision and smoother transforms.\n\n\n# NEW/FUTURE API — extended to float precision\n@dataclass\nclass PointV2:\n    x: float\n    y: float\n\n\n# DEPRECATED API — PointV1 was the original integer-coordinate implementation\n@deprecated_class(target=PointV2, deprecated_in=\"1.8\", remove_in=\"2.0\")\n@dataclass\nclass PointV1:\n    x: int\n    y: int\n\n\n# Existing callers using integer coordinates still work and are forwarded to PointV2:\np_old = PointV1(3, 4)\nprint(isinstance(p_old, PointV2))\nprint((p_old.x, p_old.y))\n\n# New callers can use higher precision directly:\np_new = PointV2(3.25, 4.75)\nprint((p_new.x, p_new.y))\n```\n\n</details>\n\n<br>\n\n<details>\n  <summary>Output: <code>Color.RED is ThemeColor.RED; Color(1) is ThemeColor.RED; (p_new.x, p_new.y)</code></summary>\n\n```\nTrue\nTrue\nTrue\nTrue\n(3, 4)\n(3.25, 4.75)\n```\n\n</details>\n\n<br>\n\n### 📝 Automatic docstring updates\n\nYou can automatically inject deprecation information into your function's docstring:\n\n<details>\n<summary>Example: <code>update_docstring=True</code> inserts a Sphinx deprecation notice before <code>Args:</code>/<code>Parameters</code></summary>\n\n```python\n# NEW/FUTURE API — renamed to be more explicit about what it does\ndef transform(x: int) -> int:\n    \"\"\"New implementation of the function.\"\"\"\n    return x * 2\n\n\n# ---------------------------\n\nfrom deprecate import deprecated\n\n\n# DEPRECATED API — `process` was the original name before the rename\n@deprecated(\n    target=transform,\n    deprecated_in=\"1.0\",\n    remove_in=\"2.0\",\n    update_docstring=True,  # Enable automatic docstring updates\n)\ndef process(x: int) -> int:\n    \"\"\"Transforms the input value.\n\n    Args:\n        x: Input value\n\n    Returns:\n        Result of computation\n    \"\"\"\n    pass\n\n\n# The docstring now includes deprecation information (inserted before \"Args:\")\nprint(process.__doc__)\n# Output includes:\n# .. deprecated:: 1.0\n#    Will be removed in 2.0.\n#    Use `__main__.transform` instead.\n```\n\n</details>\n\n<br>\n\nIf you build docs with MkDocs/Markdown, you can switch to admonition output:\n\n```python\nfrom deprecate import deprecated\n\n\ndef transform(x: int) -> int:\n    return x * 2\n\n\n@deprecated(\n    target=transform,\n    deprecated_in=\"1.0\",\n    remove_in=\"2.0\",\n    update_docstring=True,\n    docstring_style=\"mkdocs\",  # alias: \"markdown\"\n)\ndef process(x: int) -> int:\n    \"\"\"Transforms the input value.\"\"\"\n    pass\n\n\nprint(process.__doc__)\n# !!! warning \"Deprecated in 1.0\"\n#     Will be removed in 2.0.\n#     Use `__main__.transform` instead.\n```\n\nThis is useful for generating API docs with Sphinx, MkDocs, and strict Google/NumPy docstring parsers.\n\n**MkDocs** (via `mkdocstrings` + Griffe extension):\n\n![MkDocs demo — deprecation notice rendered as a warning admonition](https://github.com/Borda/pyDeprecate/raw/v0.9.0/docs/assets/images/demo-docs-mkdocs.png)\n\n**Sphinx** (via `autodoc` + Sphinx extension):\n\n![Sphinx demo — deprecation notice rendered as a styled deprecated directive](https://github.com/Borda/pyDeprecate/raw/v0.9.0/docs/assets/images/demo-docs-sphinx.png)\n\nSee the live rendered output in the online demos: [Sphinx demo](https://borda.github.io/pyDeprecate/stable/demo-sphinx/api.html) · [MkDocs demo](https://borda.github.io/pyDeprecate/stable/demo-mkdocs/api.html).\n\n<details>\n<summary>MkDocs integration: render injected notices with <code>mkdocstrings</code></summary>\n\n`@deprecated(update_docstring=True)` modifies `fn.__doc__` at **import time**. [mkdocstrings](https://mkdocstrings.github.io/) uses [Griffe](https://mkdocstrings.github.io/griffe/) to read docstrings from the **source AST**, so it never sees that runtime change. To bridge the gap, pyDeprecate ships a Griffe extension:\n\n```yaml\n# mkdocs.yml\nplugins:\n  - mkdocstrings:\n      handlers:\n        python:\n          extensions:\n            - deprecate.docstring.griffe_ext:RuntimeDocstrings\n```\n\nWith the extension registered, mkdocstrings will render the injected `!!! warning` admonition for every `@deprecated` function in your docs. No extra dependencies are required — `griffe` is already a dependency of `mkdocstrings[python]`.\n\n</details>\n\n<br>\n\n### ➕ Injecting new required arguments\n\nWhen the target function gains a new parameter that callers of the old API never passed, use `args_extra` to inject a fixed value at the wrapper level:\n\n```python\nfrom deprecate import deprecated, void\n\n\n# NEW/FUTURE API — `send_email` adds an explicit `priority` field\ndef send_email(to: str, subject: str, priority: str) -> str:\n    return f\"Sent to {to!r}: {subject!r} [{priority}]\"\n\n\n# DEPRECATED API — `notify` was the original name; it had no `priority` concept\n@deprecated(\n    target=send_email,\n    deprecated_in=\"1.5\",\n    remove_in=\"2.0\",\n    # callers of `notify` never passed `priority`, so inject a sensible default\n    args_extra={\"priority\": \"normal\"},\n)\ndef notify(to: str, subject: str) -> str:\n    \"\"\"Deprecated — use send_email() with an explicit priority instead.\"\"\"\n    return void(to, subject)\n\n\n# calling this function will raise a deprecation warning:\n#   The `notify` was deprecated since v1.5 in favor of `__main__.send_email`.\n#   It will be removed in v2.0.\nprint(notify(\"alice@example.com\", \"Hello\"))\n```\n\n<details>\n  <summary>Output: <code>notify(\"alice@example.com\", \"Hello\")</code></summary>\n\n```\nSent to 'alice@example.com': 'Hello' [normal]\n```\n\n</details>\n\n<br>\n\n> [!NOTE]\n> `args_extra` is merged into kwargs _after_ `args_mapping` is applied, so extra values can override mapped ones. It is used when `target` is a Callable or `TargetMode.ARGS_REMAP` (with `args_mapping`). For `TargetMode.NOTIFY`, it is ignored and a construction-time `UserWarning` is emitted by validation.\n\n### 🌀 Async functions\n\n`@deprecated` works natively on `async def` functions. The resulting wrapper is itself `async def`, so `inspect.iscoroutinefunction(wrapper)` returns `True` and asyncio frameworks (FastAPI, `asyncio.run`, `asyncio.gather`) recognise it. All three `TargetMode` variants work; the deprecation warning fires when the coroutine is awaited, not when the wrapper is called.\n\n```python\nimport asyncio\nfrom deprecate import TargetMode, deprecated, void\n\n\n# NEW/FUTURE API\nasync def download(url: str) -> bytes:\n    return url.encode()\n\n\n# 1) target=<callable> — forward to a replacement async function\n@deprecated(target=download, deprecated_in=\"0.9\", remove_in=\"1.0\")\nasync def fetch(url: str) -> bytes:\n    \"\"\"Deprecated — use download() instead.\"\"\"\n    return void(url)\n\n\n# 2) TargetMode.NOTIFY — warn callers; the async body still runs\n@deprecated(deprecated_in=\"0.9\", remove_in=\"1.0\")\nasync def legacy_ping() -> str:\n    \"\"\"Deprecated — going away; remove call sites.\"\"\"\n    return \"pong\"\n\n\n# 3) TargetMode.ARGS_REMAP — rename an argument within the same async function\n@deprecated(\n    target=TargetMode.ARGS_REMAP,\n    args_mapping={\"endpoint\": \"url\"},\n    deprecated_in=\"0.9\",\n    remove_in=\"1.0\",\n)\nasync def fetch_data(endpoint: str = \"\", url: str = \"\") -> bytes:\n    \"\"\"Deprecated argument `endpoint` renamed to `url`.\"\"\"\n    return url.encode()\n\n\nasyncio.run(fetch(\"https://example.com\"))\nasyncio.run(legacy_ping())\nprint(asyncio.run(fetch_data(endpoint=\"https://example.com\")))\n```\n\n<details>\n  <summary>Output: <code>asyncio.run(fetch_data(endpoint=\"https://example.com\"))</code></summary>\n\n```\nb'https://example.com'\n```\n\n</details>\n\n> [!NOTE]\n> `@deprecated` supports **async generator functions** (`async def` + `yield`). The wrapper is a sync callable — it fires the deprecation warning eagerly at call time and returns the async generator object. Callers iterate as normal with `async for item in wrapper(...):`. Because the wrapper is sync, `inspect.isasyncgenfunction(wrapper)` returns `False`; frameworks that branch on this introspection may need a thin async generator passthrough.\n\n> [!NOTE]\n> `_WrapperState` fields are plain dataclass fields with no asyncio lock — concurrent coroutines sharing one deprecated wrapper can race on warning counts. Set `num_warns=-1` to bypass the count gate in tests that assert exact emission counts.\n\n## 🔇 Understanding the `void()` Helper\n\nWhen using `@deprecated` with a `target` function, the deprecated function's body is never executed—all calls are automatically forwarded. However, your IDE might complain about \"unused parameters\". The `void()` helper function silences these warnings:\n\n```python\ndef new_add(a: int, b: int) -> int:\n    return a + b\n\n\n# ---------------------------\n\nfrom deprecate import deprecated, void\n\n\n@deprecated(target=new_add, deprecated_in=\"1.0\", remove_in=\"2.0\")\ndef old_add(a: int, b: int) -> int:\n    return void(a, b)  # Tells IDE: \"Yes, I know these parameters aren't used\"\n    # This line is never reached - call is forwarded to new_add\n\n\n# Alternative: You can also use pass or just a docstring\n@deprecated(target=new_add, deprecated_in=\"1.0\", remove_in=\"2.0\")\ndef old_add_v2(a: int, b: int) -> int:\n    \"\"\"Just a docstring works too.\"\"\"\n    pass  # This also works\n\n\nprint(old_add_v2(2, 3))\n```\n\n<details>\n  <summary>Output: <code>old_add_v2(2, 3)</code></summary>\n\n```\n5\n```\n\n</details>\n\n> [!TIP]\n> `void()` is purely for IDE convenience and has no runtime effect. It simply returns `None` after accepting any arguments.\n\n## 🔍 Audit\n\nDeprecations are only as good as the hygiene around them. The `deprecate.audit` module provides utilities for verifying that deprecated wrappers are correctly configured, that removal deadlines are actually enforced, and that chains of deprecated-to-deprecated calls don't silently pile up. These tools are designed to run in CI pipelines and test suites, catching problems before they reach users.\n\n> [!NOTE]\n> **Renamed in v0.6**: `find_deprecated_callables` → `find_deprecation_wrappers`, `validate_deprecated_callable` → `validate_deprecation_wrapper`, `DeprecatedCallableInfo` → `DeprecationWrapperInfo`. The old names are still exported for backwards compatibility but will be removed in v1.0.\n\n### Validating Wrapper Configuration\n\nDuring development, you may want to verify that your deprecated wrappers are configured correctly. pyDeprecate provides two utilities for this: `validate_deprecation_wrapper()` for inspecting a single function, and `find_deprecation_wrappers()` for scanning an entire package.\n\nThe `DeprecationWrapperInfo` dataclass contains:\n\n- `module`: Module name where the function is defined (empty for direct validation)\n- `function`: Function name\n- `deprecated_info`: The `__deprecated__` attribute dict from the decorator\n- `invalid_args`: List of args_mapping keys that don't exist in the function signature\n- `empty_args_mapping`: True if args_mapping is None or empty (no argument remapping)\n- `identity_args_mapping`: List of args where key equals value (e.g., `{'arg': 'arg'}` - no effect)\n- `self_reference`: True if target points to the same function (self-reference)\n- `no_effect`: True if wrapper has zero impact (self-reference, empty mapping, or all identity)\n- `empty_deprecated_in`: True if `deprecated_in` is absent (CI misconfiguration signal — missing introductory version metadata)\n\n<details>\n<summary><b>Validating a Single Function</b></summary>\n\nThe `validate_deprecation_wrapper()` utility extracts the configuration from the function's `__deprecated__` attribute and returns a `DeprecationWrapperInfo` dataclass that helps you identify configurations that would make your deprecation wrapper have zero impact:\n\n```python\nfrom deprecate import DeprecationWrapperInfo, TargetMode, deprecated, validate_deprecation_wrapper\n\n\n# Define your deprecated function\n@deprecated(target=TargetMode.ARGS_REMAP, args_mapping={\"old_arg\": \"new_arg\"}, deprecated_in=\"1.0\")\ndef my_func(old_arg: int = 0, new_arg: int = 0) -> int:\n    return new_arg\n\n\n# Validate the configuration - automatically extracts `args_mapping` and target from the decorator\nresult = validate_deprecation_wrapper(my_func)\n\n\n# DeprecationWrapperInfo(\n#   function='my_func',\n#   invalid_args=[],\n#   empty_args_mapping=False,\n#   identity_args_mapping=[],\n#   self_reference=False,\n#   no_effect=False\n# )\n\n\n# Example: Function with invalid args_mapping\n@deprecated(target=TargetMode.ARGS_REMAP, args_mapping={\"nonexistent\": \"new_arg\"}, deprecated_in=\"1.0\")\ndef bad_func(real_arg: int = 0) -> int:\n    return real_arg\n\n\nresult = validate_deprecation_wrapper(bad_func)\n# result.invalid_args == ['nonexistent']\nprint(result)\n\n\n# Example: Function with empty mapping (no effect)\n@deprecated(target=TargetMode.ARGS_REMAP, args_mapping={}, deprecated_in=\"1.0\")\ndef empty_func(arg: int = 0) -> int:\n    return arg\n\n\nresult = validate_deprecation_wrapper(empty_func)\n# result.empty_args_mapping == True, result.no_effect == True\nprint(result)\n\n# Quick check if wrapper has any effect\nif result.no_effect:\n    print(\"Warning: This wrapper configuration has zero impact!\")\n```\n\n</details>\n\n<br>\n\n<details>\n<summary><b>Scanning a Package for Deprecated Wrappers</b></summary>\n\nThe `find_deprecation_wrappers()` utility scans an entire package or module and returns a list of `DeprecationWrapperInfo` dataclasses:\n\n```python\nfrom deprecate import find_deprecation_wrappers\n\n# For testing purposes, we use the test module; normally you would import your own package\nfrom tests import collection_deprecate as my_package\n\n# Scan an entire package for deprecated wrappers\nresults = find_deprecation_wrappers(my_package)\n\n# Or scan using a string module path\nresults = find_deprecation_wrappers(\"tests.collection_deprecate\")\n\n# Check results - each item is a DeprecationWrapperInfo dataclass\nfor r in results:\n    print(f\"{r.module}.{r.function}: no_effect={r.no_effect}\")\n    if r.no_effect:\n        print(f\"  Warning: This wrapper has zero impact!\")\n        print(f\"  invalid_args: {r.invalid_args}, identity_args_mapping: {r.identity_args_mapping}\")\n\n# Filter to only ineffective wrappers\nineffective = [r for r in results if r.no_effect]\nif ineffective:\n    print(f\"Found {len(ineffective)} deprecated wrappers with zero impact!\")\n```\n\n</details>\n\n<br>\n\n<details>\n<summary><b>Generating Reports by Issue Type</b></summary>\n\nGroup validation results by issue type for better reporting:\n\n```python\nfrom deprecate import find_deprecation_wrappers\n\n# For testing purposes, we use the test module; normally you would import your own package\nfrom tests import collection_deprecate as my_package\n\nresults = find_deprecation_wrappers(my_package)\n\n# Group by issue type (using dataclass attribute access)\nwrong_args = [r for r in results if r.invalid_args]\nidentity_mappings = [r for r in results if r.identity_args_mapping]\nself_refs = [r for r in results if r.self_reference]\n\nprint(f\"=== Deprecation Validation Report ===\")\nprint(f\"Wrong arguments: {len(wrong_args)}\")\nprint(f\"Identity mappings: {len(identity_mappings)}\")\nprint(f\"Self-references: {len(self_refs)}\")\n```\n\n</details>\n\n<br>\n\n### Generating Deprecation Tables\n\nIf you want docs-friendly summaries, `generate_deprecation_table()` renders\nthe discovered wrapper metadata as Markdown tables. The report includes\ndeprecated class members such as methods and constructors, so wrapper metadata\nremains the single source of truth.\n\nIt supports two styles via `style=`:\n\n- `compact` (default): `Original API | API Type | New API | Deprecated | Remove | Current Status`\n- `matrix`: `Original API | API Type | New API | <all versions ...>` with lifecycle markers:\n  - `D` = deprecated in this version\n  - `R` = remove in this version\n- rows are ordered by module and symbol family (class/function), so related `args` variants stay grouped together\n\nThe **Current Status** column uses these labels:\n\n| Status                    | Meaning                                                                   |\n| ------------------------- | ------------------------------------------------------------------------- |\n| 🕒 Scheduled Deprecation  | Current version is before `deprecated_in` — not yet active                |\n| ℹ️ No Removal Target      | No `remove_in` set — no scheduled removal                                 |\n| ⚪ Status Unknown         | `packaging` not installed or `current_version` not resolvable             |\n| ⚪ Invalid Removal Target | `remove_in` cannot be parsed as a PEP 440 version                         |\n| 📢 Deprecation Active     | Between `deprecated_in` and `remove_in` — still in the deprecation window |\n| ⏰ Removal Imminent       | Dev/alpha/beta pre-release of the `remove_in` base version                |\n| 🔔 Remove Before Release  | RC pre-release of the `remove_in` base version                            |\n| 💥 Past Removal Date      | Current version ≥ `remove_in` — zombie code that should be deleted        |\n\n```python\nfrom tests import collection_deprecate as my_package\nfrom deprecate import generate_deprecation_table\n\nreport = generate_deprecation_table(my_package, current_version=\"1.5\", recursive=False)\n```\n\n> **Current version: 1.5**\n>\n> | Original API                                | API Type     | New API                         | Deprecated | Remove | Current Status           |\n> | :------------------------------------------ | :----------- | :------------------------------ | :--------: | :----: | :----------------------- |\n> | `my_package.depr_func_same_version`         | callable     | `—`                             |    v2.0    |  v3.0  | 🕒 Scheduled Deprecation |\n> | `my_package.ServiceCls.old_redirect_method` | class method | `my_package.ServiceCls.compute` |    v1.0    |  v2.0  | 📢 Deprecation Active    |\n> | `my_package.depr_pow_args`                  | callable     | `my_package.base_pow_args`      |    v1.0    |  v1.3  | 💥 Past Removal Date     |\n> | `my_package.depr_func_no_remove_in`         | callable     | `—`                             |    v1.0    |   —    | ℹ️ No Removal Target     |\n\n<br>\n\n<details>\n<summary><b>Using the CLI</b></summary>\n\nYou can also use the CLI to validate your deprecations directly from the command line.\n\nThe CLI requires the `cli` extra (includes `fire` and `rich`). Install it with:\n\n```bash\npip install 'pyDeprecate[audit,cli]'\n```\n\nThe CLI has five subcommands.\n\n```bash\n# check — wrapper config + deprecated-to-deprecated chains (default)\npydeprecate check path/to/your/package\npydeprecate path/to/your/package          # equivalent shorthand\n\n# expiry — wrappers past their remove_in deadline\n# requires: pip install 'pyDeprecate[audit]'\npydeprecate expiry path/to/your/package --version 2.0.0\npydeprecate expiry path/to/your/package   # auto-detects version from the package\n\n# chains — deprecated-to-deprecated forwarding chains only\npydeprecate chains path/to/your/package\n\n# all — single scan running check + expiry + chains, then appends a deprecation table\npydeprecate all path/to/your/package --version 2.0.0\n\n# status — print a markdown deprecation status table (standalone, no checks)\npydeprecate status path/to/your/package\npydeprecate status path/to/your/package --style matrix\npydeprecate status path/to/your/package --version 2.0.0 --output DEPRECATIONS.md\n```\n\n**Common flags** (all subcommands): `--norecursive` scans the top-level module only.\n`check`, `expiry`, `chains`, and `all` also accept `--exit-zero` to always exit `0` even when issues are found.\n`expiry`, `all`, and `status` also accept `--version VERSION` to set the current version explicitly.\n`status` additionally accepts `--style compact|matrix` (default `compact`) and `--output FILE` to also save the markdown to that file.\n\n**Quick demo** using pyDeprecate's own test fixtures (no package setup needed):\n\n```bash\n# Run all checks + deprecation table on the bundled test fixtures\npydeprecate all tests --version 1.2\n# Standalone deprecation table only\npydeprecate status tests --version 1.2\n```\n\n`tests/` contains pyDeprecate's own deprecation fixtures — useful as a live demo without needing your own package. Note: `expiry` and `chains` (run as part of `all`) require an importable package name rather than a plain directory path.\n\n**Example: catching a deprecated-to-deprecated chain**\n\n```\n$ pydeprecate chains src/mypackage\n⚠  Deprecated chain detected: old_fn → legacy_fn → new_fn\n   old_fn is deprecated and forwards to legacy_fn, which is also deprecated.\n   Update old_fn to forward directly to new_fn.\n```\n\n**Example: combined one-liner scan across all checks**\n\n```\n$ pydeprecate all src/mypackage\n✓ check:  12 wrappers validated, 0 misconfigured\n⚠ expiry: 2 wrappers past remove_in deadline\n✓ chains: no deprecated→deprecated chains detected\n```\n\n</details>\n\n<details>\n<summary><b>CI/pytest Integration</b></summary>\n\nUse in pytest to validate your package's deprecation wrappers:\n\n```python\nimport warnings\n\nimport pytest\nfrom deprecate import find_deprecation_wrappers\n\n# For testing purposes, we use the test module; normally you would import your own package\nfrom tests import collection_deprecate as my_package\n\n\ndef test_deprecated_wrappers_are_valid():\n    \"\"\"Validate all deprecated wrappers have proper configuration.\"\"\"\n    results = find_deprecation_wrappers(my_package)\n\n    # Collect issues — wrong arg names are errors, identity mappings are worth a warning\n    wrong_args = [r for r in results if r.invalid_args]\n    identity_mappings = [r for r in results if r.identity_args_mapping]\n\n    # Raise errors for wrong arguments (critical issues)\n    if wrong_args:\n        for r in wrong_args:\n            print(f\"ERROR: {r.module}.{r.function} has invalid args: {r.invalid_args}\")\n        pytest.fail(f\"Found {len(wrong_args)} deprecated wrappers with invalid arguments\")\n\n    # Warn for identity mappings (less severe)\n    for r in identity_mappings:\n        warnings.warn(f\"{r.function} has identity mapping\", UserWarning)\n```\n\n</details>\n\n<br>\n\n### ⏰ Enforcing Deprecation Removal Deadlines\n\nWhen you deprecate code with a `remove_in` version, you're making a commitment to remove that code when that version is reached. However, it's easy to forget to actually remove the code—leading to \"zombie code\" that lingers past its scheduled removal.\n\npyDeprecate provides enforcement utilities to detect and prevent zombie code in your CI/CD pipeline:\n\nThe `validate_deprecation_expiry()` utility scans an entire module or package for expired deprecations:\n\n<details>\n<summary>Example: scanning a package for expired removal deadlines</summary>\n\n```python\nfrom deprecate import validate_deprecation_expiry\n\n# For testing purposes, we use the test module; normally you would import your own package\nfrom tests import collection_deprecate as my_package\n\n# Scan your package for expired deprecations - using early-version that won't have expirations\nexpired = validate_deprecation_expiry(my_package, \"0.2\")\nprint(f\"Found {len(expired)} expired\")  # Returns a list of error messages (empty list = no expired)\n\n# Example with expired deprecations found (using later-version)\nexpired = validate_deprecation_expiry(my_package, \"0.5\")\nprint(f\"Found {len(expired)} expired\")\n\n# Auto-detect version from package metadata (mocked for demo)\nfrom unittest.mock import patch\n\nwith patch(\"importlib.metadata.version\", return_value=\"0.3\"):\n    expired = validate_deprecation_expiry(my_package)  # Automatically detects version\n    print(f\"Found {len(expired)} expired\")\n\n# Control recursion\nexpired = validate_deprecation_expiry(my_package, \"0.1\", recursive=False)  # Only scan top-level module\nprint(f\"Found {len(expired)} expired\")\n```\n\n</details>\n\n<br>\n\n<details>\n  <summary>Output: expired count per scanned version</summary>\n\n```\nFound 14 expired\nFound 28 expired\nFound 17 expired\nFound 0 expired\n```\n\n</details>\n\n<br>\n\n<details>\n<summary><b>CI/pytest Integration for Expiry Enforcement</b></summary>\n\nIntegrate expiry checks into your test suite to catch zombie code automatically:\n\n```python\nimport pytest\nfrom deprecate import validate_deprecation_expiry\n\n# For testing purposes, we use the test module; normally you would import your own package\nfrom tests import collection_deprecate as my_package\n\n\ndef test_no_zombie_deprecations():\n    \"\"\"Ensure all deprecated code is removed when it reaches its deadline.\"\"\"\n    # Use your package's actual version - for this example we use a test version\n    current_version = \"0.5\"  # Replace with: from mypackage import __version__\n\n    expired = validate_deprecation_expiry(my_package, current_version)\n\n    if expired:\n        error_msg = \"Found deprecated code past its removal deadline:\\n\"\n        for msg in expired:\n            error_msg += f\"  - {msg}\\n\"\n        pytest.fail(error_msg)\n\n\n# Alternative: Use a fixture to run on every test session\n# For testing purposes, we use the test module; normally you would import your own package\n@pytest.fixture(scope=\"session\", autouse=True)\ndef enforce_deprecation_deadlines():\n    \"\"\"Automatically check for zombie code before running any tests.\"\"\"\n    from tests import collection_deprecate as my_package\n\n    current_version = \"0.5\"  # Replace with: from mypackage import __version__\n    expired = validate_deprecation_expiry(my_package, current_version)\n    if expired:\n        raise AssertionError(\n            f\"Cannot run tests: {len(expired)} deprecated callables past removal deadline. \"\n            f\"Remove these functions first: {expired}\"\n        )\n```\n\n</details>\n\n<br>\n\n> [!TIP]\n>\n> - Callables without `remove_in` are skipped (warnings-only deprecations are allowed)\n> - Invalid version formats in `remove_in` are silently skipped\n> - PEP 440 versioning is used for comparison (e.g., \"2.0.0\" > \"1.9.5\")\n> - Pre-release versions are handled correctly (e.g., \"1.5.0a1\" < \"1.5.0\")\n\n### 🔗 Detecting Deprecation Chains\n\nWhen refactoring code, it's easy to create \"lazy\" deprecated wrappers that call other deprecated functions instead of calling the new target directly. This creates deprecation chains that defeat the purpose of deprecation.\n\nThe `validate_deprecation_chains()` utility scans a module or package for deprecated functions whose `target` is itself a deprecated callable. Such chains are wasteful: the outer wrapper should point directly to the final (non-deprecated) implementation. Detection is purely metadata-based — no source-code inspection.\n\n<details>\n<summary><b>Example: Detecting Both Chain Types</b></summary>\n\n```python\nfrom deprecate import TargetMode, deprecated, validate_deprecation_wrapper, void\n\n\ndef new_power(base: float, exponent: float = 2) -> float:\n    return base**exponent\n\n\n# deprecated forwarder — targets new_power directly\n@deprecated(target=new_power, deprecated_in=\"1.0\", remove_in=\"2.0\")\ndef power_v2(base: float, exponent: float = 2) -> float:\n    void(base, exponent)\n\n\n# self-deprecation — renames old arg \"exp\" -> \"exponent\" within the same function\n@deprecated(TargetMode.ARGS_REMAP, deprecated_in=\"1.0\", remove_in=\"2.0\", args_mapping={\"exp\": \"exponent\"})\ndef legacy_power(base: float, exp: float = 2, exponent: float = 2) -> float:\n    return base**exponent\n\n\n# BAD: targets power_v2 (another deprecated forwarder) — ChainType.TARGET\n# SOLUTION: point directly to new_power\n@deprecated(target=power_v2, deprecated_in=\"1.5\", remove_in=\"2.5\")\ndef caller_target_chain(base: float, exponent: float = 2) -> float:  # ❌\n    return void(base, exponent)\n\n\n# BAD: targets legacy_power (target=TargetMode.ARGS_REMAP with arg renaming) — ChainType.STACKED\n# Mappings chain: \"power\" -> \"exp\" -> \"exponent\" — must be composed.\n# SOLUTION: target=new_power, args_mapping={\"power\": \"exponent\"}\n@deprecated(target=legacy_power, deprecated_in=\"1.5\", remove_in=\"2.5\", args_mapping={\"power\": \"exp\"})\ndef caller_stacked_chain(base: float, power: float = 2) -> float:  # ❌\n    return void(base, power)\n\n\n# GOOD: targets final implementation directly with composed mapping\n@deprecated(target=new_power, deprecated_in=\"1.5\", remove_in=\"2.5\", args_mapping={\"power\": \"exponent\"})\ndef caller_direct(base: float, power: float = 2) -> float:  # ✅\n    return void(base, power)\n\n\nfor func in (caller_target_chain, caller_stacked_chain, caller_direct):\n    info = validate_deprecation_wrapper(func)\n    print(f\"{func.__name__}: {info.chain_type}\")\n```\n\n</details>\n\n<br>\n\n<details>\n  <summary>Output: chain types</summary>\n\n```\ncaller_target_chain: ChainType.TARGET\ncaller_stacked_chain: ChainType.STACKED\ncaller_direct: None\n```\n\n</details>\n\n<br>\n\n<details>\n<summary><b>CI/pytest Integration for Chain Detection</b></summary>\n\nIntegrate chain detection into your test suite to prevent deprecated-to-deprecated forwarding:\n\n```python\nimport pytest\nfrom deprecate import validate_deprecation_chains\n\n# normally you would import your own package\nfrom tests import collection_chains as my_package\n\n\ndef test_no_deprecation_chains():\n    \"\"\"Ensure no deprecated function targets another deprecated function.\"\"\"\n    issues = validate_deprecation_chains(my_package)\n\n    if issues:\n        lines = [\n            f\"  - {i.function}: target '{getattr(i.deprecated_info['target'], '__name__', repr(i.deprecated_info['target']))}' is deprecated\"\n            for i in issues\n        ]\n        pytest.fail(\"Found deprecation chains:\\n\" + \"\\n\".join(lines))\n\n\n# Alternative: session-scoped auto-use fixture\n@pytest.fixture(scope=\"session\", autouse=True)\ndef enforce_no_deprecation_chains():\n    from tests import collection_chains as my_package\n\n    issues = validate_deprecation_chains(my_package)\n    if issues:\n        raise AssertionError(f\"Found {len(issues)} deprecation chain(s). Fix before running tests.\")\n```\n\n</details>\n\n<br>\n\n> [!TIP]\n>\n> - The function scans all deprecated functions found by `find_deprecation_wrappers()`\n> - Returns `list[DeprecationWrapperInfo]` — each entry has `chain_type` set to a `ChainType` enum value\n> - `ChainType.TARGET` — target is a deprecated callable that forwards to another function; fix by pointing directly to the final target\n> - `ChainType.STACKED` — arg mappings chain through multiple hops and must be composed; two sub-cases:\n>   - Callable target is itself `@deprecated(TargetMode.ARGS_REMAP, args_mapping=...)` (self-renaming) — mappings compose across hops\n>   - Stacked `@deprecated(TargetMode.ARGS_REMAP, args_mapping=...)` on the same function — merge into one decorator with combined `args_mapping`\n> - Use `recursive=False` to scan only the top-level module\n\n## 🧪 Testing Deprecated Code\n\npyDeprecate provides utilities to help you test deprecated code properly:\n\n```python\nfrom deprecate import deprecated, assert_no_warnings, void\nimport pytest\n\n\ndef new_func(x: int) -> int:\n    return x * 2\n\n\n@deprecated(target=new_func, deprecated_in=\"1.0\", remove_in=\"2.0\")\ndef old_func(x: int) -> int:\n    pass\n\n\n@deprecated(target=new_func, deprecated_in=\"1.0\", remove_in=\"2.0\")\ndef old_func2(x: int) -> int:\n    return void(x)\n\n\ndef test_deprecated_function_shows_warning():\n    \"\"\"Verify the deprecation warning is shown.\"\"\"\n    with pytest.warns(FutureWarning, match=\"old_func.*deprecated\"):\n        result = old_func(42)\n    assert result == 84\n\n\ndef test_new_function_no_warning():\n    \"\"\"Verify new function doesn't trigger warnings.\"\"\"\n    with assert_no_warnings(FutureWarning):\n        result = new_func(42)\n    assert result == 84\n\n\ndef test_no_warning_after_first_call():\n    \"\"\"By default, warnings are shown only once per function.\"\"\"\n    # First call shows warning\n    with pytest.warns(FutureWarning):\n        old_func2(1)\n\n    # Subsequent calls don't show warning (by default num_warns=1)\n    with assert_no_warnings(FutureWarning):\n        old_func2(2)\n\n\n# call the tests for CI demonstration/validation\ntest_deprecated_function_shows_warning()\ntest_new_function_no_warning()\ntest_no_warning_after_first_call()\n```\n\n<details>\n<summary>Advanced: Control warning frequency</summary>\n\n```python\n# Minimal replacement implementation used in examples\ndef new_func(x: int) -> int:\n    return x * 2\n\n\n# ---------------------------\n\nfrom deprecate import deprecated\n\n\n# Show warning every time (useful for critical deprecations)\n@deprecated(target=new_func, deprecated_in=\"1.0\", remove_in=\"2.0\", num_warns=-1)\ndef old_func_always_warn(x: int) -> int:\n    pass\n\n\n# Show warning N times total\n@deprecated(target=new_func, deprecated_in=\"1.0\", remove_in=\"2.0\", num_warns=5)\ndef old_func_warn_n_times(x: int) -> int:\n    pass\n\n\nprint(old_func_warn_n_times(1))\n```\n\n</details>\n\n<details>\n  <summary>Output: <code>old_func_warn_n_times(1)</code></summary>\n\n```\n2\n```\n\n</details>\n\n<br>\n\n## 🔧 Troubleshooting\n\n### ⚠ UserWarning: `Applying @deprecated to class … is deprecated itself`\n\n**Problem:** `UserWarning: Applying @deprecated to class MyClass is not supported since v0.6.0. Use @deprecated_class() from deprecate.proxy instead.`\n\n**Cause:** You applied `@deprecated` directly to a class. This still works (it delegates to `@deprecated_class()` under the hood) but is itself deprecated — `@deprecated` is designed for functions and methods only.\n\n<details>\n<summary>Solution</summary>\n\nUse `@deprecated_class()` for class-level deprecation:\n\n```python\nfrom deprecate import TargetMode, deprecated, deprecated_class\nfrom enum import Enum\n\n\n# Correct: use @deprecated_class for classes\n@deprecated_class(target=TargetMode.NOTIFY, deprecated_in=\"1.0\", remove_in=\"2.0\")\nclass MyClass:\n    pass\n\n\n@deprecated_class(target=TargetMode.NOTIFY, deprecated_in=\"1.0\", remove_in=\"2.0\")\nclass MyEnum(Enum):\n    A = 1\n    B = 2\n\n\n# Alternative: decorate __init__ to warn at instantiation while keeping the class name\nfrom deprecate import deprecated\n\n\nclass MyClass:\n    @deprecated(target=TargetMode.NOTIFY, deprecated_in=\"1.0\", remove_in=\"2.0\")\n    def __init__(self, x: int) -> None:\n        self.x = x  # body still executes; warning fires on every new MyClass(...)\n\n\nprint(MyClass(42).x)\n```\n\n</details>\n\n<details>\n  <summary>Output: <code>MyClass(42).x</code></summary>\n\n```\n42\n```\n\n</details>\n\n<br>\n\n### ❗ TypeError: `Failed mapping`\n\n**Problem:** `TypeError: Failed mapping of 'my_func', arguments missing in target source: ['old_arg']`\n\n**Cause:** Your deprecated function has arguments that the target function doesn't accept.\n\n<details>\n<summary>Solutions</summary>\n\n1. **Skip the argument** (if it's no longer needed):\n\n   ```python\n   # define a target that ignores the extra arg\n   def new_func(required_arg: int, **kwargs) -> int:\n       return required_arg * 2\n\n\n   # ---------------------------\n\n   from deprecate import deprecated\n\n\n   # None means skip this argument\n   @deprecated(target=new_func, args_mapping={\"old_arg\": None})\n   def old_func(old_arg: int, new_arg: int) -> int:\n       pass\n   ```\n\n2. **Rename the argument** (if target uses different name):\n\n   ```python\n   def new_func(new_name: int) -> int:\n       return new_name * 2\n\n\n   # ---------------------------\n\n   from deprecate import deprecated\n\n\n   # Map old to new\n   @deprecated(target=new_func, args_mapping={\"old_name\": \"new_name\"})\n   def old_func(old_name: int) -> int:\n       pass\n   ```\n\n3. **Use `TargetMode.ARGS_REMAP` for self-deprecation** (deprecate argument of same function):\n\n   ```python\n   from deprecate import TargetMode, deprecated\n\n\n   # Deprecate within same function\n   @deprecated(target=TargetMode.ARGS_REMAP, args_mapping={\"old_arg\": \"new_arg\"})\n   def my_func(old_arg: int = 0, new_arg: int = 0) -> int:\n       return new_arg * 2\n   ```\n\n</details>\n\n<br>\n\n### ❗ TypeError: `User function 'should_ship' shall return bool`\n\n**Problem:** `TypeError: User function 'should_ship' shall return bool, but got: <type>`\n\n**Cause:** When using `skip_if` with a callable, the function must return a boolean value.\n\n<details>\n<summary>Solution</summary>\n\n```python\n# Minimal replacement function for examples\ndef new_func() -> str:\n    return \"Hi!\"\n\n\n# ---------------------------\n\nfrom deprecate import deprecated\n\n\n# Correct: function returns bool\ndef should_skip() -> bool:\n    return False  # replace with your condition\n\n\n@deprecated(target=new_func, skip_if=should_skip)\ndef old_func1():\n    pass\n\n\n# Also correct: use a lambda\n@deprecated(target=new_func, skip_if=lambda: False)\ndef old_func2():\n    pass\n\n\nprint(old_func2())\n```\n\n</details>\n\n<details>\n  <summary>Output: <code>old_func2()</code></summary>\n\n```\nHi!\n```\n\n</details>\n\n<br>\n\n### ⚠️ Warning Not Showing\n\n**Problem:** You don't see the deprecation warning.\n\n**Cause:** By default, warnings are shown **only once per function** (`num_warns=1`) to prevent log spam.\nFor per-argument deprecation (when using `args_mapping` with `TargetMode.ARGS_REMAP`), each deprecated argument\nhas its own warning counter, meaning warnings for different arguments are tracked independently.\n\n<details>\n<summary>Solutions</summary>\n\n```python\n# Minimal replacement function for examples\ndef new_func(x: int) -> int:\n    return x * 2\n\n\n# ---------------------------\n\nfrom deprecate import deprecated\n\n\n# Show warning every time\n@deprecated(target=new_func, num_warns=-1)  # -1 means unlimited\ndef old_func_always_warn():\n    pass\n\n\n# Show warning N times total\n@deprecated(target=new_func, num_warns=5)  # Show 5 times\ndef old_func_warn_n_times():\n    pass\n\n\nassert callable(old_func_warn_n_times)\n```\n\n</details>\n\n<br>\n\n### 📦 Deprecation Not Working Across Modules\n\nIf you're moving functions to a different module or package, show the pattern rather than importing a non-existent package in the docs.\n\nThe warning will correctly show the full path for real imports when used in your package.\n\n## 🤝 Contributing\n\nHave you faced this issue in the past or are you facing it now? Do you have good ideas for improvement? All contributions are welcome!\n\nPlease read our [Contributing Guide](https://github.com/Borda/pyDeprecate/raw/v0.9.0/.github/CONTRIBUTING.md) for details on how to contribute, and our [Code of Conduct](https://github.com/Borda/pyDeprecate/raw/v0.9.0/.github/CODE_OF_CONDUCT.md) for community guidelines.\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "deprecation",
          "decorator",
          "API migration",
          "call forwarding",
          "argument renaming",
          "backwards compatibility",
          "CI audit"
        ],
        "home_page": "https://borda.github.io/pyDeprecate/stable/",
        "author": "Jiri Borovec",
        "author_email": "j.borovec+github[at]gmail.com",
        "license": "Apache-2.0",
        "classifier": [
          "Environment :: Console",
          "Natural Language :: English",
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Software Development :: Libraries",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Topic :: Software Development :: Quality Assurance"
        ],
        "requires_dist": [
          "packaging>=20.0; extra == \"audit\"",
          "tomli>=2.0; python_version < \"3.11\" and extra == \"audit\"",
          "fire; extra == \"cli\"",
          "rich; extra == \"cli\""
        ],
        "requires_python": ">=3.9",
        "project_url": [
          "Documentation, https://borda.github.io/pyDeprecate/stable/",
          "Source Code, https://github.com/Borda/pyDeprecate",
          "Bug Tracker, https://github.com/Borda/pyDeprecate/issues",
          "Changelog, https://github.com/Borda/pyDeprecate/blob/main/CHANGELOG.md",
          "Agent Guide, https://borda.github.io/pyDeprecate/llms.txt"
        ],
        "provides_extra": [
          "audit",
          "cli"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231",
          "hashes": {
            "sha256": "381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "referencing",
        "version": "0.37.0",
        "summary": "JSON Referencing + Python",
        "description": "===============\n``referencing``\n===============\n\n|PyPI| |Pythons| |CI| |ReadTheDocs| |pre-commit|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/referencing.svg\n  :alt: PyPI version\n  :target: https://pypi.org/project/referencing/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/referencing.svg\n  :alt: Supported Python versions\n  :target: https://pypi.org/project/referencing/\n\n.. |CI| image:: https://github.com/python-jsonschema/referencing/workflows/CI/badge.svg\n  :alt: Build status\n  :target: https://github.com/python-jsonschema/referencing/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat\n   :alt: ReadTheDocs status\n   :target: https://referencing.readthedocs.io/en/stable/\n\n.. |pre-commit| image:: https://results.pre-commit.ci/badge/github/python-jsonschema/referencing/main.svg\n  :alt: pre-commit.ci status\n  :target: https://results.pre-commit.ci/latest/github/python-jsonschema/referencing/main\n\n\nAn implementation-agnostic implementation of JSON reference resolution.\n\nSee `the documentation <https://referencing.readthedocs.io/>`_ for more details.\n",
        "description_content_type": "text/x-rst",
        "keywords": [
          "asyncapi",
          "json",
          "jsonschema",
          "openapi",
          "referencing"
        ],
        "author_email": "Julian Berman <Julian+referencing@GrayVines.com>",
        "classifier": [
          "Development Status :: 3 - Alpha",
          "Intended Audience :: Developers",
          "Operating System :: OS Independent",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Topic :: File Formats :: JSON",
          "Topic :: File Formats :: JSON :: JSON Schema"
        ],
        "requires_dist": [
          "attrs>=22.2.0",
          "rpds-py>=0.7.0",
          "typing-extensions>=4.4.0; python_version < '3.13'"
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Documentation, https://referencing.readthedocs.io/",
          "Homepage, https://github.com/python-jsonschema/referencing",
          "Issues, https://github.com/python-jsonschema/referencing/issues/",
          "Funding, https://github.com/sponsors/Julian",
          "Tidelift, https://tidelift.com/subscription/pkg/pypi-referencing?utm_source=pypi-referencing&utm_medium=referral&utm_campaign=pypi-link",
          "Changelog, https://referencing.readthedocs.io/en/stable/changes/",
          "Source, https://github.com/python-jsonschema/referencing"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/04/8f/d2f3f532616be4d06c316ef119683e832bd3d41e112bf3a88f4151c95b17/rpds_py-2026.6.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
        "archive_info": {
          "hash": "sha256=ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6",
          "hashes": {
            "sha256": "ecabd69db66de867690f9797f2f8fa27ba501bbc24540cbdbdc649cd15888ba6"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "rpds-py",
        "version": "2026.6.3",
        "summary": "Python bindings to Rust's persistent data structures (rpds)",
        "description": "===========\n``rpds.py``\n===========\n\n|PyPI| |Pythons| |CI|\n\n.. |PyPI| image:: https://img.shields.io/pypi/v/rpds-py.svg\n  :alt: PyPI version\n  :target: https://pypi.org/project/rpds-py/\n\n.. |Pythons| image:: https://img.shields.io/pypi/pyversions/rpds-py.svg\n  :alt: Supported Python versions\n  :target: https://pypi.org/project/rpds-py/\n\n.. |CI| image:: https://github.com/crate-py/rpds/workflows/CI/badge.svg\n  :alt: Build status\n  :target: https://github.com/crate-py/rpds/actions?query=workflow%3ACI\n\n.. |ReadTheDocs| image:: https://readthedocs.org/projects/referencing/badge/?version=stable&style=flat\n   :alt: ReadTheDocs status\n   :target: https://referencing.readthedocs.io/en/stable/\n\n\nPython bindings to the `Rust rpds crate <https://docs.rs/rpds/>`_ for persistent data structures.\n\nWhat's here is quite minimal (in transparency, it was written initially to support replacing ``pyrsistent`` in the `referencing library <https://github.com/python-jsonschema/referencing>`_).\nIf you see something missing (which is very likely), a PR is definitely welcome to add it.\n\nInstallation\n------------\n\nThe distribution on PyPI is named ``rpds.py`` (equivalently ``rpds-py``), and thus can be installed via e.g.:\n\n.. code:: sh\n\n    $ pip install rpds-py\n\nNote that if you install ``rpds-py`` from source, you will need a Rust toolchain installed, as it is a build-time dependency.\nAn example of how to do so in a ``Dockerfile`` can be found `here <https://github.com/bowtie-json-schema/bowtie/blob/e77fd93598cb6e7dc1b8b1f53c00e5aa410c201a/implementations/python-jsonschema/Dockerfile#L1-L8>`_.\n\nIf you believe you are on a common platform which should have wheels built (i.e. and not need to compile from source), feel free to file an issue or pull request modifying the GitHub action used here to build wheels via ``maturin``.\n\nUsage\n-----\n\nMethods in general are named similarly to their ``rpds`` counterparts (rather than ``pyrsistent``\\ 's conventions, though probably a full drop-in ``pyrsistent``\\ -compatible wrapper module is a good addition at some point).\n\n.. code:: python\n\n    >>> from rpds import HashTrieMap, HashTrieSet, List\n\n    >>> m = HashTrieMap({\"foo\": \"bar\", \"baz\": \"quux\"})\n    >>> m.insert(\"spam\", 37) == HashTrieMap({\"foo\": \"bar\", \"baz\": \"quux\", \"spam\": 37})\n    True\n    >>> m.remove(\"foo\") == HashTrieMap({\"baz\": \"quux\"})\n    True\n\n    >>> s = HashTrieSet({\"foo\", \"bar\", \"baz\", \"quux\"})\n    >>> s.insert(\"spam\") == HashTrieSet({\"foo\", \"bar\", \"baz\", \"quux\", \"spam\"})\n    True\n    >>> s.remove(\"foo\") == HashTrieSet({\"bar\", \"baz\", \"quux\"})\n    True\n\n    >>> L = List([1, 3, 5])\n    >>> L.push_front(-1) == List([-1, 1, 3, 5])\n    True\n    >>> L.rest == List([3, 5])\n    True\n\n",
        "description_content_type": "text/x-rst; charset=UTF-8",
        "keywords": [
          "data structures",
          "rust",
          "persistent"
        ],
        "author_email": "Julian Berman <Julian+rpds@GrayVines.com>",
        "classifier": [
          "Development Status :: 3 - Alpha",
          "Intended Audience :: Developers",
          "Operating System :: OS Independent",
          "Programming Language :: Rust",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3.15",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy"
        ],
        "requires_python": ">=3.11",
        "project_url": [
          "Documentation, https://rpds.readthedocs.io/",
          "Funding, https://github.com/sponsors/Julian",
          "Homepage, https://github.com/crate-py/rpds",
          "Issues, https://github.com/crate-py/rpds/issues/",
          "Source, https://github.com/crate-py/rpds",
          "Tidelift, https://tidelift.com/subscription/pkg/pypi-rpds-py?utm_source=pypi-rpds-py&utm_medium=referral&utm_campaign=pypi-link",
          "Upstream, https://github.com/orium/rpds"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/cc/c6/d6f058ff025994b79bcda3dbd6cefd4d57927c03fe5729c22db892a94f0a/supervision-0.30.2-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=fd0f90d091abf504adc1ecf42dbb3dcefadc72adb8800ced3f40945eaa6734dc",
          "hashes": {
            "sha256": "fd0f90d091abf504adc1ecf42dbb3dcefadc72adb8800ced3f40945eaa6734dc"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "supervision",
        "version": "0.30.2",
        "dynamic": [
          "license-file"
        ],
        "summary": "A set of easy-to-use utils that will come in handy in any Computer Vision project",
        "description": "<div align=\"center\">\n  <p>\n    <a align=\"center\" href=\"https://supervision.roboflow.com\" target=\"_blank\">\n      <img\n        width=\"100%\"\n        src=\"https://media.roboflow.com/open-source/supervision/rf-supervision-banner.png?updatedAt=1678995927529\"\n      >\n    </a>\n  </p>\n\n<br>\n\n[notebooks](https://github.com/roboflow/notebooks) | [inference](https://github.com/roboflow/inference) | [autodistill](https://github.com/autodistill/autodistill) | [maestro](https://github.com/roboflow/multimodal-maestro)\n\n<br>\n\n[![version](https://badge.fury.io/py/supervision.svg)](https://badge.fury.io/py/supervision) [![downloads](https://img.shields.io/pypi/dm/supervision)](https://pypistats.org/packages/supervision) [![license](https://img.shields.io/pypi/l/supervision)](LICENSE.md) [![python-version](https://img.shields.io/pypi/pyversions/supervision)](https://badge.fury.io/py/supervision) [![codecov](https://codecov.io/gh/roboflow/supervision/graph/badge.svg?token=HMNJ5FVZ36)](https://codecov.io/gh/roboflow/supervision)\n\n[![snyk](https://snyk.io/advisor/python/supervision/badge.svg)](https://snyk.io/advisor/python/supervision) [![colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/roboflow/supervision/blob/main/demo.ipynb) [![gradio](https://img.shields.io/badge/%F0%9F%A4%97%20Hugging%20Face-Spaces-blue)](https://huggingface.co/spaces/Roboflow/Annotators) [![discord](https://img.shields.io/discord/1159501506232451173?logo=discord&label=discord&labelColor=fff&color=5865f2&link=https%3A%2F%2Fdiscord.gg%2FGbfgXGJ8Bk)](https://discord.gg/GbfgXGJ8Bk)\n\n<div align=\"center\">\n    <a href=\"https://trendshift.io/repositories/124\"  target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/124\" alt=\"roboflow%2Fsupervision | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a>\n  </div>\n\n</div>\n\n<details>\n<summary><strong>📑 Table of Contents</strong></summary>\n\n- [👋 Hello](#-hello)\n- [💻 Install](#-install)\n- [🔥 Quickstart](#-quickstart)\n  - [Models](#models)\n  - [Annotators](#annotators)\n  - [Datasets](#datasets)\n- [🎬 Tutorials](#-tutorials)\n- [💜 Built with Supervision](#-built-with-supervision)\n- [📚 Documentation](#-documentation)\n- [🏆 Contribution](#-contribution)\n\n</details>\n\n## 👋 Hello\n\n**We are your essential toolkit for computer vision.** From data loading to real-time zone counting, we provide the building blocks so you can focus on building applications around your models. 🤝\n\n## 💻 Install\n\nPip install the supervision package in a [**Python>=3.10**](https://www.python.org/) environment.\n\n```bash\npip install supervision\n```\n\nRead more about conda, mamba, and installing from source in our [guide](https://roboflow.github.io/supervision/).\n\n## 🔥 Quickstart\n\n### Models\n\nSupervision was designed to be model agnostic. Just plug in any classification, detection, or segmentation model. For your convenience, we have created [connectors](https://supervision.roboflow.com/latest/detection/core/#detections) for the most popular libraries like Ultralytics, Transformers, MMDetection, or Inference. Other integrations, like `rfdetr`, already return `sv.Detections` directly.\n\nInstall the optional dependencies for this example with `pip install pillow rfdetr`.\n\n```python\nimport supervision as sv\nfrom PIL import Image\nfrom rfdetr import RFDETRSmall\n\nimage = Image.open(\"path/to/image.jpg\")\nmodel = RFDETRSmall()\ndetections = model.predict(image, threshold=0.5)\n\nlen(detections)\n# 5\n```\n\n<details>\n<summary>👉 more model connectors</summary>\n\n- inference\n\n  Running with [Inference](https://github.com/roboflow/inference) requires a [Roboflow API KEY](https://docs.roboflow.com/api-reference/authentication#retrieve-an-api-key).\n\n  ```python\n  import supervision as sv\n  from PIL import Image\n  from inference import get_model\n\n  image = Image.open(\"path/to/image.jpg\")\n  model = get_model(model_id=\"rfdetr-small\", api_key=\"ROBOFLOW_API_KEY\")\n  result = model.infer(image)[0]\n  detections = sv.Detections.from_inference(result)\n\n  len(detections)\n  # 5\n  ```\n\n</details>\n\n### Annotators\n\nSupervision offers a wide range of highly customizable [annotators](https://supervision.roboflow.com/latest/detection/annotators/), allowing you to compose the perfect visualization for your use case.\n\n```python\nimport cv2\nimport supervision as sv\n\nimage = cv2.imread(\"path/to/image.jpg\")\n# Assuming detections are obtained from a model\ndetections = sv.Detections(...)\n\nbox_annotator = sv.BoxAnnotator()\nannotated_frame = box_annotator.annotate(scene=image.copy(), detections=detections)\n```\n\nhttps://github.com/roboflow/supervision/assets/26109316/691e219c-0565-4403-9218-ab5644f39bce\n\n### Datasets\n\nSupervision provides a set of [utils](https://supervision.roboflow.com/latest/datasets/core/) that allow you to load, split, merge, and save datasets in one of the supported formats.\n\n```python\nimport supervision as sv\nfrom roboflow import Roboflow\n\nproject = Roboflow().workspace(\"WORKSPACE_ID\").project(\"PROJECT_ID\")\ndataset = project.version(\"PROJECT_VERSION\").download(\"coco\")\n\nds = sv.DetectionDataset.from_coco(\n    images_directory_path=f\"{dataset.location}/train\",\n    annotations_path=f\"{dataset.location}/train/_annotations.coco.json\",\n)\n\npath, image, annotation = ds[0]\n# loads image on demand\n\nfor path, image, annotation in ds:\n    # loads image on demand\n    pass\n```\n\n<details>\n<summary>👉 more dataset utils</summary>\n\n- load\n\n  ```python\n  dataset = sv.DetectionDataset.from_yolo(\n      images_directory_path=...,\n      annotations_directory_path=...,\n      data_yaml_path=...,\n  )\n\n  dataset = sv.DetectionDataset.from_pascal_voc(\n      images_directory_path=...,\n      annotations_directory_path=...,\n  )\n\n  dataset = sv.DetectionDataset.from_coco(\n      images_directory_path=...,\n      annotations_path=...,\n  )\n  ```\n\n- split\n\n  ```python\n  train_dataset, test_dataset = dataset.split(split_ratio=0.7)\n  test_dataset, valid_dataset = test_dataset.split(split_ratio=0.5)\n\n  len(train_dataset), len(test_dataset), len(valid_dataset)\n  # (700, 150, 150)\n  ```\n\n- merge\n\n  ```python\n  ds_1 = sv.DetectionDataset(...)\n  len(ds_1)\n  # 100\n  ds_1.classes\n  # ['dog', 'person']\n\n  ds_2 = sv.DetectionDataset(...)\n  len(ds_2)\n  # 200\n  ds_2.classes\n  # ['cat']\n\n  ds_merged = sv.DetectionDataset.merge([ds_1, ds_2])\n  len(ds_merged)\n  # 300\n  ds_merged.classes\n  # ['cat', 'dog', 'person']\n  ```\n\n- save\n\n  ```python\n  dataset.as_yolo(\n      images_directory_path=...,\n      annotations_directory_path=...,\n      data_yaml_path=...,\n  )\n\n  dataset.as_pascal_voc(\n      images_directory_path=...,\n      annotations_directory_path=...,\n  )\n\n  dataset.as_coco(\n      images_directory_path=...,\n      annotations_path=...,\n  )\n  ```\n\n- convert\n\n  ```python\n  sv.DetectionDataset.from_yolo(\n      images_directory_path=...,\n      annotations_directory_path=...,\n      data_yaml_path=...,\n  ).as_pascal_voc(\n      images_directory_path=...,\n      annotations_directory_path=...,\n  )\n  ```\n\n</details>\n\n## 🎬 Tutorials\n\nWant to learn how to use Supervision? Explore our [how-to guides](https://supervision.roboflow.com/develop/how_to/detect_and_annotate/), [end-to-end examples](https://github.com/roboflow/supervision/tree/0.30.2/examples), [cheatsheet](https://roboflow.github.io/cheatsheet-supervision/), and [cookbooks](https://supervision.roboflow.com/develop/cookbooks/)!\n\n<br/>\n\n<p align=\"left\">\n<a href=\"https://youtu.be/hAWpsIuem10\" title=\"Dwell Time Analysis with Computer Vision | Real-Time Stream Processing\"><img src=\"https://github.com/user-attachments/assets/014cffc7-72b3-4c0a-bb89-6de265b2c06b\" alt=\"Dwell Time Analysis with Computer Vision | Real-Time Stream Processing\" width=\"300px\" align=\"left\" /></a>\n<a href=\"https://youtu.be/hAWpsIuem10\" title=\"Dwell Time Analysis with Computer Vision | Real-Time Stream Processing\"><strong>Dwell Time Analysis with Computer Vision | Real-Time Stream Processing</strong></a>\n<div><strong>Created: 5 Apr 2024</strong></div>\n<br/>Learn how to use computer vision to analyze wait times and optimize processes. This tutorial covers object detection, tracking, and calculating time spent in designated zones. Use these techniques to improve customer experience in retail, traffic management, or other scenarios.</p>\n\n<br/>\n\n<p align=\"left\">\n<a href=\"https://youtu.be/uWP6UjDeZvY\" title=\"Speed Estimation & Vehicle Tracking | Computer Vision | Open Source\"><img src=\"https://github.com/user-attachments/assets/b16b8e21-dc6c-4a73-a678-2f7d5d374793\" alt=\"Speed Estimation & Vehicle Tracking | Computer Vision | Open Source\" width=\"300px\" align=\"left\" /></a>\n<a href=\"https://youtu.be/uWP6UjDeZvY\" title=\"Speed Estimation & Vehicle Tracking | Computer Vision | Open Source\"><strong>Speed Estimation & Vehicle Tracking | Computer Vision | Open Source</strong></a>\n<div><strong>Created: 11 Jan 2024</strong></div>\n<br/>Learn how to track and estimate the speed of vehicles using YOLO, ByteTrack, and Roboflow Inference. This comprehensive tutorial covers object detection, multi-object tracking, filtering detections, perspective transformation, speed estimation, visualization improvements, and more.</p>\n\n## 💜 Built with Supervision\n\nDid you build something cool using supervision? [Let us know!](https://github.com/roboflow/supervision/discussions/categories/built-with-supervision)\n\nhttps://user-images.githubusercontent.com/26109316/207858600-ee862b22-0353-440b-ad85-caa0c4777904.mp4\n\nhttps://github.com/roboflow/supervision/assets/26109316/c9436828-9fbf-4c25-ae8c-60e9c81b3900\n\nhttps://github.com/roboflow/supervision/assets/26109316/3ac6982f-4943-4108-9b7f-51787ef1a69f\n\n## 📚 Documentation\n\nVisit our [documentation](https://roboflow.github.io/supervision) page to learn how supervision can help you build computer vision applications faster and more reliably.\n\n## 🏆 Contribution\n\nWe love your input! Please see our [contributing guide](https://github.com/roboflow/supervision/blob/0.30.2/.github/CONTRIBUTING.md) to get started. Thank you 🙏 to all our contributors!\n\n<p align=\"center\">\n    <a href=\"https://github.com/roboflow/supervision/graphs/contributors\">\n      <img src=\"https://contrib.rocks/image?repo=roboflow/supervision\" />\n    </a>\n</p>\n\n<br>\n\n<div align=\"center\">\n      <a href=\"https://youtube.com/roboflow\">\n          <img\n            src=\"https://media.roboflow.com/notebooks/template/icons/purple/youtube.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949634652\"\n            width=\"3%\"\n          />\n      </a>\n      <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n      <a href=\"https://roboflow.com\">\n          <img\n            src=\"https://media.roboflow.com/notebooks/template/icons/purple/roboflow-app.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949746649\"\n            width=\"3%\"\n          />\n      </a>\n      <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n      <a href=\"https://www.linkedin.com/company/roboflow-ai/\">\n          <img\n            src=\"https://media.roboflow.com/notebooks/template/icons/purple/linkedin.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633691\"\n            width=\"3%\"\n          />\n      </a>\n      <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n      <a href=\"https://docs.roboflow.com\">\n          <img\n            src=\"https://media.roboflow.com/notebooks/template/icons/purple/knowledge.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949634511\"\n            width=\"3%\"\n          />\n      </a>\n      <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n      <a href=\"https://discuss.roboflow.com\">\n          <img\n            src=\"https://media.roboflow.com/notebooks/template/icons/purple/forum.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633584\"\n            width=\"3%\"\n          />\n      </a>\n      <img src=\"https://raw.githubusercontent.com/ultralytics/assets/main/social/logo-transparent.png\" width=\"3%\"/>\n      <a href=\"https://blog.roboflow.com\">\n          <img\n            src=\"https://media.roboflow.com/notebooks/template/icons/purple/blog.png?ik-sdk-version=javascript-1.4.3&updatedAt=1672949633605\"\n            width=\"3%\"\n          />\n      </a>\n  </div>\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "AI",
          "deep-learning",
          "DL",
          "machine-learning",
          "ML",
          "Roboflow",
          "vision"
        ],
        "author_email": "\"Roboflow et al.\" <develop@roboflow.com>",
        "maintainer_email": "Piotr Skalski <piotr@roboflow.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Intended Audience :: Education",
          "Intended Audience :: Science/Research",
          "Operating System :: MacOS",
          "Operating System :: Microsoft :: Windows",
          "Operating System :: POSIX :: Linux",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Multimedia :: Graphics",
          "Topic :: Multimedia :: Video",
          "Topic :: Scientific/Engineering",
          "Topic :: Scientific/Engineering :: Artificial Intelligence",
          "Topic :: Scientific/Engineering :: Image Recognition",
          "Topic :: Software Development",
          "Typing :: Typed"
        ],
        "requires_dist": [
          "av>=14.2",
          "defusedxml>=0.7.1",
          "matplotlib>=3.6",
          "numpy>=1.21.2",
          "pillow>=9.4",
          "pydeprecate<0.12,>=0.9",
          "pyyaml>=5.3",
          "requests>=2.26",
          "scipy>=1.10",
          "tqdm>=4.62.3",
          "rasterio>=1.3; extra == \"geotiff\"",
          "pandas>=2; extra == \"metrics\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Documentation, https://supervision.roboflow.com/latest/",
          "Homepage, https://github.com/roboflow/supervision",
          "Repository, https://github.com/roboflow/supervision"
        ],
        "provides_extra": [
          "geotiff",
          "metrics"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/93/e4/e9b2495d0d57b9f60d63c57d0a910410a81b4b073bf70917bef815291119/torchvision-0.28.0-cp312-cp312-manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=028a3d481b37d785605620d7cdad897064c5a55bae2aa1f2658766333e291940",
          "hashes": {
            "sha256": "028a3d481b37d785605620d7cdad897064c5a55bae2aa1f2658766333e291940"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "torchvision",
        "version": "0.28.0",
        "summary": "image and video datasets and models for torch deep learning",
        "description": "# torchvision\n\n[![total torchvision downloads](https://pepy.tech/badge/torchvision)](https://pepy.tech/project/torchvision)\n[![documentation](https://img.shields.io/badge/dynamic/json.svg?label=docs&url=https%3A%2F%2Fpypi.org%2Fpypi%2Ftorchvision%2Fjson&query=%24.info.version&colorB=brightgreen&prefix=v)](https://pytorch.org/vision/stable/index.html)\n\nThe torchvision package consists of popular datasets, model architectures, and common image transformations for computer\nvision.\n\n## Installation\n\nPlease refer to the [official\ninstructions](https://pytorch.org/get-started/locally/) to install the stable\nversions of `torch` and `torchvision` on your system.\n\nTo build source, refer to our [contributing\npage](https://github.com/pytorch/vision/blob/main/CONTRIBUTING.md#development-installation).\n\nThe following is the corresponding `torchvision` versions and supported Python\nversions.\n\n| `torch`            | `torchvision`      | Python              |\n| ------------------ | ------------------ | ------------------- |\n| `main` / `nightly` | `main` / `nightly` | `>=3.10`, `<=3.14`  |\n| `2.12`             | `0.27`             | `>=3.10`, `<=3.14`  |\n| `2.11`             | `0.26`             | `>=3.10`, `<=3.14`  |\n| `2.10`             | `0.25`             | `>=3.10`, `<=3.14`  |\n| `2.9`              | `0.24`             | `>=3.10`, `<=3.14`  |\n| `2.8`              | `0.23`             | `>=3.9`, `<=3.13`   |\n| `2.7`              | `0.22`             | `>=3.9`, `<=3.13`   |\n| `2.6`              | `0.21`             | `>=3.9`, `<=3.12`   |\n\n<details>\n    <summary>older versions</summary>\n\n| `torch` | `torchvision`     | Python                    |\n|---------|-------------------|---------------------------|\n| `2.5`              | `0.20`             | `>=3.9`, `<=3.12`   |\n| `2.4`              | `0.19`             | `>=3.8`, `<=3.12`   |\n| `2.3`              | `0.18`             | `>=3.8`, `<=3.12`   |\n| `2.2`              | `0.17`             | `>=3.8`, `<=3.11`   |\n| `2.1`              | `0.16`             | `>=3.8`, `<=3.11`   |\n| `2.0`              | `0.15`             | `>=3.8`, `<=3.11`   |\n| `1.13`  | `0.14`            | `>=3.7.2`, `<=3.10`       |\n| `1.12`  | `0.13`            | `>=3.7`, `<=3.10`         |\n| `1.11`  | `0.12`            | `>=3.7`, `<=3.10`         |\n| `1.10`  | `0.11`            | `>=3.6`, `<=3.9`          |\n| `1.9`   | `0.10`            | `>=3.6`, `<=3.9`          |\n| `1.8`   | `0.9`             | `>=3.6`, `<=3.9`          |\n| `1.7`   | `0.8`             | `>=3.6`, `<=3.9`          |\n| `1.6`   | `0.7`             | `>=3.6`, `<=3.8`          |\n| `1.5`   | `0.6`             | `>=3.5`, `<=3.8`          |\n| `1.4`   | `0.5`             | `==2.7`, `>=3.5`, `<=3.8` |\n| `1.3`   | `0.4.2` / `0.4.3` | `==2.7`, `>=3.5`, `<=3.7` |\n| `1.2`   | `0.4.1`           | `==2.7`, `>=3.5`, `<=3.7` |\n| `1.1`   | `0.3`             | `==2.7`, `>=3.5`, `<=3.7` |\n| `<=1.0` | `0.2`             | `==2.7`, `>=3.5`, `<=3.7` |\n\n</details>\n\n## Image Backends\n\nTorchvision currently supports the following image backends:\n\n- torch tensors\n- PIL images:\n    - [Pillow](https://python-pillow.org/)\n    - [Pillow-SIMD](https://github.com/uploadcare/pillow-simd) - a **much faster** drop-in replacement for Pillow with SIMD.\n\nRead more in in our [docs](https://pytorch.org/vision/stable/transforms.html).\n\n## Documentation\n\nYou can find the API documentation on the pytorch website: <https://pytorch.org/vision/stable/index.html>\n\n## Contributing\n\nSee the [CONTRIBUTING](CONTRIBUTING.md) file for how to help out.\n\n## Disclaimer on Datasets\n\nThis is a utility library that downloads and prepares public datasets. We do not host or distribute these datasets,\nvouch for their quality or fairness, or claim that you have license to use the dataset. It is your responsibility to\ndetermine whether you have permission to use the dataset under the dataset's license.\n\nIf you're a dataset owner and wish to update any part of it (description, citation, etc.), or do not want your dataset\nto be included in this library, please get in touch through a GitHub issue. Thanks for your contribution to the ML\ncommunity!\n\n## Pre-trained Model License\n\nThe pre-trained models provided in this library may have their own licenses or terms and conditions derived from the\ndataset used for training. It is your responsibility to determine whether you have permission to use the models for your\nuse case.\n\nMore specifically, SWAG models are released under the CC-BY-NC 4.0 license. See\n[SWAG LICENSE](https://github.com/facebookresearch/SWAG/blob/main/LICENSE) for additional details.\n\n## Citing TorchVision\n\nIf you find TorchVision useful in your work, please consider citing the following BibTeX entry:\n\n```bibtex\n@software{torchvision2016,\n    title        = {TorchVision: PyTorch's Computer Vision library},\n    author       = {TorchVision maintainers and contributors},\n    year         = 2016,\n    journal      = {GitHub repository},\n    publisher    = {GitHub},\n    howpublished = {\\url{https://github.com/pytorch/vision}}\n}\n```\n",
        "description_content_type": "text/markdown",
        "home_page": "https://github.com/pytorch/vision",
        "author": "PyTorch Core Team",
        "author_email": "soumith@pytorch.org",
        "license": "BSD",
        "requires_dist": [
          "numpy",
          "torch (==2.13.0)",
          "pillow (!=8.3.*,>=5.3.0)",
          "gdown (>=4.7.3) ; extra == 'gdown'",
          "scipy ; extra == 'scipy'"
        ],
        "requires_python": ">=3.10,!=3.14.1",
        "provides_extra": [
          "gdown",
          "scipy"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/0d/4d/ee3728674c0bbc637bb4af88ccf0be697f92e4e90b55f5dc110c44d61b61/transformers-5.16.1-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=2f2d5b98a5ad3718713653734298fa620754ed683702a635ebb587df3ed29c7e",
          "hashes": {
            "sha256": "2f2d5b98a5ad3718713653734298fa620754ed683702a635ebb587df3ed29c7e"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "transformers",
        "version": "5.16.1",
        "dynamic": [
          "author",
          "author-email",
          "classifier",
          "description",
          "description-content-type",
          "home-page",
          "keywords",
          "license",
          "license-file",
          "provides-extra",
          "requires-dist",
          "requires-python",
          "summary"
        ],
        "summary": "Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.",
        "description": "<!---\nCopyright 2020 The HuggingFace Team. All rights reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n\n<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://huggingface.co/datasets/huggingface/documentation-images/raw/main/transformers-logo-dark.svg\">\n    <source media=\"(prefers-color-scheme: light)\" srcset=\"https://huggingface.co/datasets/huggingface/documentation-images/raw/main/transformers-logo-light.svg\">\n    <img alt=\"Hugging Face Transformers Library\" src=\"https://huggingface.co/datasets/huggingface/documentation-images/raw/main/transformers-logo-light.svg\" width=\"352\" height=\"59\" style=\"max-width: 100%;\">\n  </picture>\n  <br/>\n  <br/>\n</p>\n\n<p align=\"center\">\n    <a href=\"https://huggingface.com/models\"><img alt=\"Checkpoints on Hub\" src=\"https://img.shields.io/endpoint?url=https://huggingface.co/api/shields/models&color=brightgreen\"></a>\n    <a href=\"https://circleci.com/gh/huggingface/transformers\"><img alt=\"Build\" src=\"https://img.shields.io/circleci/build/github/huggingface/transformers/main\"></a>\n    <a href=\"https://github.com/huggingface/transformers/blob/main/LICENSE\"><img alt=\"GitHub\" src=\"https://img.shields.io/github/license/huggingface/transformers.svg?color=blue\"></a>\n    <a href=\"https://huggingface.co/docs/transformers/index\"><img alt=\"Documentation\" src=\"https://img.shields.io/website/http/huggingface.co/docs/transformers/index.svg?down_color=red&down_message=offline&up_message=online\"></a>\n    <a href=\"https://github.com/huggingface/transformers/releases\"><img alt=\"GitHub release\" src=\"https://img.shields.io/github/release/huggingface/transformers.svg\"></a>\n    <a href=\"https://github.com/huggingface/transformers/blob/main/CODE_OF_CONDUCT.md\"><img alt=\"Contributor Covenant\" src=\"https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg\"></a>\n    <a href=\"https://zenodo.org/badge/latestdoi/155220641\"><img src=\"https://zenodo.org/badge/155220641.svg\" alt=\"DOI\"></a>\n</p>\n\n<h4 align=\"center\">\n    <p>\n        <b>English</b> |\n        <a href=\"i18n/README_zh-hans.md\">简体中文</a> |\n        <a href=\"i18n/README_zh-hant.md\">繁體中文</a> |\n        <a href=\"i18n/README_ko.md\">한국어</a> |\n        <a href=\"i18n/README_es.md\">Español</a> |\n        <a href=\"i18n/README_ja.md\">日本語</a> |\n        <a href=\"i18n/README_hd.md\">हिन्दी</a> |\n        <a href=\"i18n/README_ru.md\">Русский</a> |\n        <a href=\"i18n/README_pt-br.md\">Português</a> |\n        <a href=\"i18n/README_te.md\">తెలుగు</a> |\n        <a href=\"i18n/README_fr.md\">Français</a> |\n        <a href=\"i18n/README_de.md\">Deutsch</a> |\n        <a href=\"i18n/README_it.md\">Italiano</a> |\n        <a href=\"i18n/README_vi.md\">Tiếng Việt</a> |\n        <a href=\"i18n/README_ar.md\">العربية</a> |\n        <a href=\"i18n/README_ur.md\">اردو</a> |\n        <a href=\"i18n/README_bn.md\">বাংলা</a> |\n        <a href=\"i18n/README_fa.md\">فارسی</a> |\n        <a href=\"i18n/README_ro.md\">Română</a> |\n        <a href=\"i18n/README_tr.md\">Türkçe</a>\n    </p>\n</h4>\n\n<h3 align=\"center\">\n    <p>State-of-the-art pretrained models for inference and training</p>\n</h3>\n\n<h3 align=\"center\">\n    <img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/transformers_as_a_model_definition.png\"/>\n</h3>\n\nTransformers acts as the model-definition framework for state-of-the-art machine learning with text, computer\nvision, audio, video, and multimodal models, for both inference and training.\n\nIt centralizes the model definition so that this definition is agreed upon across the ecosystem. `transformers` is the\npivot across frameworks: if a model definition is supported, it will be compatible with the majority of training\nframeworks (Axolotl, Unsloth, DeepSpeed, FSDP, PyTorch-Lightning, ...), inference engines (vLLM, SGLang, TGI, ...),\nand adjacent modeling libraries (llama.cpp, mlx, ...) which leverage the model definition from `transformers`.\n\nWe pledge to help support new state-of-the-art models and democratize their usage by having their model definition be\nsimple, customizable, and efficient.\n\nThere are over 1M+ Transformers [model checkpoints](https://huggingface.co/models?library=transformers&sort=trending) on the [Hugging Face Hub](https://huggingface.co/models) you can use.\n\nExplore the [Hub](https://huggingface.co/) today to find a model and use Transformers to help you get started right away.\n\n## Installation\n\nTransformers works with Python 3.10+, and [PyTorch](https://pytorch.org/get-started/locally/) 2.5+.\n\nCreate and activate a virtual environment with [venv](https://docs.python.org/3/library/venv.html) or [uv](https://docs.astral.sh/uv/), a fast Rust-based Python package and project manager.\n\n```py\n# venv\npython -m venv .my-env\nsource .my-env/bin/activate\n# uv\nuv venv .my-env\nsource .my-env/bin/activate\n```\n\nInstall Transformers in your virtual environment.\n\n```py\n# pip\npip install \"transformers[torch]\"\n\n# uv\nuv pip install \"transformers[torch]\"\n```\n\nInstall Transformers from source if you want the latest changes in the library or are interested in contributing. However, the *latest* version may not be stable. Feel free to open an [issue](https://github.com/huggingface/transformers/issues) if you encounter an error.\n\n```shell\ngit clone https://github.com/huggingface/transformers.git\ncd transformers\n\n# pip\npip install '.[torch]'\n\n# uv\nuv pip install '.[torch]'\n```\n\n## Quickstart\n\nGet started with Transformers right away with the [Pipeline](https://huggingface.co/docs/transformers/pipeline_tutorial) API. The `Pipeline` is a high-level inference class that supports text, audio, vision, and multimodal tasks. It handles preprocessing the input and returns the appropriate output.\n\nInstantiate a pipeline and specify model to use for text generation. The model is downloaded and cached so you can easily reuse it again. Finally, pass some text to prompt the model.\n\n```py\nfrom transformers import pipeline\n\npipeline = pipeline(task=\"text-generation\", model=\"Qwen/Qwen2.5-1.5B\")\npipeline(\"the secret to baking a really good cake is \")\n[{'generated_text': 'the secret to baking a really good cake is 1) to use the right ingredients and 2) to follow the recipe exactly. the recipe for the cake is as follows: 1 cup of sugar, 1 cup of flour, 1 cup of milk, 1 cup of butter, 1 cup of eggs, 1 cup of chocolate chips. if you want to make 2 cakes, how much sugar do you need? To make 2 cakes, you will need 2 cups of sugar.'}]\n```\n\nTo chat with a model, the usage pattern is the same. The only difference is you need to construct a chat history (the input to `Pipeline`) between you and the system.\n\n> [!TIP]\n> You can also chat with a model directly from the command line, as long as [`transformers serve` is running](https://huggingface.co/docs/transformers/main/en/serving).\n> ```shell\n> transformers chat Qwen/Qwen2.5-0.5B-Instruct\n> ```\n\n```py\nimport torch\nfrom transformers import pipeline\n\nchat = [\n    {\"role\": \"system\", \"content\": \"You are a sassy, wise-cracking robot as imagined by Hollywood circa 1986.\"},\n    {\"role\": \"user\", \"content\": \"Hey, can you tell me any fun things to do in New York?\"}\n]\n\npipeline = pipeline(task=\"text-generation\", model=\"meta-llama/Meta-Llama-3-8B-Instruct\", dtype=torch.bfloat16, device_map=\"auto\")\nresponse = pipeline(chat, max_new_tokens=512)\nprint(response[0][\"generated_text\"][-1][\"content\"])\n```\n\nExpand the examples below to see how `Pipeline` works for different modalities and tasks.\n\n<details>\n<summary>Automatic speech recognition</summary>\n\n```py\nfrom transformers import pipeline\n\npipeline = pipeline(task=\"automatic-speech-recognition\", model=\"openai/whisper-large-v3\")\npipeline(\"https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac\")\n{'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'}\n```\n\n</details>\n\n<details>\n<summary>Image classification</summary>\n\n<h3 align=\"center\">\n    <a><img src=\"https://huggingface.co/datasets/Narsil/image_dummy/raw/main/parrots.png\"></a>\n</h3>\n\n```py\nfrom transformers import pipeline\n\npipeline = pipeline(task=\"image-classification\", model=\"facebook/dinov2-small-imagenet1k-1-layer\")\npipeline(\"https://huggingface.co/datasets/Narsil/image_dummy/raw/main/parrots.png\")\n[{'label': 'macaw', 'score': 0.997848391532898},\n {'label': 'sulphur-crested cockatoo, Kakatoe galerita, Cacatua galerita',\n  'score': 0.0016551691805943847},\n {'label': 'lorikeet', 'score': 0.00018523589824326336},\n {'label': 'African grey, African gray, Psittacus erithacus',\n  'score': 7.85409429227002e-05},\n {'label': 'quail', 'score': 5.502637941390276e-05}]\n```\n\n</details>\n\n<details>\n<summary>Visual question answering</summary>\n\n<h3 align=\"center\">\n    <a><img src=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-few-shot.jpg\"></a>\n</h3>\n\n```py\nfrom transformers import pipeline\n\npipeline = pipeline(task=\"visual-question-answering\", model=\"Salesforce/blip-vqa-base\")\npipeline(\n    image=\"https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/idefics-few-shot.jpg\",\n    question=\"What is in the image?\",\n)\n[{'answer': 'statue of liberty'}]\n```\n\n</details>\n\n## Why should I use Transformers?\n\n1. Easy-to-use state-of-the-art models:\n    - High performance on natural language understanding & generation, computer vision, audio, video, and multimodal tasks.\n    - Low barrier to entry for researchers, engineers, and developers.\n    - Few user-facing abstractions with just three classes to learn.\n    - A unified API for using all our pretrained models.\n\n1. Lower compute costs, smaller carbon footprint:\n    - Share trained models instead of training from scratch.\n    - Reduce compute time and production costs.\n    - Hundreds of model architectures with 1M+ pretrained checkpoints across all modalities.\n\n1. Choose the right framework for every part of a model's lifetime:\n    - Train state-of-the-art models in 3 lines of code.\n    - Move a single model between PyTorch/JAX/TF2.0 frameworks at will.\n    - Pick the right framework for training, evaluation, and production.\n\n1. Easily customize a model or an example to your needs:\n    - We provide examples for each architecture to reproduce the results published by its original authors.\n    - Model internals are exposed as consistently as possible.\n    - Model files can be used independently of the library for quick experiments.\n\n<a target=\"_blank\" href=\"https://huggingface.co/enterprise\">\n    <img alt=\"Hugging Face Enterprise Hub\" src=\"https://github.com/user-attachments/assets/247fb16d-d251-4583-96c4-d3d76dda4925\">\n</a><br>\n\n## When shouldn't I use Transformers?\n\n- This library is not a modular toolbox of building blocks for neural nets. The code in the model files is not refactored with additional abstractions on purpose, so that researchers can quickly iterate on each of the models without diving into additional abstractions/files.\n- The training API is optimized to work with PyTorch models provided by Transformers. For generic machine learning loops, you should use another library like [Accelerate](https://huggingface.co/docs/accelerate).\n- The [example scripts](https://github.com/huggingface/transformers/tree/main/examples) are only *examples*. They may not necessarily work out-of-the-box on your specific use case and you'll need to adapt the code for it to work.\n\n## 100 projects using Transformers\n\nTransformers is more than a toolkit to use pretrained models, it's a community of projects built around it and the\nHugging Face Hub. We want Transformers to enable developers, researchers, students, professors, engineers, and anyone\nelse to build their dream projects.\n\nIn order to celebrate Transformers 100,000 stars, we wanted to put the spotlight on the\ncommunity with the [awesome-transformers](./awesome-transformers.md) page which lists 100\nincredible projects built with Transformers.\n\nIf you own or use a project that you believe should be part of the list, please open a PR to add it!\n\n## Example models\n\nYou can test most of our models directly on their [Hub model pages](https://huggingface.co/models).\n\nExpand each modality below to see a few example models for various use cases.\n\n<details>\n<summary>Audio</summary>\n\n- Audio classification with [CLAP](https://huggingface.co/laion/clap-htsat-fused)\n- Automatic speech recognition with [Parakeet](https://huggingface.co/nvidia/parakeet-ctc-1.1b#transcribing-using-transformers-%F0%9F%A4%97), [Whisper](https://huggingface.co/openai/whisper-large-v3-turbo), [GLM-ASR](https://huggingface.co/zai-org/GLM-ASR-Nano-2512) and [Moonshine-Streaming](https://huggingface.co/UsefulSensors/moonshine-streaming-medium)\n- Keyword spotting with [Wav2Vec2](https://huggingface.co/superb/wav2vec2-base-superb-ks)\n- Speech to speech generation with [Moshi](https://huggingface.co/kyutai/moshiko-pytorch-bf16)\n- Text to audio with [MusicGen](https://huggingface.co/facebook/musicgen-large)\n- Text to speech with [CSM](https://huggingface.co/sesame/csm-1b)\n\n</details>\n\n<details>\n<summary>Computer vision</summary>\n\n- Automatic mask generation with [SAM](https://huggingface.co/facebook/sam-vit-base)\n- Depth estimation with [DepthPro](https://huggingface.co/apple/DepthPro-hf)\n- Image classification with [DINO v2](https://huggingface.co/facebook/dinov2-base)\n- Keypoint detection with [SuperPoint](https://huggingface.co/magic-leap-community/superpoint)\n- Keypoint matching with [SuperGlue](https://huggingface.co/magic-leap-community/superglue_outdoor)\n- Object detection with [RT-DETRv2](https://huggingface.co/PekingU/rtdetr_v2_r50vd)\n- Pose Estimation with [VitPose](https://huggingface.co/usyd-community/vitpose-base-simple)\n- Universal segmentation with [OneFormer](https://huggingface.co/shi-labs/oneformer_ade20k_swin_large)\n- Video classification with [VideoMAE](https://huggingface.co/MCG-NJU/videomae-large)\n\n</details>\n\n<details>\n<summary>Multimodal</summary>\n\n- Audio or text to text with [Voxtral](https://huggingface.co/mistralai/Voxtral-Mini-3B-2507), [Audio Flamingo](https://huggingface.co/nvidia/audio-flamingo-3-hf)\n- Document question answering with [LayoutLMv3](https://huggingface.co/microsoft/layoutlmv3-base)\n- Image or text to text with [Qwen-VL](https://huggingface.co/Qwen/Qwen2.5-VL-3B-Instruct)\n- Image captioning [BLIP-2](https://huggingface.co/Salesforce/blip2-opt-2.7b)\n- OCR-based document understanding with [GOT-OCR2](https://huggingface.co/stepfun-ai/GOT-OCR-2.0-hf)\n- Table question answering with [TAPAS](https://huggingface.co/google/tapas-base)\n- Unified multimodal understanding and generation with [Emu3](https://huggingface.co/BAAI/Emu3-Gen)\n- Vision to text with [Llava-OneVision](https://huggingface.co/llava-hf/llava-onevision-qwen2-0.5b-ov-hf)\n- Visual question answering with [Llava](https://huggingface.co/llava-hf/llava-1.5-7b-hf)\n- Visual referring expression segmentation with [Kosmos-2](https://huggingface.co/microsoft/kosmos-2-patch14-224)\n\n</details>\n\n<details>\n<summary>NLP</summary>\n\n- Masked word completion with [ModernBERT](https://huggingface.co/answerdotai/ModernBERT-base)\n- Named entity recognition with [Gemma](https://huggingface.co/google/gemma-2-2b)\n- Question answering with [Mixtral](https://huggingface.co/mistralai/Mixtral-8x7B-v0.1)\n- Summarization with [BART](https://huggingface.co/facebook/bart-large-cnn)\n- Translation with [T5](https://huggingface.co/google-t5/t5-base)\n- Text generation with [Llama](https://huggingface.co/meta-llama/Llama-3.2-1B)\n- Text classification with [Qwen](https://huggingface.co/Qwen/Qwen2.5-0.5B)\n\n</details>\n\n## Citation\n\nWe now have a [paper](https://aclanthology.org/2020.emnlp-demos.6/) you can cite for the 🤗 Transformers library:\n```bibtex\n@inproceedings{wolf-etal-2020-transformers,\n    title = \"Transformers: State-of-the-Art Natural Language Processing\",\n    author = \"Thomas Wolf and Lysandre Debut and Victor Sanh and Julien Chaumond and Clement Delangue and Anthony Moi and Pierric Cistac and Tim Rault and Rémi Louf and Morgan Funtowicz and Joe Davison and Sam Shleifer and Patrick von Platen and Clara Ma and Yacine Jernite and Julien Plu and Canwen Xu and Teven Le Scao and Sylvain Gugger and Mariama Drame and Quentin Lhoest and Alexander M. Rush\",\n    booktitle = \"Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing: System Demonstrations\",\n    month = oct,\n    year = \"2020\",\n    address = \"Online\",\n    publisher = \"Association for Computational Linguistics\",\n    url = \"https://aclanthology.org/2020.emnlp-demos.6/\",\n    pages = \"38--45\"\n}\n```\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "machine-learning",
          "nlp",
          "python",
          "pytorch",
          "transformer",
          "llm",
          "vlm",
          "deep-learning",
          "inference",
          "training",
          "model-hub",
          "pretrained-models",
          "llama",
          "gemma",
          "qwen"
        ],
        "home_page": "https://github.com/huggingface/transformers",
        "author": "The Hugging Face team (past and future) with the help of all our contributors (https://github.com/huggingface/transformers/graphs/contributors)",
        "author_email": "transformers@huggingface.co",
        "license": "Apache 2.0 License",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Intended Audience :: Education",
          "Intended Audience :: Science/Research",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Scientific/Engineering :: Artificial Intelligence"
        ],
        "requires_dist": [
          "huggingface-hub<2.0,>=1.5.0",
          "numpy>=1.17",
          "packaging>=20.0",
          "pyyaml>=5.1",
          "regex>=2025.10.22",
          "tokenizers<0.24.0,>=0.23.1",
          "typer",
          "safetensors>=0.8.0",
          "tqdm>=4.60",
          "torch>=2.5; extra == \"torch\"",
          "accelerate>=1.1.0; extra == \"torch\"",
          "torchvision; extra == \"vision\"",
          "Pillow<=15.0,>=10.0.1; extra == \"vision\"",
          "torchaudio; extra == \"audio\"",
          "librosa; extra == \"audio\"",
          "pyctcdecode>=0.4.0; extra == \"audio\"",
          "phonemizer; extra == \"audio\"",
          "av; extra == \"video\"",
          "timm>=1.0.23; extra == \"timm\"",
          "datasets>=2.15.0; extra == \"quality\"",
          "ruff==0.14.10; extra == \"quality\"",
          "GitPython<3.1.19; extra == \"quality\"",
          "urllib3<2.0.0; extra == \"quality\"",
          "libcst; extra == \"quality\"",
          "rich; extra == \"quality\"",
          "ty==0.0.20; extra == \"quality\"",
          "tomli; extra == \"quality\"",
          "transformers-mlinter==0.1.4; extra == \"quality\"",
          "hf-doc-builder; extra == \"docs\"",
          "kernels<0.17,>=0.16.0; extra == \"kernels\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"sentencepiece\"",
          "protobuf; extra == \"sentencepiece\"",
          "tiktoken; extra == \"tiktoken\"",
          "blobfile; extra == \"tiktoken\"",
          "mistral-common[image]>=1.11.7; extra == \"mistral-common\"",
          "jinja2>=3.1.0; extra == \"chat-template\"",
          "scikit-learn; extra == \"sklearn\"",
          "accelerate>=1.1.0; extra == \"accelerate\"",
          "faiss-cpu; extra == \"retrieval\"",
          "datasets>=2.15.0; extra == \"retrieval\"",
          "sagemaker>=2.31.0; extra == \"sagemaker\"",
          "deepspeed>=0.9.3; extra == \"deepspeed\"",
          "accelerate>=1.1.0; extra == \"deepspeed\"",
          "optuna; extra == \"optuna\"",
          "kernels<0.17,>=0.16.0; extra == \"integrations\"",
          "optuna; extra == \"integrations\"",
          "codecarbon>=2.8.1; extra == \"integrations\"",
          "ray[tune]>=2.7.0; extra == \"integrations\"",
          "ray[tune]>=2.7.0; extra == \"ray\"",
          "codecarbon>=2.8.1; extra == \"codecarbon\"",
          "openai>=1.98.0; extra == \"serving\"",
          "pydantic>=2; extra == \"serving\"",
          "uvicorn; extra == \"serving\"",
          "fastapi; extra == \"serving\"",
          "starlette; extra == \"serving\"",
          "rich; extra == \"serving\"",
          "torch>=2.5; extra == \"serving\"",
          "accelerate>=1.1.0; extra == \"serving\"",
          "num2words; extra == \"num2words\"",
          "optimum-benchmark>=0.3.0; extra == \"benchmark\"",
          "fugashi>=1.0; extra == \"ja\"",
          "ipadic<2.0,>=1.0.0; extra == \"ja\"",
          "unidic_lite>=1.0.7; extra == \"ja\"",
          "unidic>=1.0.2; extra == \"ja\"",
          "rhoknp<1.3.1,>=1.1.0; extra == \"ja\"",
          "sudachipy>=0.6.6; extra == \"ja\"",
          "sudachidict_core>=20220729; extra == \"ja\"",
          "pytest<9.0.0,>=7.2.0; extra == \"testing\"",
          "pytest-asyncio>=1.2.0; extra == \"testing\"",
          "pytest-random-order; extra == \"testing\"",
          "pytest-rich; extra == \"testing\"",
          "pytest-xdist; extra == \"testing\"",
          "pytest-order; extra == \"testing\"",
          "pytest-rerunfailures<16.0; extra == \"testing\"",
          "pytest-timeout; extra == \"testing\"",
          "pytest-env; extra == \"testing\"",
          "timeout-decorator; extra == \"testing\"",
          "parameterized>=0.9; extra == \"testing\"",
          "psutil; extra == \"testing\"",
          "dill<0.3.5; extra == \"testing\"",
          "evaluate>=0.4.6; extra == \"testing\"",
          "rouge-score!=0.0.7,!=0.0.8,!=0.1,!=0.1.1; extra == \"testing\"",
          "nltk<=3.8.1; extra == \"testing\"",
          "sacremoses; extra == \"testing\"",
          "rjieba; extra == \"testing\"",
          "beautifulsoup4; extra == \"testing\"",
          "tensorboard; extra == \"testing\"",
          "sacrebleu<2.0.0,>=1.4.12; extra == \"testing\"",
          "filelock; extra == \"testing\"",
          "hf-doc-builder; extra == \"testing\"",
          "datasets>=2.15.0; extra == \"testing\"",
          "ruff==0.14.10; extra == \"testing\"",
          "GitPython<3.1.19; extra == \"testing\"",
          "urllib3<2.0.0; extra == \"testing\"",
          "libcst; extra == \"testing\"",
          "rich; extra == \"testing\"",
          "ty==0.0.20; extra == \"testing\"",
          "tomli; extra == \"testing\"",
          "transformers-mlinter==0.1.4; extra == \"testing\"",
          "faiss-cpu; extra == \"testing\"",
          "datasets>=2.15.0; extra == \"testing\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"testing\"",
          "protobuf; extra == \"testing\"",
          "openai>=1.98.0; extra == \"testing\"",
          "pydantic>=2; extra == \"testing\"",
          "uvicorn; extra == \"testing\"",
          "fastapi; extra == \"testing\"",
          "starlette; extra == \"testing\"",
          "rich; extra == \"testing\"",
          "torch>=2.5; extra == \"testing\"",
          "accelerate>=1.1.0; extra == \"testing\"",
          "mistral-common[image]>=1.11.7; extra == \"testing\"",
          "deepspeed>=0.9.3; extra == \"deepspeed-testing\"",
          "accelerate>=1.1.0; extra == \"deepspeed-testing\"",
          "pytest<9.0.0,>=7.2.0; extra == \"deepspeed-testing\"",
          "pytest-asyncio>=1.2.0; extra == \"deepspeed-testing\"",
          "pytest-random-order; extra == \"deepspeed-testing\"",
          "pytest-rich; extra == \"deepspeed-testing\"",
          "pytest-xdist; extra == \"deepspeed-testing\"",
          "pytest-order; extra == \"deepspeed-testing\"",
          "pytest-rerunfailures<16.0; extra == \"deepspeed-testing\"",
          "pytest-timeout; extra == \"deepspeed-testing\"",
          "pytest-env; extra == \"deepspeed-testing\"",
          "timeout-decorator; extra == \"deepspeed-testing\"",
          "parameterized>=0.9; extra == \"deepspeed-testing\"",
          "psutil; extra == \"deepspeed-testing\"",
          "dill<0.3.5; extra == \"deepspeed-testing\"",
          "evaluate>=0.4.6; extra == \"deepspeed-testing\"",
          "rouge-score!=0.0.7,!=0.0.8,!=0.1,!=0.1.1; extra == \"deepspeed-testing\"",
          "nltk<=3.8.1; extra == \"deepspeed-testing\"",
          "sacremoses; extra == \"deepspeed-testing\"",
          "rjieba; extra == \"deepspeed-testing\"",
          "beautifulsoup4; extra == \"deepspeed-testing\"",
          "tensorboard; extra == \"deepspeed-testing\"",
          "sacrebleu<2.0.0,>=1.4.12; extra == \"deepspeed-testing\"",
          "filelock; extra == \"deepspeed-testing\"",
          "hf-doc-builder; extra == \"deepspeed-testing\"",
          "datasets>=2.15.0; extra == \"deepspeed-testing\"",
          "ruff==0.14.10; extra == \"deepspeed-testing\"",
          "GitPython<3.1.19; extra == \"deepspeed-testing\"",
          "urllib3<2.0.0; extra == \"deepspeed-testing\"",
          "libcst; extra == \"deepspeed-testing\"",
          "rich; extra == \"deepspeed-testing\"",
          "ty==0.0.20; extra == \"deepspeed-testing\"",
          "tomli; extra == \"deepspeed-testing\"",
          "transformers-mlinter==0.1.4; extra == \"deepspeed-testing\"",
          "faiss-cpu; extra == \"deepspeed-testing\"",
          "datasets>=2.15.0; extra == \"deepspeed-testing\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"deepspeed-testing\"",
          "protobuf; extra == \"deepspeed-testing\"",
          "openai>=1.98.0; extra == \"deepspeed-testing\"",
          "pydantic>=2; extra == \"deepspeed-testing\"",
          "uvicorn; extra == \"deepspeed-testing\"",
          "fastapi; extra == \"deepspeed-testing\"",
          "starlette; extra == \"deepspeed-testing\"",
          "rich; extra == \"deepspeed-testing\"",
          "torch>=2.5; extra == \"deepspeed-testing\"",
          "accelerate>=1.1.0; extra == \"deepspeed-testing\"",
          "mistral-common[image]>=1.11.7; extra == \"deepspeed-testing\"",
          "optuna; extra == \"deepspeed-testing\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"deepspeed-testing\"",
          "protobuf; extra == \"deepspeed-testing\"",
          "torch>=2.5; extra == \"all\"",
          "accelerate>=1.1.0; extra == \"all\"",
          "torchvision; extra == \"all\"",
          "Pillow<=15.0,>=10.0.1; extra == \"all\"",
          "torchaudio; extra == \"all\"",
          "librosa; extra == \"all\"",
          "pyctcdecode>=0.4.0; extra == \"all\"",
          "phonemizer; extra == \"all\"",
          "av; extra == \"all\"",
          "kernels<0.17,>=0.16.0; extra == \"all\"",
          "timm>=1.0.23; extra == \"all\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"all\"",
          "protobuf; extra == \"all\"",
          "tiktoken; extra == \"all\"",
          "blobfile; extra == \"all\"",
          "jinja2>=3.1.0; extra == \"all\"",
          "num2words; extra == \"all\"",
          "mistral-common[image]>=1.11.7; extra == \"all\"",
          "torch>=2.5; extra == \"dev\"",
          "accelerate>=1.1.0; extra == \"dev\"",
          "torchvision; extra == \"dev\"",
          "Pillow<=15.0,>=10.0.1; extra == \"dev\"",
          "torchaudio; extra == \"dev\"",
          "librosa; extra == \"dev\"",
          "pyctcdecode>=0.4.0; extra == \"dev\"",
          "phonemizer; extra == \"dev\"",
          "av; extra == \"dev\"",
          "kernels<0.17,>=0.16.0; extra == \"dev\"",
          "timm>=1.0.23; extra == \"dev\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"dev\"",
          "protobuf; extra == \"dev\"",
          "tiktoken; extra == \"dev\"",
          "blobfile; extra == \"dev\"",
          "jinja2>=3.1.0; extra == \"dev\"",
          "num2words; extra == \"dev\"",
          "mistral-common[image]>=1.11.7; extra == \"dev\"",
          "pytest<9.0.0,>=7.2.0; extra == \"dev\"",
          "pytest-asyncio>=1.2.0; extra == \"dev\"",
          "pytest-random-order; extra == \"dev\"",
          "pytest-rich; extra == \"dev\"",
          "pytest-xdist; extra == \"dev\"",
          "pytest-order; extra == \"dev\"",
          "pytest-rerunfailures<16.0; extra == \"dev\"",
          "pytest-timeout; extra == \"dev\"",
          "pytest-env; extra == \"dev\"",
          "timeout-decorator; extra == \"dev\"",
          "parameterized>=0.9; extra == \"dev\"",
          "psutil; extra == \"dev\"",
          "dill<0.3.5; extra == \"dev\"",
          "evaluate>=0.4.6; extra == \"dev\"",
          "rouge-score!=0.0.7,!=0.0.8,!=0.1,!=0.1.1; extra == \"dev\"",
          "nltk<=3.8.1; extra == \"dev\"",
          "sacremoses; extra == \"dev\"",
          "rjieba; extra == \"dev\"",
          "beautifulsoup4; extra == \"dev\"",
          "tensorboard; extra == \"dev\"",
          "sacrebleu<2.0.0,>=1.4.12; extra == \"dev\"",
          "filelock; extra == \"dev\"",
          "hf-doc-builder; extra == \"dev\"",
          "datasets>=2.15.0; extra == \"dev\"",
          "ruff==0.14.10; extra == \"dev\"",
          "GitPython<3.1.19; extra == \"dev\"",
          "urllib3<2.0.0; extra == \"dev\"",
          "libcst; extra == \"dev\"",
          "rich; extra == \"dev\"",
          "ty==0.0.20; extra == \"dev\"",
          "tomli; extra == \"dev\"",
          "transformers-mlinter==0.1.4; extra == \"dev\"",
          "faiss-cpu; extra == \"dev\"",
          "datasets>=2.15.0; extra == \"dev\"",
          "sentencepiece!=0.1.92,>=0.1.91; extra == \"dev\"",
          "protobuf; extra == \"dev\"",
          "openai>=1.98.0; extra == \"dev\"",
          "pydantic>=2; extra == \"dev\"",
          "uvicorn; extra == \"dev\"",
          "fastapi; extra == \"dev\"",
          "starlette; extra == \"dev\"",
          "rich; extra == \"dev\"",
          "torch>=2.5; extra == \"dev\"",
          "accelerate>=1.1.0; extra == \"dev\"",
          "mistral-common[image]>=1.11.7; extra == \"dev\"",
          "fugashi>=1.0; extra == \"dev\"",
          "ipadic<2.0,>=1.0.0; extra == \"dev\"",
          "unidic_lite>=1.0.7; extra == \"dev\"",
          "unidic>=1.0.2; extra == \"dev\"",
          "rhoknp<1.3.1,>=1.1.0; extra == \"dev\"",
          "sudachipy>=0.6.6; extra == \"dev\"",
          "sudachidict_core>=20220729; extra == \"dev\"",
          "scikit-learn; extra == \"dev\""
        ],
        "requires_python": ">=3.10.0",
        "provides_extra": [
          "torch",
          "vision",
          "audio",
          "video",
          "timm",
          "quality",
          "docs",
          "kernels",
          "sentencepiece",
          "tiktoken",
          "mistral-common",
          "chat-template",
          "sklearn",
          "accelerate",
          "retrieval",
          "sagemaker",
          "deepspeed",
          "optuna",
          "integrations",
          "ray",
          "codecarbon",
          "serving",
          "num2words",
          "benchmark",
          "ja",
          "testing",
          "deepspeed-testing",
          "all",
          "dev"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/35/da/aae4506866bdd18612be95bdd95150714dc14c70ed9d83561b00bc7bd29f/onnx_graphsurgeon-0.6.1-py2.py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=fabc53fc60909dd032cfd889016dd5d4139ab566af4a9039002818f552c73547",
          "hashes": {
            "sha256": "fabc53fc60909dd032cfd889016dd5d4139ab566af4a9039002818f552c73547"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "onnx_graphsurgeon",
        "version": "0.6.1",
        "summary": "ONNX GraphSurgeon",
        "description": "# ONNX GraphSurgeon\n\n\n## Table of Contents\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n- [Examples](#examples)\n- [Understanding The Basics](#understanding-the-basics)\n    - [Importers](#importers)\n    - [IR](#ir)\n        - [Tensor](#tensor)\n        - [Node](#node)\n        - [A Note On Modifying Inputs And Outputs](#a-note-on-modifying-inputs-and-outputs)\n        - [Graph](#graph)\n    - [Exporters](#exporters)\n- [Advanced](#advanced)\n    - [Working With Models With External Data](#working-with-models-with-external-data)\n\n## Introduction\n\nONNX GraphSurgeon is a Python library that allows you to create and modify ONNX models.\n\nIf you prefer a GUI, try [Nsight DL Designer](https://developer.nvidia.com/nsight-dl-designer),\nwhich integrates ONNX GraphSurgeon and provides various extra features.\n\n\n## Installation\n\n### Using Prebuilt Wheels\n```bash\npython3 -m pip install onnx_graphsurgeon --extra-index-url https://pypi.ngc.nvidia.com\n```\n\n### Building From Source\n\n#### Using Make Targets\n```\nmake install\n```\n\n#### Building Manually\n\n1. Build a wheel:\n```\nmake build\n```\n\n2. Install the wheel manually from **outside** the repository:\n```\npython3 -m pip install onnx-graphsurgeon/dist/onnx_graphsurgeon-*-py2.py3-none-any.whl\n```\n\n\n## Examples\n\nThe [examples](./examples) directory contains several examples of common use-cases of ONNX GraphSurgeon.\n\nThe visualizations provided were generated using [Netron](https://github.com/lutzroeder/netron).\n\n\n## Understanding The Basics\n\nONNX GraphSurgeon is composed of three major components: Importers, the IR, and Exporters.\n\n### Importers\n\nImporters are used to import a graph into the ONNX GraphSurgeon IR.\nThe importer interface is defined in [base_importer.py](./onnx_graphsurgeon/importers/base_importer.py).\n\nONNX GraphSurgeon also provides [high-level importer APIs](./onnx_graphsurgeon/api/api.py) for ease of use:\n```python\ngraph = gs.import_onnx(onnx.load(\"model.onnx\"))\n```\n\n### IR\n\nThe Intermediate Representation (IR) is where all modifications to the graph are made. It can also be used to\ncreate new graphs from scratch. The IR involves three components: [Tensor](./onnx_graphsurgeon/ir/tensor.py)s,\n[Node](./onnx_graphsurgeon/ir/node.py)s, and [Graph](./onnx_graphsurgeon/ir/graph.py)s.\n\nNearly all of the member variables of each component can be freely modified. For details on the various\nattributes of these classes, you can view the help output using `help(<class_or_instance>)` in an\ninteractive shell, or using `print(help(<class_or_instance>))` in a script, where `<class_or_instance>`\nis an ONNX GraphSurgeon type, or an instance of that type.\n\n#### Tensor\n\nTensors are divided into two subclasses: `Variable` and `Constant`.\n\n- A `Constant` is a tensor whose values are known upfront, and can be retrieved as a NumPy array and modified.\n    *Note: The `values` property of a `Constant` is loaded on-demand. If the property is not accessed, the values will*\n    *not be loaded as a NumPy array*.\n- A `Variable` is a tensor whose values are unknown until inference-time, but may contain information about data type and shape.\n\nThe inputs and outputs of Tensors are always Nodes.\n\n**An example constant tensor from ResNet50:**\n```\n>>> print(tensor)\nConstant (gpu_0/res_conv1_bn_s_0)\n[0.85369843 1.1515082  0.9152944  0.9577646  1.0663182  0.55629414\n 1.2009839  1.1912311  2.2619808  0.62263143 1.1149117  1.4921428\n 0.89566356 1.0358194  1.431092   1.5360111  1.25086    0.8706703\n 1.2564877  0.8524589  0.9436758  0.7507614  0.8945271  0.93587166\n 1.8422242  3.0609846  1.3124607  1.2158023  1.3937513  0.7857263\n 0.8928106  1.3042281  1.0153942  0.89356416 1.0052011  1.2964457\n 1.1117343  1.0669073  0.91343874 0.92906713 1.0465593  1.1261675\n 1.4551278  1.8252873  1.9678202  1.1031747  2.3236883  0.8831993\n 1.1133649  1.1654979  1.2705412  2.5578163  0.9504889  1.0441847\n 1.0620039  0.92997414 1.2119316  1.3101407  0.7091761  0.99814713\n 1.3404484  0.96389204 1.3435135  0.9236031 ]\n```\n\n**An example variable tensor from ResNet50:**\n```\n>>> print(tensor)\nVariable (gpu_0/data_0): (shape=[1, 3, 224, 224], dtype=float32)\n```\n\n\n#### Node\n\nA `Node` defines an operation in the graph. A node may specify attributes; attribute values can be any\nPython primitive types, as well as ONNX GraphSurgeon `Graph`s or `Tensor`s\n\nThe inputs and outputs of Nodes are always Tensors\n\n**An example ReLU node from ResNet50:**\n```\n>>> print(node)\n (Relu)\n    Inputs: [Tensor (gpu_0/res_conv1_bn_1)]\n    Outputs: [Tensor (gpu_0/res_conv1_bn_2)]\n```\n\nIn this case, the node has no attributes. Otherwise, attributes are displayed as an `OrderedDict`.\n\n\n#### A Note On Modifying Inputs And Outputs\n\nThe `inputs`/`outputs` members of nodes and tensors have special logic that will update the inputs/outputs of all\naffected nodes/tensors when you make a change. This means, for example, that you do **not** need to update the `inputs`\nof a Node when you make a change to the `outputs` of its input tensor.\n\nConsider the following node:\n```\n>>> print(node)\n (Relu).\n    Inputs: [Tensor (gpu_0/res_conv1_bn_1)]\n    Outputs: [Tensor (gpu_0/res_conv1_bn_2)]\n```\n\nThe input tensor can be accessed like so:\n```\n>>> tensor = node.inputs[0]\n>>> print(tensor)\nTensor (gpu_0/res_conv1_bn_1)\n>>> print(tensor.outputs)\n[ (Relu).\n\tInputs: [Tensor (gpu_0/res_conv1_bn_1)]\n\tOutputs: [Tensor (gpu_0/res_conv1_bn_2)]\n```\n\nIf we remove the node from the outputs of the tensor, this is reflected in the node inputs as well:\n```\n>>> del tensor.outputs[0]\n>>> print(tensor.outputs)\n[]\n>>> print(node)\n (Relu).\n    Inputs: []\n    Outputs: [Tensor (gpu_0/res_conv1_bn_2)]\n```\n\n\n#### Graph\n\nA `Graph` contains zero or more `Node`s and input/output `Tensor`s.\n\nIntermediate tensors are not explicitly tracked, but are instead retrieved from the nodes contained within the graph.\n\nThe `Graph` class exposes several functions. A small subset is listed here:\n\n- `cleanup()`: Removes unused nodes and tensors in the graph\n- `toposort()`: Topologically sorts the graph.\n- `tensors()`: Returns a `Dict[str, Tensor]` mapping tensor names to tensors, by walking over all the tensors in the graph.\n    This is an `O(N)` operation, and so may be slow for large graphs.\n\nTo see the full Graph API, you can see `help(onnx_graphsurgeon.Graph)` in an interactive Python shell.\n\n### Exporters\n\nExporters are used to export the ONNX GraphSurgeon IR to ONNX or other types of graphs.\nThe exporter interface is defined in [base_exporter.py](./onnx_graphsurgeon/exporters/base_exporter.py).\n\nONNX GraphSurgeon also provides [high-level exporter APIs](./onnx_graphsurgeon/api/api.py) for ease of use:\n```python\nonnx.save(gs.export_onnx(graph), \"model.onnx\")\n```\n\n\n## Advanced\n\n### Working With Models With External Data\n\nUsing models with externally stored data with ONNX-GraphSurgeon is almost the same as working with\nONNX models without external data. Refer to the\n[official ONNX documentation](https://github.com/onnx/onnx/blob/master/docs/PythonAPIOverview.md#loading-an-onnx-model-with-external-data)\nfor details on how to load such models. To import the model into ONNX-GraphSurgeon, you can use the\n`import_onnx` function as normal.\n\nDuring export, you just need to take one additional step:\n\n1. Export the model from ONNX-GraphSurgeon as normal:\n    ```python\n    model = gs.export_onnx(graph)\n    ```\n\n2. Update the model so that it writes its data to the external location. If the location is not\n    specified, it defaults to the same directory as the ONNX model:\n    ```python\n    from onnx.external_data_helper import convert_model_to_external_data\n\n    convert_model_to_external_data(model, location=\"model.data\")\n    ```\n\n3. Then you can save the model as usual:\n    ```python\n    onnx.save(model, \"model.onnx\")\n    ```\n",
        "description_content_type": "text/markdown",
        "home_page": "https://github.com/NVIDIA/TensorRT/tree/main/tools/onnx-graphsurgeon",
        "author": "NVIDIA",
        "author_email": "svc_tensorrt@nvidia.com",
        "license": "Apache 2.0",
        "classifier": [
          "Intended Audience :: Developers",
          "Programming Language :: Python :: 3"
        ],
        "requires_dist": [
          "ml-dtypes",
          "numpy",
          "onnx (>=1.14.0)"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/96/eb/e6968f5e41aac3125f2ff5708855f09cb0b70d85ed3115b625b0b58305ba/onnxruntime-1.29.0-cp312-cp312-manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=2b80d8c7ec2cc7438e4da3760b88c24568cba72c9ace96d668800a6c79419acb",
          "hashes": {
            "sha256": "2b80d8c7ec2cc7438e4da3760b88c24568cba72c9ace96d668800a6c79419acb"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "onnxruntime",
        "version": "1.29.0",
        "dynamic": [
          "author",
          "author-email",
          "classifier",
          "description",
          "download-url",
          "home-page",
          "keywords",
          "license",
          "provides-extra",
          "requires-dist",
          "requires-python",
          "summary"
        ],
        "summary": "ONNX Runtime is a runtime accelerator for Machine Learning models",
        "description": "ONNX Runtime\n============\n\nONNX Runtime is a performance-focused scoring engine for Open Neural Network Exchange (ONNX) models.\nFor more information on ONNX Runtime, please see `aka.ms/onnxruntime <https://aka.ms/onnxruntime/>`_ or the `Github project <https://github.com/microsoft/onnxruntime/>`_.\n\n\nChanges\n-------\n\n1.29.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.29.0\n\n1.28.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.28.0\n\n1.27.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.27.0\n\n1.26.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.26.0\n\n1.25.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.25.0\n\n1.24.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.24.0\n\n1.23.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.23.0\n\n1.22.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.22.0\n\n1.21.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.21.0\n\n1.20.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.20.0\n\n1.19.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.19.0\n\n1.18.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.18.0\n\n1.17.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.17.0\n\n1.16.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.16.0\n\n1.15.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.15.0\n\n1.14.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.14.0\n\n1.13.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.13.0\n\n1.12.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.12.0\n\n1.11.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.11.0\n\n1.10.0\n^^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.10.0\n\n1.9.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.9.0\n\n1.8.2\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.8.2\n\n1.8.1\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.8.1\n\n1.8.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.8.0\n\n1.7.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.7.0\n\n1.6.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.6.0\n\n1.5.3\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.5.3\n\n1.5.2\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.5.2\n\n1.5.1\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.5.1\n\n\n1.4.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.4.0\n\n1.3.1\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.3.1\n\n1.3.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.3.0\n\n1.2.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.2.0\n\n1.1.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.1.0\n\n1.0.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v1.0.0\n\n0.5.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v0.5.0\n\n0.4.0\n^^^^^\n\nRelease Notes : https://github.com/Microsoft/onnxruntime/releases/tag/v0.4.0\n",
        "keywords": [
          "onnx",
          "machine",
          "learning"
        ],
        "home_page": "https://onnxruntime.ai",
        "download_url": "https://github.com/microsoft/onnxruntime/tags",
        "author": "Microsoft Corporation",
        "author_email": "onnxruntime@microsoft.com",
        "license": "MIT License",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: MIT License",
          "Operating System :: POSIX :: Linux",
          "Operating System :: Microsoft :: Windows",
          "Operating System :: MacOS",
          "Topic :: Scientific/Engineering",
          "Topic :: Scientific/Engineering :: Mathematics",
          "Topic :: Scientific/Engineering :: Artificial Intelligence",
          "Topic :: Software Development",
          "Topic :: Software Development :: Libraries",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14"
        ],
        "requires_dist": [
          "flatbuffers",
          "numpy>=1.21.6",
          "packaging",
          "protobuf>=4.25.8",
          "sympy; extra == \"symbolic\"",
          "ml_dtypes; extra == \"quantization\""
        ],
        "requires_python": ">=3.11",
        "provides_extra": [
          "symbolic",
          "quantization"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/d4/9a/64e83168e14d1d0598357f11a3074e34eeb6c9906498e2d3ffd5dea674cf/polygraphy-0.53.4-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=cfccdcee0552426c3b0cbe7c90f428a821cb1d20d0149b0871ceb5e99220cc70",
          "hashes": {
            "sha256": "cfccdcee0552426c3b0cbe7c90f428a821cb1d20d0149b0871ceb5e99220cc70"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "polygraphy",
        "version": "0.53.4",
        "summary": "Polygraphy: A Deep Learning Inference Prototyping and Debugging Toolkit",
        "description": "# Polygraphy: A Deep Learning Inference Prototyping and Debugging Toolkit\n\n\n## Table of Contents\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n- [Command-line Toolkit](#command-line-toolkit)\n- [Python API](#python-api)\n- [Examples](#examples)\n- [How-To Guides](#how-to-guides)\n- [Contributing](#contributing)\n\n\n## Introduction\n\nPolygraphy is a toolkit designed to assist in running and debugging deep learning models\nin various frameworks. It includes a [Python API](./polygraphy) and\n[a command-line interface (CLI)](./polygraphy/tools) built using this API.\n\nAmong other things, Polygraphy lets you:\n\n- Run inference among multiple backends, like TensorRT and ONNX-Runtime, and compare results\n    (example: [API](examples/api/01_comparing_frameworks/), [CLI](examples/cli/run/01_comparing_frameworks/))\n- Convert models to various formats, e.g. TensorRT engines with post-training quantization\n    (example: [API](examples/api/04_int8_calibration_in_tensorrt/), [CLI](examples/cli/convert/01_int8_calibration_in_tensorrt/))\n- View information about various types of models\n    (example: [CLI](examples/cli/inspect/))\n- Modify ONNX models on the command-line:\n    - Extract subgraphs (example: [CLI](examples/cli/surgeon/01_isolating_subgraphs/))\n    - Simplify and sanitize (example: [CLI](examples/cli/surgeon/02_folding_constants/))\n- Isolate faulty tactics in TensorRT\n    (example: [CLI](examples/cli/debug/01_debugging_flaky_trt_tactics/))\n\n\n## Installation\n\n**IMPORTANT**: **Polygraphy supports only Python 3.6 and later.**\n    **Before following the instructions below, please ensure you are using a supported version of Python.**\n\n\n### Installing Prebuilt Wheels\n\n```bash\npython -m pip install colored polygraphy --extra-index-url https://pypi.ngc.nvidia.com\n```\n\n**NOTE:** *On Linux, the command-line toolkit is usually installed to `${HOME}/.local/bin` by default.*\n    *Make sure to add this directory to your `PATH` environment variable.*\n\n\n### Building From Source\n\n#### Using Make Targets (Linux)\n\n```bash\nmake install\n```\n\n#### Using Powershell Script (Windows)\n\nMake sure you are allowed to execute scripts on your system then run:\n```ps\n.\\install.ps1\n```\n\n#### Building Manually\n\n1. Install prerequisites:\n\n```\npython -m pip install wheel\n```\n\n2. Build a wheel:\n\n```\npython setup.py bdist_wheel\n```\n\n3. Install the wheel manually from **outside** the repository:\n\n    On Linux, run:\n\n    ```\n    python -m pip install Polygraphy/dist/polygraphy-*-py2.py3-none-any.whl\n    ```\n\n    On Windows, using Powershell, run:\n\n    ```ps\n    $wheel_path = gci -Name Polygraphy\\dist\n    python -m pip install Polygraphy\\dist\\$wheel_path\n    ```\n\n\n    **NOTE:** *It is strongly recommended to install the `colored` module for colored output*\n    *from Polygraphy, as this can greatly improve readability:*\n    ```\n    python -m pip install colored\n    ```\n\n\n### Installing Dependencies\n\nPolygraphy has no hard-dependencies on other Python packages. However, much of the functionality included\ndoes require other Python packages.\n\n#### Automatically Installing Dependencies\n\nIt's non-trivial to determine all the packages that will be required ahead of time,\nsince it depends on exactly what functionality is being used.\n\nTo make this easier, Polygraphy can optionally automatically install or upgrade dependencies at runtime, as they are needed.\nTo enable this behavior, set the `POLYGRAPHY_AUTOINSTALL_DEPS` environment variable to `1` or\n`polygraphy.config.AUTOINSTALL_DEPS = True` using the Python API.\n\n**NOTE**: *By default, dependencies will be installed using the current interpreter, and may overwrite existing*\n    *packages. The default installation command, which is `python -m pip install`, can be overriden by setting*\n    *the `POLYGRAPHY_INSTALL_CMD` environment variable, or setting `polygraphy.config.INSTALL_CMD` using the Python API.*\n\nIf you'd like Polygraphy to prompt you before automatically installing or\nupgrading pacakges, set the `POLYGRAPHY_ASK_BEFORE_INSTALL` environment variable to `1`\nor `polygraphy.config.ASK_BEFORE_INSTALL = True` using the Python API.\n\n#### Installing Manually\n\nEach `backend` directory includes a `requirements.txt` file that specifies the minimum set of packages\nit depends on. This does not necessarily include all packages required for all the functionality provided\nby the backend, but does serve as a good starting point.\n\nYou can install the requirements for whichever backends you're interested in with:\n```bash\npython -m pip install -r polygraphy/backend/<name>/requirements.txt\n```\n\nIf additional packages are required, warnings or errors will be logged.\nYou can install the additional packages manually with:\n```bash\npython -m pip install <package_name>\n```\n\n\n## Command-line Toolkit\n\nFor details on the various tools included in the Polygraphy toolkit,\nsee the [CLI User Guide](./polygraphy/tools).\n\n\n### Python API\n\nFor more information on the Polygraphy Python API, including a high-level overview and the\nPython API reference documentation, see the [API directory](./polygraphy).\n\n\n## Examples\n\nFor examples of both the CLI and Python API, see the [examples directory](./examples).\n\n\n## How-To Guides\n\nFor how-to guides, see the [how-to guides directory](./how-to).\n\n\n## Contributing\n\nFor information on how you can contribute to this project, see [CONTRIBUTING.md](./CONTRIBUTING.md)\n",
        "description_content_type": "text/markdown",
        "author_email": "NVIDIA <svc_tensorrt@nvidia.com>",
        "license": "Apache 2.0",
        "classifier": [
          "Intended Audience :: Developers",
          "Programming Language :: Python :: 3"
        ],
        "requires_python": ">=3.6",
        "project_url": [
          "Homepage, https://github.com/NVIDIA/TensorRT/tree/main/tools/Polygraphy"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/27/3a/204dbfc3e08eb4cdc6e6ff57be02150bc44523ebdb50182d10025792ebd9/av-18.1.0-cp311-abi3-manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=8a032e8d8ebc73dec079364b9b4a6837638a2d106e8472314e685ffbf163e700",
          "hashes": {
            "sha256": "8a032e8d8ebc73dec079364b9b4a6837638a2d106e8472314e685ffbf163e700"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "av",
        "version": "18.1.0",
        "dynamic": [
          "license-file"
        ],
        "summary": "Pythonic bindings for FFmpeg's libraries.",
        "description": "PyAV\n====\n\nPyAV is a Pythonic binding for the [FFmpeg][ffmpeg] libraries. We aim to provide all the power and control of the underlying library, but manage the gritty details as much as possible.\n\n---\n\n[![GitHub Test Status][github-tests-badge]][github-tests] [![Documentation][docs-badge]][docs] [![Python Package Index][pypi-badge]][pypi] [![Conda Forge][conda-badge]][conda]\n\nPyAV is for direct and precise access to your media via containers, streams, packets, codecs, and frames. It exposes a few transformations of that data, and helps you get your data to/from other packages (e.g. NumPy and Pillow).\n\nThis power does come with some responsibility as working with media is horrendously complicated and PyAV can't abstract it away or make all the best decisions for you. If the `ffmpeg` command does the job without you bending over backwards, PyAV is likely going to be more of a hindrance than a help.\n\nBut where you can't work without it, PyAV is a critical tool.\n\n\nInstallation\n------------\n\nPyAV requires Python 3.11 or later. Binary wheels are provided on [PyPI][pypi] for Linux, macOS, and Windows with FFmpeg bundled. You can install these wheels by running:\n\n```bash\npip install av\n```\n\nAnother way of installing PyAV is via [conda-forge][conda-forge]:\n\n```bash\nconda install av -c conda-forge\n```\n\nSee the [Conda install][conda-install] docs to get started with Miniconda.\n\n\nAlternative installation methods\n--------------------------------\n\nDue to the complexity of the dependencies, PyAV is not always the easiest Python package to install from source. This release supports FFmpeg 8.x. To build the source distribution against an existing FFmpeg installation on Linux or macOS, run:\n\n> [!WARNING]\n> FFmpeg's development files and `pkg-config` must be available on your system.\n\n```bash\npip install av --no-binary av\n```\n\n\nInstalling from source\n----------------------\n\nOn Linux or macOS, build PyAV from a Git checkout with:\n\n```bash\ngit clone https://github.com/PyAV-Org/PyAV.git\ncd PyAV\nsource scripts/activate.sh\n\n# Build ffmpeg from source. You can skip this step if ffmpeg 8.x is already installed.\n./scripts/build-deps\n\n# Build PyAV\nmake\n\n# Testing\nmake test\n\n# Install globally\ndeactivate\npip install .\n```\n\nOn Windows, use a Conda environment and the FFmpeg development files maintained by the PyAV project:\n\n```powershell\ngit clone https://github.com/PyAV-Org/PyAV.git\ncd PyAV\nconda create --name pyav-dev --channel conda-forge python=3.11 cython setuptools numpy pillow pytest\nconda activate pyav-dev\n$ffmpegDir = Join-Path $env:CONDA_PREFIX \"Library\"\npython scripts\\fetch-vendor.py --config-file scripts\\ffmpeg-latest.json $ffmpegDir\npython setup.py build_ext --inplace --ffmpeg-dir=$ffmpegDir\npython -m pytest\n```\n\n---\n\nHave fun, [read the docs][docs], [come chat with us][discuss], and good luck!\n\n\n\n[conda-badge]: https://img.shields.io/conda/vn/conda-forge/av.svg?colorB=CCB39A\n[conda]: https://anaconda.org/conda-forge/av\n[docs-badge]: https://img.shields.io/badge/docs-on%20pyav.basswood.io-blue.svg\n[docs]: https://pyav.basswood.io\n[pypi-badge]: https://img.shields.io/pypi/v/av.svg?colorB=CCB39A\n[pypi]: https://pypi.org/project/av\n[discuss]: https://github.com/PyAV-Org/PyAV/discussions\n\n[github-tests-badge]: https://github.com/PyAV-Org/PyAV/workflows/tests/badge.svg\n[github-tests]: https://github.com/PyAV-Org/PyAV/actions?workflow=tests\n[github]: https://github.com/PyAV-Org/PyAV\n\n[ffmpeg]: https://ffmpeg.org/\n[conda-forge]: https://conda-forge.github.io/\n[conda-install]: https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html\n",
        "description_content_type": "text/markdown",
        "author_email": "WyattBlue <wyattblue@auto-editor.com>, Jeremy Lainé <jeremy.laine@m4x.org>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Natural Language :: English",
          "Operating System :: MacOS :: MacOS X",
          "Operating System :: POSIX",
          "Operating System :: Unix",
          "Operating System :: Microsoft :: Windows",
          "Programming Language :: Cython",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Topic :: Multimedia :: Sound/Audio",
          "Topic :: Multimedia :: Sound/Audio :: Conversion",
          "Topic :: Multimedia :: Video",
          "Topic :: Multimedia :: Video :: Conversion"
        ],
        "requires_python": ">=3.11",
        "project_url": [
          "Bug Tracker, https://github.com/PyAV-Org/PyAV/issues",
          "Source Code, https://github.com/PyAV-Org/PyAV",
          "homepage, https://pyav.basswood.io"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61",
          "hashes": {
            "sha256": "a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "defusedxml",
        "version": "0.7.1",
        "platform": [
          "all"
        ],
        "summary": "XML bomb protection for Python stdlib modules",
        "description": "===================================================\ndefusedxml -- defusing XML bombs and other exploits\n===================================================\n\n.. image:: https://img.shields.io/pypi/v/defusedxml.svg\n    :target: https://pypi.org/project/defusedxml/\n    :alt: Latest Version\n\n.. image:: https://img.shields.io/pypi/pyversions/defusedxml.svg\n    :target: https://pypi.org/project/defusedxml/\n    :alt: Supported Python versions\n\n.. image:: https://travis-ci.org/tiran/defusedxml.svg?branch=master\n    :target: https://travis-ci.org/tiran/defusedxml\n    :alt: Travis CI\n\n.. image:: https://codecov.io/github/tiran/defusedxml/coverage.svg?branch=master\n    :target: https://codecov.io/github/tiran/defusedxml?branch=master\n    :alt: codecov\n\n.. image:: https://img.shields.io/pypi/dm/defusedxml.svg\n    :target: https://pypistats.org/packages/defusedxml\n    :alt: PyPI downloads\n\n.. image:: https://img.shields.io/badge/code%20style-black-000000.svg\n    :target: https://github.com/psf/black\n    :alt: Code style: black\n\n..\n\n    \"It's just XML, what could probably go wrong?\"\n\nChristian Heimes <christian@python.org>\n\nSynopsis\n========\n\nThe results of an attack on a vulnerable XML library can be fairly dramatic.\nWith just a few hundred **Bytes** of XML data an attacker can occupy several\n**Gigabytes** of memory within **seconds**. An attacker can also keep\nCPUs busy for a long time with a small to medium size request. Under some\ncircumstances it is even possible to access local files on your\nserver, to circumvent a firewall, or to abuse services to rebound attacks to\nthird parties.\n\nThe attacks use and abuse less common features of XML and its parsers. The\nmajority of developers are unacquainted with features such as processing\ninstructions and entity expansions that XML inherited from SGML. At best\nthey know about ``<!DOCTYPE>`` from experience with HTML but they are not\naware that a document type definition (DTD) can generate an HTTP request\nor load a file from the file system.\n\nNone of the issues is new. They have been known for a long time. Billion\nlaughs was first reported in 2003. Nevertheless some XML libraries and\napplications are still vulnerable and even heavy users of XML are\nsurprised by these features. It's hard to say whom to blame for the\nsituation. It's too short sighted to shift all blame on XML parsers and\nXML libraries for using insecure default settings. After all they\nproperly implement XML specifications. Application developers must not rely\nthat a library is always configured for security and potential harmful data\nby default.\n\n\n.. contents:: Table of Contents\n   :depth: 2\n\n\nAttack vectors\n==============\n\nbillion laughs / exponential entity expansion\n---------------------------------------------\n\nThe `Billion Laughs`_ attack -- also known as exponential entity expansion --\nuses multiple levels of nested entities. The original example uses 9 levels\nof 10 expansions in each level to expand the string ``lol`` to a string of\n3 * 10 :sup:`9` bytes, hence the name \"billion laughs\". The resulting string\noccupies 3 GB (2.79 GiB) of memory; intermediate strings require additional\nmemory. Because most parsers don't cache the intermediate step for every\nexpansion it is repeated over and over again. It increases the CPU load even\nmore.\n\nAn XML document of just a few hundred bytes can disrupt all services on a\nmachine within seconds.\n\nExample XML::\n\n    <!DOCTYPE xmlbomb [\n    <!ENTITY a \"1234567890\" >\n    <!ENTITY b \"&a;&a;&a;&a;&a;&a;&a;&a;\">\n    <!ENTITY c \"&b;&b;&b;&b;&b;&b;&b;&b;\">\n    <!ENTITY d \"&c;&c;&c;&c;&c;&c;&c;&c;\">\n    ]>\n    <bomb>&d;</bomb>\n\n\nquadratic blowup entity expansion\n---------------------------------\n\nA quadratic blowup attack is similar to a `Billion Laughs`_ attack; it abuses\nentity expansion, too. Instead of nested entities it repeats one large entity\nwith a couple of thousand chars over and over again. The attack isn't as\nefficient as the exponential case but it avoids triggering countermeasures of\nparsers against heavily nested entities. Some parsers limit the depth and\nbreadth of a single entity but not the total amount of expanded text\nthroughout an entire XML document.\n\nA medium-sized XML document with a couple of hundred kilobytes can require a\ncouple of hundred MB to several GB of memory. When the attack is combined\nwith some level of nested expansion an attacker is able to achieve a higher\nratio of success.\n\n::\n\n    <!DOCTYPE bomb [\n    <!ENTITY a \"xxxxxxx... a couple of ten thousand chars\">\n    ]>\n    <bomb>&a;&a;&a;... repeat</bomb>\n\n\nexternal entity expansion (remote)\n----------------------------------\n\nEntity declarations can contain more than just text for replacement. They can\nalso point to external resources by public identifiers or system identifiers.\nSystem identifiers are standard URIs. When the URI is a URL (e.g. a\n``http://`` locator) some parsers download the resource from the remote\nlocation and embed them into the XML document verbatim.\n\nSimple example of a parsed external entity::\n\n    <!DOCTYPE external [\n    <!ENTITY ee SYSTEM \"http://www.python.org/some.xml\">\n    ]>\n    <root>&ee;</root>\n\nThe case of parsed external entities works only for valid XML content. The\nXML standard also supports unparsed external entities with a\n``NData declaration``.\n\nExternal entity expansion opens the door to plenty of exploits. An attacker\ncan abuse a vulnerable XML library and application to rebound and forward\nnetwork requests with the IP address of the server. It highly depends\non the parser and the application what kind of exploit is possible. For\nexample:\n\n* An attacker can circumvent firewalls and gain access to restricted\n  resources as all the requests are made from an internal and trustworthy\n  IP address, not from the outside.\n* An attacker can abuse a service to attack, spy on or DoS your servers but\n  also third party services. The attack is disguised with the IP address of\n  the server and the attacker is able to utilize the high bandwidth of a big\n  machine.\n* An attacker can exhaust additional resources on the machine, e.g. with\n  requests to a service that doesn't respond or responds with very large\n  files.\n* An attacker may gain knowledge, when, how often and from which IP address\n  an XML document is accessed.\n* An attacker could send mail from inside your network if the URL handler\n  supports ``smtp://`` URIs.\n\n\nexternal entity expansion (local file)\n--------------------------------------\n\nExternal entities with references to local files are a sub-case of external\nentity expansion. It's listed as an extra attack because it deserves extra\nattention. Some XML libraries such as lxml disable network access by default\nbut still allow entity expansion with local file access by default. Local\nfiles are either referenced with a ``file://`` URL or by a file path (either\nrelative or absolute).\n\nAn attacker may be able to access and download all files that can be read by\nthe application process. This may include critical configuration files, too.\n\n::\n\n    <!DOCTYPE external [\n    <!ENTITY ee SYSTEM \"file:///PATH/TO/simple.xml\">\n    ]>\n    <root>&ee;</root>\n\n\nDTD retrieval\n-------------\n\nThis case is similar to external entity expansion, too. Some XML libraries\nlike Python's xml.dom.pulldom retrieve document type definitions from remote\nor local locations. Several attack scenarios from the external entity case\napply to this issue as well.\n\n::\n\n    <?xml version=\"1.0\" encoding=\"utf-8\"?>\n    <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n      \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n    <html>\n        <head/>\n        <body>text</body>\n    </html>\n\n\nPython XML Libraries\n====================\n\n.. csv-table:: vulnerabilities and features\n   :header: \"kind\", \"sax\", \"etree\", \"minidom\", \"pulldom\", \"xmlrpc\", \"lxml\", \"genshi\"\n   :widths: 24, 7, 8, 8, 7, 8, 8, 8\n   :stub-columns: 0\n\n   \"billion laughs\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"False (1)\", \"False (5)\"\n   \"quadratic blowup\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"**True**\", \"False (5)\"\n   \"external entity expansion (remote)\", \"**True**\", \"False (3)\", \"False (4)\", \"**True**\", \"false\", \"False (1)\", \"False (5)\"\n   \"external entity expansion (local file)\", \"**True**\", \"False (3)\", \"False (4)\", \"**True**\", \"false\", \"**True**\", \"False (5)\"\n   \"DTD retrieval\", \"**True**\", \"False\", \"False\", \"**True**\", \"false\", \"False (1)\", \"False\"\n   \"gzip bomb\", \"False\", \"False\", \"False\", \"False\", \"**True**\", \"**partly** (2)\", \"False\"\n   \"xpath support (7)\", \"False\", \"False\", \"False\", \"False\", \"False\", \"**True**\", \"False\"\n   \"xsl(t) support (7)\", \"False\", \"False\", \"False\", \"False\", \"False\", \"**True**\", \"False\"\n   \"xinclude support (7)\", \"False\", \"**True** (6)\", \"False\", \"False\", \"False\", \"**True** (6)\", \"**True**\"\n   \"C library\", \"expat\", \"expat\", \"expat\", \"expat\", \"expat\", \"libxml2\", \"expat\"\n\n1. Lxml is protected against billion laughs attacks and doesn't do network\n   lookups by default.\n2. libxml2 and lxml are not directly vulnerable to gzip decompression bombs\n   but they don't protect you against them either.\n3. xml.etree doesn't expand entities and raises a ParserError when an entity\n   occurs.\n4. minidom doesn't expand entities and simply returns the unexpanded entity\n   verbatim.\n5. genshi.input of genshi 0.6 doesn't support entity expansion and raises a\n   ParserError when an entity occurs.\n6. Library has (limited) XInclude support but requires an additional step to\n   process inclusion.\n7. These are features but they may introduce exploitable holes, see\n   `Other things to consider`_\n\n\nSettings in standard library\n----------------------------\n\n\nxml.sax.handler Features\n........................\n\nfeature_external_ges (http://xml.org/sax/features/external-general-entities)\n  disables external entity expansion\n\nfeature_external_pes (http://xml.org/sax/features/external-parameter-entities)\n  the option is ignored and doesn't modify any functionality\n\nDOM xml.dom.xmlbuilder.Options\n..............................\n\nexternal_parameter_entities\n  ignored\n\nexternal_general_entities\n  ignored\n\nexternal_dtd_subset\n  ignored\n\nentities\n  unsure\n\n\ndefusedxml\n==========\n\nThe `defusedxml package`_ (`defusedxml on PyPI`_)\ncontains several Python-only workarounds and fixes\nfor denial of service and other vulnerabilities in Python's XML libraries.\nIn order to benefit from the protection you just have to import and use the\nlisted functions / classes from the right defusedxml module instead of the\noriginal module. Merely `defusedxml.xmlrpc`_ is implemented as monkey patch.\n\nInstead of::\n\n   >>> from xml.etree.ElementTree import parse\n   >>> et = parse(xmlfile)\n\nalter code to::\n\n   >>> from defusedxml.ElementTree import parse\n   >>> et = parse(xmlfile)\n\nAdditionally the package has an **untested** function to monkey patch\nall stdlib modules with ``defusedxml.defuse_stdlib()``.\n\nAll functions and parser classes accept three additional keyword arguments.\nThey return either the same objects as the original functions or compatible\nsubclasses.\n\nforbid_dtd (default: False)\n  disallow XML with a ``<!DOCTYPE>`` processing instruction and raise a\n  *DTDForbidden* exception when a DTD processing instruction is found.\n\nforbid_entities (default: True)\n  disallow XML with ``<!ENTITY>`` declarations inside the DTD and raise an\n  *EntitiesForbidden* exception when an entity is declared.\n\nforbid_external (default: True)\n  disallow any access to remote or local resources in external entities\n  or DTD and raising an *ExternalReferenceForbidden* exception when a DTD\n  or entity references an external resource.\n\n\ndefusedxml (package)\n--------------------\n\nDefusedXmlException, DTDForbidden, EntitiesForbidden,\nExternalReferenceForbidden, NotSupportedError\n\ndefuse_stdlib() (*experimental*)\n\n\ndefusedxml.cElementTree\n-----------------------\n\n**NOTE** ``defusedxml.cElementTree`` is deprecated and will be removed in a\nfuture release. Import from ``defusedxml.ElementTree`` instead.\n\nparse(), iterparse(), fromstring(), XMLParser\n\n\ndefusedxml.ElementTree\n-----------------------\n\nparse(), iterparse(), fromstring(), XMLParser\n\n\ndefusedxml.expatreader\n----------------------\n\ncreate_parser(), DefusedExpatParser\n\n\ndefusedxml.sax\n--------------\n\nparse(), parseString(), make_parser()\n\n\ndefusedxml.expatbuilder\n-----------------------\n\nparse(), parseString(), DefusedExpatBuilder, DefusedExpatBuilderNS\n\n\ndefusedxml.minidom\n------------------\n\nparse(), parseString()\n\n\ndefusedxml.pulldom\n------------------\n\nparse(), parseString()\n\n\ndefusedxml.xmlrpc\n-----------------\n\nThe fix is implemented as monkey patch for the stdlib's xmlrpc package (3.x)\nor xmlrpclib module (2.x). The function `monkey_patch()` enables the fixes,\n`unmonkey_patch()` removes the patch and puts the code in its former state.\n\nThe monkey patch protects against XML related attacks as well as\ndecompression bombs and excessively large requests or responses. The default\nsetting is 30 MB for requests, responses and gzip decompression. You can\nmodify the default by changing the module variable `MAX_DATA`. A value of\n`-1` disables the limit.\n\n\ndefusedxml.lxml\n---------------\n\n**DEPRECATED** The module is deprecated and will be removed in a future\nrelease.\n\nThe module acts as an *example* how you could protect code that uses\nlxml.etree. It implements a custom Element class that filters out\nEntity instances, a custom parser factory and a thread local storage for\nparser instances. It also has a check_docinfo() function which inspects\na tree for internal or external DTDs and entity declarations. In order to\ncheck for entities lxml > 3.0 is required.\n\nparse(), fromstring()\nRestrictedElement, GlobalParserTLS, getDefaultParser(), check_docinfo()\n\n\ndefusedexpat\n============\n\nThe `defusedexpat package`_ (`defusedexpat on PyPI`_)\ncomes with binary extensions and a\n`modified expat`_ library instead of the standard `expat parser`_. It's\nbasically a stand-alone version of the patches for Python's standard\nlibrary C extensions.\n\nModifications in expat\n----------------------\n\nnew definitions::\n\n  XML_BOMB_PROTECTION\n  XML_DEFAULT_MAX_ENTITY_INDIRECTIONS\n  XML_DEFAULT_MAX_ENTITY_EXPANSIONS\n  XML_DEFAULT_RESET_DTD\n\nnew XML_FeatureEnum members::\n\n  XML_FEATURE_MAX_ENTITY_INDIRECTIONS\n  XML_FEATURE_MAX_ENTITY_EXPANSIONS\n  XML_FEATURE_IGNORE_DTD\n\nnew XML_Error members::\n\n  XML_ERROR_ENTITY_INDIRECTIONS\n  XML_ERROR_ENTITY_EXPANSION\n\nnew API functions::\n\n  int XML_GetFeature(XML_Parser parser,\n                     enum XML_FeatureEnum feature,\n                     long *value);\n  int XML_SetFeature(XML_Parser parser,\n                     enum XML_FeatureEnum feature,\n                     long value);\n  int XML_GetFeatureDefault(enum XML_FeatureEnum feature,\n                            long *value);\n  int XML_SetFeatureDefault(enum XML_FeatureEnum feature,\n                            long value);\n\nXML_FEATURE_MAX_ENTITY_INDIRECTIONS\n   Limit the amount of indirections that are allowed to occur during the\n   expansion of a nested entity. A counter starts when an entity reference\n   is encountered. It resets after the entity is fully expanded. The limit\n   protects the parser against exponential entity expansion attacks (aka\n   billion laughs attack). When the limit is exceeded the parser stops and\n   fails with `XML_ERROR_ENTITY_INDIRECTIONS`.\n   A value of 0 disables the protection.\n\n   Supported range\n     0 .. UINT_MAX\n   Default\n     40\n\nXML_FEATURE_MAX_ENTITY_EXPANSIONS\n   Limit the total length of all entity expansions throughout the entire\n   document. The lengths of all entities are accumulated in a parser variable.\n   The setting protects against quadratic blowup attacks (lots of expansions\n   of a large entity declaration). When the sum of all entities exceeds\n   the limit, the parser stops and fails with `XML_ERROR_ENTITY_EXPANSION`.\n   A value of 0 disables the protection.\n\n   Supported range\n     0 .. UINT_MAX\n   Default\n     8 MiB\n\nXML_FEATURE_RESET_DTD\n   Reset all DTD information after the <!DOCTYPE> block has been parsed. When\n   the flag is set (default: false) all DTD information after the\n   endDoctypeDeclHandler has been called. The flag can be set inside the\n   endDoctypeDeclHandler. Without DTD information any entity reference in\n   the document body leads to `XML_ERROR_UNDEFINED_ENTITY`.\n\n   Supported range\n     0, 1\n   Default\n     0\n\n\nHow to avoid XML vulnerabilities\n================================\n\nBest practices\n--------------\n\n* Don't allow DTDs\n* Don't expand entities\n* Don't resolve externals\n* Limit parse depth\n* Limit total input size\n* Limit parse time\n* Favor a SAX or iterparse-like parser for potential large data\n* Validate and properly quote arguments to XSL transformations and\n  XPath queries\n* Don't use XPath expression from untrusted sources\n* Don't apply XSL transformations that come untrusted sources\n\n(based on Brad Hill's `Attacking XML Security`_)\n\n\nOther things to consider\n========================\n\nXML, XML parsers and processing libraries have more features and possible\nissue that could lead to DoS vulnerabilities or security exploits in\napplications. I have compiled an incomplete list of theoretical issues that\nneed further research and more attention. The list is deliberately pessimistic\nand a bit paranoid, too. It contains things that might go wrong under daffy\ncircumstances.\n\n\nattribute blowup / hash collision attack\n----------------------------------------\n\nXML parsers may use an algorithm with quadratic runtime O(n :sup:`2`) to\nhandle attributes and namespaces. If it uses hash tables (dictionaries) to\nstore attributes and namespaces the implementation may be vulnerable to\nhash collision attacks, thus reducing the performance to O(n :sup:`2`) again.\nIn either case an attacker is able to forge a denial of service attack with\nan XML document that contains thousands upon thousands of attributes in\na single node.\n\nI haven't researched yet if expat, pyexpat or libxml2 are vulnerable.\n\n\ndecompression bomb\n------------------\n\nThe issue of decompression bombs (aka `ZIP bomb`_) apply to all XML libraries\nthat can parse compressed XML stream like gzipped HTTP streams or LZMA-ed\nfiles. For an attacker it can reduce the amount of transmitted data by three\nmagnitudes or more. Gzip is able to compress 1 GiB zeros to roughly 1 MB,\nlzma is even better::\n\n    $ dd if=/dev/zero bs=1M count=1024 | gzip > zeros.gz\n    $ dd if=/dev/zero bs=1M count=1024 | lzma -z > zeros.xy\n    $ ls -sh zeros.*\n    1020K zeros.gz\n     148K zeros.xy\n\nNone of Python's standard XML libraries decompress streams except for\n``xmlrpclib``. The module is vulnerable <https://bugs.python.org/issue16043>\nto decompression bombs.\n\nlxml can load and process compressed data through libxml2 transparently.\nlibxml2 can handle even very large blobs of compressed data efficiently\nwithout using too much memory. But it doesn't protect applications from\ndecompression bombs. A carefully written SAX or iterparse-like approach can\nbe safe.\n\n\nProcessing Instruction\n----------------------\n\n`PI`_'s like::\n\n  <?xml-stylesheet type=\"text/xsl\" href=\"style.xsl\"?>\n\nmay impose more threats for XML processing. It depends if and how a\nprocessor handles processing instructions. The issue of URL retrieval with\nnetwork or local file access apply to processing instructions, too.\n\n\nOther DTD features\n------------------\n\n`DTD`_ has more features like ``<!NOTATION>``. I haven't researched how\nthese features may be a security threat.\n\n\nXPath\n-----\n\nXPath statements may introduce DoS vulnerabilities. Code should never execute\nqueries from untrusted sources. An attacker may also be able to create an XML\ndocument that makes certain XPath queries costly or resource hungry.\n\n\nXPath injection attacks\n-----------------------\n\nXPath injeciton attacks pretty much work like SQL injection attacks.\nArguments to XPath queries must be quoted and validated properly, especially\nwhen they are taken from the user. The page `Avoid the dangers of XPath injection`_\nlist some ramifications of XPath injections.\n\nPython's standard library doesn't have XPath support. Lxml supports\nparameterized XPath queries which does proper quoting. You just have to use\nits xpath() method correctly::\n\n   # DON'T\n   >>> tree.xpath(\"/tag[@id='%s']\" % value)\n\n   # instead do\n   >>> tree.xpath(\"/tag[@id=$tagid]\", tagid=name)\n\n\nXInclude\n--------\n\n`XML Inclusion`_ is another way to load and include external files::\n\n   <root xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n     <xi:include href=\"filename.txt\" parse=\"text\" />\n   </root>\n\nThis feature should be disabled when XML files from an untrusted source are\nprocessed. Some Python XML libraries and libxml2 support XInclude but don't\nhave an option to sandbox inclusion and limit it to allowed directories.\n\n\nXMLSchema location\n------------------\n\nA validating XML parser may download schema files from the information in a\n``xsi:schemaLocation`` attribute.\n\n::\n\n  <ead xmlns=\"urn:isbn:1-931666-22-9\"\n       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n       xsi:schemaLocation=\"urn:isbn:1-931666-22-9 http://www.loc.gov/ead/ead.xsd\">\n  </ead>\n\n\nXSL Transformation\n------------------\n\nYou should keep in mind that XSLT is a Turing complete language. Never\nprocess XSLT code from unknown or untrusted source! XSLT processors may\nallow you to interact with external resources in ways you can't even imagine.\nSome processors even support extensions that allow read/write access to file\nsystem, access to JRE objects or scripting with Jython.\n\nExample from `Attacking XML Security`_ for Xalan-J::\n\n    <xsl:stylesheet version=\"1.0\"\n     xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"\n     xmlns:rt=\"http://xml.apache.org/xalan/java/java.lang.Runtime\"\n     xmlns:ob=\"http://xml.apache.org/xalan/java/java.lang.Object\"\n     exclude-result-prefixes= \"rt ob\">\n     <xsl:template match=\"/\">\n       <xsl:variable name=\"runtimeObject\" select=\"rt:getRuntime()\"/>\n       <xsl:variable name=\"command\"\n         select=\"rt:exec($runtimeObject, &apos;c:\\Windows\\system32\\cmd.exe&apos;)\"/>\n       <xsl:variable name=\"commandAsString\" select=\"ob:toString($command)\"/>\n       <xsl:value-of select=\"$commandAsString\"/>\n     </xsl:template>\n    </xsl:stylesheet>\n\n\nRelated CVEs\n============\n\nCVE-2013-1664\n  Unrestricted entity expansion induces DoS vulnerabilities in Python XML\n  libraries (XML bomb)\n\nCVE-2013-1665\n  External entity expansion in Python XML libraries inflicts potential\n  security flaws and DoS vulnerabilities\n\n\nOther languages / frameworks\n=============================\n\nSeveral other programming languages and frameworks are vulnerable as well. A\ncouple of them are affected by the fact that libxml2 up to 2.9.0 has no\nprotection against quadratic blowup attacks. Most of them have potential\ndangerous default settings for entity expansion and external entities, too.\n\nPerl\n----\n\nPerl's XML::Simple is vulnerable to quadratic entity expansion and external\nentity expansion (both local and remote).\n\n\nRuby\n----\n\nRuby's REXML document parser is vulnerable to entity expansion attacks\n(both quadratic and exponential) but it doesn't do external entity\nexpansion by default. In order to counteract entity expansion you have to\ndisable the feature::\n\n  REXML::Document.entity_expansion_limit = 0\n\nlibxml-ruby and hpricot don't expand entities in their default configuration.\n\n\nPHP\n---\n\nPHP's SimpleXML API is vulnerable to quadratic entity expansion and loads\nentities from local and remote resources. The option ``LIBXML_NONET`` disables\nnetwork access but still allows local file access. ``LIBXML_NOENT`` seems to\nhave no effect on entity expansion in PHP 5.4.6.\n\n\nC# / .NET / Mono\n----------------\n\nInformation in `XML DoS and Defenses (MSDN)`_ suggest that .NET is\nvulnerable with its default settings. The article contains code snippets\nhow to create a secure XML reader::\n\n  XmlReaderSettings settings = new XmlReaderSettings();\n  settings.ProhibitDtd = false;\n  settings.MaxCharactersFromEntities = 1024;\n  settings.XmlResolver = null;\n  XmlReader reader = XmlReader.Create(stream, settings);\n\n\nJava\n----\n\nUntested. The documentation of Xerces and its `Xerces SecurityMananger`_\nsounds like Xerces is also vulnerable to billion laugh attacks with its\ndefault settings. It also does entity resolving when an\n``org.xml.sax.EntityResolver`` is configured. I'm not yet sure about the\ndefault setting here.\n\nJava specialists suggest to have a custom builder factory::\n\n  DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();\n  builderFactory.setXIncludeAware(False);\n  builderFactory.setExpandEntityReferences(False);\n  builderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, True);\n  # either\n  builderFactory.setFeature(\"http://apache.org/xml/features/disallow-doctype-decl\", True);\n  # or if you need DTDs\n  builderFactory.setFeature(\"http://xml.org/sax/features/external-general-entities\", False);\n  builderFactory.setFeature(\"http://xml.org/sax/features/external-parameter-entities\", False);\n  builderFactory.setFeature(\"http://apache.org/xml/features/nonvalidating/load-external-dtd\", False);\n  builderFactory.setFeature(\"http://apache.org/xml/features/nonvalidating/load-dtd-grammar\", False);\n\n\nTODO\n====\n\n* DOM: Use xml.dom.xmlbuilder options for entity handling\n* SAX: take feature_external_ges and feature_external_pes (?) into account\n* test experimental monkey patching of stdlib modules\n* improve documentation\n\n\nLicense\n=======\n\nCopyright (c) 2013-2017 by Christian Heimes <christian@python.org>\n\nLicensed to PSF under a Contributor Agreement.\n\nSee https://www.python.org/psf/license for licensing details.\n\n\nAcknowledgements\n================\n\nBrett Cannon (Python Core developer)\n  review and code cleanup\n\nAntoine Pitrou (Python Core developer)\n  code review\n\nAaron Patterson, Ben Murphy and Michael Koziarski (Ruby community)\n  Many thanks to Aaron, Ben and Michael from the Ruby community for their\n  report and assistance.\n\nThierry Carrez (OpenStack)\n  Many thanks to Thierry for his report to the Python Security Response\n  Team on behalf of the OpenStack security team.\n\nCarl Meyer (Django)\n  Many thanks to Carl for his report to PSRT on behalf of the Django security\n  team.\n\nDaniel Veillard (libxml2)\n  Many thanks to Daniel for his insight and assistance with libxml2.\n\nsemantics GmbH (https://www.semantics.de/)\n  Many thanks to my employer semantics for letting me work on the issue\n  during working hours as part of semantics's open source initiative.\n\n\nReferences\n==========\n\n* `XML DoS and Defenses (MSDN)`_\n* `Billion Laughs`_ on Wikipedia\n* `ZIP bomb`_ on Wikipedia\n* `Configure SAX parsers for secure processing`_\n* `Testing for XML Injection`_\n\n.. _defusedxml package: https://github.com/tiran/defusedxml\n.. _defusedxml on PyPI: https://pypi.python.org/pypi/defusedxml\n.. _defusedexpat package: https://github.com/tiran/defusedexpat\n.. _defusedexpat on PyPI: https://pypi.python.org/pypi/defusedexpat\n.. _modified expat: https://github.com/tiran/expat\n.. _expat parser: http://expat.sourceforge.net/\n.. _Attacking XML Security: https://www.isecpartners.com/media/12976/iSEC-HILL-Attacking-XML-Security-bh07.pdf\n.. _Billion Laughs: https://en.wikipedia.org/wiki/Billion_laughs\n.. _XML DoS and Defenses (MSDN): https://msdn.microsoft.com/en-us/magazine/ee335713.aspx\n.. _ZIP bomb: https://en.wikipedia.org/wiki/Zip_bomb\n.. _DTD: https://en.wikipedia.org/wiki/Document_Type_Definition\n.. _PI: https://en.wikipedia.org/wiki/Processing_Instruction\n.. _Avoid the dangers of XPath injection: http://www.ibm.com/developerworks/xml/library/x-xpathinjection/index.html\n.. _Configure SAX parsers for secure processing: http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html\n.. _Testing for XML Injection: https://www.owasp.org/index.php/Testing_for_XML_Injection_(OWASP-DV-008)\n.. _Xerces SecurityMananger: https://xerces.apache.org/xerces2-j/javadocs/xerces2/org/apache/xerces/util/SecurityManager.html\n.. _XML Inclusion: https://www.w3.org/TR/xinclude/#include_element\n\nChangelog\n=========\n\ndefusedxml 0.7.1\n---------------------\n\n*Release date: 08-Mar-2021*\n\n- Fix regression ``defusedxml.ElementTree.ParseError`` (#63)\n  The ``ParseError`` exception is now the same class object as\n  ``xml.etree.ElementTree.ParseError`` again.\n\n\ndefusedxml 0.7.0\n----------------\n\n*Release date: 4-Mar-2021*\n\n- No changes\n\n\ndefusedxml 0.7.0rc2\n-------------------\n\n*Release date: 12-Jan-2021*\n\n- Re-add and deprecate ``defusedxml.cElementTree``\n- Use GitHub Actions instead of TravisCI\n- Restore ``ElementTree`` attribute of ``xml.etree`` module after patching\n\ndefusedxml 0.7.0rc1\n-------------------\n\n*Release date: 04-May-2020*\n\n- Add support for Python 3.9\n- ``defusedxml.cElementTree`` is not available with Python 3.9.\n- Python 2 is deprecate. Support for Python 2 will be removed in 0.8.0.\n\n\ndefusedxml 0.6.0\n----------------\n\n*Release date: 17-Apr-2019*\n\n- Increase test coverage.\n- Add badges to README.\n\n\ndefusedxml 0.6.0rc1\n-------------------\n\n*Release date: 14-Apr-2019*\n\n- Test on Python 3.7 stable and 3.8-dev\n- Drop support for Python 3.4\n- No longer pass *html* argument to XMLParse. It has been deprecated and\n  ignored for a long time. The DefusedXMLParser still takes a html argument.\n  A deprecation warning is issued when the argument is False and a TypeError\n  when it's True.\n- defusedxml now fails early when pyexpat stdlib module is not available or\n  broken.\n- defusedxml.ElementTree.__all__ now lists ParseError as public attribute.\n- The defusedxml.ElementTree and defusedxml.cElementTree modules had a typo\n  and used XMLParse instead of XMLParser as an alias for DefusedXMLParser.\n  Both the old and fixed name are now available.\n\n\ndefusedxml 0.5.0\n----------------\n\n*Release date: 07-Feb-2017*\n\n- No changes\n\n\ndefusedxml 0.5.0.rc1\n--------------------\n\n*Release date: 28-Jan-2017*\n\n- Add compatibility with Python 3.6\n- Drop support for Python 2.6, 3.1, 3.2, 3.3\n- Fix lxml tests (XMLSyntaxError: Detected an entity reference loop)\n\n\ndefusedxml 0.4.1\n----------------\n\n*Release date: 28-Mar-2013*\n\n- Add more demo exploits, e.g. python_external.py and Xalan XSLT demos.\n- Improved documentation.\n\n\ndefusedxml 0.4\n--------------\n\n*Release date: 25-Feb-2013*\n\n- As per http://seclists.org/oss-sec/2013/q1/340 please REJECT\n  CVE-2013-0278, CVE-2013-0279 and CVE-2013-0280 and use CVE-2013-1664,\n  CVE-2013-1665 for OpenStack/etc.\n- Add missing parser_list argument to sax.make_parser(). The argument is\n  ignored, though. (thanks to Florian Apolloner)\n- Add demo exploit for external entity attack on Python's SAX parser, XML-RPC\n  and WebDAV.\n\n\ndefusedxml 0.3\n--------------\n\n*Release date: 19-Feb-2013*\n\n- Improve documentation\n\n\ndefusedxml 0.2\n--------------\n\n*Release date: 15-Feb-2013*\n\n- Rename ExternalEntitiesForbidden to ExternalReferenceForbidden\n- Rename defusedxml.lxml.check_dtd() to check_docinfo()\n- Unify argument names in callbacks\n- Add arguments and formatted representation to exceptions\n- Add forbid_external argument to all functions and classes\n- More tests\n- LOTS of documentation\n- Add example code for other languages (Ruby, Perl, PHP) and parsers (Genshi)\n- Add protection against XML and gzip attacks to xmlrpclib\n\ndefusedxml 0.1\n--------------\n\n*Release date: 08-Feb-2013*\n\n- Initial and internal release for PSRT review\n\n\n",
        "keywords": [
          "xml",
          "bomb",
          "DoS"
        ],
        "home_page": "https://github.com/tiran/defusedxml",
        "download_url": "https://pypi.python.org/pypi/defusedxml",
        "author": "Christian Heimes",
        "author_email": "christian@python.org",
        "maintainer": "Christian Heimes",
        "maintainer_email": "christian@python.org",
        "license": "PSFL",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: Python Software Foundation License",
          "Natural Language :: English",
          "Programming Language :: Python",
          "Programming Language :: Python :: 2",
          "Programming Language :: Python :: 2.7",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.5",
          "Programming Language :: Python :: 3.6",
          "Programming Language :: Python :: 3.7",
          "Programming Language :: Python :: 3.8",
          "Programming Language :: Python :: 3.9",
          "Topic :: Text Processing :: Markup :: XML"
        ],
        "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/c3/0e/3e45bbe0dd48f4e56b1d46649d342de853cd1c7e815323472ab62687f153/huggingface_hub-1.30.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=96ae0a8e99a234374a6fe43e989ebd21c04640b91ab2927e7e5773ba1131ca59",
          "hashes": {
            "sha256": "96ae0a8e99a234374a6fe43e989ebd21c04640b91ab2927e7e5773ba1131ca59"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "huggingface_hub",
        "version": "1.30.0",
        "dynamic": [
          "author",
          "author-email",
          "classifier",
          "description",
          "description-content-type",
          "home-page",
          "keywords",
          "license",
          "license-file",
          "provides-extra",
          "requires-dist",
          "requires-python",
          "summary"
        ],
        "summary": "Client library to download and publish models, datasets and other repos on the huggingface.co hub",
        "description": "<p align=\"center\">\n  <picture>\n    <source media=\"(prefers-color-scheme: dark)\" srcset=\"https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub-dark.svg\">\n    <source media=\"(prefers-color-scheme: light)\" srcset=\"https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub.svg\">\n    <img alt=\"huggingface_hub library logo\" src=\"https://huggingface.co/datasets/huggingface/documentation-images/raw/main/huggingface_hub.svg\" width=\"352\" height=\"59\" style=\"max-width: 100%\">\n  </picture>\n  <br/>\n  <br/>\n</p> \n\n<p align=\"center\">\n    <i>The official CLI and Python client for the Hugging Face Hub.</i>\n    <br/>\n    <a href=\"#what-is-huggingface_hub\">About</a>\n    ·\n    <a href=\"https://huggingface.co/docs/huggingface_hub\">Documentation</a>\n    ·\n    <a href=\"https://huggingface.co/docs/huggingface_hub/en/installation\">Install</a>\n    ·\n    <a href=\"https://huggingface.co/docs/huggingface_hub/en/guides/cli\">CLI Guide</a>\n    ·\n    <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/CONTRIBUTING.md\">Contributing</a>\n</p>\n\n<p align=\"center\">\n    <a href=\"https://huggingface.co/docs/huggingface_hub/en/index\"><img alt=\"Documentation\" src=\"https://img.shields.io/website/http/huggingface.co/docs/huggingface_hub/index.svg?down_color=red&down_message=offline&up_message=online&label=doc\"></a>\n    <a href=\"https://github.com/huggingface/huggingface_hub/releases\"><img alt=\"GitHub release\" src=\"https://img.shields.io/github/release/huggingface/huggingface_hub.svg\"></a>\n    <a href=\"https://github.com/huggingface/huggingface_hub\"><img alt=\"PyPi version\" src=\"https://img.shields.io/pypi/pyversions/huggingface_hub.svg\"></a>\n    <a href=\"https://pypi.org/project/huggingface-hub\"><img alt=\"PyPI - Downloads\" src=\"https://img.shields.io/pypi/dm/huggingface_hub\"></a>\n    <a href=\"https://codecov.io/gh/huggingface/huggingface_hub\"><img alt=\"Code coverage\" src=\"https://codecov.io/gh/huggingface/huggingface_hub/branch/main/graph/badge.svg?token=RXP95LE2XL\"></a>\n</p>\n\n<h4 align=\"center\">\n    <p>\n        <b>English</b> |\n        <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_de.md\">Deutsch</a> |\n        <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_fr.md\">Français</a> |\n        <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_hi.md\">हिंदी</a> |\n        <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_ko.md\">한국어</a> |\n        <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_cn.md\">中文 (简体)</a> |\n        <a href=\"https://github.com/huggingface/huggingface_hub/blob/main/i18n/README_kn.md\">ಕನ್ನಡ</a>\n    </p>\n</h4>\n\n## Quick start\n\nInstall the [`hf` CLI](https://huggingface.co/docs/huggingface_hub/en/guides/cli) with the standalone installer:\n\n```bash\n# On macOS and Linux.\ncurl -LsSf https://hf.co/cli/install.sh | bash\n```\n\n```powershell\n# On Windows.\npowershell -ExecutionPolicy ByPass -c \"irm https://hf.co/cli/install.ps1 | iex\"\n```\n\nLog in, then start working with the Hub:\n\n```bash\n# Log in (use --token $HF_TOKEN in non-interactive environments)\nhf auth login\n\n# Find models served by Inference Providers\nhf models ls --warm\n\n# Download a model\nhf download Qwen/Qwen3-0.6B\n\n# Upload files to your own repo\nhf upload username/my-cool-model ./model.safetensors\n\n# Sync a local folder to a storage bucket\nhf buckets sync ./checkpoints hf://buckets/username/my-bucket\n\n# Run a job on Hugging Face infrastructure\nhf jobs run python:3.12 python -c \"print('Hello from the cloud!')\"\n\n# Discover everything else\nhf --help\n```\n\nThe Hub uses tokens to authenticate applications (see [docs](https://huggingface.co/docs/hub/security-tokens)). Check out the [CLI guide](https://huggingface.co/docs/huggingface_hub/en/guides/cli) for a tour of the main features.\n\n## What is `huggingface_hub`?\n\nThe `huggingface_hub` library allows you to interact with the [Hugging Face Hub](https://huggingface.co/), a platform democratizing open-source Machine Learning for creators and collaborators. Discover pre-trained models and datasets for your projects, play with the thousands of machine learning apps hosted on the Hub, or create and share your own models, datasets and demos with the community. Everything ships in one package with two interfaces: the [`hf` CLI](https://huggingface.co/docs/huggingface_hub/en/guides/cli) for your terminal and the `huggingface_hub` library for Python — both designed to work well for humans and AI agents. Use them to:\n\n- [Download files](https://huggingface.co/docs/huggingface_hub/en/guides/download) from the Hub.\n- [Upload files](https://huggingface.co/docs/huggingface_hub/en/guides/upload) to the Hub.\n- [Manage your repositories](https://huggingface.co/docs/huggingface_hub/en/guides/repository).\n- [Run Inference](https://huggingface.co/docs/huggingface_hub/en/guides/inference) on deployed models.\n- [Run Jobs](https://huggingface.co/docs/huggingface_hub/en/guides/jobs) on Hugging Face infrastructure.\n- [Search](https://huggingface.co/docs/huggingface_hub/en/guides/search) for models, datasets and Spaces.\n- [Share Model Cards](https://huggingface.co/docs/huggingface_hub/en/guides/model-cards) to document your models.\n- [Engage with the community](https://huggingface.co/docs/huggingface_hub/en/guides/community) through PRs and comments.\n- Do all of the above from the terminal with the [`hf` CLI](https://huggingface.co/docs/huggingface_hub/en/guides/cli).\n\n## Built for humans and AI agents\n\nThe `hf` CLI is designed for people and coding agents alike: the same commands adapt their output when run by an agent. If you use Claude Code, Codex, Cursor, or another coding agent, install the `hf` CLI Skill — a command reference generated from your installed CLI:\n\n```bash\n# for Codex, Cursor, OpenCode, Pi and other agents that load skills from `.agents/skills`\nhf skills add\n# includes the above + Claude Code\nhf skills add --claude\n```\n\nLearn more in the [Hugging Face CLI for AI agents guide](https://huggingface.co/docs/hub/agents-cli) and the [announcement blog post](https://huggingface.co/blog/hf-cli-for-agents).\n\n## Use the Python library\n\nInstall the `huggingface_hub` package with [pip](https://pypi.org/project/huggingface-hub/) (this also installs the `hf` CLI):\n\n```bash\npip install huggingface_hub\n```\n\nWe recommend using [`uv`](https://docs.astral.sh/uv/) for a fast and reliable install:\n\n```bash\nuv pip install huggingface_hub\n```\n\nIn order to keep the package minimal by default, `huggingface_hub` comes with optional dependencies useful for some use cases. For example, if you want to use the MCP module, run:\n\n```bash\npip install \"huggingface_hub[mcp]\"\n```\n\nTo learn more about installation and optional dependencies, check out the [installation guide](https://huggingface.co/docs/huggingface_hub/en/installation).\n\n### Download files\n\nDownload a single file\n\n```py\nfrom huggingface_hub import hf_hub_download\n\nhf_hub_download(repo_id=\"zai-org/GLM-5.2\", filename=\"config.json\")\n```\n\nOr an entire repository\n\n```py\nfrom huggingface_hub import snapshot_download\n\nsnapshot_download(\"sentence-transformers/all-MiniLM-L6-v2\")\n```\n\nFiles will be downloaded in a local cache folder. More details in [this guide](https://huggingface.co/docs/huggingface_hub/en/guides/manage-cache).\n\n### Create a repository\n\n```py\nfrom huggingface_hub import create_repo\n\ncreate_repo(repo_id=\"super-cool-model\")\n```\n\n### Upload files\n\nUpload a single file\n\n```py\nfrom huggingface_hub import upload_file\n\nupload_file(\n    path_or_fileobj=\"/home/lysandre/dummy-test/README.md\",\n    path_in_repo=\"README.md\",\n    repo_id=\"lysandre/test-model\",\n)\n```\n\nOr an entire folder\n\n```py\nfrom huggingface_hub import upload_folder\n\nupload_folder(\n    folder_path=\"/path/to/local/space\",\n    repo_id=\"username/my-cool-space\",\n    repo_type=\"space\",\n)\n```\n\nMore details in the [upload guide](https://huggingface.co/docs/huggingface_hub/en/guides/upload).\n\n## Integrating with the Hub.\n\nWe're partnering with cool open source ML libraries to provide free model hosting and versioning. You can find the existing integrations [here](https://huggingface.co/docs/hub/libraries).\n\nThe advantages are:\n\n- Free model or dataset hosting for libraries and their users.\n- Built-in file versioning, even with very large files, made possible by [Xet](https://huggingface.co/docs/hub/xet/index), the Hub's chunk-deduplicated storage backend.\n- In-browser widgets to play with the uploaded models.\n- Anyone can upload a new model for your library, they just need to add the corresponding tag for the model to be discoverable.\n- Fast downloads! We use Cloudfront (a CDN) to geo-replicate downloads so they're blazing fast from anywhere on the globe.\n- Usage stats and more features to come.\n\nIf you would like to integrate your library, feel free to open an issue to begin the discussion. We wrote a [step-by-step guide](https://huggingface.co/docs/hub/adding-a-library) with ❤️ showing how to do this integration.\n\n## Contributions (feature requests, bugs, etc.) are super welcome 💙💚💛💜🧡❤️\n\nEveryone is welcome to contribute, and we value everybody's contribution. Code is not the only way to help the community.\nAnswering questions, helping others, reaching out and improving the documentations are immensely valuable to the community.\nWe wrote a [contribution guide](https://github.com/huggingface/huggingface_hub/blob/main/CONTRIBUTING.md) to summarize\nhow to get started to contribute to this repository.\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "model-hub",
          "machine-learning",
          "models",
          "natural-language-processing",
          "deep-learning",
          "pytorch",
          "pretrained-models"
        ],
        "home_page": "https://github.com/huggingface/huggingface_hub",
        "author": "Hugging Face, Inc.",
        "author_email": "julien@huggingface.co",
        "license": "Apache-2.0",
        "classifier": [
          "Intended Audience :: Developers",
          "Intended Audience :: Education",
          "Intended Audience :: Science/Research",
          "License :: OSI Approved :: Apache Software License",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Scientific/Engineering :: Artificial Intelligence"
        ],
        "requires_dist": [
          "click<9.0.0,>=8.4.2",
          "filelock>=3.10.0",
          "fsspec>=2023.5.0",
          "hf-xet<2.0.0,>=1.5.2; platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\"",
          "httpx<1,>=0.23.0",
          "packaging>=20.9",
          "pyyaml>=5.1",
          "tqdm>=4.42.1",
          "typing-extensions>=4.1.0",
          "authlib>=1.3.2; extra == \"oauth\"",
          "fastapi; extra == \"oauth\"",
          "httpx; extra == \"oauth\"",
          "itsdangerous; extra == \"oauth\"",
          "torch; extra == \"torch\"",
          "safetensors[torch]; extra == \"torch\"",
          "toml; extra == \"fastai\"",
          "fastai>=2.4; extra == \"fastai\"",
          "fastcore>=1.3.27; extra == \"fastai\"",
          "hf-xet<2.0.0,>=1.5.2; extra == \"hf-xet\"",
          "mcp<2.0.0,>=1.8.0; extra == \"mcp\"",
          "authlib>=1.3.2; extra == \"testing\"",
          "fastapi; extra == \"testing\"",
          "httpx; extra == \"testing\"",
          "itsdangerous; extra == \"testing\"",
          "jedi; extra == \"testing\"",
          "Jinja2; extra == \"testing\"",
          "pytest>=8.4.2; extra == \"testing\"",
          "pytest-cov; extra == \"testing\"",
          "pytest-env; extra == \"testing\"",
          "pytest-xdist; extra == \"testing\"",
          "pytest-vcr; extra == \"testing\"",
          "pytest-asyncio; extra == \"testing\"",
          "pytest-rerunfailures>=16.2; extra == \"testing\"",
          "pytest-mock; extra == \"testing\"",
          "urllib3<2.0; extra == \"testing\"",
          "soundfile; extra == \"testing\"",
          "Pillow; extra == \"testing\"",
          "numpy; extra == \"testing\"",
          "duckdb; extra == \"testing\"",
          "fastapi; extra == \"testing\"",
          "gradio>=5.0.0; extra == \"gradio\"",
          "requests; extra == \"gradio\"",
          "typing-extensions>=4.8.0; extra == \"typing\"",
          "types-PyYAML; extra == \"typing\"",
          "types-simplejson; extra == \"typing\"",
          "types-toml; extra == \"typing\"",
          "types-tqdm; extra == \"typing\"",
          "types-urllib3; extra == \"typing\"",
          "ruff>=0.9.0; extra == \"quality\"",
          "mypy==1.15.0; extra == \"quality\"",
          "libcst>=1.4.0; extra == \"quality\"",
          "ty; extra == \"quality\"",
          "authlib>=1.3.2; extra == \"all\"",
          "fastapi; extra == \"all\"",
          "httpx; extra == \"all\"",
          "itsdangerous; extra == \"all\"",
          "jedi; extra == \"all\"",
          "Jinja2; extra == \"all\"",
          "pytest>=8.4.2; extra == \"all\"",
          "pytest-cov; extra == \"all\"",
          "pytest-env; extra == \"all\"",
          "pytest-xdist; extra == \"all\"",
          "pytest-vcr; extra == \"all\"",
          "pytest-asyncio; extra == \"all\"",
          "pytest-rerunfailures>=16.2; extra == \"all\"",
          "pytest-mock; extra == \"all\"",
          "urllib3<2.0; extra == \"all\"",
          "soundfile; extra == \"all\"",
          "Pillow; extra == \"all\"",
          "numpy; extra == \"all\"",
          "duckdb; extra == \"all\"",
          "fastapi; extra == \"all\"",
          "ruff>=0.9.0; extra == \"all\"",
          "mypy==1.15.0; extra == \"all\"",
          "libcst>=1.4.0; extra == \"all\"",
          "ty; extra == \"all\"",
          "typing-extensions>=4.8.0; extra == \"all\"",
          "types-PyYAML; extra == \"all\"",
          "types-simplejson; extra == \"all\"",
          "types-toml; extra == \"all\"",
          "types-tqdm; extra == \"all\"",
          "types-urllib3; extra == \"all\"",
          "authlib>=1.3.2; extra == \"dev\"",
          "fastapi; extra == \"dev\"",
          "httpx; extra == \"dev\"",
          "itsdangerous; extra == \"dev\"",
          "jedi; extra == \"dev\"",
          "Jinja2; extra == \"dev\"",
          "pytest>=8.4.2; extra == \"dev\"",
          "pytest-cov; extra == \"dev\"",
          "pytest-env; extra == \"dev\"",
          "pytest-xdist; extra == \"dev\"",
          "pytest-vcr; extra == \"dev\"",
          "pytest-asyncio; extra == \"dev\"",
          "pytest-rerunfailures>=16.2; extra == \"dev\"",
          "pytest-mock; extra == \"dev\"",
          "urllib3<2.0; extra == \"dev\"",
          "soundfile; extra == \"dev\"",
          "Pillow; extra == \"dev\"",
          "numpy; extra == \"dev\"",
          "duckdb; extra == \"dev\"",
          "fastapi; extra == \"dev\"",
          "ruff>=0.9.0; extra == \"dev\"",
          "mypy==1.15.0; extra == \"dev\"",
          "libcst>=1.4.0; extra == \"dev\"",
          "ty; extra == \"dev\"",
          "typing-extensions>=4.8.0; extra == \"dev\"",
          "types-PyYAML; extra == \"dev\"",
          "types-simplejson; extra == \"dev\"",
          "types-toml; extra == \"dev\"",
          "types-tqdm; extra == \"dev\"",
          "types-urllib3; extra == \"dev\""
        ],
        "requires_python": ">=3.10.0",
        "provides_extra": [
          "oauth",
          "torch",
          "fastai",
          "hf-xet",
          "mcp",
          "testing",
          "gradio",
          "typing",
          "quality",
          "all",
          "dev"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/c9/cf/b4ad2cc81b6672ea29ea04e64e350a9f9b493b0908ccd884c67eeff8f7b2/matplotlib-3.11.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl",
        "archive_info": {
          "hash": "sha256=ba8f811b8ddfac493734d6af0b2dff96919d0c28ca0d641858dab4262777c6ea",
          "hashes": {
            "sha256": "ba8f811b8ddfac493734d6af0b2dff96919d0c28ca0d641858dab4262777c6ea"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "matplotlib",
        "version": "3.11.1",
        "summary": "Python plotting package",
        "description": "[![PyPi](https://img.shields.io/pypi/v/matplotlib)](https://pypi.org/project/matplotlib/)\n[![Conda](https://img.shields.io/conda/vn/conda-forge/matplotlib)](https://anaconda.org/conda-forge/matplotlib)\n[![Downloads](https://img.shields.io/pypi/dm/matplotlib)](https://pypi.org/project/matplotlib)\n[![NUMFocus](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](https://numfocus.org)\n[![LFX Health Score](https://insights.linuxfoundation.org/api/badge/health-score?project=matplotlib)](https://insights.linuxfoundation.org/project/matplotlib)\n\n[![Discourse help forum](https://img.shields.io/badge/help_forum-discourse-blue.svg)](https://discourse.matplotlib.org)\n[![Discourse chat](https://img.shields.io/badge/chat-discourse-mediumaquamarine)](https://discourse.matplotlib.org/chat/c/matplotlib/2)\n[![GitHub issues](https://img.shields.io/badge/issue_tracking-github-blue.svg)](https://github.com/matplotlib/matplotlib/issues)\n[![Contributing](https://img.shields.io/badge/PR-Welcome-%23FF8300.svg?)](https://matplotlib.org/stable/devel/index.html)\n\n[![GitHub actions status](https://github.com/matplotlib/matplotlib/workflows/Tests/badge.svg)](https://github.com/matplotlib/matplotlib/actions?query=workflow%3ATests)\n[![Azure pipelines status](https://dev.azure.com/matplotlib/matplotlib/_apis/build/status/matplotlib.matplotlib?branchName=main)](https://dev.azure.com/matplotlib/matplotlib/_build/latest?definitionId=1&branchName=main)\n[![AppVeyor status](https://ci.appveyor.com/api/projects/status/github/matplotlib/matplotlib?branch=main&svg=true)](https://ci.appveyor.com/project/matplotlib/matplotlib)\n[![Codecov status](https://codecov.io/github/matplotlib/matplotlib/badge.svg?branch=main&service=github)](https://app.codecov.io/gh/matplotlib/matplotlib)\n[![EffVer Versioning](https://img.shields.io/badge/version_scheme-EffVer-0097a7)](https://jacobtomlinson.dev/effver)\n\n![Matplotlib logotype](https://matplotlib.org/stable/_static/logo2.svg)\n\nMatplotlib is a comprehensive library for creating static, animated, and\ninteractive visualizations in Python.\n\nCheck out our [home page](https://matplotlib.org/) for more information.\n\n![image](https://matplotlib.org/stable/_static/readme_preview.png)\n\nMatplotlib produces publication-quality figures in a variety of hardcopy\nformats and interactive environments across platforms. Matplotlib can be\nused in Python scripts, Python/IPython shells, web application servers,\nand various graphical user interface toolkits.\n\n## Install\n\nSee the [install\ndocumentation](https://matplotlib.org/stable/users/installing/index.html),\nwhich is generated from `/doc/install/index.rst`\n\n## Contribute\n\nYou've discovered a bug or something else you want to change — excellent!\n\nYou've worked out a way to fix it — even better!\n\nYou want to tell us about it — best of all!\n\nStart at the [contributing\nguide](https://matplotlib.org/devdocs/devel/contribute.html)!\n\n## Contact\n\n[Discourse](https://discourse.matplotlib.org/) is the discussion forum\nfor general questions and discussions and our recommended starting\npoint.\n\nOur active mailing lists (which are mirrored on Discourse) are:\n\n-   [Users](https://mail.python.org/mailman/listinfo/matplotlib-users)\n    mailing list: <matplotlib-users@python.org>\n-   [Announcement](https://mail.python.org/mailman/listinfo/matplotlib-announce)\n    mailing list: <matplotlib-announce@python.org>\n-   [Development](https://mail.python.org/mailman/listinfo/matplotlib-devel)\n    mailing list: <matplotlib-devel@python.org>\n\n[Discourse Chat](https://discourse.matplotlib.org/chat/c/matplotlib/2) is for\ncoordinating development and asking questions directly related to contributing\nto matplotlib.\n\n## Citing Matplotlib\n\nIf Matplotlib contributes to a project that leads to publication, please\nacknowledge this by citing Matplotlib.\n\n[A ready-made citation\nentry](https://matplotlib.org/stable/users/project/citing.html) is\navailable.\n",
        "description_content_type": "text/markdown",
        "author": "John D. Hunter, Michael Droettboom",
        "author_email": "Unknown <matplotlib-users@python.org>",
        "license": "License agreement for matplotlib versions 1.3.0 and later\n =========================================================\n\n 1. This LICENSE AGREEMENT is between the Matplotlib Development Team\n (\"MDT\"), and the Individual or Organization (\"Licensee\") accessing and\n otherwise using matplotlib software in source or binary form and its\n associated documentation.\n\n 2. Subject to the terms and conditions of this License Agreement, MDT\n hereby grants Licensee a nonexclusive, royalty-free, world-wide license\n to reproduce, analyze, test, perform and/or display publicly, prepare\n derivative works, distribute, and otherwise use matplotlib\n alone or in any derivative version, provided, however, that MDT's\n License Agreement and MDT's notice of copyright, i.e., \"Copyright (c)\n 2012- Matplotlib Development Team; All Rights Reserved\" are retained in\n matplotlib  alone or in any derivative version prepared by\n Licensee.\n\n 3. In the event Licensee prepares a derivative work that is based on or\n incorporates matplotlib or any part thereof, and wants to\n make the derivative work available to others as provided herein, then\n Licensee hereby agrees to include in any such work a brief summary of\n the changes made to matplotlib .\n\n 4. MDT is making matplotlib available to Licensee on an \"AS\n IS\" basis.  MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR\n IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND\n DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS\n FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB\n WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.\n\n 5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB\n  FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR\n LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING\n MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF\n THE POSSIBILITY THEREOF.\n\n 6. This License Agreement will automatically terminate upon a material\n breach of its terms and conditions.\n\n 7. Nothing in this License Agreement shall be deemed to create any\n relationship of agency, partnership, or joint venture between MDT and\n Licensee.  This License Agreement does not grant permission to use MDT\n trademarks or trade name in a trademark sense to endorse or promote\n products or services of Licensee, or any third party.\n\n 8. By copying, installing or otherwise using matplotlib ,\n Licensee agrees to be bound by the terms and conditions of this License\n Agreement.\n\n License agreement for matplotlib versions prior to 1.3.0\n ========================================================\n\n 1. This LICENSE AGREEMENT is between John D. Hunter (\"JDH\"), and the\n Individual or Organization (\"Licensee\") accessing and otherwise using\n matplotlib software in source or binary form and its associated\n documentation.\n\n 2. Subject to the terms and conditions of this License Agreement, JDH\n hereby grants Licensee a nonexclusive, royalty-free, world-wide license\n to reproduce, analyze, test, perform and/or display publicly, prepare\n derivative works, distribute, and otherwise use matplotlib\n alone or in any derivative version, provided, however, that JDH's\n License Agreement and JDH's notice of copyright, i.e., \"Copyright (c)\n 2002-2011 John D. Hunter; All Rights Reserved\" are retained in\n matplotlib  alone or in any derivative version prepared by\n Licensee.\n\n 3. In the event Licensee prepares a derivative work that is based on or\n incorporates matplotlib  or any part thereof, and wants to\n make the derivative work available to others as provided herein, then\n Licensee hereby agrees to include in any such work a brief summary of\n the changes made to matplotlib.\n\n 4. JDH is making matplotlib  available to Licensee on an \"AS\n IS\" basis.  JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR\n IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND\n DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS\n FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB\n WILL NOT INFRINGE ANY THIRD PARTY RIGHTS.\n\n 5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB\n  FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR\n LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING\n MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF\n THE POSSIBILITY THEREOF.\n\n 6. This License Agreement will automatically terminate upon a material\n breach of its terms and conditions.\n\n 7. Nothing in this License Agreement shall be deemed to create any\n relationship of agency, partnership, or joint venture between JDH and\n Licensee.  This License Agreement does not grant permission to use JDH\n trademarks or trade name in a trademark sense to endorse or promote\n products or services of Licensee, or any third party.\n\n 8. By copying, installing or otherwise using matplotlib,\n Licensee agrees to be bound by the terms and conditions of this License\n Agreement.\n ----\n\n This binary distrubution of Matplotlib can also bundle the following software\n (depending on the build):\n\n Name: AMS Fonts\n Files: matplotlib/tests/cmr10.pfb\n Description: Type-1 version of one of Knuth's Computer Modern fonts\n License: OFL-1.1\n   The cmr10.pfb file is a Type-1 version of one of Knuth's Computer Modern fonts.\n   It is included here as test data only, but the following license applies.\n\n   Copyright (c) 1997, 2009, American Mathematical Society (http://www.ams.org).\n   All Rights Reserved.\n\n   \"cmb10\" is a Reserved Font Name for this Font Software.\n   \"cmbsy10\" is a Reserved Font Name for this Font Software.\n   \"cmbsy5\" is a Reserved Font Name for this Font Software.\n   \"cmbsy6\" is a Reserved Font Name for this Font Software.\n   \"cmbsy7\" is a Reserved Font Name for this Font Software.\n   \"cmbsy8\" is a Reserved Font Name for this Font Software.\n   \"cmbsy9\" is a Reserved Font Name for this Font Software.\n   \"cmbx10\" is a Reserved Font Name for this Font Software.\n   \"cmbx12\" is a Reserved Font Name for this Font Software.\n   \"cmbx5\" is a Reserved Font Name for this Font Software.\n   \"cmbx6\" is a Reserved Font Name for this Font Software.\n   \"cmbx7\" is a Reserved Font Name for this Font Software.\n   \"cmbx8\" is a Reserved Font Name for this Font Software.\n   \"cmbx9\" is a Reserved Font Name for this Font Software.\n   \"cmbxsl10\" is a Reserved Font Name for this Font Software.\n   \"cmbxti10\" is a Reserved Font Name for this Font Software.\n   \"cmcsc10\" is a Reserved Font Name for this Font Software.\n   \"cmcsc8\" is a Reserved Font Name for this Font Software.\n   \"cmcsc9\" is a Reserved Font Name for this Font Software.\n   \"cmdunh10\" is a Reserved Font Name for this Font Software.\n   \"cmex10\" is a Reserved Font Name for this Font Software.\n   \"cmex7\" is a Reserved Font Name for this Font Software.\n   \"cmex8\" is a Reserved Font Name for this Font Software.\n   \"cmex9\" is a Reserved Font Name for this Font Software.\n   \"cmff10\" is a Reserved Font Name for this Font Software.\n   \"cmfi10\" is a Reserved Font Name for this Font Software.\n   \"cmfib8\" is a Reserved Font Name for this Font Software.\n   \"cminch\" is a Reserved Font Name for this Font Software.\n   \"cmitt10\" is a Reserved Font Name for this Font Software.\n   \"cmmi10\" is a Reserved Font Name for this Font Software.\n   \"cmmi12\" is a Reserved Font Name for this Font Software.\n   \"cmmi5\" is a Reserved Font Name for this Font Software.\n   \"cmmi6\" is a Reserved Font Name for this Font Software.\n   \"cmmi7\" is a Reserved Font Name for this Font Software.\n   \"cmmi8\" is a Reserved Font Name for this Font Software.\n   \"cmmi9\" is a Reserved Font Name for this Font Software.\n   \"cmmib10\" is a Reserved Font Name for this Font Software.\n   \"cmmib5\" is a Reserved Font Name for this Font Software.\n   \"cmmib6\" is a Reserved Font Name for this Font Software.\n   \"cmmib7\" is a Reserved Font Name for this Font Software.\n   \"cmmib8\" is a Reserved Font Name for this Font Software.\n   \"cmmib9\" is a Reserved Font Name for this Font Software.\n   \"cmr10\" is a Reserved Font Name for this Font Software.\n   \"cmr12\" is a Reserved Font Name for this Font Software.\n   \"cmr17\" is a Reserved Font Name for this Font Software.\n   \"cmr5\" is a Reserved Font Name for this Font Software.\n   \"cmr6\" is a Reserved Font Name for this Font Software.\n   \"cmr7\" is a Reserved Font Name for this Font Software.\n   \"cmr8\" is a Reserved Font Name for this Font Software.\n   \"cmr9\" is a Reserved Font Name for this Font Software.\n   \"cmsl10\" is a Reserved Font Name for this Font Software.\n   \"cmsl12\" is a Reserved Font Name for this Font Software.\n   \"cmsl8\" is a Reserved Font Name for this Font Software.\n   \"cmsl9\" is a Reserved Font Name for this Font Software.\n   \"cmsltt10\" is a Reserved Font Name for this Font Software.\n   \"cmss10\" is a Reserved Font Name for this Font Software.\n   \"cmss12\" is a Reserved Font Name for this Font Software.\n   \"cmss17\" is a Reserved Font Name for this Font Software.\n   \"cmss8\" is a Reserved Font Name for this Font Software.\n   \"cmss9\" is a Reserved Font Name for this Font Software.\n   \"cmssbx10\" is a Reserved Font Name for this Font Software.\n   \"cmssdc10\" is a Reserved Font Name for this Font Software.\n   \"cmssi10\" is a Reserved Font Name for this Font Software.\n   \"cmssi12\" is a Reserved Font Name for this Font Software.\n   \"cmssi17\" is a Reserved Font Name for this Font Software.\n   \"cmssi8\" is a Reserved Font Name for this Font Software.\n   \"cmssi9\" is a Reserved Font Name for this Font Software.\n   \"cmssq8\" is a Reserved Font Name for this Font Software.\n   \"cmssqi8\" is a Reserved Font Name for this Font Software.\n   \"cmsy10\" is a Reserved Font Name for this Font Software.\n   \"cmsy5\" is a Reserved Font Name for this Font Software.\n   \"cmsy6\" is a Reserved Font Name for this Font Software.\n   \"cmsy7\" is a Reserved Font Name for this Font Software.\n   \"cmsy8\" is a Reserved Font Name for this Font Software.\n   \"cmsy9\" is a Reserved Font Name for this Font Software.\n   \"cmtcsc10\" is a Reserved Font Name for this Font Software.\n   \"cmtex10\" is a Reserved Font Name for this Font Software.\n   \"cmtex8\" is a Reserved Font Name for this Font Software.\n   \"cmtex9\" is a Reserved Font Name for this Font Software.\n   \"cmti10\" is a Reserved Font Name for this Font Software.\n   \"cmti12\" is a Reserved Font Name for this Font Software.\n   \"cmti7\" is a Reserved Font Name for this Font Software.\n   \"cmti8\" is a Reserved Font Name for this Font Software.\n   \"cmti9\" is a Reserved Font Name for this Font Software.\n   \"cmtt10\" is a Reserved Font Name for this Font Software.\n   \"cmtt12\" is a Reserved Font Name for this Font Software.\n   \"cmtt8\" is a Reserved Font Name for this Font Software.\n   \"cmtt9\" is a Reserved Font Name for this Font Software.\n   \"cmu10\" is a Reserved Font Name for this Font Software.\n   \"cmvtt10\" is a Reserved Font Name for this Font Software.\n   \"euex10\" is a Reserved Font Name for this Font Software.\n   \"euex7\" is a Reserved Font Name for this Font Software.\n   \"euex8\" is a Reserved Font Name for this Font Software.\n   \"euex9\" is a Reserved Font Name for this Font Software.\n   \"eufb10\" is a Reserved Font Name for this Font Software.\n   \"eufb5\" is a Reserved Font Name for this Font Software.\n   \"eufb7\" is a Reserved Font Name for this Font Software.\n   \"eufm10\" is a Reserved Font Name for this Font Software.\n   \"eufm5\" is a Reserved Font Name for this Font Software.\n   \"eufm7\" is a Reserved Font Name for this Font Software.\n   \"eurb10\" is a Reserved Font Name for this Font Software.\n   \"eurb5\" is a Reserved Font Name for this Font Software.\n   \"eurb7\" is a Reserved Font Name for this Font Software.\n   \"eurm10\" is a Reserved Font Name for this Font Software.\n   \"eurm5\" is a Reserved Font Name for this Font Software.\n   \"eurm7\" is a Reserved Font Name for this Font Software.\n   \"eusb10\" is a Reserved Font Name for this Font Software.\n   \"eusb5\" is a Reserved Font Name for this Font Software.\n   \"eusb7\" is a Reserved Font Name for this Font Software.\n   \"eusm10\" is a Reserved Font Name for this Font Software.\n   \"eusm5\" is a Reserved Font Name for this Font Software.\n   \"eusm7\" is a Reserved Font Name for this Font Software.\n   \"lasy10\" is a Reserved Font Name for this Font Software.\n   \"lasy5\" is a Reserved Font Name for this Font Software.\n   \"lasy6\" is a Reserved Font Name for this Font Software.\n   \"lasy7\" is a Reserved Font Name for this Font Software.\n   \"lasy8\" is a Reserved Font Name for this Font Software.\n   \"lasy9\" is a Reserved Font Name for this Font Software.\n   \"lasyb10\" is a Reserved Font Name for this Font Software.\n   \"lcircle1\" is a Reserved Font Name for this Font Software.\n   \"lcirclew\" is a Reserved Font Name for this Font Software.\n   \"lcmss8\" is a Reserved Font Name for this Font Software.\n   \"lcmssb8\" is a Reserved Font Name for this Font Software.\n   \"lcmssi8\" is a Reserved Font Name for this Font Software.\n   \"line10\" is a Reserved Font Name for this Font Software.\n   \"linew10\" is a Reserved Font Name for this Font Software.\n   \"msam10\" is a Reserved Font Name for this Font Software.\n   \"msam5\" is a Reserved Font Name for this Font Software.\n   \"msam6\" is a Reserved Font Name for this Font Software.\n   \"msam7\" is a Reserved Font Name for this Font Software.\n   \"msam8\" is a Reserved Font Name for this Font Software.\n   \"msam9\" is a Reserved Font Name for this Font Software.\n   \"msbm10\" is a Reserved Font Name for this Font Software.\n   \"msbm5\" is a Reserved Font Name for this Font Software.\n   \"msbm6\" is a Reserved Font Name for this Font Software.\n   \"msbm7\" is a Reserved Font Name for this Font Software.\n   \"msbm8\" is a Reserved Font Name for this Font Software.\n   \"msbm9\" is a Reserved Font Name for this Font Software.\n   \"wncyb10\" is a Reserved Font Name for this Font Software.\n   \"wncyi10\" is a Reserved Font Name for this Font Software.\n   \"wncyr10\" is a Reserved Font Name for this Font Software.\n   \"wncysc10\" is a Reserved Font Name for this Font Software.\n   \"wncyss10\" is a Reserved Font Name for this Font Software.\n\n   This Font Software is licensed under the SIL Open Font License, Version 1.1.\n   This license is copied below, and is also available with a FAQ at:\n   http://scripts.sil.org/OFL\n\n   -----------------------------------------------------------\n   SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n   -----------------------------------------------------------\n\n   PREAMBLE\n   The goals of the Open Font License (OFL) are to stimulate worldwide\n   development of collaborative font projects, to support the font creation\n   efforts of academic and linguistic communities, and to provide a free and\n   open framework in which fonts may be shared and improved in partnership\n   with others.\n\n   The OFL allows the licensed fonts to be used, studied, modified and\n   redistributed freely as long as they are not sold by themselves. The\n   fonts, including any derivative works, can be bundled, embedded,\n   redistributed and/or sold with any software provided that any reserved\n   names are not used by derivative works. The fonts and derivatives,\n   however, cannot be released under any other type of license. The\n   requirement for fonts to remain under this license does not apply\n   to any document created using the fonts or their derivatives.\n\n   DEFINITIONS\n   \"Font Software\" refers to the set of files released by the Copyright\n   Holder(s) under this license and clearly marked as such. This may\n   include source files, build scripts and documentation.\n\n   \"Reserved Font Name\" refers to any names specified as such after the\n   copyright statement(s).\n\n   \"Original Version\" refers to the collection of Font Software components as\n   distributed by the Copyright Holder(s).\n\n   \"Modified Version\" refers to any derivative made by adding to, deleting,\n   or substituting -- in part or in whole -- any of the components of the\n   Original Version, by changing formats or by porting the Font Software to a\n   new environment.\n\n   \"Author\" refers to any designer, engineer, programmer, technical\n   writer or other person who contributed to the Font Software.\n\n   PERMISSION & CONDITIONS\n   Permission is hereby granted, free of charge, to any person obtaining\n   a copy of the Font Software, to use, study, copy, merge, embed, modify,\n   redistribute, and sell modified and unmodified copies of the Font\n   Software, subject to the following conditions:\n\n   1) Neither the Font Software nor any of its individual components,\n   in Original or Modified Versions, may be sold by itself.\n\n   2) Original or Modified Versions of the Font Software may be bundled,\n   redistributed and/or sold with any software, provided that each copy\n   contains the above copyright notice and this license. These can be\n   included either as stand-alone text files, human-readable headers or\n   in the appropriate machine-readable metadata fields within text or\n   binary files as long as those fields can be easily viewed by the user.\n\n   3) No Modified Version of the Font Software may use the Reserved Font\n   Name(s) unless explicit written permission is granted by the corresponding\n   Copyright Holder. This restriction only applies to the primary font name as\n   presented to the users.\n\n   4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\n   Software shall not be used to promote, endorse or advertise any\n   Modified Version, except to acknowledge the contribution(s) of the\n   Copyright Holder(s) and the Author(s) or with their explicit written\n   permission.\n\n   5) The Font Software, modified or unmodified, in part or in whole,\n   must be distributed entirely under this license, and must not be\n   distributed under any other license. The requirement for fonts to\n   remain under this license does not apply to any document created\n   using the Font Software.\n\n   TERMINATION\n   This license becomes null and void if any of the above conditions are\n   not met.\n\n   DISCLAIMER\n   THE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\n   OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\n   COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\n   DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n   FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\n   OTHER DEALINGS IN THE FONT SOFTWARE.\n\n\n\n Name: BaKoMa Fonts\n Files: matplotlib/mpl-data/fonts/ttf/cm*.ttf matplotlib/mpl-data/fonts/afm/cm*.afm\n Description: Computer Modern Fonts in PostScript Type 1 and TrueType font formats.\n License: BaKoMa Fonts Licence\n         BaKoMa Fonts Licence\n         --------------------\n\n     This licence covers two font packs (known as BaKoMa Fonts Collection,\n     which is available at `CTAN:fonts/cm/ps-type1/bakoma/'):\n\n       1) BaKoMa-CM (1.1/12-Nov-94)\n          Computer Modern Fonts in PostScript Type 1 and TrueType font formats.\n\n       2) BaKoMa-AMS (1.2/19-Jan-95)\n          AMS TeX fonts in PostScript Type 1 and TrueType font formats.\n\n     Copyright (C) 1994, 1995, Basil K. Malyshev. All Rights Reserved.\n\n     Permission to copy and distribute these fonts for any purpose is\n     hereby granted without fee, provided that the above copyright notice,\n     author statement and this permission notice appear in all copies of\n     these fonts and related documentation.\n\n     Permission to modify and distribute modified fonts for any purpose is\n     hereby granted without fee, provided that the copyright notice,\n     author statement, this permission notice and location of original\n     fonts (http://www.ctan.org/tex-archive/fonts/cm/ps-type1/bakoma)\n     appear in all copies of modified fonts and related documentation.\n\n     Permission to use these fonts (embedding into PostScript, PDF, SVG\n     and printing by using any software) is hereby granted without fee.\n     It is not required to provide any notices about using these fonts.\n\n    Basil K. Malyshev\n    INSTITUTE FOR HIGH ENERGY PHYSICS\n    IHEP, OMVT\n    Moscow Region\n    142281 PROTVINO\n    RUSSIA\n\n    E-Mail:\tbakoma@mail.ru\n         or\tmalyshev@mail.ihep.ru\n\n\n\n\n Name: ColorBrewer Color Schemes\n Files: lib/matplotlib/_cm.py\n Description: Color schemes from ColorBrewer\n License: Apache-2.0\n   Apache-Style Software License for ColorBrewer software and ColorBrewer Color Schemes\n\n   Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n   http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software distributed\n   under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n   CONDITIONS OF ANY KIND, either express or implied. See the License for the\n   specific language governing permissions and limitations under the License.\n\n\n Name: Courier 10\n Files: matplotlib/tests/Courier10PitchBT-Bold.pfb\n Description: Courier 10 font, used in tests.\n License: Bitstream-Charter\n   The Courier10PitchBT-Bold.pfb file is a Type-1 version of\n   Courier 10 Pitch BT Bold by Bitstream, obtained from\n   <https://ctan.org/tex-archive/fonts/courierten>. It is included\n   here as test data only, but the following license applies.\n\n\n   (c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA.\n\n   You are hereby granted permission under all Bitstream propriety rights\n   to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream\n   Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts\n   for any purpose and without restriction; provided, that this notice is\n   left intact on all copies of such fonts and that Bitstream's trademark\n   is acknowledged as shown below on all unmodified copies of the 4 Charter\n   Type 1 fonts.\n\n   BITSTREAM CHARTER is a registered trademark of Bitstream Inc.\n\n\n Name: FreeType\n Files: matplotlib/ft2font.*.so\n Description: Font rendering library\n License: FTL OR GPL-2.0-or-later\n   The FreeType  2 font  engine is  copyrighted work  and cannot  be used\n   legally without  a software  license.  In order  to make  this project\n   usable to  a vast majority of  developers, we distribute it  under two\n   mutually exclusive open-source licenses.\n\n   This means that *you* must choose  *one* of the two licenses described\n   below, then obey all its terms and conditions when using FreeType 2 in\n   any of your projects or products.\n\n     - The FreeType License,  found in the file  `docs/FTL.TXT`, which is\n       similar to the  original BSD license *with*  an advertising clause\n       that forces  you to explicitly  cite the FreeType project  in your\n       product's  documentation.  All  details are  in the  license file.\n       This license is suited to products which don't use the GNU General\n       Public License.\n\n       Note that  this license  is compatible to  the GNU  General Public\n       License version 3, but not version 2.\n\n     - The   GNU   General   Public   License   version   2,   found   in\n       `docs/GPLv2.TXT`  (any  later  version  can  be  used  also),  for\n       programs  which  already  use  the  GPL.  Note  that  the  FTL  is\n       incompatible with GPLv2 due to its advertisement clause.\n\n   The contributed  BDF and PCF  drivers come  with a license  similar to\n   that  of the  X Window  System.   It is  compatible to  the above  two\n   licenses (see files `src/bdf/README`  and `src/pcf/README`).  The same\n   holds   for   the   source    code   files   `src/base/fthash.c`   and\n   `include/freetype/internal/fthash.h`; they were part of the BDF driver\n   in earlier FreeType versions.\n\n   The gzip  module uses the  zlib license (see  `src/gzip/zlib.h`) which\n   too is compatible to the above two licenses.\n\n   The files `src/autofit/ft-hb.c` and `src/autofit/ft-hb.h` contain code\n   taken almost  verbatim from the  HarfBuzz file `hb-ft.cc`,  which uses\n   the 'Old MIT' license, compatible to the above two licenses.\n\n   The  MD5 checksum  support  (only used  for  debugging in  development\n   builds) is in the public domain.\n\n\n Name: HarfBuzz\n Files: matplotlib/ft2font.*.so\n Description: Text shaping library\n License: MIT-Modern-Variant\n   HarfBuzz is licensed under the so-called \"Old MIT\" license.  Details follow.\n   For parts of HarfBuzz that are licensed under different licenses see individual\n   files names COPYING in subdirectories where applicable.\n\n   Copyright © 2010-2022  Google, Inc.\n   Copyright © 2015-2020  Ebrahim Byagowi\n   Copyright © 2019,2020  Facebook, Inc.\n   Copyright © 2012,2015  Mozilla Foundation\n   Copyright © 2011  Codethink Limited\n   Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)\n   Copyright © 2009  Keith Stribley\n   Copyright © 2011  Martin Hosken and SIL International\n   Copyright © 2007  Chris Wilson\n   Copyright © 2005,2006,2020,2021,2022,2023  Behdad Esfahbod\n   Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023  Red Hat, Inc.\n   Copyright © 1998-2005  David Turner and Werner Lemberg\n   Copyright © 2016  Igalia S.L.\n   Copyright © 2022  Matthias Clasen\n   Copyright © 2018,2021  Khaled Hosny\n   Copyright © 2018,2019,2020  Adobe, Inc\n   Copyright © 2013-2015  Alexei Podtelezhnikov\n\n   For full copyright notices consult the individual files in the package.\n\n\n   Permission is hereby granted, without written agreement and without\n   license or royalty fees, to use, copy, modify, and distribute this\n   software and its documentation for any purpose, provided that the\n   above copyright notice and the following two paragraphs appear in\n   all copies of this software.\n\n   IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR\n   DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\n   ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN\n   IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH\n   DAMAGE.\n\n   THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,\n   BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\n   FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\n   ON AN \"AS IS\" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO\n   PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\n\n\n Name: JSXTools resize observer\n Files: lib/matplotlib/backends/web_backend/js/mpl.js\n Description: Minimal polyfill for the ResizeObserver API\n License: CC0-1.0\n   # CC0 1.0 Universal\n\n   ## Statement of Purpose\n\n   The laws of most jurisdictions throughout the world automatically confer\n   exclusive Copyright and Related Rights (defined below) upon the creator and\n   subsequent owner(s) (each and all, an “owner”) of an original work of\n   authorship and/or a database (each, a “Work”).\n\n   Certain owners wish to permanently relinquish those rights to a Work for the\n   purpose of contributing to a commons of creative, cultural and scientific works\n   (“Commons”) that the public can reliably and without fear of later claims of\n   infringement build upon, modify, incorporate in other works, reuse and\n   redistribute as freely as possible in any form whatsoever and for any purposes,\n   including without limitation commercial purposes. These owners may contribute\n   to the Commons to promote the ideal of a free culture and the further\n   production of creative, cultural and scientific works, or to gain reputation or\n   greater distribution for their Work in part through the use and efforts of\n   others.\n\n   For these and/or other purposes and motivations, and without any expectation of\n   additional consideration or compensation, the person associating CC0 with a\n   Work (the “Affirmer”), to the extent that he or she is an owner of Copyright\n   and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and\n   publicly distribute the Work under its terms, with knowledge of his or her\n   Copyright and Related Rights in the Work and the meaning and intended legal\n   effect of CC0 on those rights.\n\n   1. Copyright and Related Rights. A Work made available under CC0 may be\n      protected by copyright and related or neighboring rights (“Copyright and\n      Related Rights”). Copyright and Related Rights include, but are not limited\n      to, the following:\n      1. the right to reproduce, adapt, distribute, perform, display, communicate,\n         and translate a Work;\n      2. moral rights retained by the original author(s) and/or performer(s);\n      3. publicity and privacy rights pertaining to a person’s image or likeness\n         depicted in a Work;\n      4. rights protecting against unfair competition in regards to a Work,\n         subject to the limitations in paragraph 4(i), below;\n      5. rights protecting the extraction, dissemination, use and reuse of data in\n         a Work;\n      6. database rights (such as those arising under Directive 96/9/EC of the\n         European Parliament and of the Council of 11 March 1996 on the legal\n         protection of databases, and under any national implementation thereof,\n         including any amended or successor version of such directive); and\n      7. other similar, equivalent or corresponding rights throughout the world\n         based on applicable law or treaty, and any national implementations\n         thereof.\n\n   2. Waiver. To the greatest extent permitted by, but not in contravention of,\n      applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and\n      unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright\n      and Related Rights and associated claims and causes of action, whether now\n      known or unknown (including existing as well as future claims and causes of\n      action), in the Work (i) in all territories worldwide, (ii) for the maximum\n      duration provided by applicable law or treaty (including future time\n      extensions), (iii) in any current or future medium and for any number of\n      copies, and (iv) for any purpose whatsoever, including without limitation\n      commercial, advertising or promotional purposes (the “Waiver”). Affirmer\n      makes the Waiver for the benefit of each member of the public at large and\n      to the detriment of Affirmer’s heirs and successors, fully intending that\n      such Waiver shall not be subject to revocation, rescission, cancellation,\n      termination, or any other legal or equitable action to disrupt the quiet\n      enjoyment of the Work by the public as contemplated by Affirmer’s express\n      Statement of Purpose.\n\n   3. Public License Fallback. Should any part of the Waiver for any reason be\n      judged legally invalid or ineffective under applicable law, then the Waiver\n      shall be preserved to the maximum extent permitted taking into account\n      Affirmer’s express Statement of Purpose. In addition, to the extent the\n      Waiver is so judged Affirmer hereby grants to each affected person a\n      royalty-free, non transferable, non sublicensable, non exclusive,\n      irrevocable and unconditional license to exercise Affirmer’s Copyright and\n      Related Rights in the Work (i) in all territories worldwide, (ii) for the\n      maximum duration provided by applicable law or treaty (including future time\n      extensions), (iii) in any current or future medium and for any number of\n      copies, and (iv) for any purpose whatsoever, including without limitation\n      commercial, advertising or promotional purposes (the “License”). The License\n      shall be deemed effective as of the date CC0 was applied by Affirmer to the\n      Work. Should any part of the License for any reason be judged legally\n      invalid or ineffective under applicable law, such partial invalidity or\n      ineffectiveness shall not invalidate the remainder of the License, and in\n      such case Affirmer hereby affirms that he or she will not (i) exercise any\n      of his or her remaining Copyright and Related Rights in the Work or (ii)\n      assert any associated claims and causes of action with respect to the Work,\n      in either case contrary to Affirmer’s express Statement of Purpose.\n\n   4. Limitations and Disclaimers.\n      1. No trademark or patent rights held by Affirmer are waived, abandoned,\n         surrendered, licensed or otherwise affected by this document.\n      2. Affirmer offers the Work as-is and makes no representations or warranties\n         of any kind concerning the Work, express, implied, statutory or\n         otherwise, including without limitation warranties of title,\n         merchantability, fitness for a particular purpose, non infringement, or\n         the absence of latent or other defects, accuracy, or the present or\n         absence of errors, whether or not discoverable, all to the greatest\n         extent permissible under applicable law.\n      3. Affirmer disclaims responsibility for clearing rights of other persons\n         that may apply to the Work or any use thereof, including without\n         limitation any person’s Copyright and Related Rights in the Work.\n         Further, Affirmer disclaims responsibility for obtaining any necessary\n         consents, permissions or other rights required for any use of the Work.\n      4. Affirmer understands and acknowledges that Creative Commons is not a\n         party to this document and has no duty or obligation with respect to this\n         CC0 or use of the Work.\n\n   For more information, please see\n   http://creativecommons.org/publicdomain/zero/1.0/.\n\n\n Name: Last Resort fonts\n Files: matplotlib/mpl-data/fonts/ttf/LastResortHE-Regular.ttf\n Description: Last Resort High-Efficiency Font\n License: OFL-1.1\n   This Font Software is licensed under the SIL Open Font License,\n   Version 1.1.\n\n   This license is copied below, and is also available with a FAQ at:\n   http://scripts.sil.org/OFL\n\n   -----------------------------------------------------------\n   SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n   -----------------------------------------------------------\n\n   PREAMBLE\n   The goals of the Open Font License (OFL) are to stimulate worldwide\n   development of collaborative font projects, to support the font\n   creation efforts of academic and linguistic communities, and to\n   provide a free and open framework in which fonts may be shared and\n   improved in partnership with others.\n\n   The OFL allows the licensed fonts to be used, studied, modified and\n   redistributed freely as long as they are not sold by themselves. The\n   fonts, including any derivative works, can be bundled, embedded,\n   redistributed and/or sold with any software provided that any reserved\n   names are not used by derivative works. The fonts and derivatives,\n   however, cannot be released under any other type of license. The\n   requirement for fonts to remain under this license does not apply to\n   any document created using the fonts or their derivatives.\n\n   DEFINITIONS\n   \"Font Software\" refers to the set of files released by the Copyright\n   Holder(s) under this license and clearly marked as such. This may\n   include source files, build scripts and documentation.\n\n   \"Reserved Font Name\" refers to any names specified as such after the\n   copyright statement(s).\n\n   \"Original Version\" refers to the collection of Font Software\n   components as distributed by the Copyright Holder(s).\n\n   \"Modified Version\" refers to any derivative made by adding to,\n   deleting, or substituting -- in part or in whole -- any of the\n   components of the Original Version, by changing formats or by porting\n   the Font Software to a new environment.\n\n   \"Author\" refers to any designer, engineer, programmer, technical\n   writer or other person who contributed to the Font Software.\n\n   PERMISSION & CONDITIONS\n   Permission is hereby granted, free of charge, to any person obtaining\n   a copy of the Font Software, to use, study, copy, merge, embed,\n   modify, redistribute, and sell modified and unmodified copies of the\n   Font Software, subject to the following conditions:\n\n   1) Neither the Font Software nor any of its individual components, in\n   Original or Modified Versions, may be sold by itself.\n\n   2) Original or Modified Versions of the Font Software may be bundled,\n   redistributed and/or sold with any software, provided that each copy\n   contains the above copyright notice and this license. These can be\n   included either as stand-alone text files, human-readable headers or\n   in the appropriate machine-readable metadata fields within text or\n   binary files as long as those fields can be easily viewed by the user.\n\n   3) No Modified Version of the Font Software may use the Reserved Font\n   Name(s) unless explicit written permission is granted by the\n   corresponding Copyright Holder. This restriction only applies to the\n   primary font name as presented to the users.\n\n   4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\n   Software shall not be used to promote, endorse or advertise any\n   Modified Version, except to acknowledge the contribution(s) of the\n   Copyright Holder(s) and the Author(s) or with their explicit written\n   permission.\n\n   5) The Font Software, modified or unmodified, in part or in whole,\n   must be distributed entirely under this license, and must not be\n   distributed under any other license. The requirement for fonts to\n   remain under this license does not apply to any document created using\n   the Font Software.\n\n   TERMINATION\n   This license becomes null and void if any of the above conditions are\n   not met.\n\n   DISCLAIMER\n   THE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\n   OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\n   COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\n   DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n   FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\n   OTHER DEALINGS IN THE FONT SOFTWARE.\n\n   SPDX-License-Identifier: OFL-1.1\n\n\n Name: libraqm\n Files: matplotlib/ft2font.*.so\n Description: Complex text layout library\n License: MIT\n   The MIT License (MIT)\n\n   Copyright © 2015 Information Technology Authority (ITA) <foss@ita.gov.om>\n   Copyright © 2016-2023 Khaled Hosny <khaled@aliftype.com>\n\n   Permission is hereby granted, free of charge, to any person obtaining a copy\n   of this software and associated documentation files (the \"Software\"), to deal\n   in the Software without restriction, including without limitation the rights\n   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n   copies of the Software, and to permit persons to whom the Software is\n   furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in all\n   copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n   SOFTWARE.\n\n\n Name: QHull\n Files: matplotlib/_qhull.*.so\n Description: Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection\n License: Qhull\n                       Qhull, Copyright (c) 1993-2020\n\n                               C.B. Barber\n                              Arlington, MA\n\n                                  and\n\n          The National Science and Technology Research Center for\n           Computation and Visualization of Geometric Structures\n                           (The Geometry Center)\n                          University of Minnesota\n\n                          email: qhull@qhull.org\n\n   This software includes Qhull from C.B. Barber and The Geometry Center.\n   Files derived from Qhull 1.0 are copyrighted by the Geometry Center.  The\n   remaining files are copyrighted by C.B. Barber.  Qhull is free software\n   and may be obtained via http from www.qhull.org.  It may be freely copied,\n   modified, and redistributed under the following conditions:\n\n   1. All copyright notices must remain intact in all files.\n\n   2. A copy of this text file must be distributed along with any copies\n      of Qhull that you redistribute; this includes copies that you have\n      modified, or copies of programs or other software products that\n      include Qhull.\n\n   3. If you modify Qhull, you must include a notice giving the\n      name of the person performing the modification, the date of\n      modification, and the reason for such modification.\n\n   4. When distributing modified versions of Qhull, or other software\n      products that include Qhull, you must provide notice that the original\n      source code may be obtained as noted above.\n\n   5. There is no warranty or other guarantee of fitness for Qhull, it is\n      provided solely \"as is\".  Bug reports or fixes may be sent to\n      qhull_bug@qhull.org; the authors may or may not act on them as\n      they desire.\n\n\n Name: Qt4 Editor\n Files: matplotlib/backends/qt_editor\n Description: Module creating PyQt4 form dialogs/layouts to edit various type of parameters\n License: MIT\n   Module creating PyQt4 form dialogs/layouts to edit various type of parameters\n\n\n   formlayout License Agreement (MIT License)\n   ------------------------------------------\n\n   Copyright (c) 2009 Pierre Raybaut\n\n   Permission is hereby granted, free of charge, to any person\n   obtaining a copy of this software and associated documentation\n   files (the \"Software\"), to deal in the Software without\n   restriction, including without limitation the rights to use,\n   copy, modify, merge, publish, distribute, sublicense, and/or sell\n   copies of the Software, and to permit persons to whom the\n   Software is furnished to do so, subject to the following\n   conditions:\n\n   The above copyright notice and this permission notice shall be\n   included in all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\n   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\n   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\n   OTHER DEALINGS IN THE SOFTWARE.\n\n\n Name: SheenBidi\n Files: matplotlib/ft2font.*.so\n Description: Unicode Bidirectional Algorithm implementation\n License: Apache-2.0\n                                    Apache License\n                              Version 2.0, January 2004\n                           http://www.apache.org/licenses/\n\n      TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n      1. Definitions.\n\n         \"License\" shall mean the terms and conditions for use, reproduction,\n         and distribution as defined by Sections 1 through 9 of this document.\n\n         \"Licensor\" shall mean the copyright owner or entity authorized by\n         the copyright owner that is granting the License.\n\n         \"Legal Entity\" shall mean the union of the acting entity and all\n         other entities that control, are controlled by, or are under common\n         control with that entity. For the purposes of this definition,\n         \"control\" means (i) the power, direct or indirect, to cause the\n         direction or management of such entity, whether by contract or\n         otherwise, or (ii) ownership of fifty percent (50%) or more of the\n         outstanding shares, or (iii) beneficial ownership of such entity.\n\n         \"You\" (or \"Your\") shall mean an individual or Legal Entity\n         exercising permissions granted by this License.\n\n         \"Source\" form shall mean the preferred form for making modifications,\n         including but not limited to software source code, documentation\n         source, and configuration files.\n\n         \"Object\" form shall mean any form resulting from mechanical\n         transformation or translation of a Source form, including but\n         not limited to compiled object code, generated documentation,\n         and conversions to other media types.\n\n         \"Work\" shall mean the work of authorship, whether in Source or\n         Object form, made available under the License, as indicated by a\n         copyright notice that is included in or attached to the work\n         (an example is provided in the Appendix below).\n\n         \"Derivative Works\" shall mean any work, whether in Source or Object\n         form, that is based on (or derived from) the Work and for which the\n         editorial revisions, annotations, elaborations, or other modifications\n         represent, as a whole, an original work of authorship. For the purposes\n         of this License, Derivative Works shall not include works that remain\n         separable from, or merely link (or bind by name) to the interfaces of,\n         the Work and Derivative Works thereof.\n\n         \"Contribution\" shall mean any work of authorship, including\n         the original version of the Work and any modifications or additions\n         to that Work or Derivative Works thereof, that is intentionally\n         submitted to Licensor for inclusion in the Work by the copyright owner\n         or by an individual or Legal Entity authorized to submit on behalf of\n         the copyright owner. For the purposes of this definition, \"submitted\"\n         means any form of electronic, verbal, or written communication sent\n         to the Licensor or its representatives, including but not limited to\n         communication on electronic mailing lists, source code control systems,\n         and issue tracking systems that are managed by, or on behalf of, the\n         Licensor for the purpose of discussing and improving the Work, but\n         excluding communication that is conspicuously marked or otherwise\n         designated in writing by the copyright owner as \"Not a Contribution.\"\n\n         \"Contributor\" shall mean Licensor and any individual or Legal Entity\n         on behalf of whom a Contribution has been received by Licensor and\n         subsequently incorporated within the Work.\n\n      2. Grant of Copyright License. Subject to the terms and conditions of\n         this License, each Contributor hereby grants to You a perpetual,\n         worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n         copyright license to reproduce, prepare Derivative Works of,\n         publicly display, publicly perform, sublicense, and distribute the\n         Work and such Derivative Works in Source or Object form.\n\n      3. Grant of Patent License. Subject to the terms and conditions of\n         this License, each Contributor hereby grants to You a perpetual,\n         worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n         (except as stated in this section) patent license to make, have made,\n         use, offer to sell, sell, import, and otherwise transfer the Work,\n         where such license applies only to those patent claims licensable\n         by such Contributor that are necessarily infringed by their\n         Contribution(s) alone or by combination of their Contribution(s)\n         with the Work to which such Contribution(s) was submitted. If You\n         institute patent litigation against any entity (including a\n         cross-claim or counterclaim in a lawsuit) alleging that the Work\n         or a Contribution incorporated within the Work constitutes direct\n         or contributory patent infringement, then any patent licenses\n         granted to You under this License for that Work shall terminate\n         as of the date such litigation is filed.\n\n      4. Redistribution. You may reproduce and distribute copies of the\n         Work or Derivative Works thereof in any medium, with or without\n         modifications, and in Source or Object form, provided that You\n         meet the following conditions:\n\n         (a) You must give any other recipients of the Work or\n             Derivative Works a copy of this License; and\n\n         (b) You must cause any modified files to carry prominent notices\n             stating that You changed the files; and\n\n         (c) You must retain, in the Source form of any Derivative Works\n             that You distribute, all copyright, patent, trademark, and\n             attribution notices from the Source form of the Work,\n             excluding those notices that do not pertain to any part of\n             the Derivative Works; and\n\n         (d) If the Work includes a \"NOTICE\" text file as part of its\n             distribution, then any Derivative Works that You distribute must\n             include a readable copy of the attribution notices contained\n             within such NOTICE file, excluding those notices that do not\n             pertain to any part of the Derivative Works, in at least one\n             of the following places: within a NOTICE text file distributed\n             as part of the Derivative Works; within the Source form or\n             documentation, if provided along with the Derivative Works; or,\n             within a display generated by the Derivative Works, if and\n             wherever such third-party notices normally appear. The contents\n             of the NOTICE file are for informational purposes only and\n             do not modify the License. You may add Your own attribution\n             notices within Derivative Works that You distribute, alongside\n             or as an addendum to the NOTICE text from the Work, provided\n             that such additional attribution notices cannot be construed\n             as modifying the License.\n\n         You may add Your own copyright statement to Your modifications and\n         may provide additional or different license terms and conditions\n         for use, reproduction, or distribution of Your modifications, or\n         for any such Derivative Works as a whole, provided Your use,\n         reproduction, and distribution of the Work otherwise complies with\n         the conditions stated in this License.\n\n      5. Submission of Contributions. Unless You explicitly state otherwise,\n         any Contribution intentionally submitted for inclusion in the Work\n         by You to the Licensor shall be under the terms and conditions of\n         this License, without any additional terms or conditions.\n         Notwithstanding the above, nothing herein shall supersede or modify\n         the terms of any separate license agreement you may have executed\n         with Licensor regarding such Contributions.\n\n      6. Trademarks. This License does not grant permission to use the trade\n         names, trademarks, service marks, or product names of the Licensor,\n         except as required for reasonable and customary use in describing the\n         origin of the Work and reproducing the content of the NOTICE file.\n\n      7. Disclaimer of Warranty. Unless required by applicable law or\n         agreed to in writing, Licensor provides the Work (and each\n         Contributor provides its Contributions) on an \"AS IS\" BASIS,\n         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n         implied, including, without limitation, any warranties or conditions\n         of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n         PARTICULAR PURPOSE. You are solely responsible for determining the\n         appropriateness of using or redistributing the Work and assume any\n         risks associated with Your exercise of permissions under this License.\n\n      8. Limitation of Liability. In no event and under no legal theory,\n         whether in tort (including negligence), contract, or otherwise,\n         unless required by applicable law (such as deliberate and grossly\n         negligent acts) or agreed to in writing, shall any Contributor be\n         liable to You for damages, including any direct, indirect, special,\n         incidental, or consequential damages of any character arising as a\n         result of this License or out of the use or inability to use the\n         Work (including but not limited to damages for loss of goodwill,\n         work stoppage, computer failure or malfunction, or any and all\n         other commercial damages or losses), even if such Contributor\n         has been advised of the possibility of such damages.\n\n      9. Accepting Warranty or Additional Liability. While redistributing\n         the Work or Derivative Works thereof, You may choose to offer,\n         and charge a fee for, acceptance of support, warranty, indemnity,\n         or other liability obligations and/or rights consistent with this\n         License. However, in accepting such obligations, You may act only\n         on Your own behalf and on Your sole responsibility, not on behalf\n         of any other Contributor, and only if You agree to indemnify,\n         defend, and hold each Contributor harmless for any liability\n         incurred by, or claims asserted against, such Contributor by reason\n         of your accepting any such warranty or additional liability.\n\n      END OF TERMS AND CONDITIONS\n\n      APPENDIX: How to apply the Apache License to your work.\n\n         To apply the Apache License to your work, attach the following\n         boilerplate notice, with the fields enclosed by brackets \"[]\"\n         replaced with your own identifying information. (Don't include\n         the brackets!)  The text should be enclosed in the appropriate\n         comment syntax for the file format. We also recommend that a\n         file or class name and description of purpose be included on the\n         same \"printed page\" as the copyright notice for easier\n         identification within third-party archives.\n\n      Copyright [yyyy] [name of copyright owner]\n\n      Licensed under the Apache License, Version 2.0 (the \"License\");\n      you may not use this file except in compliance with the License.\n      You may obtain a copy of the License at\n\n          http://www.apache.org/licenses/LICENSE-2.0\n\n      Unless required by applicable law or agreed to in writing, software\n      distributed under the License is distributed on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n      See the License for the specific language governing permissions and\n      limitations under the License.\n\n\n Name: Solarized\n Files: matplotlib/mpl-data/stylelib/Solarize_Light2.mplstyle\n Description: Solarized color scheme/style\n License: MIT\n   https://github.com/altercation/solarized/blob/master/LICENSE\n   Copyright (c) 2011 Ethan Schoonover\n\n   Permission is hereby granted, free of charge, to any person obtaining a copy\n   of this software and associated documentation files (the \"Software\"), to deal\n   in the Software without restriction, including without limitation the rights\n   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n   copies of the Software, and to permit persons to whom the Software is\n   furnished to do so, subject to the following conditions:\n\n   The above copyright notice and this permission notice shall be included in\n   all copies or substantial portions of the Software.\n\n   THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n   THE SOFTWARE.\n\n\n Name: Stix fonts\n Files: matplotlib/mpl-data/fonts/ttf/STIX*.ttf\n Description: STIX fonts\n License: OFL-1.1\n   STIX Font License\n\n   24 May 2010\n\n   Copyright (c) 2001-2010 by the STI Pub Companies, consisting of the American\n   Institute of Physics, the American Chemical Society, the American Mathematical\n   Society, the American Physical Society, Elsevier, Inc., and The Institute of\n   Electrical and Electronic Engineers, Inc. (www.stixfonts.org), with Reserved\n   Font Name STIX Fonts, STIX Fonts (TM) is a  trademark of The Institute of\n   Electrical and Electronics Engineers, Inc.\n\n   Portions copyright (c) 1998-2003 by MicroPress, Inc. (www.micropress-inc.com),\n   with Reserved Font Name TM Math. To obtain additional mathematical fonts, please\n   contact MicroPress, Inc., 68-30 Harrow Street, Forest Hills, NY 11375, USA,\n   Phone: (718) 575-1816.\n\n   Portions copyright (c) 1990 by Elsevier, Inc.\n\n   This Font Software is licensed under the SIL Open Font License, Version 1.1.\n   This license is copied below, and is also available with a FAQ at:\n   https://scripts.sil.org/OFL\n\n   -----------------------------------------------------------\n   SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007\n   -----------------------------------------------------------\n\n   PREAMBLE\n   The goals of the Open Font License (OFL) are to stimulate worldwide\n   development of collaborative font projects, to support the font creation\n   efforts of academic and linguistic communities, and to provide a free and\n   open framework in which fonts may be shared and improved in partnership\n   with others.\n\n   The OFL allows the licensed fonts to be used, studied, modified and\n   redistributed freely as long as they are not sold by themselves. The\n   fonts, including any derivative works, can be bundled, embedded,\n   redistributed and/or sold with any software provided that any reserved\n   names are not used by derivative works. The fonts and derivatives,\n   however, cannot be released under any other type of license. The\n   requirement for fonts to remain under this license does not apply\n   to any document created using the fonts or their derivatives.\n\n   DEFINITIONS\n   \"Font Software\" refers to the set of files released by the Copyright\n   Holder(s) under this license and clearly marked as such. This may\n   include source files, build scripts and documentation.\n\n   \"Reserved Font Name\" refers to any names specified as such after the\n   copyright statement(s).\n\n   \"Original Version\" refers to the collection of Font Software components as\n   distributed by the Copyright Holder(s).\n\n   \"Modified Version\" refers to any derivative made by adding to, deleting,\n   or substituting -- in part or in whole -- any of the components of the\n   Original Version, by changing formats or by porting the Font Software to a\n   new environment.\n\n   \"Author\" refers to any designer, engineer, programmer, technical\n   writer or other person who contributed to the Font Software.\n\n   PERMISSION & CONDITIONS\n   Permission is hereby granted, free of charge, to any person obtaining\n   a copy of the Font Software, to use, study, copy, merge, embed, modify,\n   redistribute, and sell modified and unmodified copies of the Font\n   Software, subject to the following conditions:\n\n   1) Neither the Font Software nor any of its individual components,\n   in Original or Modified Versions, may be sold by itself.\n\n   2) Original or Modified Versions of the Font Software may be bundled,\n   redistributed and/or sold with any software, provided that each copy\n   contains the above copyright notice and this license. These can be\n   included either as stand-alone text files, human-readable headers or\n   in the appropriate machine-readable metadata fields within text or\n   binary files as long as those fields can be easily viewed by the user.\n\n   3) No Modified Version of the Font Software may use the Reserved Font\n   Name(s) unless explicit written permission is granted by the corresponding\n   Copyright Holder. This restriction only applies to the primary font name as\n   presented to the users.\n\n   4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font\n   Software shall not be used to promote, endorse or advertise any\n   Modified Version, except to acknowledge the contribution(s) of the\n   Copyright Holder(s) and the Author(s) or with their explicit written\n   permission.\n\n   5) The Font Software, modified or unmodified, in part or in whole,\n   must be distributed entirely under this license, and must not be\n   distributed under any other license. The requirement for fonts to\n   remain under this license does not apply to any document created\n   using the Font Software.\n\n   TERMINATION\n   This license becomes null and void if any of the above conditions are\n   not met.\n\n   DISCLAIMER\n   THE FONT SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF\n   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT\n   OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE\n   COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\n   INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL\n   DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n   FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM\n   OTHER DEALINGS IN THE FONT SOFTWARE.\n\n Name: Yorick Colormaps\n Files: lib/matplotlib/_cm.py\n Description: Gist/Yorick colormaps\n License:\n   BSD-style license for gist/yorick colormaps.\n\n   Copyright:\n\n     Copyright (c) 1996.  The Regents of the University of California.\n                          All rights reserved.\n\n   Permission to use, copy, modify, and distribute this software for any\n   purpose without fee is hereby granted, provided that this entire\n   notice is included in all copies of any software which is or includes\n   a copy or modification of this software and in all copies of the\n   supporting documentation for such software.\n\n   This work was produced at the University of California, Lawrence\n   Livermore National Laboratory under contract no. W-7405-ENG-48 between\n   the U.S. Department of Energy and The Regents of the University of\n   California for the operation of UC LLNL.\n\n\n               DISCLAIMER\n\n   This software was prepared as an account of work sponsored by an\n   agency of the United States Government.  Neither the United States\n   Government nor the University of California nor any of their\n   employees, makes any warranty, express or implied, or assumes any\n   liability or responsibility for the accuracy, completeness, or\n   usefulness of any information, apparatus, product, or process\n   disclosed, or represents that its use would not infringe\n   privately-owned rights.  Reference herein to any specific commercial\n   products, process, or service by trade name, trademark, manufacturer,\n   or otherwise, does not necessarily constitute or imply its\n   endorsement, recommendation, or favoring by the United States\n   Government or the University of California.  The views and opinions of\n   authors expressed herein do not necessarily state or reflect those of\n   the United States Government or the University of California, and\n   shall not be used for advertising or product endorsement purposes.\n\n\n           AUTHOR\n\n   David H. Munro wrote Yorick and Gist.  Berkeley Yacc (byacc) generated\n   the Yorick parser.  The routines in Math are from LAPACK and FFTPACK;\n   MathC contains C translations by David H. Munro.  The algorithms for\n   Yorick's random number generator and several special functions in\n   Yorick/include were taken from Numerical Recipes by Press, et. al.,\n   although the Yorick implementations are unrelated to those in\n   Numerical Recipes.  A small amount of code in Gist was adapted from\n   the X11R4 release, copyright M.I.T. -- the complete copyright notice\n   may be found in the (unused) file Gist/host.c.\n",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Framework :: Matplotlib",
          "Intended Audience :: Science/Research",
          "Intended Audience :: Education",
          "License :: OSI Approved :: Python Software Foundation License",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Scientific/Engineering :: Visualization"
        ],
        "requires_dist": [
          "contourpy>=1.0.1",
          "cycler>=0.10",
          "fonttools>=4.28.2",
          "kiwisolver>=1.3.1",
          "numpy>=1.25",
          "packaging>=20.0",
          "pillow>=9",
          "pyparsing>=3",
          "python-dateutil>=2.7"
        ],
        "requires_python": ">=3.11",
        "project_url": [
          "Homepage, https://matplotlib.org",
          "Download, https://matplotlib.org/stable/install/index.html",
          "Documentation, https://matplotlib.org",
          "Source Code, https://github.com/matplotlib/matplotlib",
          "Bug Tracker, https://github.com/matplotlib/matplotlib/issues",
          "Forum, https://discourse.matplotlib.org/",
          "Donate, https://numfocus.org/donate-to-matplotlib"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/c7/f9/7d76c1eae866f5d4636401b31b6d6dd90e4b4ced1fa7cfdfcca9c60e4bd3/ml_dtypes-0.6.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=3b4a480aa8fd54a1805b8ac10f3f91763926a74f73c0c364c10f9231854f4170",
          "hashes": {
            "sha256": "3b4a480aa8fd54a1805b8ac10f3f91763926a74f73c0c364c10f9231854f4170"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "ml_dtypes",
        "version": "0.6.0",
        "summary": "ml_dtypes is a stand-alone implementation of several NumPy dtype extensions used in machine learning.",
        "description": "# ml_dtypes\n\n[![Unittests](https://github.com/jax-ml/ml_dtypes/actions/workflows/test.yml/badge.svg)](https://github.com/jax-ml/ml_dtypes/actions/workflows/test.yml)\n[![Wheel Build](https://github.com/jax-ml/ml_dtypes/actions/workflows/wheels.yml/badge.svg)](https://github.com/jax-ml/ml_dtypes/actions/workflows/wheels.yml)\n[![PyPI version](https://badge.fury.io/py/ml_dtypes.svg)](https://badge.fury.io/py/ml_dtypes)\n\n`ml_dtypes` is a stand-alone implementation of several NumPy dtype extensions used in machine learning libraries, including:\n\n- [`bfloat16`](https://en.wikipedia.org/wiki/Bfloat16_floating-point_format):\n  an alternative to the standard [`float16`](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) format\n- 8-bit floating point representations, parameterized by number of exponent and\n  mantissa bits, as well as the bias (if any) and representability of infinity,\n  NaN, and signed zero.\n  * `float8_e3m4`\n  * `float8_e4m3`\n  * `float8_e4m3b11fnuz`\n  * `float8_e4m3fn`\n  * `float8_e4m3fnuz`\n  * `float8_e5m2`\n  * `float8_e5m2fnuz`\n  * `float8_e8m0fnu`\n- Microscaling (MX) sub-byte floating point representations:\n  * `float4_e2m1fn`\n  * `float6_e2m3fn`\n  * `float6_e3m2fn`\n- Narrow integer encodings:\n  * `int1`\n  * `int2`\n  * `int4`\n  * `uint1`\n  * `uint2`\n  * `uint4`\n\nSee below for specifications of these number formats.\n\n## Installation\n\nThe `ml_dtypes` package is tested with Python versions 3.9-3.12, and can be installed\nwith the following command:\n```\npip install ml_dtypes\n```\nTo test your installation, you can run the following:\n```\npip install absl-py pytest\npytest --pyargs ml_dtypes\n```\nTo build from source, clone the repository and run:\n```\ngit submodule init\ngit submodule update\npip install .\n```\n\n## Example Usage\n\n```python\n>>> from ml_dtypes import bfloat16\n>>> import numpy as np\n>>> np.zeros(4, dtype=bfloat16)\narray([0, 0, 0, 0], dtype=bfloat16)\n```\nImporting `ml_dtypes` also registers the data types with numpy, so that they may\nbe referred to by their string name:\n\n```python\n>>> np.dtype('bfloat16')\ndtype(bfloat16)\n>>> np.dtype('float8_e5m2')\ndtype(float8_e5m2)\n```\n\n## Specifications of implemented floating point formats\n\n### `bfloat16`\n\nA `bfloat16` number is a single-precision float truncated at 16 bits.\n\nExponent: 8, Mantissa: 7, exponent bias: 127. IEEE 754, with NaN and inf.\n\n### `float4_e2m1fn`\n\nExponent: 2, Mantissa: 1, bias: 1.\n\nExtended range: no inf, no NaN.\n\nMicroscaling format, 4 bits (encoding: `0bSEEM`) using byte storage (higher 4\nbits are unused). NaN representation is undefined.\n\nPossible absolute values: [`0`, `0.5`, `1`, `1.5`, `2`, `3`, `4`, `6`]\n\n### `float6_e2m3fn`\n\nExponent: 2, Mantissa: 3, bias: 1.\n\nExtended range: no inf, no NaN.\n\nMicroscaling format, 6 bits (encoding: `0bSEEMMM`) using byte storage (higher 2\nbits are unused). NaN representation is undefined.\n\nPossible values range: [`-7.5`; `7.5`]\n\n### `float6_e3m2fn`\n\nExponent: 3, Mantissa: 2, bias: 3.\n\nExtended range: no inf, no NaN.\n\nMicroscaling format, 4 bits (encoding: `0bSEEEMM`) using byte storage (higher 2\nbits are unused). NaN representation is undefined.\n\nPossible values range: [`-28`; `28`]\n\n### `float8_e3m4`\n\nExponent: 3, Mantissa: 4, bias: 3. IEEE 754, with NaN and inf.\n\n### `float8_e4m3`\n\nExponent: 4, Mantissa: 3, bias: 7. IEEE 754, with NaN and inf.\n\n### `float8_e4m3b11fnuz`\n\nExponent: 4, Mantissa: 3, bias: 11.\n\nExtended range: no inf, NaN represented by 0b1000'0000.\n\n### `float8_e4m3fn`\n\nExponent: 4, Mantissa: 3, bias: 7.\n\nExtended range: no inf, NaN represented by 0bS111'1111.\n\nThe `fn` suffix is for consistency with the corresponding LLVM/MLIR type, signaling this type is not consistent with IEEE-754.  The `f` indicates it is finite values only. The `n` indicates it includes NaNs, but only at the outer range.\n\n### `float8_e4m3fnuz`\n\n8-bit floating point with 3 bit mantissa.\n\nAn 8-bit floating point type with 1 sign bit, 4 bits exponent and 3 bits mantissa. The suffix `fnuz` is consistent with LLVM/MLIR naming and is derived from the differences to IEEE floating point conventions. `F` is for \"finite\" (no infinities), `N` for with special NaN encoding, `UZ` for unsigned zero.\n\nThis type has the following characteristics:\n * bit encoding: S1E4M3 - `0bSEEEEMMM`\n * exponent bias: 8\n * infinities: Not supported\n * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s - `0b10000000`\n * denormals when exponent is 0\n\n### `float8_e5m2`\n\nExponent: 5, Mantissa: 2, bias: 15. IEEE 754, with NaN and inf.\n\n### `float8_e5m2fnuz`\n\n8-bit floating point with 2 bit mantissa.\n\nAn 8-bit floating point type with 1 sign bit, 5 bits exponent and 2 bits mantissa. The suffix `fnuz` is consistent with LLVM/MLIR naming and is derived from the differences to IEEE floating point conventions. `F` is for \"finite\" (no infinities), `N` for with special NaN encoding, `UZ` for unsigned zero.\n\nThis type has the following characteristics:\n * bit encoding: S1E5M2 - `0bSEEEEEMM`\n * exponent bias: 16\n * infinities: Not supported\n * NaNs: Supported with sign bit set to 1, exponent bits and mantissa bits set to all 0s - `0b10000000`\n * denormals when exponent is 0\n\n### `float8_e8m0fnu`\n\n[OpenCompute MX](https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf)\nscale format E8M0, which has the following properties:\n  * Unsigned format\n  * 8 exponent bits\n  * Exponent range from -127 to 127\n  * No zero and infinity\n  * Single NaN value (0xFF).\n\n## `int1`, `uint1`, `int2`, `int4`, `uint2` and `uint4`\n\n1, 2 and 4-bit integer types, where each element is represented unpacked (i.e.,\npadded up to a byte in memory).\n\nNumPy does not support types smaller than a single byte: for example, the\ndistance between adjacent elements in an array (`.strides`) is expressed as\nan integer number of bytes. Relaxing this restriction would be a considerable\nengineering project. These types therefore use an unpacked representation, where\neach element of the array is padded up to a byte in memory. The lower two or four\nbits of each byte contain the representation of the number, whereas the remaining\nupper bits are ignored.\n\n## Quirks of low-precision Arithmetic\n\nIf you're exploring the use of low-precision dtypes in your code, you should be\ncareful to anticipate when the precision loss might lead to surprising results.\nOne example is the behavior of aggregations like `sum`; consider this `bfloat16`\nsummation in NumPy (run with version 1.24.2):\n\n```python\n>>> from ml_dtypes import bfloat16\n>>> import numpy as np\n>>> rng = np.random.default_rng(seed=0)\n>>> vals = rng.uniform(size=10000).astype(bfloat16)\n>>> vals.sum()\n256\n```\nThe true sum should be close to 5000, but numpy returns exactly 256: this is\nbecause `bfloat16` does not have the precision to increment `256` by values less than\n`1`:\n\n```python\n>>> bfloat16(256) + bfloat16(1)\n256\n```\nAfter 256, the next representable value in bfloat16 is 258:\n\n```python\n>>> np.nextafter(bfloat16(256), bfloat16(np.inf))\n258\n```\nFor better results you can specify that the accumulation should happen in a\nhigher-precision type like `float32`:\n\n```python\n>>> vals.sum(dtype='float32').astype(bfloat16)\n4992\n```\nIn contrast to NumPy, projects like [JAX](http://jax.readthedocs.io/) which support\nlow-precision arithmetic more natively will often do these kinds of higher-precision\naccumulations automatically:\n\n```python\n>>> import jax.numpy as jnp\n>>> jnp.array(vals).sum()\nArray(4992, dtype=bfloat16)\n```\n\n## License\n\n*This is not an officially supported Google product.*\n\nThe `ml_dtypes` source code is licensed under the Apache 2.0 license\n(see [LICENSE](LICENSE)). Pre-compiled wheels are built with the\n[EIGEN](https://eigen.tuxfamily.org/) project, which is released under the\nMPL 2.0 license (see [LICENSE.eigen](LICENSE.eigen)).\n",
        "description_content_type": "text/markdown",
        "author_email": "ml_dtypes authors <ml_dtypes@google.com>",
        "classifier": [
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3 :: Only",
          "Intended Audience :: Science/Research"
        ],
        "requires_dist": [
          "numpy>=2.0.0",
          "numpy>=2.1.0; python_version >= \"3.13\"",
          "numpy>=2.3.0; python_version >= \"3.14\"",
          "absl-py; extra == \"dev\"",
          "pytest; extra == \"dev\"",
          "pytest-xdist; extra == \"dev\"",
          "pylint>=2.6.0; extra == \"dev\"",
          "pyink; extra == \"dev\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "homepage, https://github.com/jax-ml/ml_dtypes",
          "repository, https://github.com/jax-ml/ml_dtypes"
        ],
        "provides_extra": [
          "dev"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/65/af/aa78d1a88805456e212b65461354cd943197fb9acecc4c90fd12295123a3/numpy-2.5.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=b7e18c623bb5c95acb3b3328861272816ba199fb531921c5d6d0b675f1fde9e3",
          "hashes": {
            "sha256": "b7e18c623bb5c95acb3b3328861272816ba199fb531921c5d6d0b675f1fde9e3"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "numpy",
        "version": "2.5.3",
        "summary": "Fundamental package for array computing in Python",
        "description": "<h1 align=\"center\">\n<img src=\"https://raw.githubusercontent.com/numpy/numpy/main/branding/logo/primary/numpylogo.svg\" width=\"300\">\n</h1><br>\n\n\n[![Powered by NumFOCUS](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](\nhttps://numfocus.org)\n[![PyPI Downloads](https://img.shields.io/pypi/dm/numpy.svg?label=PyPI%20downloads)](\nhttps://pypi.org/project/numpy/)\n[![Conda Downloads](https://img.shields.io/conda/dn/conda-forge/numpy.svg?label=Conda%20downloads)](\nhttps://anaconda.org/conda-forge/numpy)\n[![Stack Overflow](https://img.shields.io/badge/stackoverflow-Ask%20questions-blue.svg)](\nhttps://stackoverflow.com/questions/tagged/numpy)\n[![Nature Paper](https://img.shields.io/badge/DOI-10.1038%2Fs41586--020--2649--2-blue)](\nhttps://doi.org/10.1038/s41586-020-2649-2)\n[![LFX Health Score](https://insights.linuxfoundation.org/api/badge/health-score?project=numpy)](https://insights.linuxfoundation.org/project/numpy)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/numpy/numpy/badge)](https://securityscorecards.dev/viewer/?uri=github.com/numpy/numpy)\n[![Typing](https://img.shields.io/pypi/types/numpy)](https://pypi.org/project/numpy/)\n\n\nNumPy is the fundamental package for scientific computing with Python.\n\n- **Website:** https://numpy.org\n- **Documentation:** https://numpy.org/doc\n- **Mailing list:** https://mail.python.org/mailman/listinfo/numpy-discussion\n- **Source code:** https://github.com/numpy/numpy\n- **Contributing:** https://numpy.org/devdocs/dev/index.html\n- **Bug reports:** https://github.com/numpy/numpy/issues\n- **Report a security vulnerability:** https://github.com/numpy/numpy/security/policy (via Tidelift)\n\nIt provides:\n\n- a powerful N-dimensional array object\n- sophisticated (broadcasting) functions\n- tools for integrating C/C++ and Fortran code\n- useful linear algebra, Fourier transform, and random number capabilities\n\nTesting:\n\nNumPy requires `pytest` and `hypothesis`.  Tests can then be run after installation with:\n\n    python -c \"import numpy, sys; sys.exit(numpy.test() is False)\"\n\nCode of Conduct\n----------------------\n\nNumPy is a community-driven open source project developed by a diverse group of\n[contributors](https://numpy.org/teams/). The NumPy leadership has made a strong\ncommitment to creating an open, inclusive, and positive community. Please read the\n[NumPy Code of Conduct](https://numpy.org/code-of-conduct/) for guidance on how to interact\nwith others in a way that makes our community thrive.\n\nCall for Contributions\n----------------------\n\nThe NumPy project welcomes your expertise and enthusiasm!\n\nSmall improvements or fixes are always appreciated. If you are considering larger contributions\nto the source code, please contact us through the [mailing\nlist](https://mail.python.org/mailman/listinfo/numpy-discussion) first.\n\nWriting code isn’t the only way to contribute to NumPy. You can also:\n- review pull requests\n- help us stay on top of new and old issues\n- develop tutorials, presentations, and other educational materials\n- maintain and improve [our website](https://github.com/numpy/numpy.org)\n- develop graphic design for our brand assets and promotional materials\n- translate website content\n- help with outreach and onboard new contributors\n- write grant proposals and help with other fundraising efforts\n\nFor more information about the ways you can contribute to NumPy, visit [our website](https://numpy.org/contribute/). \nIf you’re unsure where to start or how your skills fit in, reach out! You can\nask on the mailing list or here, on GitHub, by opening a new issue or leaving a\ncomment on a relevant issue that is already open.\n\nOur preferred channels of communication are all public, but if you’d like to\nspeak to us in private first, contact our community coordinators at\nnumpy-team@googlegroups.com or on Slack (write numpy-team@googlegroups.com for\nan invitation).\n\nWe also have a biweekly community call, details of which are announced on the\nmailing list. You are very welcome to join.\n\nIf you are new to contributing to open source, [this\nguide](https://opensource.guide/how-to-contribute/) helps explain why, what,\nand how to successfully get involved.\n",
        "description_content_type": "text/markdown",
        "author": "Travis E. Oliphant et al.",
        "maintainer_email": "NumPy Developers <numpy-discussion@python.org>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Science/Research",
          "Intended Audience :: Developers",
          "Programming Language :: C",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3.15",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: Implementation :: CPython",
          "Topic :: Software Development",
          "Topic :: Scientific/Engineering",
          "Typing :: Typed",
          "Operating System :: Microsoft :: Windows",
          "Operating System :: POSIX",
          "Operating System :: Unix",
          "Operating System :: MacOS"
        ],
        "requires_python": ">=3.12",
        "project_url": [
          "homepage, https://numpy.org",
          "documentation, https://numpy.org/doc/",
          "source, https://github.com/numpy/numpy",
          "download, https://pypi.org/project/numpy/#files",
          "tracker, https://github.com/numpy/numpy/issues",
          "release notes, https://numpy.org/doc/stable/release"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/4b/8b/9cc6d4123033f7cb82df6cd8ce19eb0fc18a964afe060a03c9b26757c9f3/regex-2026.9.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=665207e41bacd435db001099eeab44103197c2c1a729d73ade74688a905ed4ce",
          "hashes": {
            "sha256": "665207e41bacd435db001099eeab44103197c2c1a729d73ade74688a905ed4ce"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "regex",
        "version": "2026.9.3",
        "dynamic": [
          "license-file"
        ],
        "summary": "Alternative regular expression module, to replace re.",
        "description": "Introduction\n------------\n\nThis regex implementation is backwards-compatible with the standard 're' module, but offers additional functionality.\n\nPython 2\n--------\n\nPython 2 is no longer supported. The last release that supported Python 2 was 2021.11.10.\n\nPyPy\n----\n\nThis module is targeted at CPython. It expects that all codepoints are the same width, so it won't behave properly with PyPy outside U+0000..U+007F because PyPy stores strings as UTF-8.\n\nMultithreading\n--------------\n\nThe regex module releases the GIL during matching on instances of the built-in (immutable) string classes, enabling other Python threads to run concurrently. It is also possible to force the regex module to release the GIL during matching by calling the matching methods with the keyword argument ``concurrent=True``. The behaviour is undefined if the string changes during matching, so use it *only* when it is guaranteed that that won't happen.\n\nUnicode\n-------\n\nThis module supports Unicode 17.0.0. Full Unicode case-folding is supported.\n\nFlags\n-----\n\nThere are 2 kinds of flag: scoped and global. Scoped flags can apply to only part of a pattern and can be turned on or off; global flags apply to the entire pattern and can only be turned on.\n\nThe scoped flags are: ``ASCII (?a)``, ``FULLCASE (?f)``, ``IGNORECASE (?i)``, ``LOCALE (?L)``, ``MULTILINE (?m)``, ``DOTALL (?s)``, ``UNICODE (?u)``, ``VERBOSE (?x)``, ``WORD (?w)``.\n\nThe global flags are: ``BESTMATCH (?b)``, ``ENHANCEMATCH (?e)``, ``POSIX (?p)``, ``REVERSE (?r)``, ``VERSION0 (?V0)``, ``VERSION1 (?V1)``.\n\nIf neither the ``ASCII``, ``LOCALE`` nor ``UNICODE`` flag is specified, it will default to ``UNICODE`` if the regex pattern is a Unicode string and ``ASCII`` if it's a bytestring.\n\nThe ``ENHANCEMATCH`` flag makes fuzzy matching attempt to improve the fit of the next match that it finds.\n\nThe ``BESTMATCH`` flag makes fuzzy matching search for the best match instead of the next match.\n\nOld vs new behaviour\n--------------------\n\nIn order to be compatible with the re module, this module has 2 behaviours:\n\n* **Version 0** behaviour (old behaviour, compatible with the re module):\n\n  Please note that the re module's behaviour may change over time, and I'll endeavour to match that behaviour in version 0.\n\n  * Indicated by the ``VERSION0`` flag.\n\n  * Zero-width matches are not handled correctly in the re module before Python 3.7. The behaviour in those earlier versions is:\n\n    * ``.split`` won't split a string at a zero-width match.\n\n    * ``.sub`` will advance by one character after a zero-width match.\n\n  * Inline flags apply to the entire pattern, and they can't be turned off.\n\n  * Only simple sets are supported.\n\n  * Case-insensitive matches in Unicode use simple case-folding by default.\n\n* **Version 1** behaviour (new behaviour, possibly different from the re module):\n\n  * Indicated by the ``VERSION1`` flag.\n\n  * Zero-width matches are handled correctly.\n\n  * Inline flags apply to the end of the group or pattern, and they can be turned off.\n\n  * Nested sets and set operations are supported.\n\n  * Case-insensitive matches in Unicode use full case-folding by default.\n\nIf no version is specified, the regex module will default to ``regex.DEFAULT_VERSION``.\n\nCase-insensitive matches in Unicode\n-----------------------------------\n\nThe regex module supports both simple and full case-folding for case-insensitive matches in Unicode. Use of full case-folding can be turned on using the ``FULLCASE`` flag. Please note that this flag affects how the ``IGNORECASE`` flag works; the ``FULLCASE`` flag itself does not turn on case-insensitive matching.\n\nVersion 0 behaviour: the flag is off by default.\n\nVersion 1 behaviour: the flag is on by default.\n\nNested sets and set operations\n------------------------------\n\nIt's not possible to support both simple sets, as used in the re module, and nested sets at the same time because of a difference in the meaning of an unescaped ``\"[\"`` in a set.\n\nFor example, the pattern ``[[a-z]--[aeiou]]`` is treated in the version 0 behaviour (simple sets, compatible with the re module) as:\n\n* Set containing \"[\" and the letters \"a\" to \"z\"\n\n* Literal \"--\"\n\n* Set containing letters \"a\", \"e\", \"i\", \"o\", \"u\"\n\n* Literal \"]\"\n\nbut in the version 1 behaviour (nested sets, enhanced behaviour) as:\n\n* Set which is:\n\n  * Set containing the letters \"a\" to \"z\"\n\n* but excluding:\n\n  * Set containing the letters \"a\", \"e\", \"i\", \"o\", \"u\"\n\nVersion 0 behaviour: only simple sets are supported.\n\nVersion 1 behaviour: nested sets and set operations are supported.\n\nNotes on named groups\n---------------------\n\nAll groups have a group number, starting from 1.\n\nGroups with the same group name will have the same group number, and groups with a different group name will have a different group number.\n\nThe same name can be used by more than one group, with later captures 'overwriting' earlier captures. All the captures of the group will be available from the ``captures`` method of the match object.\n\nGroup numbers will be reused across different branches of a branch reset, eg. ``(?|(first)|(second))`` has only group 1. If groups have different group names then they will, of course, have different group numbers, eg. ``(?|(?P<foo>first)|(?P<bar>second))`` has group 1 (\"foo\") and group 2 (\"bar\").\n\nIn the regex ``(\\s+)(?|(?P<foo>[A-Z]+)|(\\w+) (?P<foo>[0-9]+)`` there are 2 groups:\n\n* ``(\\s+)`` is group 1.\n\n* ``(?P<foo>[A-Z]+)`` is group 2, also called \"foo\".\n\n* ``(\\w+)`` is group 2 because of the branch reset.\n\n* ``(?P<foo>[0-9]+)`` is group 2 because it's called \"foo\".\n\nIf you want to prevent ``(\\w+)`` from being group 2, you need to name it (different name, different group number).\n\nAdditional features\n-------------------\n\nThe issue numbers relate to the Python bug tracker, except where listed otherwise.\n\nAdded ``\\p{Horiz_Space}`` and ``\\p{Vert_Space}`` (`GitHub issue 477 <https://github.com/mrabarnett/mrab-regex/issues/477#issuecomment-1216779547>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``\\p{Horiz_Space}`` or ``\\p{H}`` matches horizontal whitespace and ``\\p{Vert_Space}`` or ``\\p{V}`` matches vertical whitespace.\n\nAdded support for lookaround in conditional pattern (`Hg issue 163 <https://github.com/mrabarnett/mrab-regex/issues/163>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe test of a conditional pattern can be a lookaround.\n\n.. sourcecode:: python\n\n  >>> regex.match(r'(?(?=\\d)\\d+|\\w+)', '123abc')\n  <regex.Match object; span=(0, 3), match='123'>\n  >>> regex.match(r'(?(?=\\d)\\d+|\\w+)', 'abc123')\n  <regex.Match object; span=(0, 6), match='abc123'>\n\nThis is not quite the same as putting a lookaround in the first branch of a pair of alternatives.\n\n.. sourcecode:: python\n\n  >>> print(regex.match(r'(?:(?=\\d)\\d+\\b|\\w+)', '123abc'))\n  <regex.Match object; span=(0, 6), match='123abc'>\n  >>> print(regex.match(r'(?(?=\\d)\\d+\\b|\\w+)', '123abc'))\n  None\n\nIn the first example, the lookaround matched, but the remainder of the first branch failed to match, and so the second branch was attempted, whereas in the second example, the lookaround matched, and the first branch failed to match, but the second branch was **not** attempted.\n\nAdded POSIX matching (leftmost longest) (`Hg issue 150 <https://github.com/mrabarnett/mrab-regex/issues/150>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe POSIX standard for regex is to return the leftmost longest match. This can be turned on using the ``POSIX`` flag.\n\nIt looks for the longest overall match. It doesn't look for the longest match for each group.\n\n.. sourcecode:: python\n\n  >>> # Normal matching.\n  >>> regex.search(r'Mr|Mrs', 'Mrs')\n  <regex.Match object; span=(0, 2), match='Mr'>\n  >>> regex.search(r'one(self)?(selfsufficient)?', 'oneselfsufficient')\n  <regex.Match object; span=(0, 7), match='oneself'>\n  >>> # POSIX matching.\n  >>> regex.search(r'(?p)Mr|Mrs', 'Mrs')\n  <regex.Match object; span=(0, 3), match='Mrs'>\n  >>> regex.search(r'(?p)one(self)?(selfsufficient)?', 'oneselfsufficient')\n  <regex.Match object; span=(0, 17), match='oneselfsufficient'>\n\nNote that it will take longer to find matches because when it finds a match at a certain position, it won't return that immediately, but will keep looking to see if there's another longer match there.\n\nAdded ``(?(DEFINE)...)`` (`Hg issue 152 <https://github.com/mrabarnett/mrab-regex/issues/152>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf there's no group called \"DEFINE\", then ... will be ignored except that any groups defined within it can be called and that the normal rules for numbering groups still apply.\n\n.. sourcecode:: python\n\n  >>> regex.search(r'(?(DEFINE)(?P<quant>\\d+)(?P<item>\\w+))(?&quant) (?&item)', '5 elephants')\n  <regex.Match object; span=(0, 11), match='5 elephants'>\n\nAdded ``(*PRUNE)``, ``(*SKIP)`` and ``(*FAIL)`` (`Hg issue 153 <https://github.com/mrabarnett/mrab-regex/issues/153>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``(*PRUNE)`` discards the backtracking info up to that point. When used in an atomic group or a lookaround, it won't affect the enclosing pattern.\n\n``(*SKIP)`` is similar to ``(*PRUNE)``, except that it also sets where in the text the next attempt to match will start. When used in an atomic group or a lookaround, it won't affect the enclosing pattern.\n\n``(*FAIL)`` causes immediate backtracking. ``(*F)`` is a permitted abbreviation.\n\nAdded ``\\K`` (`Hg issue 151 <https://github.com/mrabarnett/mrab-regex/issues/151>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nKeeps the part of the entire match after the position where ``\\K`` occurred; the part before it is discarded.\n\nIt does not affect what groups return.\n\n.. sourcecode:: python\n\n  >>> m = regex.search(r'(\\w\\w\\K\\w\\w\\w)', 'abcdef')\n  >>> m[0]\n  'cde'\n  >>> m[1]\n  'abcde'\n  >>>\n  >>> m = regex.search(r'(?r)(\\w\\w\\K\\w\\w\\w)', 'abcdef')\n  >>> m[0]\n  'bc'\n  >>> m[1]\n  'bcdef'\n\nAdded capture subscripting for ``expandf`` and ``subf``/``subfn`` (`Hg issue 133 <https://github.com/mrabarnett/mrab-regex/issues/133>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nYou can use subscripting to get the captures of a repeated group.\n\n.. sourcecode:: python\n\n  >>> m = regex.match(r\"(\\w)+\", \"abc\")\n  >>> m.expandf(\"{1}\")\n  'c'\n  >>> m.expandf(\"{1[0]} {1[1]} {1[2]}\")\n  'a b c'\n  >>> m.expandf(\"{1[-1]} {1[-2]} {1[-3]}\")\n  'c b a'\n  >>>\n  >>> m = regex.match(r\"(?P<letter>\\w)+\", \"abc\")\n  >>> m.expandf(\"{letter}\")\n  'c'\n  >>> m.expandf(\"{letter[0]} {letter[1]} {letter[2]}\")\n  'a b c'\n  >>> m.expandf(\"{letter[-1]} {letter[-2]} {letter[-3]}\")\n  'c b a'\n\nAdded support for referring to a group by number using ``(?P=...)``\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThis is in addition to the existing ``\\g<...>``.\n\nFixed the handling of locale-sensitive regexes\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe ``LOCALE`` flag is intended for legacy code and has limited support. You're still recommended to use Unicode instead.\n\nAdded partial matches (`Hg issue 102 <https://github.com/mrabarnett/mrab-regex/issues/102>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA partial match is one that matches up to the end of string, but that string has been truncated and you want to know whether a complete match could be possible if the string had not been truncated.\n\nPartial matches are supported by ``match``, ``search``, ``fullmatch`` and ``finditer`` with the ``partial`` keyword argument.\n\nMatch objects have a ``partial`` attribute, which is ``True`` if it's a partial match.\n\nFor example, if you wanted a user to enter a 4-digit number and check it character by character as it was being entered:\n\n.. sourcecode:: python\n\n  >>> pattern = regex.compile(r'\\d{4}')\n\n  >>> # Initially, nothing has been entered:\n  >>> print(pattern.fullmatch('', partial=True))\n  <regex.Match object; span=(0, 0), match='', partial=True>\n\n  >>> # An empty string is OK, but it's only a partial match.\n  >>> # The user enters a letter:\n  >>> print(pattern.fullmatch('a', partial=True))\n  None\n  >>> # It'll never match.\n\n  >>> # The user deletes that and enters a digit:\n  >>> print(pattern.fullmatch('1', partial=True))\n  <regex.Match object; span=(0, 1), match='1', partial=True>\n  >>> # It matches this far, but it's only a partial match.\n\n  >>> # The user enters 2 more digits:\n  >>> print(pattern.fullmatch('123', partial=True))\n  <regex.Match object; span=(0, 3), match='123', partial=True>\n  >>> # It matches this far, but it's only a partial match.\n\n  >>> # The user enters another digit:\n  >>> print(pattern.fullmatch('1234', partial=True))\n  <regex.Match object; span=(0, 4), match='1234'>\n  >>> # It's a complete match.\n\n  >>> # If the user enters another digit:\n  >>> print(pattern.fullmatch('12345', partial=True))\n  None\n  >>> # It's no longer a match.\n\n  >>> # This is a partial match:\n  >>> pattern.match('123', partial=True).partial\n  True\n\n  >>> # This is a complete match:\n  >>> pattern.match('1233', partial=True).partial\n  False\n\n``*`` operator not working correctly with sub() (`Hg issue 106 <https://github.com/mrabarnett/mrab-regex/issues/106>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nSometimes it's not clear how zero-width matches should be handled. For example, should ``.*`` match 0 characters directly after matching >0 characters?\n\n.. sourcecode:: python\n\n  >>> regex.sub('.*', 'x', 'test')\n  'xx'\n  >>> regex.sub('.*?', '|', 'test')\n  '|||||||||'\n\nAdded ``capturesdict`` (`Hg issue 86 <https://github.com/mrabarnett/mrab-regex/issues/86>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``capturesdict`` is a combination of ``groupdict`` and ``captures``:\n\n``groupdict`` returns a dict of the named groups and the last capture of those groups.\n\n``captures`` returns a list of all the captures of a group\n\n``capturesdict`` returns a dict of the named groups and lists of all the captures of those groups.\n\n.. sourcecode:: python\n\n  >>> m = regex.match(r\"(?:(?P<word>\\w+) (?P<digits>\\d+)\\n)+\", \"one 1\\ntwo 2\\nthree 3\\n\")\n  >>> m.groupdict()\n  {'word': 'three', 'digits': '3'}\n  >>> m.captures(\"word\")\n  ['one', 'two', 'three']\n  >>> m.captures(\"digits\")\n  ['1', '2', '3']\n  >>> m.capturesdict()\n  {'word': ['one', 'two', 'three'], 'digits': ['1', '2', '3']}\n\nAdded ``allcaptures`` and ``allspans`` (`Git issue 474 <https://github.com/mrabarnett/mrab-regex/issues/474>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``allcaptures`` returns a list of all the captures of all the groups.\n\n``allspans`` returns a list of all the spans of the all captures of all the groups.\n\n.. sourcecode:: python\n\n  >>> m = regex.match(r\"(?:(?P<word>\\w+) (?P<digits>\\d+)\\n)+\", \"one 1\\ntwo 2\\nthree 3\\n\")\n  >>> m.allcaptures()\n  (['one 1\\ntwo 2\\nthree 3\\n'], ['one', 'two', 'three'], ['1', '2', '3'])\n  >>> m.allspans()\n  ([(0, 20)], [(0, 3), (6, 9), (12, 17)], [(4, 5), (10, 11), (18, 19)])\n\nAllow duplicate names of groups (`Hg issue 87 <https://github.com/mrabarnett/mrab-regex/issues/87>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nGroup names can be duplicated.\n\n.. sourcecode:: python\n\n  >>> # With optional groups:\n  >>>\n  >>> # Both groups capture, the second capture 'overwriting' the first.\n  >>> m = regex.match(r\"(?P<item>\\w+)? or (?P<item>\\w+)?\", \"first or second\")\n  >>> m.group(\"item\")\n  'second'\n  >>> m.captures(\"item\")\n  ['first', 'second']\n  >>> # Only the second group captures.\n  >>> m = regex.match(r\"(?P<item>\\w+)? or (?P<item>\\w+)?\", \" or second\")\n  >>> m.group(\"item\")\n  'second'\n  >>> m.captures(\"item\")\n  ['second']\n  >>> # Only the first group captures.\n  >>> m = regex.match(r\"(?P<item>\\w+)? or (?P<item>\\w+)?\", \"first or \")\n  >>> m.group(\"item\")\n  'first'\n  >>> m.captures(\"item\")\n  ['first']\n  >>>\n  >>> # With mandatory groups:\n  >>>\n  >>> # Both groups capture, the second capture 'overwriting' the first.\n  >>> m = regex.match(r\"(?P<item>\\w*) or (?P<item>\\w*)?\", \"first or second\")\n  >>> m.group(\"item\")\n  'second'\n  >>> m.captures(\"item\")\n  ['first', 'second']\n  >>> # Again, both groups capture, the second capture 'overwriting' the first.\n  >>> m = regex.match(r\"(?P<item>\\w*) or (?P<item>\\w*)\", \" or second\")\n  >>> m.group(\"item\")\n  'second'\n  >>> m.captures(\"item\")\n  ['', 'second']\n  >>> # And yet again, both groups capture, the second capture 'overwriting' the first.\n  >>> m = regex.match(r\"(?P<item>\\w*) or (?P<item>\\w*)\", \"first or \")\n  >>> m.group(\"item\")\n  ''\n  >>> m.captures(\"item\")\n  ['first', '']\n\nAdded ``fullmatch`` (`issue #16203 <https://bugs.python.org/issue16203>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``fullmatch`` behaves like ``match``, except that it must match all of the string.\n\n.. sourcecode:: python\n\n  >>> print(regex.fullmatch(r\"abc\", \"abc\").span())\n  (0, 3)\n  >>> print(regex.fullmatch(r\"abc\", \"abcx\"))\n  None\n  >>> print(regex.fullmatch(r\"abc\", \"abcx\", endpos=3).span())\n  (0, 3)\n  >>> print(regex.fullmatch(r\"abc\", \"xabcy\", pos=1, endpos=4).span())\n  (1, 4)\n  >>>\n  >>> regex.match(r\"a.*?\", \"abcd\").group(0)\n  'a'\n  >>> regex.fullmatch(r\"a.*?\", \"abcd\").group(0)\n  'abcd'\n\nAdded ``subf`` and ``subfn``\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``subf`` and ``subfn`` are alternatives to ``sub`` and ``subn`` respectively. When passed a replacement string, they treat it as a format string.\n\n.. sourcecode:: python\n\n  >>> regex.subf(r\"(\\w+) (\\w+)\", \"{0} => {2} {1}\", \"foo bar\")\n  'foo bar => bar foo'\n  >>> regex.subf(r\"(?P<word1>\\w+) (?P<word2>\\w+)\", \"{word2} {word1}\", \"foo bar\")\n  'bar foo'\n\nAdded ``expandf`` to match object\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``expandf`` is an alternative to ``expand``. When passed a replacement string, it treats it as a format string.\n\n.. sourcecode:: python\n\n  >>> m = regex.match(r\"(\\w+) (\\w+)\", \"foo bar\")\n  >>> m.expandf(\"{0} => {2} {1}\")\n  'foo bar => bar foo'\n  >>>\n  >>> m = regex.match(r\"(?P<word1>\\w+) (?P<word2>\\w+)\", \"foo bar\")\n  >>> m.expandf(\"{word2} {word1}\")\n  'bar foo'\n\nDetach searched string\n^^^^^^^^^^^^^^^^^^^^^^\n\nA match object contains a reference to the string that was searched, via its ``string`` attribute. The ``detach_string`` method will 'detach' that string, making it available for garbage collection, which might save valuable memory if that string is very large.\n\n.. sourcecode:: python\n\n  >>> m = regex.search(r\"\\w+\", \"Hello world\")\n  >>> print(m.group())\n  Hello\n  >>> print(m.string)\n  Hello world\n  >>> m.detach_string()\n  >>> print(m.group())\n  Hello\n  >>> print(m.string)\n  None\n\nRecursive patterns (`Hg issue 27 <https://github.com/mrabarnett/mrab-regex/issues/27>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRecursive and repeated patterns are supported.\n\n``(?R)`` or ``(?0)`` tries to match the entire regex recursively. ``(?1)``, ``(?2)``, etc, try to match the relevant group.\n\n``(?&name)`` tries to match the named group.\n\n.. sourcecode:: python\n\n  >>> regex.match(r\"(Tarzan|Jane) loves (?1)\", \"Tarzan loves Jane\").groups()\n  ('Tarzan',)\n  >>> regex.match(r\"(Tarzan|Jane) loves (?1)\", \"Jane loves Tarzan\").groups()\n  ('Jane',)\n\n  >>> m = regex.search(r\"(\\w)(?:(?R)|(\\w?))\\1\", \"kayak\")\n  >>> m.group(0, 1, 2)\n  ('kayak', 'k', None)\n\nThe first two examples show how the subpattern within the group is reused, but is _not_ itself a group. In other words, ``\"(Tarzan|Jane) loves (?1)\"`` is equivalent to ``\"(Tarzan|Jane) loves (?:Tarzan|Jane)\"``.\n\nIt's possible to backtrack into a recursed or repeated group.\n\nYou can't call a group if there is more than one group with that group name or group number (``\"ambiguous group reference\"``).\n\nThe alternative forms ``(?P>name)`` and ``(?P&name)`` are also supported.\n\nFull Unicode case-folding is supported\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIn version 1 behaviour, the regex module uses full case-folding when performing case-insensitive matches in Unicode.\n\n.. sourcecode:: python\n\n  >>> regex.match(r\"(?iV1)strasse\", \"stra\\N{LATIN SMALL LETTER SHARP S}e\").span()\n  (0, 6)\n  >>> regex.match(r\"(?iV1)stra\\N{LATIN SMALL LETTER SHARP S}e\", \"STRASSE\").span()\n  (0, 7)\n\nIn version 0 behaviour, it uses simple case-folding for backward compatibility with the re module.\n\nApproximate \"fuzzy\" matching (`Hg issue 12 <https://github.com/mrabarnett/mrab-regex/issues/12>`_, `Hg issue 41 <https://github.com/mrabarnett/mrab-regex/issues/41>`_, `Hg issue 109 <https://github.com/mrabarnett/mrab-regex/issues/109>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nRegex usually attempts an exact match, but sometimes an approximate, or \"fuzzy\", match is needed, for those cases where the text being searched may contain errors in the form of inserted, deleted or substituted characters.\n\nA fuzzy regex specifies which types of errors are permitted, and, optionally, either the minimum and maximum or only the maximum permitted number of each type. (You cannot specify only a minimum.)\n\nThe 3 types of error are:\n\n* Insertion, indicated by \"i\"\n\n* Deletion, indicated by \"d\"\n\n* Substitution, indicated by \"s\"\n\nIn addition, \"e\" indicates any type of error.\n\nThe fuzziness of a regex item is specified between \"{\" and \"}\" after the item.\n\nExamples:\n\n* ``foo`` match \"foo\" exactly\n\n* ``(?:foo){i}`` match \"foo\", permitting insertions\n\n* ``(?:foo){d}`` match \"foo\", permitting deletions\n\n* ``(?:foo){s}`` match \"foo\", permitting substitutions\n\n* ``(?:foo){i,s}`` match \"foo\", permitting insertions and substitutions\n\n* ``(?:foo){e}`` match \"foo\", permitting errors\n\nIf a certain type of error is specified, then any type not specified will **not** be permitted.\n\nIn the following examples I'll omit the item and write only the fuzziness:\n\n* ``{d<=3}`` permit at most 3 deletions, but no other types\n\n* ``{i<=1,s<=2}`` permit at most 1 insertion and at most 2 substitutions, but no deletions\n\n* ``{1<=e<=3}`` permit at least 1 and at most 3 errors\n\n* ``{i<=2,d<=2,e<=3}`` permit at most 2 insertions, at most 2 deletions, at most 3 errors in total, but no substitutions\n\nIt's also possible to state the costs of each type of error and the maximum permitted total cost.\n\nExamples:\n\n* ``{2i+2d+1s<=4}`` each insertion costs 2, each deletion costs 2, each substitution costs 1, the total cost must not exceed 4\n\n* ``{i<=1,d<=1,s<=1,2i+2d+1s<=4}`` at most 1 insertion, at most 1 deletion, at most 1 substitution; each insertion costs 2, each deletion costs 2, each substitution costs 1, the total cost must not exceed 4\n\nYou can also use \"<\" instead of \"<=\" if you want an exclusive minimum or maximum.\n\nYou can add a test to perform on a character that's substituted or inserted.\n\nExamples:\n\n* ``{s<=2:[a-z]}`` at most 2 substitutions, which must be in the character set ``[a-z]``.\n\n* ``{s<=2,i<=3:\\d}`` at most 2 substitutions, at most 3 insertions, which must be digits.\n\nBy default, fuzzy matching searches for the first match that meets the given constraints. The ``ENHANCEMATCH`` flag will cause it to attempt to improve the fit (i.e. reduce the number of errors) of the match that it has found.\n\nThe ``BESTMATCH`` flag will make it search for the best match instead.\n\nFurther examples to note:\n\n* ``regex.search(\"(dog){e}\", \"cat and dog\")[1]`` returns ``\"cat\"`` because that matches ``\"dog\"`` with 3 errors (an unlimited number of errors is permitted).\n\n* ``regex.search(\"(dog){e<=1}\", \"cat and dog\")[1]`` returns ``\" dog\"`` (with a leading space) because that matches ``\"dog\"`` with 1 error, which is within the limit.\n\n* ``regex.search(\"(?e)(dog){e<=1}\", \"cat and dog\")[1]`` returns ``\"dog\"`` (without a leading space) because the fuzzy search matches ``\" dog\"`` with 1 error, which is within the limit, and the ``(?e)`` then it attempts a better fit.\n\nIn the first two examples there are perfect matches later in the string, but in neither case is it the first possible match.\n\nThe match object has an attribute ``fuzzy_counts`` which gives the total number of substitutions, insertions and deletions.\n\n.. sourcecode:: python\n\n  >>> # A 'raw' fuzzy match:\n  >>> regex.fullmatch(r\"(?:cats|cat){e<=1}\", \"cat\").fuzzy_counts\n  (0, 0, 1)\n  >>> # 0 substitutions, 0 insertions, 1 deletion.\n\n  >>> # A better match might be possible if the ENHANCEMATCH flag used:\n  >>> regex.fullmatch(r\"(?e)(?:cats|cat){e<=1}\", \"cat\").fuzzy_counts\n  (0, 0, 0)\n  >>> # 0 substitutions, 0 insertions, 0 deletions.\n\nThe match object also has an attribute ``fuzzy_changes`` which gives a tuple of the positions of the substitutions, insertions and deletions.\n\n.. sourcecode:: python\n\n  >>> m = regex.search('(fuu){i<=2,d<=2,e<=5}', 'anaconda foo bar')\n  >>> m\n  <regex.Match object; span=(7, 10), match='a f', fuzzy_counts=(0, 2, 2)>\n  >>> m.fuzzy_changes\n  ([], [7, 8], [10, 11])\n\nWhat this means is that if the matched part of the string had been:\n\n.. sourcecode:: python\n\n  'anacondfuuoo bar'\n\nit would've been an exact match.\n\nHowever, there were insertions at positions 7 and 8:\n\n.. sourcecode:: python\n\n  'anaconda fuuoo bar'\n          ^^\n\nand deletions at positions 10 and 11:\n\n.. sourcecode:: python\n\n  'anaconda f~~oo bar'\n             ^^\n\nSo the actual string was:\n\n.. sourcecode:: python\n\n  'anaconda foo bar'\n\nNamed lists ``\\L<name>`` (`Hg issue 11 <https://github.com/mrabarnett/mrab-regex/issues/11>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThere are occasions where you may want to include a list (actually, a set) of options in a regex.\n\nOne way is to build the pattern like this:\n\n.. sourcecode:: python\n\n  >>> p = regex.compile(r\"first|second|third|fourth|fifth\")\n\nbut if the list is large, parsing the resulting regex can take considerable time, and care must also be taken that the strings are properly escaped and properly ordered, for example, \"cats\" before \"cat\".\n\nThe new alternative is to use a named list:\n\n.. sourcecode:: python\n\n  >>> option_set = [\"first\", \"second\", \"third\", \"fourth\", \"fifth\"]\n  >>> p = regex.compile(r\"\\L<options>\", options=option_set)\n\nThe order of the items is irrelevant, they are treated as a set. The named lists are available as the ``.named_lists`` attribute of the pattern object :\n\n.. sourcecode:: python\n\n  >>> print(p.named_lists)\n  {'options': frozenset({'third', 'first', 'fifth', 'fourth', 'second'})}\n\nIf there are any unused keyword arguments, ``ValueError`` will be raised unless you tell it otherwise:\n\n.. sourcecode:: python\n\n  >>> option_set = [\"first\", \"second\", \"third\", \"fourth\", \"fifth\"]\n  >>> p = regex.compile(r\"\\L<options>\", options=option_set, other_options=[])\n  Traceback (most recent call last):\n    File \"<stdin>\", line 1, in <module>\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 353, in compile\n      return _compile(pattern, flags, ignore_unused, kwargs, cache_pattern)\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 500, in _compile\n      complain_unused_args()\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 483, in complain_unused_args\n      raise ValueError('unused keyword argument {!a}'.format(any_one))\n  ValueError: unused keyword argument 'other_options'\n  >>> p = regex.compile(r\"\\L<options>\", options=option_set, other_options=[], ignore_unused=True)\n  >>> p = regex.compile(r\"\\L<options>\", options=option_set, other_options=[], ignore_unused=False)\n  Traceback (most recent call last):\n    File \"<stdin>\", line 1, in <module>\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 353, in compile\n      return _compile(pattern, flags, ignore_unused, kwargs, cache_pattern)\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 500, in _compile\n      complain_unused_args()\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 483, in complain_unused_args\n      raise ValueError('unused keyword argument {!a}'.format(any_one))\n  ValueError: unused keyword argument 'other_options'\n  >>>\n\nStart and end of word\n^^^^^^^^^^^^^^^^^^^^^\n\n``\\m`` matches at the start of a word.\n\n``\\M`` matches at the end of a word.\n\nCompare with ``\\b``, which matches at the start or end of a word.\n\nUnicode line separators\n^^^^^^^^^^^^^^^^^^^^^^^\n\nNormally the only line separator is ``\\n`` (``\\x0A``), but if the ``WORD`` flag is turned on then the line separators are ``\\x0D\\x0A``, ``\\x0A``, ``\\x0B``, ``\\x0C`` and ``\\x0D``, plus ``\\x85``, ``\\u2028`` and ``\\u2029`` when working with Unicode.\n\nThis affects the regex dot ``\".\"``, which, with the ``DOTALL`` flag turned off, matches any character except a line separator. It also affects the line anchors ``^`` and ``$`` (in multiline mode).\n\nSet operators\n^^^^^^^^^^^^^\n\n**Version 1 behaviour only**\n\nSet operators have been added, and a set ``[...]`` can include nested sets.\n\nThe operators, in order of increasing precedence, are:\n\n* ``||`` for union (\"x||y\" means \"x or y\")\n\n* ``~~`` (double tilde) for symmetric difference (\"x~~y\" means \"x or y, but not both\")\n\n* ``&&`` for intersection (\"x&&y\" means \"x and y\")\n\n* ``--`` (double dash) for difference (\"x--y\" means \"x but not y\")\n\nImplicit union, ie, simple juxtaposition like in ``[ab]``, has the highest precedence. Thus, ``[ab&&cd]`` is the same as ``[[a||b]&&[c||d]]``.\n\nExamples:\n\n* ``[ab]`` # Set containing 'a' and 'b'\n\n* ``[a-z]`` # Set containing 'a' .. 'z'\n\n* ``[[a-z]--[qw]]`` # Set containing 'a' .. 'z', but not 'q' or 'w'\n\n* ``[a-z--qw]`` # Same as above\n\n* ``[\\p{L}--QW]`` # Set containing all letters except 'Q' and 'W'\n\n* ``[\\p{N}--[0-9]]`` # Set containing all numbers except '0' .. '9'\n\n* ``[\\p{ASCII}&&\\p{Letter}]`` # Set containing all characters which are ASCII and letter\n\nregex.escape (`issue #2650 <https://bugs.python.org/issue2650>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nregex.escape has an additional keyword parameter ``special_only``. When True, only 'special' regex characters, such as '?', are escaped.\n\n.. sourcecode:: python\n\n  >>> regex.escape(\"foo!?\", special_only=False)\n  'foo\\\\!\\\\?'\n  >>> regex.escape(\"foo!?\", special_only=True)\n  'foo!\\\\?'\n\nregex.escape (`Hg issue 249 <https://github.com/mrabarnett/mrab-regex/issues/249>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nregex.escape has an additional keyword parameter ``literal_spaces``. When True, spaces are not escaped.\n\n.. sourcecode:: python\n\n  >>> regex.escape(\"foo bar!?\", literal_spaces=False)\n  'foo\\\\ bar!\\\\?'\n  >>> regex.escape(\"foo bar!?\", literal_spaces=True)\n  'foo bar!\\\\?'\n\nRepeated captures (`issue #7132 <https://bugs.python.org/issue7132>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA match object has additional methods which return information on all the successful matches of a repeated group. These methods are:\n\n* ``matchobject.captures([group1, ...])``\n\n  * Returns a list of the strings matched in a group or groups. Compare with ``matchobject.group([group1, ...])``.\n\n* ``matchobject.starts([group])``\n\n  * Returns a list of the start positions. Compare with ``matchobject.start([group])``.\n\n* ``matchobject.ends([group])``\n\n  * Returns a list of the end positions. Compare with ``matchobject.end([group])``.\n\n* ``matchobject.spans([group])``\n\n  * Returns a list of the spans. Compare with ``matchobject.span([group])``.\n\n.. sourcecode:: python\n\n  >>> m = regex.search(r\"(\\w{3})+\", \"123456789\")\n  >>> m.group(1)\n  '789'\n  >>> m.captures(1)\n  ['123', '456', '789']\n  >>> m.start(1)\n  6\n  >>> m.starts(1)\n  [0, 3, 6]\n  >>> m.end(1)\n  9\n  >>> m.ends(1)\n  [3, 6, 9]\n  >>> m.span(1)\n  (6, 9)\n  >>> m.spans(1)\n  [(0, 3), (3, 6), (6, 9)]\n\nAtomic grouping ``(?>...)`` (`issue #433030 <https://bugs.python.org/issue433030>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nIf the following pattern subsequently fails, then the subpattern as a whole will fail.\n\nPossessive quantifiers\n^^^^^^^^^^^^^^^^^^^^^^\n\n``(?:...)?+`` ; ``(?:...)*+`` ; ``(?:...)++`` ; ``(?:...){min,max}+``\n\nThe subpattern is matched up to 'max' times. If the following pattern subsequently fails, then all the repeated subpatterns will fail as a whole. For example, ``(?:...)++`` is equivalent to ``(?>(?:...)+)``.\n\nScoped flags (`issue #433028 <https://bugs.python.org/issue433028>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``(?flags-flags:...)``\n\nThe flags will apply only to the subpattern. Flags can be turned on or off.\n\nDefinition of 'word' character (`issue #1693050 <https://bugs.python.org/issue1693050>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe definition of a 'word' character has been expanded for Unicode. It conforms to the Unicode specification at ``http://www.unicode.org/reports/tr29/``.\n\nVariable-length lookbehind\n^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA lookbehind can match a variable-length string.\n\nFlags argument for regex.split, regex.sub and regex.subn (`issue #3482 <https://bugs.python.org/issue3482>`_)\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``regex.split``, ``regex.sub`` and ``regex.subn`` support a 'flags' argument.\n\nPos and endpos arguments for regex.sub and regex.subn\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``regex.sub`` and ``regex.subn`` support 'pos' and 'endpos' arguments.\n\n'Overlapped' argument for regex.findall and regex.finditer\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``regex.findall`` and ``regex.finditer`` support an 'overlapped' flag which permits overlapped matches.\n\nSplititer\n^^^^^^^^^\n\n``regex.splititer`` has been added. It's a generator equivalent of ``regex.split``.\n\nSubscripting match objects for groups\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nA match object accepts access to the groups via subscripting and slicing:\n\n.. sourcecode:: python\n\n  >>> m = regex.search(r\"(?P<before>.*?)(?P<num>\\d+)(?P<after>.*)\", \"pqr123stu\")\n  >>> print(m[\"before\"])\n  pqr\n  >>> print(len(m))\n  4\n  >>> print(m[:])\n  ('pqr123stu', 'pqr', '123', 'stu')\n\nNamed groups\n^^^^^^^^^^^^\n\nGroups can be named with ``(?<name>...)`` as well as the existing ``(?P<name>...)``.\n\nGroup references\n^^^^^^^^^^^^^^^^\n\nGroups can be referenced within a pattern with ``\\g<name>``. This also allows there to be more than 99 groups.\n\nNamed characters ``\\N{name}``\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nNamed characters are supported. Note that only those known by Python's Unicode database will be recognised.\n\nUnicode codepoint properties, including scripts and blocks\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n``\\p{property=value}``; ``\\P{property=value}``; ``\\p{value}`` ; ``\\P{value}``\n\nMany Unicode properties are supported, including blocks and scripts. ``\\p{property=value}`` or ``\\p{property:value}`` matches a character whose property ``property`` has value ``value``. The inverse of ``\\p{property=value}`` is ``\\P{property=value}`` or ``\\p{^property=value}``.\n\nIf the short form ``\\p{value}`` is used, the properties are checked in the order: ``General_Category``, ``Script``, ``Block``, binary property:\n\n* ``Latin``, the 'Latin' script (``Script=Latin``).\n\n* ``BasicLatin``, the 'BasicLatin' block (``Block=BasicLatin``).\n\n* ``Alphabetic``, the 'Alphabetic' binary property (``Alphabetic=Yes``).\n\nA short form starting with ``Is`` indicates a script or binary property:\n\n* ``IsLatin``, the 'Latin' script (``Script=Latin``).\n\n* ``IsAlphabetic``, the 'Alphabetic' binary property (``Alphabetic=Yes``).\n\nA short form starting with ``In`` indicates a block property:\n\n* ``InBasicLatin``, the 'BasicLatin' block (``Block=BasicLatin``).\n\nPOSIX character classes\n^^^^^^^^^^^^^^^^^^^^^^^\n\n``[[:alpha:]]``; ``[[:^alpha:]]``\n\nPOSIX character classes are supported. These are normally treated as an alternative form of ``\\p{...}``.\n\nThe exceptions are ``alnum``, ``digit``, ``punct`` and ``xdigit``, whose definitions are different from those of Unicode.\n\n``[[:alnum:]]`` is equivalent to ``\\p{posix_alnum}``.\n\n``[[:digit:]]`` is equivalent to ``\\p{posix_digit}``.\n\n``[[:punct:]]`` is equivalent to ``\\p{posix_punct}``.\n\n``[[:xdigit:]]`` is equivalent to ``\\p{posix_xdigit}``.\n\nSearch anchor ``\\G``\n^^^^^^^^^^^^^^^^^^^^\n\nA search anchor has been added. It matches at the position where each search started/continued and can be used for contiguous matches or in negative variable-length lookbehinds to limit how far back the lookbehind goes:\n\n.. sourcecode:: python\n\n  >>> regex.findall(r\"\\w{2}\", \"abcd ef\")\n  ['ab', 'cd', 'ef']\n  >>> regex.findall(r\"\\G\\w{2}\", \"abcd ef\")\n  ['ab', 'cd']\n\n* The search starts at position 0 and matches 'ab'.\n\n* The search continues at position 2 and matches 'cd'.\n\n* The search continues at position 4 and fails to match any letters.\n\n* The anchor stops the search start position from being advanced, so there are no more results.\n\nReverse searching\n^^^^^^^^^^^^^^^^^\n\nSearches can also work backwards:\n\n.. sourcecode:: python\n\n  >>> regex.findall(r\".\", \"abc\")\n  ['a', 'b', 'c']\n  >>> regex.findall(r\"(?r).\", \"abc\")\n  ['c', 'b', 'a']\n\nNote that the result of a reverse search is not necessarily the reverse of a forward search:\n\n.. sourcecode:: python\n\n  >>> regex.findall(r\"..\", \"abcde\")\n  ['ab', 'cd']\n  >>> regex.findall(r\"(?r)..\", \"abcde\")\n  ['de', 'bc']\n\nMatching a single grapheme ``\\X``\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe grapheme matcher is supported. It conforms to the Unicode specification at ``http://www.unicode.org/reports/tr29/``.\n\nBranch reset ``(?|...|...)``\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nGroup numbers will be reused across the alternatives, but groups with different names will have different group numbers.\n\n.. sourcecode:: python\n\n  >>> regex.match(r\"(?|(first)|(second))\", \"first\").groups()\n  ('first',)\n  >>> regex.match(r\"(?|(first)|(second))\", \"second\").groups()\n  ('second',)\n\nNote that there is only one group.\n\nDefault Unicode word boundary\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nThe ``WORD`` flag changes the definition of a 'word boundary' to that of a default Unicode word boundary. This applies to ``\\b`` and ``\\B``.\n\nTimeout\n^^^^^^^\n\nThe matching methods and functions support timeouts. The timeout (in seconds) applies to the entire operation:\n\n.. sourcecode:: python\n\n  >>> from time import sleep\n  >>>\n  >>> def fast_replace(m):\n  ...     return 'X'\n  ...\n  >>> def slow_replace(m):\n  ...     sleep(0.5)\n  ...     return 'X'\n  ...\n  >>> regex.sub(r'[a-z]', fast_replace, 'abcde', timeout=2)\n  'XXXXX'\n  >>> regex.sub(r'[a-z]', slow_replace, 'abcde', timeout=2)\n  Traceback (most recent call last):\n    File \"<stdin>\", line 1, in <module>\n    File \"C:\\Python310\\lib\\site-packages\\regex\\regex.py\", line 278, in sub\n      return pat.sub(repl, string, count, pos, endpos, concurrent, timeout)\n  TimeoutError: regex timed out\n",
        "description_content_type": "text/x-rst",
        "author_email": "Matthew Barnett <regex@mrabarnett.plus.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3.15",
          "Topic :: Scientific/Engineering :: Information Analysis",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Topic :: Text Processing",
          "Topic :: Text Processing :: General"
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/mrabarnett/mrab-regex"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/28/50/f203ff3a3ddfe19308efc83c5a3a29ed02bf786732ec35e68bf9162f3365/safetensors-0.8.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
        "archive_info": {
          "hash": "sha256=fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774",
          "hashes": {
            "sha256": "fd6f3f93c9a0a7cc2788ee63fb763353d4bd2e89b0751bc78fcf7dda00bea774"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "safetensors",
        "version": "0.8.0",
        "description": "## Installation\n\n```\npip install safetensors\n```\n\n\n## Usage\n\n### Numpy\n\n```python\nfrom safetensors.numpy import save_file, load_file\nimport numpy as np\n\ntensors = {\n   \"a\": np.zeros((2, 2)),\n   \"b\": np.zeros((2, 3), dtype=np.uint8)\n}\n\nsave_file(tensors, \"./model.safetensors\")\n\n\n# Now loading\nloaded = load_file(\"./model.safetensors\")\n```\n\n### Torch\n\n```python\nfrom safetensors.torch import save_file, load_file\nimport torch\n\ntensors = {\n   \"a\": torch.zeros((2, 2)),\n   \"b\": torch.zeros((2, 3), dtype=torch.uint8)\n}\n\nsave_file(tensors, \"./model.safetensors\")\n\n\n# Now loading\nloaded = load_file(\"./model.safetensors\")\n```\n\n### Developing\n\n```\n# inside ./safetensors/bindings/python\npip install .[dev]\n```\nShould be enough to install this library locally.\n\n### Testing\n\n```\n# inside ./safetensors/bindings/python\npip install .[dev]\npytest -sv tests/\n```\n\n",
        "description_content_type": "text/markdown; charset=UTF-8; variant=GFM",
        "author_email": "Nicolas Patry <patry.nicolas@protonmail.com>, Luc Georges <luc@huggingface.co>, Daniël De Kok <daniel.dekok@huggingface.co>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Intended Audience :: Education",
          "Intended Audience :: Science/Research",
          "License :: OSI Approved :: Apache Software License",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Scientific/Engineering :: Artificial Intelligence",
          "Typing :: Typed"
        ],
        "requires_dist": [
          "safetensors[torch] ; extra == 'all'",
          "safetensors[numpy] ; extra == 'all'",
          "safetensors[jax] ; extra == 'all'",
          "safetensors[paddlepaddle] ; extra == 'all'",
          "safetensors[convert] ; extra == 'all'",
          "safetensors[quality] ; extra == 'all'",
          "safetensors[testing] ; extra == 'all'",
          "safetensors[torch] ; extra == 'convert'",
          "huggingface-hub>=1.4 ; extra == 'convert'",
          "safetensors[all] ; extra == 'dev'",
          "safetensors[pinned-tf] ; extra == 'dev'",
          "safetensors[numpy] ; extra == 'jax'",
          "flax>=0.6.3 ; extra == 'jax'",
          "jax>=0.3.25 ; extra == 'jax'",
          "jaxlib>=0.3.25 ; extra == 'jax'",
          "mlx>=0.0.9 ; extra == 'mlx'",
          "numpy>=1.24.6 ; extra == 'numpy'",
          "safetensors[numpy] ; extra == 'paddlepaddle'",
          "paddlepaddle>=2.4.1 ; extra == 'paddlepaddle'",
          "safetensors[numpy] ; extra == 'pinned-tf'",
          "tensorflow==2.18.0 ; extra == 'pinned-tf'",
          "ruff ; extra == 'quality'",
          "safetensors[numpy] ; extra == 'tensorflow'",
          "tensorflow>=2.11.0 ; extra == 'tensorflow'",
          "safetensors[numpy] ; extra == 'testing'",
          "h5py>=3.7.0 ; extra == 'testing'",
          "setuptools-rust>=1.12.0 ; extra == 'testing'",
          "pytest>=9.0 ; extra == 'testing'",
          "pytest-benchmark>=5.2 ; extra == 'testing'",
          "hypothesis>=6.70.2 ; extra == 'testing'",
          "fsspec>=2024.6.0 ; extra == 'testing'",
          "s3fs>=2024.6.0 ; extra == 'testing'",
          "safetensors[numpy] ; extra == 'tf-nightly'",
          "tf-nightly ; extra == 'tf-nightly'",
          "safetensors[numpy] ; extra == 'torch'",
          "torch>=2.4 ; extra == 'torch'"
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/huggingface/safetensors",
          "Source, https://github.com/huggingface/safetensors"
        ],
        "provides_extra": [
          "all",
          "convert",
          "dev",
          "jax",
          "mlx",
          "numpy",
          "paddlepaddle",
          "pinned-tf",
          "quality",
          "tensorflow",
          "testing",
          "tf-nightly",
          "torch"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/2c/ca/ca6b93c7820df123b2662a9469e8facc826ccc94e98fdd0d615f6431e73a/tokenizers-0.23.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
        "archive_info": {
          "hash": "sha256=41c2f84d172449b4dadb9cdc508e3e364076613c35b16e76ecfe47a60d1e3305",
          "hashes": {
            "sha256": "41c2f84d172449b4dadb9cdc508e3e364076613c35b16e76ecfe47a60d1e3305"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "tokenizers",
        "version": "0.23.2",
        "description": "<p align=\"center\">\n    <br>\n    <img src=\"https://huggingface.co/landing/assets/tokenizers/tokenizers-logo.png\" width=\"600\"/>\n    <br>\n<p>\n<p align=\"center\">\n    <a href=\"https://badge.fury.io/py/tokenizers\">\n         <img alt=\"Build\" src=\"https://badge.fury.io/py/tokenizers.svg\">\n    </a>\n    <a href=\"https://github.com/huggingface/tokenizers/blob/master/LICENSE\">\n        <img alt=\"GitHub\" src=\"https://img.shields.io/github/license/huggingface/tokenizers.svg?color=blue\">\n    </a>\n</p>\n<br>\n\n# Tokenizers\n\nProvides an implementation of today's most used tokenizers, with a focus on performance and\nversatility.\n\nBindings over the [Rust](https://github.com/huggingface/tokenizers/tree/master/tokenizers) implementation.\nIf you are interested in the High-level design, you can go check it there.\n\nOtherwise, let's dive in!\n\n## Main features:\n\n - Train new vocabularies and tokenize using 4 pre-made tokenizers (Bert WordPiece and the 3\n   most common BPE versions).\n - Extremely fast (both training and tokenization), thanks to the Rust implementation. Takes\n   less than 20 seconds to tokenize a GB of text on a server's CPU.\n - Easy to use, but also extremely versatile.\n - Designed for research and production.\n - Normalization comes with alignments tracking. It's always possible to get the part of the\n   original sentence that corresponds to a given token.\n - Does all the pre-processing: Truncate, Pad, add the special tokens your model needs.\n\n### Installation\n\n#### With pip:\n\n```bash\npip install tokenizers\n```\n\n#### From sources:\n\nTo use this method, you need to have the Rust installed:\n\n```bash\n# Install with:\ncurl https://sh.rustup.rs -sSf | sh -s -- -y\nexport PATH=\"$HOME/.cargo/bin:$PATH\"\n```\n\nOnce Rust is installed, you can compile doing the following\n\n```bash\ngit clone https://github.com/huggingface/tokenizers\ncd tokenizers/bindings/python\n\n# Create a virtual env (you can use yours as well)\npython -m venv .env\nsource .env/bin/activate\n\n# Install `tokenizers` in the current virtual env\npip install -e .\n```\n\n### Free-threaded Python (3.14t)\n\n`tokenizers` ships dedicated wheels for the [free-threaded build of CPython](https://docs.python.org/3.14/howto/free-threading-python.html)\n(`python3.14t`). These wheels declare `Py_MOD_GIL_NOT_USED`, so importing\n`tokenizers` does **not** force the GIL back on — multi-threaded code stays\nGIL-free.\n\nThe full mutable API works on 3.14t — the same as on regular CPython.\nSetters are thread-safe: the inner tokenizer state is wrapped in a\n`std::sync::RwLock`, so concurrent `tokenizer.X = …` from multiple threads\nserialize correctly and concurrent encode operations take a read guard\nthat blocks writers only briefly.\n\n```python\nfrom tokenizers import Tokenizer\nfrom tokenizers.models import BPE\nfrom tokenizers.pre_tokenizers import Whitespace\nfrom tokenizers.processors import ByteLevel\n\ntok = Tokenizer(BPE())\ntok.pre_tokenizer = Whitespace()                 # ✅ thread-safe on 3.14t\ntok.post_processor = ByteLevel(trim_offsets=True)\n```\n\n**Caveat — compound mutations are not atomic.** Statements like\n`tokenizer.post_processor.special_tokens = X` evaluate in two steps from\nPython's point of view (read attribute → set attribute on the result). If\nanother thread swaps `tokenizer.post_processor` between those steps, the\nmutation lands on an orphaned component. This is the same class of race\nas `dict[k] = v` interleaved with `dict.clear()` — coordinate with a Python\nlock if you need the compound to be atomic.\n\nFor the full thread-safety analysis, see\n[`docs/free-threading-audit.md`](./docs/free-threading-audit.md).\n\n### Load a pretrained tokenizer from the Hub\n\n```python\nfrom tokenizers import Tokenizer\n\ntokenizer = Tokenizer.from_pretrained(\"bert-base-cased\")\n```\n\n### Using the provided Tokenizers\n\nWe provide some pre-build tokenizers to cover the most common cases. You can easily load one of\nthese using some `vocab.json` and `merges.txt` files:\n\n```python\nfrom tokenizers import CharBPETokenizer\n\n# Initialize a tokenizer\nvocab = \"./path/to/vocab.json\"\nmerges = \"./path/to/merges.txt\"\ntokenizer = CharBPETokenizer(vocab, merges)\n\n# And then encode:\nencoded = tokenizer.encode(\"I can feel the magic, can you?\")\nprint(encoded.ids)\nprint(encoded.tokens)\n```\n\nAnd you can train them just as simply:\n\n```python\nfrom tokenizers import CharBPETokenizer\n\n# Initialize a tokenizer\ntokenizer = CharBPETokenizer()\n\n# Then train it!\ntokenizer.train([ \"./path/to/files/1.txt\", \"./path/to/files/2.txt\" ])\n\n# Now, let's use it:\nencoded = tokenizer.encode(\"I can feel the magic, can you?\")\n\n# And finally save it somewhere\ntokenizer.save(\"./path/to/directory/my-bpe.tokenizer.json\")\n```\n\n#### Provided Tokenizers\n\n - `CharBPETokenizer`: The original BPE\n - `ByteLevelBPETokenizer`: The byte level version of the BPE\n - `SentencePieceBPETokenizer`: A BPE implementation compatible with the one used by SentencePiece\n - `BertWordPieceTokenizer`: The famous Bert tokenizer, using WordPiece\n\nAll of these can be used and trained as explained above!\n\n### Build your own\n\nWhenever these provided tokenizers don't give you enough freedom, you can build your own tokenizer,\nby putting all the different parts you need together.\nYou can check how we implemented the [provided tokenizers](https://github.com/huggingface/tokenizers/tree/master/bindings/python/py_src/tokenizers/implementations) and adapt them easily to your own needs.\n\n#### Building a byte-level BPE\n\nHere is an example showing how to build your own byte-level BPE by putting all the different pieces\ntogether, and then saving it to a single file:\n\n```python\nfrom tokenizers import Tokenizer, models, pre_tokenizers, decoders, trainers, processors\n\n# Initialize a tokenizer\ntokenizer = Tokenizer(models.BPE())\n\n# Customize pre-tokenization and decoding\ntokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=True)\ntokenizer.decoder = decoders.ByteLevel()\ntokenizer.post_processor = processors.ByteLevel(trim_offsets=True)\n\n# And then train\ntrainer = trainers.BpeTrainer(\n    vocab_size=20000,\n    min_frequency=2,\n    initial_alphabet=pre_tokenizers.ByteLevel.alphabet()\n)\ntokenizer.train([\n    \"./path/to/dataset/1.txt\",\n    \"./path/to/dataset/2.txt\",\n    \"./path/to/dataset/3.txt\"\n], trainer=trainer)\n\n# And Save it\ntokenizer.save(\"byte-level-bpe.tokenizer.json\", pretty=True)\n```\n\nNow, when you want to use this tokenizer, this is as simple as:\n\n```python\nfrom tokenizers import Tokenizer\n\ntokenizer = Tokenizer.from_file(\"byte-level-bpe.tokenizer.json\")\n\nencoded = tokenizer.encode(\"I can feel the magic, can you?\")\n```\n\n### Typing support and stub generation\n\nThe compiled PyO3 extension does not expose type annotations, so editors and type checkers would otherwise see most objects as `Any`. To provide full typing support, we use a two-step stub generation process:\n\n1. **Rust introspection** (`tools/stub-gen/`): Uses `pyo3-introspection` to analyze the compiled extension and generate `.pyi` stub files\n2. **Python enrichment** (`stub.py`): Adds docstrings from the runtime module and generates forwarding `__init__.py` shims\n\n#### Running stub generation\n\nThe easiest way to regenerate stubs is via `make style`:\n\n```bash\ncd bindings/python\nmake style\n```\n\nThis will:\n1. Build the extension with `maturin develop --release`\n2. Run introspection to generate `.pyi` files\n3. Enrich stubs with docstrings via `stub.py`\n4. Format with `ruff`\n\n#### Running manually\n\nTo run the stub generator directly:\n\n```bash\ncd bindings/python\ncargo run --manifest-path tools/stub-gen/Cargo.toml\npython stub.py\n```\n\nThe stub generator automatically:\n- Builds the extension using maturin\n- Copies the built `.so` to the project root for introspection\n- Detects and sets `PYTHONHOME` for embedded Python (handles uv/venv environments)\n- Generates stubs to `py_src/tokenizers/`\n\n#### Troubleshooting\n\nIf you encounter Python initialization errors, you can manually set `PYTHONHOME`:\n\n```bash\nexport PYTHONHOME=$(python3 -c 'import sys; print(sys.base_prefix)')\ncargo run --manifest-path tools/stub-gen/Cargo.toml\n```\n\n",
        "description_content_type": "text/markdown; charset=UTF-8; variant=GFM",
        "keywords": [
          "NLP",
          "tokenizer",
          "BPE",
          "transformer",
          "deep learning"
        ],
        "author_email": "Nicolas Patry <patry.nicolas@protonmail.com>, Anthony Moi <anthony@huggingface.co>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Intended Audience :: Education",
          "Intended Audience :: Science/Research",
          "License :: OSI Approved :: Apache Software License",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3 :: Only",
          "Topic :: Scientific/Engineering :: Artificial Intelligence"
        ],
        "requires_dist": [
          "huggingface-hub>=0.16.4,<2.0",
          "tokenizers[testing] ; extra == 'dev'",
          "sphinx ; extra == 'docs'",
          "sphinx-rtd-theme ; extra == 'docs'",
          "setuptools-rust ; extra == 'docs'",
          "pytest ; extra == 'testing'",
          "pytest-asyncio ; extra == 'testing'",
          "requests ; extra == 'testing'",
          "numpy ; extra == 'testing'",
          "datasets ; extra == 'testing'",
          "ruff ; extra == 'testing'",
          "ty ; extra == 'testing'"
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/huggingface/tokenizers",
          "Source, https://github.com/huggingface/tokenizers"
        ],
        "provides_extra": [
          "dev",
          "docs",
          "testing"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4",
          "hashes": {
            "sha256": "7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "flatbuffers",
        "version": "25.12.19",
        "dynamic": [
          "author",
          "author-email",
          "classifier",
          "description",
          "home-page",
          "license",
          "project-url",
          "summary"
        ],
        "summary": "The FlatBuffers serialization format for Python",
        "description": "Python runtime library for use with the `Flatbuffers <https://google.github.io/flatbuffers/>`_ serialization format.\n",
        "home_page": "https://google.github.io/flatbuffers/",
        "author": "Derek Bailey",
        "author_email": "derekbailey@google.com",
        "license": "Apache 2.0",
        "classifier": [
          "Intended Audience :: Developers",
          "License :: OSI Approved :: Apache Software License",
          "Operating System :: OS Independent",
          "Programming Language :: Python",
          "Programming Language :: Python :: 2",
          "Programming Language :: Python :: 3",
          "Topic :: Software Development :: Libraries :: Python Modules"
        ],
        "project_url": [
          "Documentation, https://google.github.io/flatbuffers/",
          "Source, https://github.com/google/flatbuffers"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb",
          "hashes": {
            "sha256": "33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "rich",
        "version": "15.0.0",
        "summary": "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal",
        "description": "[![Supported Python Versions](https://img.shields.io/pypi/pyversions/rich)](https://pypi.org/project/rich/) [![PyPI version](https://badge.fury.io/py/rich.svg)](https://badge.fury.io/py/rich)\n\n[![Downloads](https://pepy.tech/badge/rich/month)](https://pepy.tech/project/rich)\n[![codecov](https://img.shields.io/codecov/c/github/Textualize/rich?label=codecov&logo=codecov)](https://codecov.io/gh/Textualize/rich)\n[![Rich blog](https://img.shields.io/badge/blog-rich%20news-yellowgreen)](https://www.willmcgugan.com/tag/rich/)\n[![Twitter Follow](https://img.shields.io/twitter/follow/willmcgugan.svg?style=social)](https://twitter.com/willmcgugan)\n\n![Logo](https://github.com/textualize/rich/raw/master/imgs/logo.svg)\n\n[English readme](https://github.com/textualize/rich/blob/master/README.md)\n • [简体中文 readme](https://github.com/textualize/rich/blob/master/README.cn.md)\n • [正體中文 readme](https://github.com/textualize/rich/blob/master/README.zh-tw.md)\n • [Lengua española readme](https://github.com/textualize/rich/blob/master/README.es.md)\n • [Deutsche readme](https://github.com/textualize/rich/blob/master/README.de.md)\n • [Läs på svenska](https://github.com/textualize/rich/blob/master/README.sv.md)\n • [日本語 readme](https://github.com/textualize/rich/blob/master/README.ja.md)\n • [한국어 readme](https://github.com/textualize/rich/blob/master/README.kr.md)\n • [Français readme](https://github.com/textualize/rich/blob/master/README.fr.md)\n • [Schwizerdütsch readme](https://github.com/textualize/rich/blob/master/README.de-ch.md)\n • [हिन्दी readme](https://github.com/textualize/rich/blob/master/README.hi.md)\n • [Português brasileiro readme](https://github.com/textualize/rich/blob/master/README.pt-br.md)\n • [Italian readme](https://github.com/textualize/rich/blob/master/README.it.md)\n • [Русский readme](https://github.com/textualize/rich/blob/master/README.ru.md)\n • [Indonesian readme](https://github.com/textualize/rich/blob/master/README.id.md)\n • [فارسی readme](https://github.com/textualize/rich/blob/master/README.fa.md)\n • [Türkçe readme](https://github.com/textualize/rich/blob/master/README.tr.md)\n • [Polskie readme](https://github.com/textualize/rich/blob/master/README.pl.md)\n\n\nRich is a Python library for _rich_ text and beautiful formatting in the terminal.\n\nThe [Rich API](https://rich.readthedocs.io/en/latest/) makes it easy to add color and style to terminal output. Rich can also render pretty tables, progress bars, markdown, syntax highlighted source code, tracebacks, and more — out of the box.\n\n![Features](https://github.com/textualize/rich/raw/master/imgs/features.png)\n\nFor a video introduction to Rich see [calmcode.io](https://calmcode.io/rich/introduction.html) by [@fishnets88](https://twitter.com/fishnets88).\n\nSee what [people are saying about Rich](https://www.willmcgugan.com/blog/pages/post/rich-tweets/).\n\n## Compatibility\n\nRich works with Linux, macOS and Windows. True color / emoji works with new Windows Terminal, classic terminal is limited to 16 colors. Rich requires Python 3.8 or later.\n\nRich works with [Jupyter notebooks](https://jupyter.org/) with no additional configuration required.\n\n## Installing\n\nInstall with `pip` or your favorite PyPI package manager.\n\n```sh\npython -m pip install rich\n```\n\nRun the following to test Rich output on your terminal:\n\n```sh\npython -m rich\n```\n\n## Rich Print\n\nTo effortlessly add rich output to your application, you can import the [rich print](https://rich.readthedocs.io/en/latest/introduction.html#quick-start) method, which has the same signature as the builtin Python function. Try this:\n\n```python\nfrom rich import print\n\nprint(\"Hello, [bold magenta]World[/bold magenta]!\", \":vampire:\", locals())\n```\n\n![Hello World](https://github.com/textualize/rich/raw/master/imgs/print.png)\n\n## Rich REPL\n\nRich can be installed in the Python REPL, so that any data structures will be pretty printed and highlighted.\n\n```python\n>>> from rich import pretty\n>>> pretty.install()\n```\n\n![REPL](https://github.com/textualize/rich/raw/master/imgs/repl.png)\n\n## Using the Console\n\nFor more control over rich terminal content, import and construct a [Console](https://rich.readthedocs.io/en/latest/reference/console.html#rich.console.Console) object.\n\n```python\nfrom rich.console import Console\n\nconsole = Console()\n```\n\nThe Console object has a `print` method which has an intentionally similar interface to the builtin `print` function. Here's an example of use:\n\n```python\nconsole.print(\"Hello\", \"World!\")\n```\n\nAs you might expect, this will print `\"Hello World!\"` to the terminal. Note that unlike the builtin `print` function, Rich will word-wrap your text to fit within the terminal width.\n\nThere are a few ways of adding color and style to your output. You can set a style for the entire output by adding a `style` keyword argument. Here's an example:\n\n```python\nconsole.print(\"Hello\", \"World!\", style=\"bold red\")\n```\n\nThe output will be something like the following:\n\n![Hello World](https://github.com/textualize/rich/raw/master/imgs/hello_world.png)\n\nThat's fine for styling a line of text at a time. For more finely grained styling, Rich renders a special markup which is similar in syntax to [bbcode](https://en.wikipedia.org/wiki/BBCode). Here's an example:\n\n```python\nconsole.print(\"Where there is a [bold cyan]Will[/bold cyan] there [u]is[/u] a [i]way[/i].\")\n```\n\n![Console Markup](https://github.com/textualize/rich/raw/master/imgs/where_there_is_a_will.png)\n\nYou can use a Console object to generate sophisticated output with minimal effort. See the [Console API](https://rich.readthedocs.io/en/latest/console.html) docs for details.\n\n## Rich Inspect\n\nRich has an [inspect](https://rich.readthedocs.io/en/latest/reference/init.html?highlight=inspect#rich.inspect) function which can produce a report on any Python object, such as class, instance, or builtin.\n\n```python\n>>> my_list = [\"foo\", \"bar\"]\n>>> from rich import inspect\n>>> inspect(my_list, methods=True)\n```\n\n![Log](https://github.com/textualize/rich/raw/master/imgs/inspect.png)\n\nSee the [inspect docs](https://rich.readthedocs.io/en/latest/reference/init.html#rich.inspect) for details.\n\n# Rich Library\n\nRich contains a number of builtin _renderables_ you can use to create elegant output in your CLI and help you debug your code.\n\nClick the following headings for details:\n\n<details>\n<summary>Log</summary>\n\nThe Console object has a `log()` method which has a similar interface to `print()`, but also renders a column for the current time and the file and line which made the call. By default Rich will do syntax highlighting for Python structures and for repr strings. If you log a collection (i.e. a dict or a list) Rich will pretty print it so that it fits in the available space. Here's an example of some of these features.\n\n```python\nfrom rich.console import Console\nconsole = Console()\n\ntest_data = [\n    {\"jsonrpc\": \"2.0\", \"method\": \"sum\", \"params\": [None, 1, 2, 4, False, True], \"id\": \"1\",},\n    {\"jsonrpc\": \"2.0\", \"method\": \"notify_hello\", \"params\": [7]},\n    {\"jsonrpc\": \"2.0\", \"method\": \"subtract\", \"params\": [42, 23], \"id\": \"2\"},\n]\n\ndef test_log():\n    enabled = False\n    context = {\n        \"foo\": \"bar\",\n    }\n    movies = [\"Deadpool\", \"Rise of the Skywalker\"]\n    console.log(\"Hello from\", console, \"!\")\n    console.log(test_data, log_locals=True)\n\n\ntest_log()\n```\n\nThe above produces the following output:\n\n![Log](https://github.com/textualize/rich/raw/master/imgs/log.png)\n\nNote the `log_locals` argument, which outputs a table containing the local variables where the log method was called.\n\nThe log method could be used for logging to the terminal for long running applications such as servers, but is also a very nice debugging aid.\n\n</details>\n<details>\n<summary>Logging Handler</summary>\n\nYou can also use the builtin [Handler class](https://rich.readthedocs.io/en/latest/logging.html) to format and colorize output from Python's logging module. Here's an example of the output:\n\n![Logging](https://github.com/textualize/rich/raw/master/imgs/logging.png)\n\n</details>\n\n<details>\n<summary>Emoji</summary>\n\nTo insert an emoji in to console output place the name between two colons. Here's an example:\n\n```python\n>>> console.print(\":smiley: :vampire: :pile_of_poo: :thumbs_up: :raccoon:\")\n😃 🧛 💩 👍 🦝\n```\n\nPlease use this feature wisely.\n\n</details>\n\n<details>\n<summary>Tables</summary>\n\nRich can render flexible [tables](https://rich.readthedocs.io/en/latest/tables.html) with unicode box characters. There is a large variety of formatting options for borders, styles, cell alignment etc.\n\n![table movie](https://github.com/textualize/rich/raw/master/imgs/table_movie.gif)\n\nThe animation above was generated with [table_movie.py](https://github.com/textualize/rich/blob/master/examples/table_movie.py) in the examples directory.\n\nHere's a simpler table example:\n\n```python\nfrom rich.console import Console\nfrom rich.table import Table\n\nconsole = Console()\n\ntable = Table(show_header=True, header_style=\"bold magenta\")\ntable.add_column(\"Date\", style=\"dim\", width=12)\ntable.add_column(\"Title\")\ntable.add_column(\"Production Budget\", justify=\"right\")\ntable.add_column(\"Box Office\", justify=\"right\")\ntable.add_row(\n    \"Dec 20, 2019\", \"Star Wars: The Rise of Skywalker\", \"$275,000,000\", \"$375,126,118\"\n)\ntable.add_row(\n    \"May 25, 2018\",\n    \"[red]Solo[/red]: A Star Wars Story\",\n    \"$275,000,000\",\n    \"$393,151,347\",\n)\ntable.add_row(\n    \"Dec 15, 2017\",\n    \"Star Wars Ep. VIII: The Last Jedi\",\n    \"$262,000,000\",\n    \"[bold]$1,332,539,889[/bold]\",\n)\n\nconsole.print(table)\n```\n\nThis produces the following output:\n\n![table](https://github.com/textualize/rich/raw/master/imgs/table.png)\n\nNote that console markup is rendered in the same way as `print()` and `log()`. In fact, anything that is renderable by Rich may be included in the headers / rows (even other tables).\n\nThe `Table` class is smart enough to resize columns to fit the available width of the terminal, wrapping text as required. Here's the same example, with the terminal made smaller than the table above:\n\n![table2](https://github.com/textualize/rich/raw/master/imgs/table2.png)\n\n</details>\n\n<details>\n<summary>Progress Bars</summary>\n\nRich can render multiple flicker-free [progress](https://rich.readthedocs.io/en/latest/progress.html) bars to track long-running tasks.\n\nFor basic usage, wrap any sequence in the `track` function and iterate over the result. Here's an example:\n\n```python\nfrom rich.progress import track\n\nfor step in track(range(100)):\n    do_step(step)\n```\n\nIt's not much harder to add multiple progress bars. Here's an example taken from the docs:\n\n![progress](https://github.com/textualize/rich/raw/master/imgs/progress.gif)\n\nThe columns may be configured to show any details you want. Built-in columns include percentage complete, file size, file speed, and time remaining. Here's another example showing a download in progress:\n\n![progress](https://github.com/textualize/rich/raw/master/imgs/downloader.gif)\n\nTo try this out yourself, see [examples/downloader.py](https://github.com/textualize/rich/blob/master/examples/downloader.py) which can download multiple URLs simultaneously while displaying progress.\n\n</details>\n\n<details>\n<summary>Status</summary>\n\nFor situations where it is hard to calculate progress, you can use the [status](https://rich.readthedocs.io/en/latest/reference/console.html#rich.console.Console.status) method which will display a 'spinner' animation and message. The animation won't prevent you from using the console as normal. Here's an example:\n\n```python\nfrom time import sleep\nfrom rich.console import Console\n\nconsole = Console()\ntasks = [f\"task {n}\" for n in range(1, 11)]\n\nwith console.status(\"[bold green]Working on tasks...\") as status:\n    while tasks:\n        task = tasks.pop(0)\n        sleep(1)\n        console.log(f\"{task} complete\")\n```\n\nThis generates the following output in the terminal.\n\n![status](https://github.com/textualize/rich/raw/master/imgs/status.gif)\n\nThe spinner animations were borrowed from [cli-spinners](https://www.npmjs.com/package/cli-spinners). You can select a spinner by specifying the `spinner` parameter. Run the following command to see the available values:\n\n```\npython -m rich.spinner\n```\n\nThe above command generates the following output in the terminal:\n\n![spinners](https://github.com/textualize/rich/raw/master/imgs/spinners.gif)\n\n</details>\n\n<details>\n<summary>Tree</summary>\n\nRich can render a [tree](https://rich.readthedocs.io/en/latest/tree.html) with guide lines. A tree is ideal for displaying a file structure, or any other hierarchical data.\n\nThe labels of the tree can be simple text or anything else Rich can render. Run the following for a demonstration:\n\n```\npython -m rich.tree\n```\n\nThis generates the following output:\n\n![markdown](https://github.com/textualize/rich/raw/master/imgs/tree.png)\n\nSee the [tree.py](https://github.com/textualize/rich/blob/master/examples/tree.py) example for a script that displays a tree view of any directory, similar to the linux `tree` command.\n\n</details>\n\n<details>\n<summary>Columns</summary>\n\nRich can render content in neat [columns](https://rich.readthedocs.io/en/latest/columns.html) with equal or optimal width. Here's a very basic clone of the (MacOS / Linux) `ls` command which displays a directory listing in columns:\n\n```python\nimport os\nimport sys\n\nfrom rich import print\nfrom rich.columns import Columns\n\ndirectory = os.listdir(sys.argv[1])\nprint(Columns(directory))\n```\n\nThe following screenshot is the output from the [columns example](https://github.com/textualize/rich/blob/master/examples/columns.py) which displays data pulled from an API in columns:\n\n![columns](https://github.com/textualize/rich/raw/master/imgs/columns.png)\n\n</details>\n\n<details>\n<summary>Markdown</summary>\n\nRich can render [markdown](https://rich.readthedocs.io/en/latest/markdown.html) and does a reasonable job of translating the formatting to the terminal.\n\nTo render markdown import the `Markdown` class and construct it with a string containing markdown code. Then print it to the console. Here's an example:\n\n```python\nfrom rich.console import Console\nfrom rich.markdown import Markdown\n\nconsole = Console()\nwith open(\"README.md\") as readme:\n    markdown = Markdown(readme.read())\nconsole.print(markdown)\n```\n\nThis will produce output something like the following:\n\n![markdown](https://github.com/textualize/rich/raw/master/imgs/markdown.png)\n\n</details>\n\n<details>\n<summary>Syntax Highlighting</summary>\n\nRich uses the [pygments](https://pygments.org/) library to implement [syntax highlighting](https://rich.readthedocs.io/en/latest/syntax.html). Usage is similar to rendering markdown; construct a `Syntax` object and print it to the console. Here's an example:\n\n```python\nfrom rich.console import Console\nfrom rich.syntax import Syntax\n\nmy_code = '''\ndef iter_first_last(values: Iterable[T]) -> Iterable[Tuple[bool, bool, T]]:\n    \"\"\"Iterate and generate a tuple with a flag for first and last value.\"\"\"\n    iter_values = iter(values)\n    try:\n        previous_value = next(iter_values)\n    except StopIteration:\n        return\n    first = True\n    for value in iter_values:\n        yield first, False, previous_value\n        first = False\n        previous_value = value\n    yield first, True, previous_value\n'''\nsyntax = Syntax(my_code, \"python\", theme=\"monokai\", line_numbers=True)\nconsole = Console()\nconsole.print(syntax)\n```\n\nThis will produce the following output:\n\n![syntax](https://github.com/textualize/rich/raw/master/imgs/syntax.png)\n\n</details>\n\n<details>\n<summary>Tracebacks</summary>\n\nRich can render [beautiful tracebacks](https://rich.readthedocs.io/en/latest/traceback.html) which are easier to read and show more code than standard Python tracebacks. You can set Rich as the default traceback handler so all uncaught exceptions will be rendered by Rich.\n\nHere's what it looks like on OSX (similar on Linux):\n\n![traceback](https://github.com/textualize/rich/raw/master/imgs/traceback.png)\n\n</details>\n\nAll Rich renderables make use of the [Console Protocol](https://rich.readthedocs.io/en/latest/protocol.html), which you can also use to implement your own Rich content.\n\n# Rich CLI\n\n\nSee also [Rich CLI](https://github.com/textualize/rich-cli) for a command line application powered by Rich. Syntax highlight code, render markdown, display CSVs in tables, and more, directly from the command prompt.\n\n\n![Rich CLI](https://raw.githubusercontent.com/Textualize/rich-cli/main/imgs/rich-cli-splash.jpg)\n\n# Textual\n\nSee also Rich's sister project, [Textual](https://github.com/Textualize/textual), which you can use to build sophisticated User Interfaces in the terminal.\n\n![textual-splash](https://github.com/user-attachments/assets/4caeb77e-48c0-4cf7-b14d-c53ded855ffd)\n\n# Toad\n\n[Toad](https://github.com/batrachianai/toad) is a unified interface for agentic coding. Built with Rich and Textual.\n\n![toad](https://github.com/user-attachments/assets/6678b707-1aeb-420f-99ad-abfcd4356771)\n\n",
        "description_content_type": "text/markdown",
        "author": "Will McGugan",
        "author_email": "willmcgugan@gmail.com",
        "license": "MIT",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Environment :: Console",
          "Framework :: IPython",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: MIT License",
          "Operating System :: MacOS",
          "Operating System :: Microsoft :: Windows",
          "Operating System :: POSIX :: Linux",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Typing :: Typed"
        ],
        "requires_dist": [
          "ipywidgets (>=7.5.1,<9) ; extra == \"jupyter\"",
          "markdown-it-py (>=2.2.0)",
          "pygments (>=2.13.0,<3.0.0)"
        ],
        "requires_python": ">=3.9.0",
        "project_url": [
          "Documentation, https://rich.readthedocs.io/en/latest/",
          "Homepage, https://github.com/Textualize/rich"
        ],
        "provides_extra": [
          "jupyter"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/dc/bf/205d0004930ede8f542fb58f601526fccf4ae7626075ca1e6c4de5d3d652/typer-0.27.2-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=b3a5fc4342d5fc8fda8fc3010b1cf117e9249aab7fae800c2eff62fd3842d97d",
          "hashes": {
            "sha256": "b3a5fc4342d5fc8fda8fc3010b1cf117e9249aab7fae800c2eff62fd3842d97d"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "typer",
        "version": "0.27.2",
        "summary": "Typer, build great CLIs. Easy to code. Based on Python type hints.",
        "description": "<p align=\"center\">\n  <a href=\"https://typer.tiangolo.com\"><img src=\"https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg#only-light\" alt=\"Typer\"></a>\n\n</p>\n<p align=\"center\">\n    <em>Typer, build great CLIs. Easy to code. Based on Python type hints.</em>\n</p>\n<p align=\"center\">\n<a href=\"https://github.com/fastapi/typer/actions?query=workflow%3ATest+event%3Apush+branch%3Amaster\">\n    <img src=\"https://github.com/fastapi/typer/actions/workflows/test.yml/badge.svg?event=push&branch=master\" alt=\"Test\">\n</a>\n<a href=\"https://coverage-badge.samuelcolvin.workers.dev/redirect/fastapi/typer\">\n    <img src=\"https://coverage-badge.samuelcolvin.workers.dev/fastapi/typer.svg\" alt=\"Coverage\">\n<a href=\"https://pypi.org/project/typer\">\n    <img src=\"https://img.shields.io/pypi/v/typer?color=%2334D058&label=pypi%20package\" alt=\"Package version\">\n</a>\n</p>\n\n---\n\n**Documentation**: [https://typer.tiangolo.com](https://typer.tiangolo.com)\n\n**Source Code**: [https://github.com/fastapi/typer](https://github.com/fastapi/typer)\n\n---\n\nTyper is a library for building <abbr title=\"command line interface, programs executed from a terminal\">CLI</abbr> applications that users will **love using** and developers will **love creating**. Based on Python type hints.\n\nIt's also a command line tool to run scripts, automatically converting them to CLI applications.\n\nThe key features are:\n\n* **Intuitive to write**: Great editor support. <abbr title=\"also known as auto-complete, autocompletion, IntelliSense\">Completion</abbr> everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.\n* **Easy to use**: It's easy to use for the final users. Automatic help, and automatic completion for all shells.\n* **Short**: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.\n* **Start simple**: The simplest example adds only 2 lines of code to your app: **1 import, 1 function call**.\n* **Grow large**: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.\n* **Run scripts**: Typer includes a `typer` command/program that you can use to run scripts, automatically converting them to CLIs, even if they don't use Typer internally.\n\n## FastAPI of CLIs\n\n**Typer** is [FastAPI](https://fastapi.tiangolo.com)'s little sibling, it's the FastAPI of CLIs.\n\n## Installation\n\nFirst, [install `uv`](https://docs.astral.sh/uv/getting-started/installation/), and then add **Typer** to your project:\n\n<div class=\"termy\">\n\n```console\n$ uv add typer\n---> 100%\n```\n\n</div>\n\nThis installs both the Typer library and the `typer` command in the project's virtual environment. To use `typer` directly with shell completion, [activate the project environment and install completion](tutorial/install.md#activate-the-virtual-environment).\n\nIf you prefer to use `pip`, install `typer` inside a virtual environment. See the [installation guide](tutorial/install.md) for the alternative steps.\n\n## Example\n\n### The absolute minimum\n\n* Create a file `main.py` with:\n\n```Python\ndef main(name: str):\n    print(f\"Hello {name}\")\n```\n\nThis script doesn't even use Typer internally. But you can use the `typer` command to run it as a CLI application.\n\n### Run it\n\nRun your application with the `typer` command:\n\n<div class=\"termy\">\n\n```console\n// Run your application\n$ typer main.py run\n\n// You get a nice error, you are missing 'name'\nUsage: typer [PATH_OR_MODULE] run [OPTIONS] {name}\nTry 'typer [PATH_OR_MODULE] run --help' for help.\n╭─ Error ───────────────────────────────────────────╮\n│ Missing argument 'name'.                          │\n╰───────────────────────────────────────────────────╯\n\n\n// You get a --help for free\n$ typer main.py run --help\n\nUsage: typer [PATH_OR_MODULE] run [OPTIONS] {name}\n\nRun the provided Typer app.\n\n╭─ Arguments ───────────────────────────────────────╮\n│ *    name      <str>  [required]                  │\n╰───────────────────────────────────────────────────╯\n╭─ Options ─────────────────────────────────────────╮\n│ --help          Show this message and exit.       │\n╰───────────────────────────────────────────────────╯\n\n// Now pass the 'name' argument\n$ typer main.py run Camila\n\nHello Camila\n\n// It works! 🎉\n```\n\n</div>\n\nThis is the simplest use case, not even using Typer internally, but it can already be quite useful for simple scripts.\n\n**Note**: auto-completion works when you create a Python package and run it with `--install-completion` or when you use the `typer` command.\n\n## Use Typer in your code\n\nNow let's start using Typer in your own code, update `main.py` with:\n\n```Python\nimport typer\n\n\ndef main(name: str):\n    print(f\"Hello {name}\")\n\n\nif __name__ == \"__main__\":\n    typer.run(main)\n```\n\nNow you could run it with Python directly:\n\n<div class=\"termy\">\n\n```console\n// Run your application\n$ uv run python main.py\n\n// You get a nice error, you are missing 'name'\nUsage: main.py [OPTIONS] {name}\nTry 'main.py --help' for help.\n╭─ Error ───────────────────────────────────────────╮\n│ Missing argument 'name'.                          │\n╰───────────────────────────────────────────────────╯\n\n\n// You get a --help for free\n$ uv run python main.py --help\n\nUsage: main.py [OPTIONS] {name}\n\n╭─ Arguments ───────────────────────────────────────╮\n│ *    name      <str>  [required]                  │\n╰───────────────────────────────────────────────────╯\n╭─ Options ─────────────────────────────────────────╮\n│ --help          Show this message and exit.       │\n╰───────────────────────────────────────────────────╯\n\n// Now pass the 'name' argument\n$ uv run python main.py Camila\n\nHello Camila\n\n// It works! 🎉\n```\n\n</div>\n\n**Note**: you can also call this same script with the `typer` command, but you don't need to.\n\n## Example upgrade\n\nThis was the simplest example possible.\n\nNow let's see one a bit more complex.\n\n### An example with two subcommands\n\nModify the file `main.py`.\n\nCreate a `typer.Typer()` app, and create two subcommands with their parameters.\n\n```Python hl_lines=\"3  6  11  20\"\nimport typer\n\napp = typer.Typer()\n\n\n@app.command()\ndef hello(name: str):\n    print(f\"Hello {name}\")\n\n\n@app.command()\ndef goodbye(name: str, formal: bool = False):\n    if formal:\n        print(f\"Goodbye Ms. {name}. Have a good day.\")\n    else:\n        print(f\"Bye {name}!\")\n\n\nif __name__ == \"__main__\":\n    app()\n```\n\nAnd that will:\n\n* Explicitly create a `typer.Typer` app.\n    * The previous `typer.run` actually creates one implicitly for you.\n* Add two subcommands with `@app.command()`.\n* Execute the `app()` itself, as if it was a function (instead of `typer.run`).\n\n### Run the upgraded example\n\nCheck the new help:\n\n<div class=\"termy\">\n\n```console\n$ uv run python main.py --help\n\n Usage: main.py [OPTIONS] COMMAND [ARGS]...\n\n╭─ Options ─────────────────────────────────────────╮\n│ --install-completion          Install completion  │\n│                               for the current     │\n│                               shell.              │\n│ --show-completion             Show completion for │\n│                               the current shell,  │\n│                               to copy it or       │\n│                               customize the       │\n│                               installation.       │\n│ --help                        Show this message   │\n│                               and exit.           │\n╰───────────────────────────────────────────────────╯\n╭─ Commands ────────────────────────────────────────╮\n│ hello                                             │\n│ goodbye                                           │\n╰───────────────────────────────────────────────────╯\n\n// When you create a package you get ✨ auto-completion ✨ for free, installed with --install-completion\n\n// You have 2 subcommands (the 2 functions): hello and goodbye\n```\n\n</div>\n\nNow check the help for the `hello` command:\n\n<div class=\"termy\">\n\n```console\n$ uv run python main.py hello --help\n\n Usage: main.py hello [OPTIONS] {name}\n\n╭─ Arguments ───────────────────────────────────────╮\n│ *    name      <str>  [required]                  │\n╰───────────────────────────────────────────────────╯\n╭─ Options ─────────────────────────────────────────╮\n│ --help          Show this message and exit.       │\n╰───────────────────────────────────────────────────╯\n```\n\n</div>\n\nAnd now check the help for the `goodbye` command:\n\n<div class=\"termy\">\n\n```console\n$ uv run python main.py goodbye --help\n\n Usage: main.py goodbye [OPTIONS] {name}\n\n╭─ Arguments ───────────────────────────────────────╮\n│ *    name      <str>  [required]                  │\n╰───────────────────────────────────────────────────╯\n╭─ Options ─────────────────────────────────────────╮\n│ --formal    --no-formal      [default: no-formal] │\n│ --help                       Show this message    │\n│                              and exit.            │\n╰───────────────────────────────────────────────────╯\n\n// Automatic --formal and --no-formal for the bool option 🎉\n```\n\n</div>\n\nNow you can try out the new command line application:\n\n<div class=\"termy\">\n\n```console\n// Use it with the hello command\n\n$ uv run python main.py hello Camila\n\nHello Camila\n\n// And with the goodbye command\n\n$ uv run python main.py goodbye Camila\n\nBye Camila!\n\n// And with --formal\n\n$ uv run python main.py goodbye --formal Camila\n\nGoodbye Ms. Camila. Have a good day.\n```\n\n</div>\n\n**Note**: If your app only has one command, by default the command name is **omitted** in usage: `python main.py Camila`. However, when there are multiple commands, you must **explicitly include the command name**: `python main.py hello Camila`. See [One or Multiple Commands](https://typer.tiangolo.com/tutorial/commands/one-or-multiple/) for more details.\n\n### Recap\n\nIn summary, you declare **once** the types of parameters (*CLI arguments* and *CLI options*) as function parameters.\n\nYou do that with standard modern Python types.\n\nYou don't have to learn a new syntax, the methods or classes of a specific library, etc.\n\nJust standard **Python**.\n\nFor example, for an `int`:\n\n```Python\ntotal: int\n```\n\nor for a `bool` flag:\n\n```Python\nforce: bool\n```\n\nAnd similarly for **files**, **paths**, **enums** (choices), etc. And there are tools to create **groups of subcommands**, add metadata, extra **validation**, etc.\n\n**You get**: great editor support, including **completion** and **type checks** everywhere.\n\n**Your users get**: automatic **`--help`**, **auto-completion** in their terminal (Bash, Zsh, Fish, PowerShell) when they install your package or when using the `typer` command.\n\nFor a more complete example including more features, see the <a href=\"https://typer.tiangolo.com/tutorial/\">Tutorial - User Guide</a>.\n\n## Dependencies\n\n**Typer** requires only a few dependencies (most are tiny):\n\n* [`rich`](https://rich.readthedocs.io/en/stable/index.html): to show nicely formatted errors automatically.\n* [`shellingham`](https://github.com/sarugaku/shellingham): to automatically detect the current shell when installing completion.\n* [`annotated-doc`](https://github.com/fastapi/annotated-doc): to generate documentation from Python type annotations.\n* [`colorama`](https://github.com/tartley/colorama) (only on Windows): for producing colored terminal text on Windows.\n\n### Click code\n\nTyper used to depend on [Click](https://click.palletsprojects.com/) as well, a popular tool for building CLIs in Python.\n\nSince version 0.26.0, Typer has vendored Click (included Click's source code internally, instead of installing it as a third party package) and has unified the code interactions between Typer and the embedded Click source code for easier maintainability in the future.\n\nNote that some Click functionality will not be available anymore in the future, as we continue to improve and extend Typer's codebase.\n\n### `typer-slim`\n\nThere used to be a slimmed-down version of Typer called `typer-slim`, which didn't include the dependencies `rich` and `shellingham`, nor the `typer` command.\n\nHowever, since version 0.22.0, we have stopped supporting this, and `typer-slim` now simply installs (all of) Typer.\n\nIf you want to disable Rich globally, you can set an environmental variable `TYPER_USE_RICH` to `False` or `0`.\n\n## License\n\nThis project is licensed under the terms of the MIT license.\n",
        "description_content_type": "text/markdown",
        "author_email": "=?utf-8?q?Sebasti=C3=A1n_Ram=C3=ADrez?= <tiangolo@gmail.com>",
        "classifier": [
          "Intended Audience :: Information Technology",
          "Intended Audience :: System Administrators",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python",
          "Topic :: Software Development :: Libraries :: Application Frameworks",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Topic :: Software Development :: Libraries",
          "Topic :: Software Development",
          "Typing :: Typed",
          "Development Status :: 4 - Beta",
          "Intended Audience :: Developers",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14"
        ],
        "requires_dist": [
          "shellingham>=1.3.0",
          "rich>=13.8.0",
          "annotated-doc>=0.0.2",
          "colorama; platform_system == \"Windows\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Homepage, https://github.com/fastapi/typer",
          "Documentation, https://typer.tiangolo.com",
          "Repository, https://github.com/fastapi/typer",
          "Issues, https://github.com/fastapi/typer/issues",
          "Changelog, https://typer.tiangolo.com/release-notes/"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl",
        "archive_info": {
          "hash": "sha256=4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1",
          "hashes": {
            "sha256": "4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "contourpy",
        "version": "1.3.3",
        "summary": "Python library for calculating contours of 2D quadrilateral grids",
        "description": "<img alt=\"ContourPy\" src=\"https://raw.githubusercontent.com/contourpy/contourpy/main/docs/_static/contourpy_logo_horiz.svg\" height=\"90\">\n\nContourPy is a Python library for calculating contours of 2D quadrilateral grids.  It is written in C++11 and wrapped using pybind11.\n\nIt contains the 2005 and 2014 algorithms used in Matplotlib as well as a newer algorithm that includes more features and is available in both serial and multithreaded versions.  It provides an easy way for Python libraries to use contouring algorithms without having to include Matplotlib as a dependency.\n\n  * **Documentation**: https://contourpy.readthedocs.io\n  * **Source code**: https://github.com/contourpy/contourpy\n\n| | |\n| --- | --- |\n| Latest release | [![PyPI version](https://img.shields.io/pypi/v/contourpy.svg?label=pypi&color=fdae61)](https://pypi.python.org/pypi/contourpy) [![conda-forge version](https://img.shields.io/conda/v/conda-forge/contourpy.svg?label=conda-forge&color=a6d96a)](https://anaconda.org/conda-forge/contourpy) |\n| Downloads | [![PyPi downloads](https://img.shields.io/pypi/dm/contourpy?label=pypi&style=flat&color=fdae61)](https://pepy.tech/project/contourpy) |\n| Python version | [![Platforms](https://img.shields.io/pypi/pyversions/contourpy?color=fdae61)](https://pypi.org/project/contourpy/) |\n| Coverage | [![Codecov](https://img.shields.io/codecov/c/gh/contourpy/contourpy?color=fdae61&label=codecov)](https://app.codecov.io/gh/contourpy/contourpy) |\n",
        "description_content_type": "text/markdown",
        "author_email": "Ian Thomas <ianthomas23@gmail.com>",
        "license": "BSD 3-Clause License\n\n Copyright (c) 2021-2025, ContourPy Developers.\n All rights reserved.\n\n Redistribution and use in source and binary forms, with or without\n modification, are permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice, this\n    list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright notice,\n    this list of conditions and the following disclaimer in the documentation\n    and/or other materials provided with the distribution.\n\n 3. Neither the name of the copyright holder nor the names of its\n    contributors may be used to endorse or promote products derived from\n    this software without specific prior written permission.\n\n THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\n FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Intended Audience :: Science/Research",
          "License :: OSI Approved :: BSD License",
          "Programming Language :: C++",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Topic :: Scientific/Engineering :: Information Analysis",
          "Topic :: Scientific/Engineering :: Mathematics",
          "Topic :: Scientific/Engineering :: Visualization"
        ],
        "requires_dist": [
          "numpy>=1.25",
          "furo; extra == \"docs\"",
          "sphinx>=7.2; extra == \"docs\"",
          "sphinx-copybutton; extra == \"docs\"",
          "bokeh; extra == \"bokeh\"",
          "selenium; extra == \"bokeh\"",
          "contourpy[bokeh,docs]; extra == \"mypy\"",
          "bokeh; extra == \"mypy\"",
          "docutils-stubs; extra == \"mypy\"",
          "mypy==1.17.0; extra == \"mypy\"",
          "types-Pillow; extra == \"mypy\"",
          "contourpy[test-no-images]; extra == \"test\"",
          "matplotlib; extra == \"test\"",
          "Pillow; extra == \"test\"",
          "pytest; extra == \"test-no-images\"",
          "pytest-cov; extra == \"test-no-images\"",
          "pytest-rerunfailures; extra == \"test-no-images\"",
          "pytest-xdist; extra == \"test-no-images\"",
          "wurlitzer; extra == \"test-no-images\""
        ],
        "requires_python": ">=3.11",
        "project_url": [
          "Homepage, https://github.com/contourpy/contourpy",
          "Changelog, https://contourpy.readthedocs.io/en/latest/changelog.html",
          "Documentation, https://contourpy.readthedocs.io",
          "Repository, https://github.com/contourpy/contourpy"
        ],
        "provides_extra": [
          "docs",
          "bokeh",
          "mypy",
          "test",
          "test-no-images"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30",
          "hashes": {
            "sha256": "85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "cycler",
        "version": "0.12.1",
        "summary": "Composable style cycles",
        "description": "|PyPi|_ |Conda|_ |Supported Python versions|_ |GitHub Actions|_ |Codecov|_\n\n.. |PyPi| image:: https://img.shields.io/pypi/v/cycler.svg?style=flat\n.. _PyPi: https://pypi.python.org/pypi/cycler\n\n.. |Conda| image:: https://img.shields.io/conda/v/conda-forge/cycler\n.. _Conda:  https://anaconda.org/conda-forge/cycler\n\n.. |Supported Python versions| image:: https://img.shields.io/pypi/pyversions/cycler.svg\n.. _Supported Python versions: https://pypi.python.org/pypi/cycler\n\n.. |GitHub Actions| image:: https://github.com/matplotlib/cycler/actions/workflows/tests.yml/badge.svg\n.. _GitHub Actions: https://github.com/matplotlib/cycler/actions\n\n.. |Codecov| image:: https://codecov.io/github/matplotlib/cycler/badge.svg?branch=main&service=github\n.. _Codecov: https://codecov.io/github/matplotlib/cycler?branch=main\n\ncycler: composable cycles\n=========================\n\nDocs: https://matplotlib.org/cycler/\n",
        "description_content_type": "text/x-rst",
        "keywords": [
          "cycle",
          "kwargs"
        ],
        "author_email": "Thomas A Caswell <matplotlib-users@python.org>",
        "license": "Copyright (c) 2015, matplotlib project\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of the matplotlib project nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.",
        "classifier": [
          "License :: OSI Approved :: BSD License",
          "Development Status :: 4 - Beta",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.8",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3 :: Only"
        ],
        "requires_dist": [
          "ipython ; extra == 'docs'",
          "matplotlib ; extra == 'docs'",
          "numpydoc ; extra == 'docs'",
          "sphinx ; extra == 'docs'",
          "pytest ; extra == 'tests'",
          "pytest-cov ; extra == 'tests'",
          "pytest-xdist ; extra == 'tests'"
        ],
        "requires_python": ">=3.8",
        "project_url": [
          "homepage, https://matplotlib.org/cycler/",
          "repository, https://github.com/matplotlib/cycler"
        ],
        "provides_extra": [
          "docs",
          "tests"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/dc/8f/e5f2906ea833d362916c64a2f6b1922a07b19442744fd3cd89563f429bff/fonttools-4.64.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl",
        "archive_info": {
          "hash": "sha256=66a83f93579fb3493e458c4449d1d566a7b2a1c7b19915cd0fa3c9b8b5a8540b",
          "hashes": {
            "sha256": "66a83f93579fb3493e458c4449d1d566a7b2a1c7b19915cd0fa3c9b8b5a8540b"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "fonttools",
        "version": "4.64.0",
        "dynamic": [
          "author",
          "author-email",
          "classifier",
          "description",
          "description-content-type",
          "home-page",
          "license",
          "license-file",
          "maintainer",
          "maintainer-email",
          "platform",
          "provides-extra",
          "requires-python",
          "summary"
        ],
        "platform": [
          "Any"
        ],
        "summary": "Tools to manipulate font files",
        "description": "|CI Build Status| |Coverage Status| |PyPI| |Gitter Chat|\n\nWhat is this?\n~~~~~~~~~~~~~\n\n| fontTools is a library for manipulating fonts, written in Python. The\n  project includes the TTX tool, that can convert TrueType and OpenType\n  fonts to and from an XML text format, which is also called TTX. It\n  supports TrueType, OpenType, AFM and to an extent Type 1 and some\n  Mac-specific formats. The project has an `MIT open-source\n  license <LICENSE>`__.\n| Among other things this means you can use it free of charge.\n\n`User documentation <https://fonttools.readthedocs.io/en/latest/>`_ and\n`developer documentation <https://fonttools.readthedocs.io/en/latest/developer.html>`_\nare available at `Read the Docs <https://fonttools.readthedocs.io/>`_.\n\nInstallation\n~~~~~~~~~~~~\n\nFontTools requires `Python <http://www.python.org/download/>`__ 3.10\nor later. We try to follow the same schedule of minimum Python version support as\nNumPy (see `NEP 29 <https://numpy.org/neps/nep-0029-deprecation_policy.html>`__).\n\nThe package is listed in the Python Package Index (PyPI), so you can\ninstall it with `pip <https://pip.pypa.io>`__:\n\n.. code:: sh\n\n    pip install fonttools\n\nIf you would like to contribute to its development, you can clone the\nrepository from GitHub, install the package in 'editable' mode and\nmodify the source code in place. We recommend creating a virtual\nenvironment, using `virtualenv <https://virtualenv.pypa.io>`__ or\nPython 3 `venv <https://docs.python.org/3/library/venv.html>`__ module.\n\n.. code:: sh\n\n    # download the source code to 'fonttools' folder\n    git clone https://github.com/fonttools/fonttools.git\n    cd fonttools\n\n    # create new virtual environment called e.g. 'fonttools-venv', or anything you like\n    python -m virtualenv fonttools-venv\n\n    # source the `activate` shell script to enter the environment (Unix-like); to exit, just type `deactivate`\n    . fonttools-venv/bin/activate\n\n    # to activate the virtual environment in Windows `cmd.exe`, do\n    fonttools-venv\\Scripts\\activate.bat\n\n    # install in 'editable' mode\n    pip install -e .\n\nOptional Requirements\n---------------------\n\nThe ``fontTools`` package currently has no (required) external dependencies\nbesides the modules included in the Python Standard Library.\nHowever, a few extra dependencies are required by some of its modules, which\nare needed to unlock optional features.\nThe ``fonttools`` PyPI distribution also supports so-called \"extras\", i.e. a\nset of keywords that describe a group of additional dependencies, which can be\nused when installing via pip, or when specifying a requirement.\nFor example:\n\n.. code:: sh\n\n    pip install fonttools[ufo,lxml,woff,unicode]\n\nThis command will install fonttools, as well as the optional dependencies that\nare required to unlock the extra features named \"ufo\", etc.\n\n- ``Lib/fontTools/misc/etree.py``\n\n  The module exports a ElementTree-like API for reading/writing XML files, and\n  allows to use as the backend either the built-in ``xml.etree`` module or\n  `lxml <https://lxml.de>`__. The latter is preferred whenever present,\n  as it is generally faster and more secure.\n\n  *Extra:* ``lxml``\n\n- ``Lib/fontTools/ttLib/woff2.py``\n\n  Module to compress/decompress WOFF 2.0 web fonts; it requires:\n\n  * `brotli <https://pypi.python.org/pypi/Brotli>`__: Python bindings of\n    the Brotli compression library.\n\n  *Extra:* ``woff``\n\n- ``Lib/fontTools/ttLib/sfnt.py``\n\n  To better compress WOFF 1.0 web fonts, the following module can be used\n  instead of the built-in ``zlib`` library:\n\n  * `zopfli <https://pypi.python.org/pypi/zopfli>`__: Python bindings of\n    the Zopfli compression library.\n\n  *Extra:* ``woff``\n\n- ``Lib/fontTools/unicode.py``\n\n  To display the Unicode character names when dumping the ``cmap`` table\n  with ``ttx`` we use the ``unicodedata`` module in the Standard Library.\n  The version included in there varies between different Python versions.\n  To use the latest available data, you can install:\n\n  * `unicodedata2 <https://pypi.python.org/pypi/unicodedata2>`__:\n    ``unicodedata`` backport for Python 3.x updated to the latest Unicode\n    version 17.0.\n\n  *Extra:* ``unicode``\n\n- ``Lib/fontTools/varLib/interpolatable.py``\n\n  Module for finding wrong contour/component order between different masters.\n  It requires one of the following packages in order to solve the so-called\n  \"minimum weight perfect matching problem in bipartite graphs\", or\n  the Assignment problem:\n\n  * `scipy <https://pypi.python.org/pypi/scipy>`__: the Scientific Library\n    for Python, which internally uses `NumPy <https://pypi.python.org/pypi/numpy>`__\n    arrays and hence is very fast;\n  * `munkres <https://pypi.python.org/pypi/munkres>`__: a pure-Python\n    module that implements the Hungarian or Kuhn-Munkres algorithm. Slower than\n    SciPy, but useful for minimalistic systems where adding SciPy is undesirable.\n\n  This ensures both performance (via SciPy) and minimal footprint (via Munkres)\n  are possible.\n\n  To plot the results to a PDF or HTML format, you also need to install:\n\n  * `pycairo <https://pypi.org/project/pycairo/>`__: Python bindings for the\n    Cairo graphics library. Note that wheels are currently only available for\n    Windows, for other platforms see pycairo's `installation instructions\n    <https://pycairo.readthedocs.io/en/latest/getting_started.html>`__.\n\n  *Extra:* ``interpolatable``\n\n- ``Lib/fontTools/varLib/plot.py``\n\n  Module for visualizing DesignSpaceDocument and resulting VariationModel.\n\n  * `matplotlib <https://pypi.org/pypi/matplotlib>`__: 2D plotting library.\n\n  *Extra:* ``plot``\n\n- ``Lib/fontTools/misc/symfont.py``\n\n  Advanced module for symbolic font statistics analysis; it requires:\n\n  * `sympy <https://pypi.python.org/pypi/sympy>`__: the Python library for\n    symbolic mathematics.\n\n  *Extra:* ``symfont``\n\n- ``Lib/fontTools/t1Lib.py``\n\n  To get the file creator and type of Macintosh PostScript Type 1 fonts\n  on Python 3 you need to install the following module, as the old ``MacOS``\n  module is no longer included in Mac Python:\n\n  * `xattr <https://pypi.python.org/pypi/xattr>`__: Python wrapper for\n    extended filesystem attributes (macOS platform only).\n\n  *Extra:* ``type1``\n\n- ``Lib/fontTools/ttLib/removeOverlaps.py``\n\n  Simplify TrueType glyphs by merging overlapping contours and components.\n\n  * `skia-pathops <https://pypi.python.org/pypi/skia-pathops>`__: Python\n    bindings for the Skia library's PathOps module, performing boolean\n    operations on paths (union, intersection, etc.).\n\n  *Extra:* ``pathops``\n\n- ``Lib/fontTools/ufoLib``\n\n  Package for reading and writing UFO source files; if available, it will use:\n\n  * `fs <https://pypi.org/pypi/fs>`__: (aka ``pyfilesystem2``) filesystem abstraction layer\n\n  for reading and writing UFOs to the local filesystem or zip files (.ufoz), instead of\n  the built-in ``fontTools.misc.filesystem`` package.\n  The reader and writer classes can in theory also accept any object compatible the\n  ``fs.base.FS`` interface, although not all have been tested.\n\n- ``Lib/fontTools/pens/cocoaPen.py`` and ``Lib/fontTools/pens/quartzPen.py``\n\n  Pens for drawing glyphs with Cocoa ``NSBezierPath`` or ``CGPath`` require:\n\n  * `PyObjC <https://pypi.python.org/pypi/pyobjc>`__: the bridge between\n    Python and the Objective-C runtime (macOS platform only).\n\n- ``Lib/fontTools/pens/qtPen.py``\n\n  Pen for drawing glyphs with Qt's ``QPainterPath``, requires:\n\n  * `PyQt5 <https://pypi.python.org/pypi/PyQt5>`__: Python bindings for\n    the Qt cross platform UI and application toolkit.\n\n- ``Lib/fontTools/pens/reportLabPen.py``\n\n  Pen to drawing glyphs as PNG images, requires:\n\n  * `reportlab <https://pypi.python.org/pypi/reportlab>`__: Python toolkit\n    for generating PDFs and graphics.\n\n- ``Lib/fontTools/pens/freetypePen.py``\n\n  Pen to drawing glyphs with FreeType as raster images, requires:\n\n  * `freetype-py <https://pypi.python.org/pypi/freetype-py>`__: Python binding\n    for the FreeType library.\n    \n- ``Lib/fontTools/ttLib/tables/otBase.py``\n\n  Use the Harfbuzz library to serialize GPOS/GSUB using ``hb_repack`` method, requires:\n  \n  * `uharfbuzz <https://pypi.python.org/pypi/uharfbuzz>`__: Streamlined Cython\n    bindings for the harfbuzz shaping engine\n    \n  *Extra:* ``repacker``\n\nHow to make a new release\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\n1) Update ``NEWS.rst`` with all the changes since the last release. Write a\n   changelog entry for each PR, with one or two short sentences summarizing it,\n   as well as links to the PR and relevant issues addressed by the PR. Do not\n   put a new title, the next command will do it for you.\n2) Use semantic versioning to decide whether the new release will be a 'major',\n   'minor' or 'patch' release. It's usually one of the latter two, depending on\n   whether new backward compatible APIs were added, or simply some bugs were fixed.\n3) From inside a venv, first do ``pip install -r dev-requirements.txt``, then run\n   the ``python setup.py release`` command from the tip of the ``main`` branch.\n   By default this bumps the third or 'patch' digit only, unless you pass ``--major``\n   or ``--minor`` to bump respectively the first or second digit.\n   This bumps the package version string, extracts the changes since the latest\n   version from ``NEWS.rst``, and uses that text to create an annotated git tag\n   (or a signed git tag if you pass the ``--sign`` option and your git and Github\n   account are configured for `signing commits <https://docs.github.com/en/github/authenticating-to-github/managing-commit-signature-verification/signing-commits>`__\n   using a GPG key).\n   It also commits an additional version bump which opens the main branch for\n   the subsequent developmental cycle\n4) Push both the tag and commit to the upstream repository, by running the command\n   ``git push --follow-tags``. Note: it may push other local tags as well, be\n   careful.\n5) Let the CI build the wheel and source distribution packages and verify both\n   get uploaded to the Python Package Index (PyPI).\n6) [Optional] Go to fonttools `Github Releases <https://github.com/fonttools/fonttools/releases>`__\n   page and create a new release, copy-pasting the content of the git tag\n   message. This way, the release notes are nicely formatted as markdown, and\n   users watching the repo will get an email notification. One day we shall\n   automate that too.\n\n\nAcknowledgments\n~~~~~~~~~~~~~~~~\n\nIn alphabetical order:\n\naschmitz, Olivier Berten, Samyak Bhuta, Erik van Blokland, Petr van Blokland,\nJelle Bosma, Sascha Brawer, Tom Byrer, Antonio Cavedoni, Frédéric Coiffier,\nVincent Connare, David Corbett, Simon Cozens, Dave Crossland, Simon Daniels,\nPeter Dekkers, Behdad Esfahbod, Behnam Esfahbod, Hannes Famira, Sam Fishman,\nMatt Fontaine, Takaaki Fuji, Rob Hagemans, Yannis Haralambous, Greg Hitchcock,\nJeremie Hornus, Khaled Hosny, John Hudson, Denis Moyogo Jacquerye, Jack Jansen,\nTom Kacvinsky, Jens Kutilek, Antoine Leca, Werner Lemberg, Tal Leming, Liang Hai, Peter\nLofting, Cosimo Lupo, Olli Meier, Masaya Nakamura, Dave Opstad, Laurence Penney,\nRoozbeh Pournader, Garret Rieger, Read Roberts, Colin Rofls, Guido van Rossum,\nJust van Rossum, Andreas Seidel, Georg Seifert, Chris Simpkins, Miguel Sousa,\nAdam Twardoch, Adrien Tétar, Vitaly Volkov, Paul Wise.\n\nCopyrights\n~~~~~~~~~~\n\n| Copyright (c) 1999-2004 Just van Rossum, LettError\n  (just@letterror.com)\n| See `LICENSE <LICENSE>`__ for the full license.\n\nCopyright (c) 2000 BeOpen.com. All Rights Reserved.\n\nCopyright (c) 1995-2001 Corporation for National Research Initiatives.\nAll Rights Reserved.\n\nCopyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam. All\nRights Reserved.\n\nHave fun!\n\n.. |CI Build Status| image:: https://github.com/fonttools/fonttools/workflows/Test/badge.svg\n   :target: https://github.com/fonttools/fonttools/actions?query=workflow%3ATest\n.. |Coverage Status| image:: https://codecov.io/gh/fonttools/fonttools/branch/main/graph/badge.svg\n   :target: https://codecov.io/gh/fonttools/fonttools\n.. |PyPI| image:: https://img.shields.io/pypi/v/fonttools.svg\n   :target: https://pypi.org/project/FontTools\n.. |Gitter Chat| image:: https://badges.gitter.im/fonttools-dev/Lobby.svg\n   :alt: Join the chat at https://gitter.im/fonttools-dev/Lobby\n   :target: https://gitter.im/fonttools-dev/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge\n\nChangelog\n~~~~~~~~~\n\n4.64.0 (released 2026-08-31)\n----------------------------\n\n- [feaLib] Fix name-table parsing for multibyte Mac encodings (#1196, #4092).\n- [ttProgram] Also indent TrueType assembly following ``IDEF[ ]``, like function\n  definitions (#4093).\n- [subset] Keep East Asian spacing ``palt`` by default (#4094).\n- [subset] Bug fix for MATH table in which constructions for glyphs that are only\n  added during MATH closure were kept (#4096).\n- [ufoLib] Make glyph-to-group construction accessible outside of lookup function\n  (#4102).\n- [glyf] Use reverse glyph map for O(1) ``__setitem__`` membership (#4103).\n- [ttLib] Fix ``fixLookupOverFlows()`` reporting success when it had not promoted\n  any lookup to Extension, masking unresolvable overflows.\n- [ttLib] Add support for TrueType Collection version 2 (#4100).\n- [ttLib] Pin a single head.modified timestamp across ``TTCollection.save`` (#4111).\n- [ttLib] Give an actionable error when LookupList overflow is unrecoverable (#4109).\n- [ttLib] Add support for the AAT bitmap tables ``bhed``, ``bdat``, ``bloc``,\n  variants of ``head``, ``EBDT``, ``EBLC`` used in legacy Apple bitmap-only fonts\n  (#4115).\n- [ttLib] Check ``OS/2`` fsSelection/macStyle consistency against ``bhed`` as well\n  as ``head`` (#4118, #4119).\n- [misc.roundTools] Add types and documentation (#4123).\n- [varLib.instancer] Instance the ``BASE`` table (#4137).\n- [varLib.instancer] Fix Private-dict ``vsindex`` handling in ``instantiateCFF2``\n  (#4129, #4132).\n- [varLib.instancer] Fix crash instancing CFF2 fonts without a VariationStore\n  (#4130, #4131).\n- [sfnt] Raise ``TTLibError`` instead of ``AssertionError`` or ``struct.error``\n  when reading a font truncated within the table directory or a table entry\n  (#4147, #4149).\n- [misc.xmlWriter] Escape the ``]]>`` terminator inside CDATA sections, so an SVG\n  document containing it can no longer smuggle markup past a TTX round trip\n  (#4139).\n- [varLib.instancer] Implement avar2 partial-instancing: the avar version 2\n  ItemVariationStore is adjusted so that remaining axes behave the same after\n  limiting the designspace (#4045).\n- [feaLib] Add shorthand for the value at the default location in a variable\n  scalar: ``(100 wght=900:120)`` means ``(wght=400:100 wght=900:120)`` when the\n  wght default is 400 (#4024).\n- [cmap] Raise ``TTLibError`` for a truncated or out-of-bounds cmap subtable\n  header (#4151).\n- [designspaceLib] Reject conflicting duplicate inputs in axis maps instead of\n  silently keeping the last one (#4153).\n- [designspaceLib] Read an empty ``<lib>`` element as an empty lib instead of\n  raising ``IndexError`` (#4142, #4144).\n- [colorLib] Raise a legible error when a COLRv0 layer, or a COLRv1 PaintGlyph or\n  PaintColrGlyph, references a glyph missing from the glyphMap, instead of failing\n  obscurely later (#2629, #4141).\n- [cmap] Don't drop subtables in unsupported formats when compiling or dumping a\n  font read from binary (#4136).\n- [ttLib] Implement ``splitSinglePos`` so GPOS lookup type 1 offset overflows can\n  be recovered by splitting the subtable (#4091, #4108).\n- [cmap] Round-trip empty Macintosh format 2 subtables (#3663, #4117).\n- [glyf] Raise ``TTLibError`` instead of ``RecursionError`` when ``recalcBounds()``\n  hits a composite-component reference cycle (#3899, #4116).\n- [svgLib] Fix crash parsing an SVG path with consecutive closepath commands\n  (``Z Z``) (#4122).\n- [ttLib] Fix ``DefaultTable`` type annotations (#4126).\n- [ttLib] Add support for the ``EBSC`` (Embedded Bitmap Scaling) table (#4113).\n- [svgLib] Suppress spurious close segments caused by floating-point drift in\n  relative path commands (#3860, #4127).\n- [qu2cu] Fix ``TypeError`` in the Cython-compiled build when ``Qu2CuPen`` passes\n  tuple splines (#4160).\n- [mort] Add semantic decompilation, TTX, and compilation support for\n  rearrangement, contextual-substitution, ligature, and insertion subtables\n  (#4158, #4159, #4161).\n- [svgLib] Start a new subpath at the just-closed subpath's initial point when a\n  drawto command follows a closepath, per SVG spec (#4154, #4155).\n- [misc.filesystem] **SECURITY** Reject paths that resolve outside the filesystem\n  root: a malicious UFO could read arbitrary files via ``..`` components in\n  ``contents.plist``, and a crafted ``.ufoz`` could create files outside its\n  temporary mirror (#4124).\n- [ttLib] **SECURITY** Sanitise glyph names used as filenames in EBDT/CBDT\n  ``ttx -z extfile`` export, preventing arbitrary file writes from untrusted\n  fonts (#4128).\n- [misc.etree] **SECURITY** Don't resolve external XML entities in ``XMLParser``\n  when lxml is used, preventing XXE file disclosure on lxml < 5.0 (#4145).\n- [subset] Fully prune ``VARC`` auxiliary data: collect and remap variation\n  indices referenced by condition tables when subsetting the ``MultiVarStore``,\n  and drop the ``AxisIndicesList``, ``ConditionList``, and ``MultiVarStore``\n  when they end up empty (#4162).\n\n4.63.0 (released 2026-05-14)\n----------------------------\n\n- [ttLib] Add support for Apple Color Emoji ``bgcl`` table (#4065).\n- [ttLib] Add support for ``IFT`` and ``IFTX`` tables (Incremental Font Transfer,\n  PatchMapFormat2) (#4070, #4072).\n- [otData] Introduce ``FieldSpec`` dataclass for OpenType table schema definitions,\n  replacing raw tuples in ``otData.py`` (#4076).\n- [Feat] Show ``name`` table strings as comments next to label IDs in TTX output,\n  matching the convention used by ``fvar``, ``STAT``, ``trak`` (#4089).\n- [cu2qu] Fix Cython complex-division rounding difference in\n  ``split_cubic_into_three`` that could cause ±1 off-curve coordinate shifts\n  (#3928, #4083).\n- [designspaceLib] Fix ``map_backward`` for many-to-one (flat-segment) axis maps\n  that silently dropped entries via dict comprehension\n  (googlefonts/ufo2ft#978, #4085).\n- [OS/2] Fix ``setUnicodeRanges`` to accept reserved bits 123-127, restoring\n  round-trip with ``getUnicodeRanges`` and fixing ``recalcUnicodeRanges`` crash\n  in the subsetter (#4087, #4088).\n- [cython] Declare Cython extensions as free-threading compatible on Python 3.13+,\n  so that importing them on free-threaded Python no longer re-enables the GIL\n  (#4073, #4090).\n\n4.62.1 (released 2026-03-13)\n----------------------------\n\n- [feaLib] Extend contextual rule merging to all rule types: single subst, GSUB/GPOS\n  named lookups, ignore rules, and chained alternate subst (#4061).\n\n4.62.0 (released 2026-03-09)\n----------------------------\n\n- [diff] Add new ``fonttools diff`` command for comparing font files, imported from the\n  ``fdiff`` project and heavily reworked (#1190, #4007, #4009, #4011, #4013, #4019).\n- [feaLib] Fix ``VariableScalar`` interpolation bug with non-linear avar mappings. Also\n  decouple ``VariableScalar`` from compiled fonts, allowing it to work with designspace data\n  before compilation (#3938, #4054).\n- [feaLib] Fix ``VariableScalar`` axis ordering and iterative delta rounding to match fontc\n  behavior (#4053).\n- [feaLib] Merge chained multi subst rules with same context into a single subtable instead of\n  emitting one subtable per glyph (#4016, #4058).\n- [feaLib] Pass location to ``ConditionsetStatement`` to fix glyphsLib round-tripping\n  (fontra/fontra-glyphs#130, #4057).\n- [feaLib] Write ``0xFFFF`` instead of ``0`` for missing nameIDs in ``cv`` feature params\n  (#4010, #4012).\n- [cmap] Fix ``CmapSubtable.__lt__()`` ``TypeError`` on Python 3 when subtables share the\n  same encoding record, and add compile-time validation for unique encoding records (#4035,\n  #4055).\n- [svgLib] Skip non-element XML nodes (comments, processing instructions) when drawing SVG\n  paths (#4042, #4043).\n- [glifLib] Fix regression reading glyph outlines when ``glyphObject=None`` (#4030, #4031).\n- [pointPen] Fix ``SegmentToPointPen`` edge case: only remove a duplicate final point on\n  ``closePath()`` if it is an on-curve point (#4014, #4015).\n- [cffLib] **SECURITY** Replace ``eval()`` with ``safeEval()`` in ``parseBlendList()`` to\n  prevent arbitrary code execution from crafted TTX files (#4039, #4040).\n- [ttLib] Remove defunct Adobe SING Glyphlet tables (``META``, ``SING``, ``GMAP``, ``GPKG``)\n  (#4044).\n- [varLib.interpolatable] Various bugfixes: fix swapped nodeTypes assignment, duplicate\n  kink-detector condition, typos, CFF2 vsindex parsing, glyph existence check, and plot\n  helpers (#4046).\n- [varLib.models] Fix ``getSubModel`` not forwarding ``extrapolate``/``axisRanges``; check\n  location uniqueness after stripping zeros (#4047).\n- [varLib] Fix ``--variable-fonts`` filter in ``build_many``; remove dead code and fix\n  comments (#4048).\n- [avar] Preserve existing name table in build; keep ``unbuild`` return types consistent;\n  validate ``map`` CLI coordinates (#4051).\n- [cu2qu/qu2cu] Add input validation: reject non-positive tolerances, validate curve inputs\n  and list lengths (#4052).\n- [colorLib] Raise a clear ``ColorLibError`` when base glyphs are missing from glyphMap,\n  instead of a confusing ``KeyError`` (#4041).\n- [glyf] Remove unnecessary ``fvar`` table dependency (#4017).\n- [fvar/trak] Remove unnecessary ``name`` table dependency (#4018).\n- [ufoLib] Relax guideline validation to follow the updated spec (#3537, #3553).\n- [ttFont] Fix ``saveXML`` regression with empty table lists, clarify docstring (#4025, #4026,\n  #4056).\n- [setup.py] Link ``libm`` for Cython extensions using math functions (#4028, #4029).\n- Add typing annotations for ``DSIG``, ``DefaultTable``, ``ttProgram`` (#4033).\n\n4.61.1 (released 2025-12-12)\n----------------------------\n\n- [otlLib] buildCoverage: return empty Coverage instead of None (#4003, #4004).\n- [instancer] bug fix in ``avar2`` full instancing (#4002).\n- [designspaceLib] Preserve empty conditionsets when serializing to XML (#4001).\n- [fontBu ilder] Fix FontBuilder ``setupOS2()`` default params globally polluted (#3996, #3997).\n- [ttFont] Add more typing annotations to ttFont, xmlWriter, sfnt, varLib.models and others (#3952, #3826).\n- Explicitly test and declare support for Python 3.14, even though we were already shipping pre-built wheels for it (#3990).\n\n4.60.2 (released 2025-12-09)\n----------------------------\n\n- **Backport release** Same as 4.61.0 but without \"Drop support for EOL Python 3.9\" change to allow\n  downstream projects still on Python 3.9 to avail of the security fix for CVE-2025-66034 (#3994, #3999).\n\n4.61.0 (released 2025-11-28)\n----------------------------\n\n- [varLib.main]: **SECURITY** Only use basename(vf.filename) to prevent path traversal attacks when\n  running ``fonttools varLib`` command, or code which invokes ``fonttools.varLib.main()``.\n  Fixes CVE-2025-66034, see:\n  https://github.com/fonttools/fonttools/security/advisories/GHSA-768j-98cg-p3fv.\n- [feaLib] Sort BaseLangSysRecords by tag (#3986).\n- Drop support for EOL Python 3.9 (#3982).\n- [instancer] Support --remove-overlaps for fonts with CFF2 table (#3975).\n- [CFF2ToCFF] Add --remove-overlaps option (#3976).\n- [feaLib] Raise an error for rsub with NULL target (#3979).\n- [bezierTools] Fix logic bug in curveCurveIntersections (#3963).\n- [feaLib] Error when condition sets have the same name (#3958).\n- [cu2qu.ufo] skip processing empty glyphs to support sparse kerning masters (#3956).\n- [unicodedata] Update to Unicode 17. Require ``unicodedata2 >= 17.0.0`` when installed with 'unicode' extra.\n\n4.60.1 (released 2025-09-29)\n----------------------------\n\n- [ufoLib] Reverted accidental method name change in ``UFOReader.getKerningGroupConversionRenameMaps``\n  that broke compatibility with downstream projects like defcon (#3948, #3947, robotools/defcon#478).\n- [ufoLib] Added test coverage for ``getKerningGroupConversionRenameMaps`` method (#3950).\n- [subset] Don't try to subset BASE table; pass it through by default instead (#3949).\n- [subset] Remove empty BaseRecord entries in MarkBasePos lookups (#3897, #3892).\n- [subset] Add pruning for MarkLigPos and MarkMarkPos lookups (#3946).\n- [subset] Remove duplicate features when subsetting (#3945).\n- [Docs] Added documentation for the visitor module (#3944).\n\n4.60.0 (released 2025-09-17)\n----------------------------\n\n- [pointPen] Allow ``reverseFlipped`` parameter of ``DecomposingPointPen`` to take a ``ReverseFlipped``\n  enum value to control whether/how to reverse contour direction of flipped components, in addition to\n  the existing True/False. This allows to set ``ReverseFlipped.ON_CURVE_FIRST`` to ensure that\n  the decomposed outline starts with an on-curve point before being reversed, for better consistency\n  with other segment-oriented contour transformations. The change is backward compatible, and the\n  default behavior hasn't changed (#3934).\n- [filterPen] Added ``ContourFilterPointPen``, base pen for buffered contour operations, and\n  ``OnCurveStartPointPen`` filter to ensure contours start with an on-curve point (#3934).\n- [cu2qu] Fixed difference in cython vs pure-python complex division by real number (#3930).\n- [varLib.avar] Refactored and added some new sub-modules and scripts (#3926).\n  * ``varLib.avar.build`` module to build avar (and a missing fvar) binaries into a possibly empty TTFont,\n  * ``varLib.avar.unbuild`` module to print a .designspace snippet that would generate the same avar binary,\n  * ``varLib.avar.map`` module to take TTFont and do the mapping, in user/normalized space,\n  * ``varLib.avar.plan`` module moved from ``varLib.avarPlanner``.\n  The bare ``fonttools varLib.avar`` script is deprecated, in favour of ``fonttools varLib.avar.build`` (or ``unbuild``).\n- [interpolatable] Clarify ``linear_sum_assignment`` backend options and minimal dependency\n  usage (#3927).\n- [post] Speed up ``build_psNameMapping`` (#3923).\n- [ufoLib] Added typing annotations to fontTools.ufoLib (#3875).\n\n4.59.2 (released 2025-08-27)\n----------------------------\n\n- [varLib] Clear ``USE_MY_METRICS`` component flags when inconsistent across masters (#3912).\n- [varLib.instancer] Avoid negative advance width/height values when instatiating HVAR/VVAR,\n  (unlikely in well-behaved fonts) (#3918).\n- [subset] Fix shaping behaviour when pruning empty mark sets (#3915, harfbuzz/harfbuzz#5499).\n- [cu2qu] Fixed ``dot()`` product of perpendicular vectors not always returning exactly 0.0\n  in all Python implementations (#3911)\n- [varLib.instancer] Implemented fully-instantiating ``avar2`` fonts (#3909).\n- [feaLib] Allow float values in ``VariableScalar``'s axis locations (#3906, #3907).\n- [cu2qu] Handle special case in ``calc_intersect`` for degenerate cubic curves where 3 to 4\n  control points are equal (#3904).\n\n4.59.1 (released 2025-08-14)\n----------------------------\n\n- [featureVars] Update OS/2.usMaxContext if possible after addFeatureVariationsRaw (#3894).\n- [vhmtx] raise TTLibError('not enough data...') when hmtx/vmtx are truncated (#3843, #3901).\n- [feaLib] Combine duplicate features that have the same set of lookups regardless of the order in which those lookups are added to the feature (#3895).\n- [varLib] Deprecate ``varLib.mutator`` in favor of ``varLib.instancer``. The latter\n  provides equivalent full (static font) instancing in addition to partial VF instancing.\n  CLI users should replace ``fonttools varLib.mutator`` with ``fonttools varLib.instancer``.\n  API users should migrate to ``fontTools.varLib.instancer.instantiateVariableFont`` (#2680).\n\n\n4.59.0 (released 2025-07-16)\n----------------------------\n\n- Removed hard-dependency on pyfilesystem2 (``fs`` package) from ``fonttools[ufo]`` extra.\n  This is replaced by the `fontTools.misc.filesystem` package, a stdlib-only, drop-in\n  replacement for the subset of the pyfilesystem2's API used by ``fontTools.ufoLib``.\n  The latter should continue to work with the upstream ``fs`` (we even test with/without).\n  Clients who wish to continue using ``fs`` can do so by depending on it directly instead\n  of via the ``fonttools[ufo]`` extra (#3885, #3620).\n- [xmlWriter] Replace illegal XML characters (e.g. control or non-characters) with \"?\"\n  when dumping to ttx (#3868, #71).\n- [varLib.hvar] Fixed vertical metrics fields copy/pasta error (#3884).\n- Micro optimizations in ttLib and sstruct modules (#3878, #3879).\n- [unicodedata] Add Garay script to RTL_SCRIPTS (#3882).\n- [roundingPen] Remove unreliable kwarg usage. Argument names aren’t consistent among\n  point pens’ ``.addComponent()`` implementations, in particular ``baseGlyphName``\n  vs ``glyphName`` (#3880).\n\n4.58.5 (released 2025-07-03)\n----------------------------\n\n- [feaLib] Don't try to combine ligature & multisub rules (#3874).\n- [feaLib/ast] Use weakref proxies to avoid cycles in visitor (#3873).\n- [varLib.instancer] Fixed instancing CFF2 fonts where VarData contains more than 64k items (#3858).\n\n4.58.4 (released 2025-06-13)\n----------------------------\n\n- [feaLib] Allow for empty MarkFilter & MarkAttach sets (#3856).\n\n4.58.3 (released 2025-06-13)\n----------------------------\n\n- [feaLib] Fixed iterable check for Python 3.13.4 and newer (#3854, #3855).\n\n4.58.2 (released 2025-06-06)\n----------------------------\n\n- [ttLib.reorderGlyphs] Handle CFF2 when reordering glyphs (#3852)\n- [subset] Copy name IDs in use before scrapping or scrambling them for webfonts (#3853)\n\n4.58.1 (released 2025-05-28)\n----------------------------\n\n- [varLib] Make sure that fvar named instances only reuse name ID 2 or 17 if they are at the default location across all axes, to match OT spec requirement (#3831).\n- [feaLib] Improve single substitution promotion to multiple/ligature substitutions, fixing a few bugs as well (#3849).\n- [loggingTools] Make ``Timer._time`` a static method that doesn't take self, makes it easier to override (#3836).\n- [featureVars] Use ``None`` for empty ConditionSet, which translates to a null offset in the compiled table (#3850).\n- [feaLib] Raise an error on conflicting ligature substitution rules instead of silently taking the last one (#3835).\n- Add typing annotations to T2CharStringPen (#3837).\n- [feaLib] Add single substitutions that were promoted to multiple or ligature substitutions to ``aalt`` feature (#3847).\n- [featureVars] Create a default ``LangSys`` in a ``ScriptRecord`` if missing when adding feature variations to existing GSUB later in the build (#3838).\n- [symfont] Added a ``main()``.\n- [cffLib.specializer] Fix rmoveto merging when blends used (#3839, #3840).\n- [pyftmerge] Add support for cmap format 14 in the merge tool (#3830).\n- [varLib.instancer/cff2] Fix vsindex of Private dicts when instantiating (#3828, #3232).\n- Update text file read to use UTF-8 with optional BOM so it works with e.g. Windows Notepad.exe (#3824).\n- [varLib] Ensure that instances only reuse name ID 2 or 17 if they are at the default location across all axes (#3831).\n- [varLib] Create a dflt LangSys in a ScriptRecord when adding variations later, to fix an avoidable crash in an edge case (#3838).\n\n4.58.0 (released 2025-05-10)\n----------------------------\n\n- Drop Python 3.8, require 3.9+ (#3819)\n- [HVAR, VVAR] Prune unused regions when using a direct mapping (#3797)\n- [Docs] Improvements to ufoLib documentation (#3721)\n- [Docs] Improvements to varLib documentation (#3727)\n- [Docs] Improvements to Pens and pen-module documentation (#3724)\n- [Docs] Miscellany updates to docs (misc modules and smaller modules) (#3730)\n- [subset] Close codepoints over BiDi mirror variants. (#3801)\n- [feaLib] Fix serializing ChainContextPosStatement and\n  ChainContextSubstStatement in some rare cases (#3788)\n- [designspaceLib] Clarify user expectations for getStatNames (#2892)\n- [GVAR] Add support for new `GVAR` table (#3728)\n- [TSI0, TSI5] Derive number of entries to decompile from data length (#2477)\n- [ttLib] Fix `AttributeError` when reporting table overflow (#3808)\n- [ttLib] Apply rounding more often in getCoordinates (#3798)\n- [ttLib] Ignore component bounds if empty (#3799)\n- [ttLib] Change the separator for duplicate glyph names from \"#\" to \".\" (#3809)\n- [feaLib] Support subtable breaks in CursivePos, MarkBasePos, MarkToLigPos and\n  MarkToMarkPos lookups (#3800, #3807)\n- [feaLib] If the same lookup has single substitutions and ligature\n  substitutions, upgrade single substitutions to ligature substitutions with\n  one input glyph (#3805)\n- [feaLib] Correctly handle <NULL> in single pos lookups (#3803)\n- [feaLib] Remove duplicates from class pair pos classes instead of raising an\n  error (#3804)\n- [feaLib] Support creating extension lookups using useExtenion lookup flag\n  instead of silently ignoring it (#3811)\n- [STAT] Add typing for the simpler STAT arguments (#3812)\n- [otlLib.builder] Add future import for annotations (#3814)\n- [cffLib] Fix reading supplement encoding (#3813)\n- [voltLib] Add some missing functionality and fixes to voltLib and VoltToFea,\n  making the conversion to feature files more robust. Add also `fonttools\n  voltLib` command line tool to compile VOLT sources directly (doing an\n  intermediate fea conversion internally) (#3818)\n- [pens] Add some PointPen annotations (#3820)\n\n4.57.0 (released 2025-04-03)\n----------------------------\n\n- [ttLib.__main__] Add `--no-recalc-timestamp` flag (#3771)\n- [ttLib.__main__] Add `-b` (recalcBBoxes=False) flag (#3772)\n- [cmap] Speed up glyphOrder loading from cmap (#3774)\n- [ttLib.__main__] Improvements around the `-t` flag (#3776)\n- [Debg] Fix parsing from XML; add roundtrip tests (#3781)\n- [fealib] Support \\*Base.MinMax tables (#3783, #3786)\n- [config] Add OPTIMIZE_FONT_SPEED (#3784)\n- [varLib.hvar] New module to add HVAR table to the font (#3780)\n- [otlLib.optimize] Fix crash when the provided TTF does not contain a `GPOS` (#3794)\n\n4.56.0 (released 2025-02-07)\n----------------------------\n\n- [varStore] Sort the input todo list with the same sorting key used for the opimizer's output (#3767).\n- [otData] Fix DeviceTable's ``DeltaValue`` repeat value which caused a crash after importing from XML and then compiling a GPOS containing Device tables (#3758).\n- [feaLib] Make ``FeatureLibError`` pickleable, so client can e.g. use feaLib to can compile features in parallel with multiprocessing (#3762).\n- [varLib/gvar] Removed workaround for old, long-fixed macOS bug about composite glyphs with all zero deltas (#1381, #1788).\n- [Docs] Updated ttLib documentation, beefed up TTFont and TTGlyphSet explanations (#3720).\n\n4.55.8 (released 2025-01-29)\n----------------------------\n\n- [MetaTools] Fixed bug in buildUCD.py script whereby the first non-header line of some UCD text file was being skipped. This affected in particular the U+00B7 (MIDDLE DOT) entry of ScriptExtensions.txt (#3756).\n\n4.55.7 (released 2025-01-28)\n----------------------------\n\n- Shorten the changelog included in PyPI package description to accommodate maximum length limit imposed by Azure DevOps. No actual code changes since v4.55.6 (#3754).\n\n4.55.6 (released 2025-01-24)\n----------------------------\n\n- [glyf] Fixed regression introduced in 4.55.5 when computing bounds of nested composite glyphs  with transformed components (#3752).\n\n4.55.5 (released 2025-01-23)\n----------------------------\n\n- [glyf] Fixed recalcBounds of transformed components with unrounded coordinates (#3750).\n- [feaLib] Allow duplicate script/language statements (#3749).\n\n4.55.4 (released 2025-01-21)\n----------------------------\n\n- [bezierTools] Fixed ``splitCubicAtT`` sometimes not returning identical start/end points as result of numerical precision (#3742, #3743).\n- [feaLib/ast] Fixed docstring of ``AlternateSubstStatement`` (#3735).\n- [transform] Typing fixes (#3734).\n\n4.55.3 (released 2024-12-10)\n----------------------------\n\n- [Docs] fill out ttLib table section [#3716]\n- [feaLib] More efficient inline format 4 lookups [#3726]\n\n4.55.2 (released 2024-12-05)\n----------------------------\n\n- [Docs] update Sphinx config (#3712)\n- [designspaceLib] Allow axisOrdering to be set to zero (#3715)\n- [feaLib] Don’t modify variable anchors in place (#3717)\n\n4.55.1 (released 2024-12-02)\n----------------------------\n\n- [ttGlyphSet] Support VARC CFF2 fonts (#3683)\n- [DecomposedTransform] Document and implement always skewY == 0 (#3697)\n- [varLib] \"Fix\" cython iup issue? (#3704)\n- Cython minor refactor (#3705)\n\n\n4.55.0 (released 2024-11-14)\n----------------------------\n\n- [cffLib.specializer] Adjust stack use calculation (#3689)\n- [varLib] Lets not add mac names if the rest of name doesn't have them (#3688)\n- [ttLib.reorderGlyphs] Update CFF table charstrings and charset (#3682)\n- [cffLib.specializer] Add cmdline to specialize a CFF2 font (#3675, #3679)\n- [CFF2] Lift uint16 VariationStore.length limitation (#3674)\n- [subset] consider variation selectors subsetting cmap14 (#3672)\n- [varLib.interpolatable] Support CFF2 fonts (#3670)\n- Set isfinal to true in XML parser for proper resource cleanup (#3669)\n- [removeOverlaps] Fix CFF CharString width (#3659)\n- [glyf] Add optimizeSize option (#3657)\n- Python 3.13 support (#3656)\n- [TupleVariation] Optimize for loading speed, not size (#3650, #3653)\n\n\n4.54.1 (released 2024-09-24)\n----------------------------\n\n- [unicodedata] Update to Unicode 16\n- [subset] Escape ``\\\\`` in doc string\n\n4.54.0 (released 2024-09-23)\n----------------------------\n\n- [Docs] Small docs cleanups by @n8willis (#3611)\n- [Docs] cleanup code blocks by @n8willis (#3627)\n- [Docs] fix Sphinx builds by @n8willis (#3625)\n- [merge] Minor fixes to documentation for merge by @drj11 (#3588)\n- [subset] Small tweaks to pyftsubset documentation by @RoelN (#3633)\n- [Tests] Do not require fonttools command to be available by @behdad (#3612)\n- [Tests] subset_test: add failing test to reproduce issue #3616 by @anthrotype (#3622)\n- [ttLib] NameRecordVisitor: include whole sequence of character variants' UI labels, not just the first by @anthrotype (#3617)\n- [varLib.avar] Reconstruct mappings from binary by @behdad (#3598)\n- [varLib.instancer] Fix visual artefacts with partial L2 instancing by @Hoolean (#3635)\n- [varLib.interpolatable] Support discrete axes in .designspace by @behdad (#3599)\n- [varLib.models] By default, assume OpenType-like normalized space by @behdad (#3601)\n\n4.53.1 (released 2024-07-05)\n----------------------------\n\n- [feaLib] Improve the sharing of inline chained lookups (#3559)\n- [otlLib] Correct the calculation of OS/2.usMaxContext with reversed chaining contextual single substitutions (#3569)\n- [misc.visitor] Visitors search the inheritance chain of objects they are visiting (#3581)\n\n4.53.0 (released 2024-05-31)\n----------------------------\n\n- [ttLib.removeOverlaps] Support CFF table to aid in downconverting CFF2 fonts (#3528)\n- [avar] Fix crash when accessing not-yet-existing attribute (#3550)\n- [docs] Add buildMathTable to otlLib.builder documentation (#3540)\n- [feaLib] Allow UTF-8 with BOM when reading features (#3495)\n- [SVGPathPen] Revert rounding coordinates to two decimal places by default (#3543)\n- [varLib.instancer] Refix output filename decision-making  (#3545, #3544, #3548)\n\n4.52.4 (released 2024-05-27)\n----------------------------\n\n- [varLib.cff] Restore and deprecate convertCFFtoCFF2 that was removed in 4.52.0\n  release as it is used by downstream projects (#3535).\n\n4.52.3 (released 2024-05-27)\n----------------------------\n\n- Fixed a small syntax error in the reStructuredText-formatted NEWS.rst file\n  which caused the upload to PyPI to fail for 4.52.2. No other code changes.\n\n4.52.2 (released 2024-05-27)\n----------------------------\n\n- [varLib.interpolatable] Ensure that scipy/numpy output is JSON-serializable\n  (#3522, #3526).\n- [housekeeping] Regenerate table lists, to fix pyinstaller packaging of the new\n  ``VARC`` table (#3531, #3529).\n- [cffLib] Make CFFToCFF2 and CFF2ToCFF more robust (#3521, #3525).\n\n4.52.1 (released 2024-05-24)\n----------------------------\n\n- Fixed a small syntax error in the reStructuredText-formatted NEWS.rst file\n  which caused the upload to PyPI to fail for 4.52.0. No other code changes.\n\n4.52.0 (released 2024-05-24)\n----------------------------\n\n- Added support for the new ``VARC`` (Variable Composite) table that is being\n  proposed to OpenType spec (#3395). For more info:\n  https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md\n- [ttLib.__main__] Fixed decompiling all tables (90fed08).\n- [feaLib] Don't reference the same lookup index multiple times within the same\n  feature record, it is only applied once anyway (#3520).\n- [cffLib] Moved methods to desubroutinize, remove hints and unused subroutines\n  from subset module to cffLib (#3517).\n- [varLib.instancer] Added support for partial-instancing CFF2 tables! Also, added\n  method to down-convert from CFF2 to CFF 1.0, and CLI entry points to convert\n  CFF<->CFF2 (#3506).\n- [subset] Prune unused user name IDs even with --name-IDs='*' (#3410).\n- [ttx] use GNU-style getopt to intermix options and positional arguments (#3509).\n- [feaLib.variableScalar] Fixed ``value_at_location()`` method (#3491)\n- [psCharStrings] Shorten output of ``encodeFloat`` (#3492).\n- [bezierTools] Fix infinite-recursion in ``calcCubicArcLength`` (#3502).\n- [avar2] Implement ``avar2`` support in ``TTFont.getGlyphSet()`` (#3473).\n\n4.51.0 (released 2024-04-05)\n----------------------------\n\n- [ttLib] Optimization on loading aux fields (#3464).\n- [ttFont] Add reorderGlyphs (#3468).\n\n4.50.0 (released 2024-03-15)\n----------------------------\n\n- [pens] Added decomposing filter pens that draw components as regular contours (#3460).\n- [instancer] Drop explicit no-op axes from TupleVariations (#3457).\n- [cu2qu/ufo] Return set of modified glyph names from fonts_to_quadratic (#3456).\n\n4.49.0 (released 2024-02-15)\n----------------------------\n\n- [otlLib] Add API for building ``MATH`` table (#3446)\n\n4.48.1 (released 2024-02-06)\n----------------------------\n\n- Fixed uploading wheels to PyPI, no code changes since v4.48.0.\n\n4.48.0 (released 2024-02-06)\n----------------------------\n\n- [varLib] Do not log when there are no OTL tables to be merged.\n- [setup.py] Do not restrict lxml<5 any more, tests pass just fine with lxml>=5.\n- [feaLib] Remove glyph and class names length restrictions in FEA (#3424).\n- [roundingPens] Added ``transformRoundFunc`` parameter to the rounding pens to allow\n  for custom rounding of the components' transforms (#3426).\n- [feaLib] Keep declaration order of ligature components within a ligature set, instead\n  of sorting by glyph name (#3429).\n- [feaLib] Fixed ordering of alternates in ``aalt`` lookups, following the declaration\n  order of feature references within the ``aalt`` feature block (#3430).\n- [varLib.instancer] Fixed a bug in the instancer's IUP optimization (#3432).\n- [sbix] Support sbix glyphs with new graphicType \"flip\" (#3433).\n- [svgPathPen] Added ``--glyphs`` option to dump the SVG paths for the named glyphs\n  in the font (0572f78).\n- [designspaceLib] Added \"description\" attribute to ``<mappings>`` and ``<mapping>``\n  elements, and allow multiple ``<mappings>`` elements to group ``<mapping>`` elements\n  that are logically related (#3435, #3437).\n- [otlLib] Correctly choose the most compact GSUB contextual lookup format (#3439).\n\n4.47.2 (released 2024-01-11)\n----------------------------\n\nMinor release to fix uploading wheels to PyPI.\n\n4.47.1 (released 2024-01-11)\n----------------------------\n\n- [merge] Improve help message and add standard command line options (#3408)\n- [otlLib] Pass ``ttFont`` to ``name.addName`` in ``buildStatTable`` (#3406)\n- [featureVars] Re-use ``FeatureVariationRecord``'s when possible (#3413)\n\n4.47.0 (released 2023-12-18)\n----------------------------\n\n- [varLib.models] New API for VariationModel: ``getMasterScalars`` and\n  ``interpolateFromValuesAndScalars``.\n- [varLib.interpolatable] Various bugfixes and rendering improvements. In particular,\n  add a Summary page in the front, and an Index and Table-of-Contents in the back.\n  Change the page size to Letter.\n- [Docs/designspaceLib] Defined a new ``public.fontInfo`` lib key, not used anywhere yet (#3358).\n\n4.46.0 (released 2023-12-02)\n----------------------------\n\n- [featureVars] Allow to register the same set of substitution rules to multiple features.\n  The ``addFeatureVariations`` function can now take a list of featureTags; similarly, the\n  lib key 'com.github.fonttools.varLib.featureVarsFeatureTag' can now take a\n  comma-separateed string of feature tags (e.g. \"salt,ss01\") instead of a single tag (#3360).\n- [featureVars] Don't overwrite GSUB FeatureVariations, but append new records to it\n  for features which are not already there. But raise ``VarLibError`` if the feature tag\n  already has feature variations associated with it (#3363).\n- [varLib] Added ``addGSUBFeatureVariations`` function to add GSUB Feature Variations\n  to an existing variable font from rules defined in a DesignSpace document (#3362).\n- [varLib.interpolatable] Various bugfixes and rendering improvements. In particular,\n  a new test for \"underweight\" glyphs. The new test reports quite a few false-positives\n  though. Please send feedback.\n\n4.45.1 (released 2023-11-23)\n----------------------------\n\n- [varLib.interpolatable] Various bugfixes and improvements, better reporting, reduced\n  false positives.\n- [ttGlyphSet] Added option to not recalculate glyf bounds (#3348).\n\n4.45.0 (released 2023-11-20)\n----------------------------\n\n- [varLib.interpolatable] Vastly improved algorithms. Also available now is ``--pdf``\n  and ``--html`` options to generate a PDF or HTML report of the interpolation issues.\n  The PDF/HTML report showcases the problematic masters, the interpolated broken\n  glyph, as well as the proposed fixed version.\n\n4.44.3 (released 2023-11-15)\n----------------------------\n\n- [subset] Only prune codepage ranges for OS/2.version >= 1, ignore otherwise (#3334).\n- [instancer] Ensure hhea vertical metrics stay in sync with OS/2 ones after instancing\n  MVAR table containing 'hasc', 'hdsc' or 'hlgp' tags (#3297).\n\n4.44.2 (released 2023-11-14)\n----------------------------\n\n- [glyf] Have ``Glyph.recalcBounds`` skip empty components (base glyph with no contours)\n  when computing the bounding box of composite glyphs. This simply restores the existing\n  behavior before some changes were introduced in fonttools 4.44.0 (#3333).\n\n4.44.1 (released 2023-11-14)\n----------------------------\n\n- [feaLib] Ensure variable mark anchors are deep-copied while building since they\n  get modified in-place and later reused (#3330).\n- [OS/2|subset] Added method to ``recalcCodePageRanges`` to OS/2 table class; added\n  ``--prune-codepage-ranges`` to `fonttools subset` command (#3328, #2607).\n\n4.44.0 (released 2023-11-03)\n----------------------------\n\n- [instancer] Recalc OS/2 AvgCharWidth after instancing if default changes (#3317).\n- [otlLib] Make ClassDefBuilder class order match varLib.merger's, i.e. large\n  classes first, then glyph lexicographic order (#3321, #3324).\n- [instancer] Allow not specifying any of min:default:max values and let be filled\n  up with fvar's values (#3322, #3323).\n- [instancer] When running --update-name-table ignore axes that have no STAT axis\n  values (#3318, #3319).\n- [Debg] When dumping to ttx, write the embedded JSON as multi-line string with\n  indentation (92cbfee0d).\n- [varStore] Handle > 65535 items per encoding by splitting VarData subtable (#3310).\n- [subset] Handle null-offsets in MarkLigPos subtables.\n- [subset] Keep East Asian spacing fatures vhal, halt, chws, vchw by default (#3305).\n- [instancer.solver] Fixed case where axisDef < lower and upper < axisMax (#3304).\n- [glyf] Speed up compilation, mostly around ``recalcBounds`` (#3301).\n- [varLib.interpolatable] Speed it up when working on variable fonts, plus various\n  micro-optimizations (#3300).\n- Require unicodedata2 >= 15.1.0 when installed with 'unicode' extra, contains UCD 15.1.\n\n4.43.1 (released 2023-10-06)\n----------------------------\n\n- [EBDT] Fixed TypeError exception in `_reverseBytes` method triggered when dumping\n  some bitmap fonts with `ttx -z bitwise` option (#3162).\n- [v/hhea] Fixed UnboundLocalError exception in ``recalc`` method when no vmtx or hmtx\n  tables are present (#3290).\n- [bezierTools] Fixed incorrectly typed cython local variable leading to TypeError when\n  calling ``calcQuadraticArcLength`` (#3288).\n- [feaLib/otlLib] Better error message when building Coverage table with missing glyph (#3286).\n\n4.43.0 (released 2023-09-29)\n----------------------------\n\n- [subset] Set up lxml ``XMLParser(resolve_entities=False)`` when parsing OT-SVG documents\n  to prevent XML External Entity (XXE) attacks (9f61271dc):\n  https://codeql.github.com/codeql-query-help/python/py-xxe/\n- [varLib.iup] Added workaround for a Cython bug in ``iup_delta_optimize`` that was\n  leading to IUP tolerance being incorrectly initialised, resulting in sub-optimal deltas\n  (60126435d, cython/cython#5732).\n- [varLib] Added new command-line entry point ``fonttools varLib.avar`` to add an\n  ``avar`` table to an existing VF from axes mappings in a .designspace file (0a3360e52).\n- [instancer] Fixed bug whereby no longer used variation regions were not correctly pruned\n  after VarData optimization (#3268).\n- Added support for Python 3.12 (#3283).\n\n4.42.1 (released 2023-08-20)\n----------------------------\n\n- [t1Lib] Fixed several Type 1 issues (#3238, #3240).\n- [otBase/packer] Allow sharing tables reached by different offset sizes (#3241, #3236).\n- [varLib/merger] Fix Cursive attachment merging error when all anchors are NULL (#3248, #3247).\n- [ttLib] Fixed warning when calling ``addMultilingualName`` and ``ttFont`` parameter was not\n  passed on to ``findMultilingualName`` (#3253).\n\n4.42.0 (released 2023-08-02)\n----------------------------\n\n- [varLib] Use sentinel value 0xFFFF to mark a glyph advance in hmtx/vmtx as non\n  participating, allowing sparse masters to contain glyphs for variation purposes other\n  than {H,V}VAR (#3235).\n- [varLib/cff] Treat empty glyphs in non-default masters as missing, thus not participating\n  in CFF2 delta computation, similarly to how varLib already treats them for gvar (#3234).\n- Added varLib.avarPlanner script to deduce 'correct' avar v1 axis mappings based on\n  glyph average weights (#3223).\n\n4.41.1 (released 2023-07-21)\n----------------------------\n\n- [subset] Fixed perf regression in v4.41.0 by making ``NameRecordVisitor`` only visit\n  tables that do contain nameID references (#3213, #3214).\n- [varLib.instancer] Support instancing fonts containing null ConditionSet offsets in\n  FeatureVariationRecords (#3211, #3212).\n- [statisticsPen] Report font glyph-average weight/width and font-wide slant.\n- [fontBuilder] Fixed head.created date incorrectly set to 0 instead of the current\n  timestamp, regression introduced in v4.40.0 (#3210).\n- [varLib.merger] Support sparse ``CursivePos`` masters (#3209).\n\n4.41.0 (released 2023-07-12)\n----------------------------\n\n- [fontBuilder] Fixed bug in setupOS2 with default panose attribute incorrectly being\n  set to a dict instead of a Panose object (#3201).\n- [name] Added method to ``removeUnusedNameRecords`` in the user range (#3185).\n- [varLib.instancer] Fixed issue with L4 instancing (moving default) (#3179).\n- [cffLib] Use latin1 so we can roundtrip non-ASCII in {Full,Font,Family}Name (#3202).\n- [designspaceLib] Mark <source name=\"...\"> as optional in docs (as it is in the code).\n- [glyf-1] Fixed drawPoints() bug whereby last cubic segment becomes quadratic (#3189, #3190).\n- [fontBuilder] Propagate the 'hidden' flag to the fvar Axis instance (#3184).\n- [fontBuilder] Update setupAvar() to also support avar 2, fixing ``_add_avar()`` call\n  site (#3183).\n- Added new ``voltLib.voltToFea`` submodule (originally Tiro Typeworks' \"Volto\") for\n  converting VOLT OpenType Layout sources to FEA format (#3164).\n\n4.40.0 (released 2023-06-12)\n----------------------------\n\n- Published native binary wheels to PyPI for all the python minor versions and platform\n  and architectures currently supported that would benefit from this. They will include\n  precompiled Cython-accelerated modules (e.g. cu2qu) without requiring to compile them\n  from source. The pure-python wheel and source distribution will continue to be\n  published as always (pip will automatically chose them when no binary wheel is\n  available for the given platform, e.g. pypy). Use ``pip install --no-binary=fonttools fonttools``\n  to expliclity request pip to install from the pure-python source.\n- [designspaceLib|varLib] Add initial support for specifying axis mappings and build\n  ``avar2`` table from those (#3123).\n- [feaLib] Support variable ligature caret position (#3130).\n- [varLib|glyf] Added option to --drop-implied-oncurves; test for impliable oncurve\n  points either before or after rounding (#3146, #3147, #3155, #3156).\n- [TTGlyphPointPen] Don't error with empty contours, simply ignore them (#3145).\n- [sfnt] Fixed str vs bytes remnant of py3 transition in code dealing with de/compiling\n  WOFF metadata (#3129).\n- [instancer-solver] Fixed bug when moving default instance with sparse masters (#3139, #3140).\n- [feaLib] Simplify variable scalars that don’t vary (#3132).\n- [pens] Added filter pen that explicitly emits closing line when lastPt != movePt (#3100).\n- [varStore] Improve optimize algorithm and better document the algorithm (#3124, #3127).\n  Added ``quantization`` option (#3126).\n- Added CI workflow config file for building native binary wheels (#3121).\n- [fontBuilder] Added glyphDataFormat=0 option; raise error when glyphs contain cubic\n  outlines but glyphDataFormat was not explicitly set to 1 (#3113, #3119).\n- [subset] Prune emptied GDEF.MarkGlyphSetsDef and remap indices; ensure GDEF is\n  subsetted before GSUB and GPOS (#3114, #3118).\n- [xmlReader] Fixed issue whereby DSIG table data was incorrectly parsed (#3115, #2614).\n- [varLib/merger] Fixed merging of SinglePos with pos=0 (#3111, #3112).\n- [feaLib] Demote \"Feature has not been defined\" error to a warning when building aalt\n  and referenced feature is empty (#3110).\n- [feaLib] Dedupe multiple substitutions with classes (#3105).\n\n4.39.4 (released 2023-05-10)\n----------------------------\n\n- [varLib.interpolatable] Allow for sparse masters (#3075)\n- [merge] Handle differing default/nominalWidthX in CFF (#3070)\n- [ttLib] Add missing main.py file to ttLib package (#3088)\n- [ttx] Fix missing composite instructions in XML (#3092)\n- [ttx] Fix split tables option to work on filenames containing '%' (#3096)\n- [featureVars] Process lookups for features other than rvrn last (#3099)\n- [feaLib] support multiple substitution with classes (#3103)\n\n4.39.3 (released 2023-03-28)\n----------------------------\n\n- [sbix] Fixed TypeError when compiling empty glyphs whose imageData is None, regression\n  was introduced in v4.39 (#3059).\n- [ttFont] Fixed AttributeError on python <= 3.10 when opening a TTFont from a tempfile\n  SpooledTemporaryFile, seekable method only added on python 3.11 (#3052).\n\n4.39.2 (released 2023-03-16)\n----------------------------\n\n- [varLib] Fixed regression introduced in 4.39.1 whereby an incomplete 'STAT' table\n  would be built even though a DesignSpace v5 did contain 'STAT' definitions (#3045, #3046).\n\n4.39.1 (released 2023-03-16)\n----------------------------\n\n- [avar2] Added experimental support for reading/writing avar version 2 as specified in\n  this draft proposal: https://github.com/harfbuzz/boring-expansion-spec/blob/main/avar2.md\n- [glifLib] Wrap underlying XML library exceptions with GlifLibError when parsing GLIFs,\n  and also print the name and path of the glyph that fails to be parsed (#3042).\n- [feaLib] Consult avar for normalizing user-space values in ConditionSets and in\n  VariableScalars (#3042, #3043).\n- [ttProgram] Handle string input to Program.fromAssembly() (#3038).\n- [otlLib] Added a config option to emit GPOS 7 lookups, currently disabled by default\n  because of a macOS bug (#3034).\n- [COLRv1] Added method to automatically compute ClipBoxes (#3027).\n- [ttFont] Fixed getGlyphID to raise KeyError on missing glyphs instead of returning\n  None. The regression was introduced in v4.27.0 (#3032).\n- [sbix] Fixed UnboundLocalError: cannot access local variable 'rawdata' (#3031).\n- [varLib] When building VF, do not overwrite a pre-existing ``STAT`` table that was built\n  with feaLib from FEA feature file. Also, added support for building multiple VFs\n  defined in Designspace v5 from ``fonttools varLib`` script (#3024).\n- [mtiLib] Only add ``Debg`` table with lookup names when ``FONTTOOLS_LOOKUP_DEBUGGING``\n  env variable is set (#3023).\n\n4.39.0 (released 2023-03-06)\n----------------------------\n\n- [mtiLib] Optionally add `Debg` debug info for MTI feature builds (#3018).\n- [ttx] Support reading input file from standard input using special `-` character,\n  similar to existing `-o -` option to write output to standard output (#3020).\n- [cython] Prevent ``cython.compiled`` raise AttributeError if cython not installed\n  properly (#3017).\n- [OS/2] Guard against ZeroDivisionError when calculating xAvgCharWidth in the unlikely\n  scenario no glyph has non-zero advance (#3015).\n- [subset] Recompute xAvgCharWidth independently of --no-prune-unicode-ranges,\n  previously the two options were involuntarily bundled together (#3012).\n- [fontBuilder] Add ``debug`` parameter to addOpenTypeFeatures method to add source\n  debugging information to the font in the ``Debg`` private table (#3008).\n- [name] Make NameRecord `__lt__` comparison not fail on Unicode encoding errors (#3006).\n- [featureVars] Fixed bug in ``overlayBox`` (#3003, #3005).\n- [glyf] Added experimental support for cubic bezier curves in TrueType glyf table, as\n  outlined in glyf v1 proposal (#2988):\n  https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-cubicOutlines.md\n- Added new qu2cu module and related qu2cuPen, the reverse of cu2qu for converting\n  TrueType quadratic splines to cubic bezier curves (#2993).\n- [glyf] Added experimental support for reading and writing Variable Composites/Components\n  as defined in glyf v1 spec proposal (#2958):\n  https://github.com/harfbuzz/boring-expansion-spec/blob/main/glyf1-varComposites.md.\n- [pens]: Added `addVarComponent` method to pen protocols' base classes, which pens can implement\n  to handle varcomponents (by default they get decomposed) (#2958).\n- [misc.transform] Added DecomposedTransform class which implements an affine transformation\n  with separate translate, rotation, scale, skew, and transformation-center components (#2598)\n- [sbix] Ensure Glyph.referenceGlyphName is set; fixes error after dumping and\n  re-compiling sbix table with 'dupe' glyphs (#2984).\n- [feaLib] Be cleverer when merging chained single substitutions into same lookup\n  when they are specified using the inline notation (#2150, #2974).\n- [instancer] Clamp user-inputted axis ranges to those of fvar (#2959).\n- [otBase/subset] Define ``__getstate__`` for BaseTable so that a copied/pickled 'lazy'\n  object gets its own OTTableReader to read from; incidentally fixes a bug while\n  subsetting COLRv1 table containing ClipBoxes on python 3.11 (#2965, #2968).\n- [sbix] Handle glyphs with \"dupe\" graphic type on compile correctly (#2963).\n- [glyf] ``endPointsOfContours`` field should be unsigned! Kudos to behdad for\n  spotting one of the oldest bugs in FT. Probably nobody has ever dared to make\n  glyphs with more than 32767 points... (#2957).\n- [feaLib] Fixed handling of ``ignore`` statements with unmarked glyphs to match\n  makeotf behavior, which assumes the first glyph is marked (#2950).\n- Reformatted code with ``black`` and enforce new code style via CI check (#2925).\n- [feaLib] Sort name table entries following OT spec prescribed order in the builder (#2927).\n- [cu2quPen] Add Cu2QuMultiPen that converts multiple outlines at a time in\n  interpolation compatible way; its methods take a list of tuples arguments\n  that would normally be passed to individual segment pens, and at the end it\n  dispatches the converted outlines to each pen (#2912).\n- [reverseContourPen/ttGlyphPen] Add outputImpliedClosingLine option (#2913, #2914,\n  #2921, #2922, #2995).\n- [gvar] Avoid expanding all glyphs unnecessarily upon compile (#2918).\n- [scaleUpem] Fixed bug whereby CFF2 vsindex was scaled; it should not (#2893, #2894).\n- [designspaceLib] Add DS.getAxisByTag and refactor getAxis (#2891).\n- [unicodedata] map Zmth<->math in ot_tag_{to,from}_script (#1737, #2889).\n- [woff2] Support encoding/decoding OVERLAP_SIMPLE glyf flags (#2576, #2884).\n- [instancer] Update OS/2 class and post.italicAngle when default moved (L4)\n- Dropped support for Python 3.7 which reached EOL, fontTools requires 3.8+.\n- [instancer] Fixed instantiateFeatureVariations logic when a rule range becomes\n  default-applicable (#2737, #2880).\n- [ttLib] Add main to ttFont and ttCollection that just decompile and re-compile the\n  input font (#2869).\n- [featureVars] Insert 'rvrn' lookup at the beginning of LookupList, to work around bug\n  in Apple implementation of 'rvrn' feature which the spec says it should be processed\n  early whereas on macOS 10.15 it follows lookup order (#2140, #2867).\n- [instancer/mutator] Remove 'DSIG' table if present.\n- [svgPathPen] Don't close path in endPath(), assume open unless closePath() (#2089, #2865).\n\n4.38.0 (released 2022-10-21)\n----------------------------\n\n- [varLib.instancer] Added support for L4 instancing, i.e. moving the default value of\n  an axis while keeping it variable. Thanks Behdad! (#2728, #2861).\n  It's now also possible to restrict an axis min/max values beyond the current default\n  value, e.g. a font wght has min=100, def=400, max=900 and you want a partial VF that\n  only varies between 500 and 700, you can now do that.\n  You can either specify two min/max values (wght=500:700), and the new default will be\n  set to either the minimum or maximum, depending on which one is closer to the current\n  default (e.g. 500 in this case). Or you can specify three values (e.g. wght=500:600:700)\n  to specify the new default value explicitly.\n- [otlLib/featureVars] Set a few Count values so one doesn't need to compile the font\n  to update them (#2860).\n- [varLib.models] Make extrapolation work for 2-master models as well where one master\n  is at the default location (#2843, #2846).\n  Add optional extrapolate=False to normalizeLocation() (#2847, #2849).\n- [varLib.cff] Fixed sub-optimal packing of CFF2 deltas by no longer rounding them to\n  integer (#2838).\n- [scaleUpem] Calculate numShorts in VarData after scale; handle CFF hintmasks (#2840).\n\n4.37.4 (released 2022-09-30)\n----------------------------\n\n- [subset] Keep nameIDs used by CPAL palette entry labels (#2837).\n- [varLib] Avoid negative hmtx values when creating font from variable CFF2 font (#2827).\n- [instancer] Don't prune stat.ElidedFallbackNameID (#2828).\n- [unicodedata] Update Scripts/Blocks to Unicode 15.0 (#2833).\n\n4.37.3 (released 2022-09-20)\n----------------------------\n\n- Fix arguments in calls to (glyf) glyph.draw() and drawPoints(), whereby offset wasn't\n  correctly passed down; this fix also exposed a second bug, where lsb and tsb were not\n  set (#2824, #2825, adobe-type-tools/afdko#1560).\n\n4.37.2 (released 2022-09-15)\n----------------------------\n\n- [subset] Keep CPAL table and don't attempt to prune unused color indices if OT-SVG\n  table is present even if COLR table was subsetted away; OT-SVG may be referencing the\n  CPAL table; for now we assume that's the case (#2814, #2815).\n- [varLib.instancer] Downgrade GPOS/GSUB version if there are no more FeatureVariations\n  after instancing (#2812).\n- [subset] Added ``--no-lazy`` to optionally load fonts eagerly (mostly to ease\n  debugging of table lazy loading, no practical effects) (#2807).\n- [varLib] Avoid building empty COLR.DeltaSetIndexMap with only identity mappings (#2803).\n- [feaLib] Allow multiple value record types (by promoting to the most general format)\n  within the same PairPos subtable; e.g. this allows variable and non variable kerning\n  rules to share the same subtable. This also fixes a bug whereby some kerning pairs\n  would become unreachable while shapiong because of premature subtable splitting (#2772, #2776).\n- [feaLib] Speed up ``VarScalar`` by caching models for recurring master locations (#2798).\n- [feaLib] Optionally cythonize ``feaLib.lexer``, speeds up parsing FEA a bit (#2799).\n- [designspaceLib] Avoid crash when handling unbounded rule conditions (#2797).\n- [post] Don't crash if ``post`` legacy format 1 is malformed/improperly used (#2786)\n- [gvar] Don't be \"lazy\" (load all glyph variations up front) when TTFont.lazy=False (#2771).\n- [TTFont] Added ``normalizeLocation`` method to normalize a location dict from the\n  font's defined axes space (also known as \"user space\") into the normalized (-1..+1)\n  space. It applies ``avar`` mapping if the font contains an ``avar`` table (#2789).\n- [TTVarGlyphSet] Support drawing glyph instances from CFF2 variable glyph set (#2784).\n- [fontBuilder] Do not error when building cmap if there are zero code points (#2785).\n- [varLib.plot] Added ability to plot a variation model and set of accompaning master\n  values corresponding to the model's master locations into a pyplot figure (#2767).\n- [Snippets] Added ``statShape.py`` script to draw statistical shape of a glyph as an\n  ellips (requires pycairo) (baecd88).\n- [TTVarGlyphSet] implement drawPoints natively, avoiding going through\n  SegmentToPointPen (#2778).\n- [TTVarGlyphSet] Fixed bug whereby drawing a composite glyph multiple times, its\n  components would shif; needed an extra copy (#2774).\n\n4.37.1 (released 2022-08-24)\n----------------------------\n\n- [subset] Fixed regression introduced with v4.37.0 while subsetting the VarStore of\n  ``HVAR`` and ``VVAR`` tables, whereby an ``AttributeError: subset_varidxes`` was\n  thrown because an apparently unused import statement (with the side-effect of\n  dynamically binding that ``subset_varidxes`` method to the VarStore class) had been\n  accidentally deleted in an unrelated PR (#2679, #2773).\n- [pens] Added ``cairoPen`` (#2678).\n- [gvar] Read ``gvar`` more lazily by not parsing all of the ``glyf`` table (#2771).\n- [ttGlyphSet] Make ``drawPoints(pointPen)`` method work for CFF fonts as well via\n  adapter pen (#2770).\n\n4.37.0 (released 2022-08-23)\n----------------------------\n\n- [varLib.models] Reverted PR #2717 which added support for \"narrow tents\" in v4.36.0,\n  as it introduced a regression (#2764, #2765). It will be restored in upcoming release\n  once we found a solution to the bug.\n- [cff.specializer] Fixed issue in charstring generalizer with the ``blend`` operator\n  (#2750, #1975).\n- [varLib.models] Added support for extrapolation (#2757).\n- [ttGlyphSet] Ensure the newly added ``_TTVarGlyphSet`` inherits from ``_TTGlyphSet``\n  to keep backward compatibility with existing API (#2762).\n- [kern] Allow compiling legacy kern tables with more than 64k entries (d21cfdede).\n- [visitor] Added new visitor API to traverse tree of objects and dispatch based\n  on the attribute type: cf. ``fontTools.misc.visitor`` and ``fontTools.ttLib.ttVisitor``. Added ``fontTools.ttLib.scaleUpem`` module that uses the latter to\n  change a font's units-per-em and scale all the related fields accordingly (#2718,\n  #2755).\n\n4.36.0 (released 2022-08-17)\n----------------------------\n\n- [varLib.models] Use a simpler model that generates narrower \"tents\" (regions, master\n  supports) whenever possible: specifically when any two axes that actively \"cooperate\"\n  (have masters at non-zero positions for both axes) have a complete set of intermediates.\n  The simpler algorithm produces fewer overlapping regions and behaves better with\n  respect to rounding at the peak positions than the generic solver, always matching\n  intermediate masters exactly, instead of maximally 0.5 units off. This may be useful\n  when 100% metrics compatibility is desired (#2218, #2717).\n- [feaLib] Remove warning when about ``GDEF`` not being built when explicitly not\n  requested; don't build one unconditonally even when not requested (#2744, also works\n  around #2747).\n- [ttFont] ``TTFont.getGlyphSet`` method now supports selecting a location that\n  represents an instance of a variable font (supports both user-scale and normalized\n  axes coordinates via the ``normalized=False`` parameter). Currently this only works\n  for TrueType-flavored variable fonts (#2738).\n\n4.35.0 (released 2022-08-15)\n----------------------------\n\n- [otData/otConverters] Added support for 'biased' PaintSweepGradient start/end angles\n  to match latest COLRv1 spec (#2743).\n- [varLib.instancer] Fixed bug in ``_instantiateFeatureVariations`` when at the same\n  time pinning one axis and restricting the range of a subsequent axis; the wrong axis\n  tag was being used in the latter step (as the records' axisIdx was updated in the\n  preceding step but looked up using the old axes order in the following step) (#2733,\n  #2734).\n- [mtiLib] Pad script tags with space when less than 4 char long (#1727).\n- [merge] Use ``'.'`` instead of ``'#'`` in duplicate glyph names (#2742).\n- [gvar] Added support for lazily loading glyph variations (#2741).\n- [varLib] In ``build_many``, we forgot to pass on ``colr_layer_reuse`` parameter to\n  the ``build`` method (#2730).\n- [svgPathPen] Add a main that prints SVG for input text (6df779fd).\n- [cffLib.width] Fixed off-by-one in optimized values; previous code didn't match the\n  code block above it (2963fa50).\n- [varLib.interpolatable] Support reading .designspace and .glyphs files (via optional\n  ``glyphsLib``).\n- Compile some modules with Cython when available and building/installing fonttools\n  from source: ``varLib.iup`` (35% faster), ``pens.momentsPen`` (makes\n  ``varLib.interpolatable`` 3x faster).\n- [feaLib] Allow features to be built for VF without also building a GDEF table (e.g.\n  only build GSUB); warn when GDEF would be needed but isn't requested (#2705, 2694).\n- [otBase] Fixed ``AttributeError`` when uharfbuzz < 0.23.0 and 'repack' method is\n  missing (32aa8eaf). Use new ``uharfbuzz.repack_with_tag`` when available (since\n  uharfbuzz>=0.30.0), enables table-specific optimizations to be performed during\n  repacking (#2724).\n- [statisticsPen] By default report all glyphs (4139d891). Avoid division-by-zero\n  (52b28f90).\n- [feaLib] Added missing required argument to FeatureLibError exception (#2693)\n- [varLib.merge] Fixed error during error reporting (#2689). Fixed undefined\n  ``NotANone`` variable (#2714).\n\n4.34.4 (released 2022-07-07)\n----------------------------\n\n- Fixed typo in varLib/merger.py that causes NameError merging COLR glyphs\n  containing more than 255 layers (#2685).\n\n4.34.3 (released 2022-07-07)\n----------------------------\n\n- [designspaceLib] Don't make up bad PS names when no STAT data (#2684)\n\n4.34.2 (released 2022-07-06)\n----------------------------\n\n- [varStore/subset] fixed KeyError exception to do with NO_VARIATION_INDEX while\n  subsetting varidxes in GPOS/GDEF (a08140d).\n\n4.34.1 (released 2022-07-06)\n----------------------------\n\n- [instancer] When optimizing HVAR/VVAR VarStore, use_NO_VARIATION_INDEX=False to avoid\n  including NO_VARIATION_INDEX in AdvWidthMap, RsbMap, LsbMap mappings, which would\n  push the VarIdx width to maximum (4bytes), which is not desirable. This also fixes\n  a hard crash when attempting to subset a varfont after it had been partially instanced\n  with use_NO_VARIATION_INDEX=True.\n\n4.34.0 (released 2022-07-06)\n----------------------------\n\n- [instancer] Set RIBBI bits in head and OS/2 table when cutting instances and the\n  subfamily nameID=2 contains strings like 'Italic' or 'Bold' (#2673).\n- [otTraverse] Addded module containing methods for traversing trees of otData tables\n  (#2660).\n- [otTables] Made DeltaSetIndexMap TTX dump less verbose by omitting no-op entries\n  (#2660).\n- [colorLib.builder] Added option to disable PaintColrLayers's reuse of layers from\n  LayerList (#2660).\n- [varLib] Added support for merging multiple master COLRv1 tables into a variable\n  COLR table (#2660, #2328). Base color glyphs of same name in different masters must have\n  identical paint graph structure (incl. number of layers, palette indices, number\n  of color line stops, corresponding paint formats at each level of the graph),\n  but can differ in the variable fields (e.g. PaintSolid.Alpha). PaintVar* tables\n  are produced when this happens and a VarStore/DeltaSetIndexMap is added to the\n  variable COLR table. It is possible for non-default masters to be 'sparse', i.e.\n  omit some of the color glyphs present in the default master.\n- [feaLib] Let the Parser set nameIDs 1 through 6 that were previously reserved (#2675).\n- [varLib.varStore] Support NO_VARIATION_INDEX in optimizer and instancer.\n- [feaLib] Show all missing glyphs at once at end of parsing (#2665).\n- [varLib.iup] Rewrite force-set conditions and limit DP loopback length (#2651).\n  For Noto Sans, IUP time drops from 23s down to 9s, with only a slight size increase\n  in the final font. This basically turns the algorithm from O(n^3) into O(n).\n- [featureVars] Report about missing glyphs in substitution rules (#2654).\n- [mutator/instancer] Added CLI flag to --no-recalc-timestamp (#2649).\n- [SVG] Allow individual SVG documents in SVG OT table to be compressed on uncompressed,\n  and remember that when roundtripping to/from ttx. The SVG.docList is now a list\n  of SVGDocument namedtuple-like dataclass containing an extra ``compressed`` field,\n  and no longer a bare 3-tuple (#2645).\n- [designspaceLib] Check for descriptor types with hasattr() to allow custom classes\n  that don't inherit the default descriptors (#2634).\n- [subset] Enable sharing across subtables of extension lookups for harfbuzz packing\n  (#2626). Updated how table packing falls back to fontTools from harfbuzz (#2668).\n- [subset] Updated default feature tags following current Harfbuzz (#2637).\n- [svgLib] Fixed regex for real number to support e.g. 1e-4 in addition to 1.0e-4.\n  Support parsing negative rx, ry on arc commands (#2596, #2611).\n- [subset] Fixed subsetting SinglePosFormat2 when ValueFormat=0 (#2603).\n\n4.33.3 (released 2022-04-26)\n----------------------------\n\n- [designspaceLib] Fixed typo in ``deepcopyExceptFonts`` method, preventing font\n  references to be transferred (#2600). Fixed another typo in the name of ``Range``\n  dataclass's ``__post_init__`` magic method (#2597).\n\n4.33.2 (released 2022-04-22)\n----------------------------\n\n- [otBase] Make logging less verbose when harfbuzz fails to serialize. Do not exit\n  at the first failure but continue attempting to fix offset overflow error using\n  the pure-python serializer even when the ``USE_HARFBUZZ_REPACKER`` option was\n  explicitly set to ``True``. This is normal with fonts with relatively large\n  tables, at least until hb.repack implements proper table splitting.\n\n4.33.1 (released 2022-04-22)\n----------------------------\n\n- [otlLib] Put back the ``FONTTOOLS_GPOS_COMPACT_MODE`` environment variable to fix\n  regression in ufo2ft (and thus fontmake) introduced with v4.33.0 (#2592, #2593).\n  This is deprecated and will be removed one ufo2ft gets updated to use the new\n  config setup.\n\n4.33.0 (released 2022-04-21)\n----------------------------\n\n- [OS/2 / merge] Automatically recalculate ``OS/2.xAvgCharWidth`` after merging\n  fonts with ``fontTools.merge`` (#2591, #2538).\n- [misc/config] Added ``fontTools.misc.configTools`` module, a generic configuration\n  system (#2416, #2439).\n  Added ``fontTools.config`` module, a fontTools-specific configuration\n  system using ``configTools`` above.\n  Attached a ``Config`` object to ``TTFont``.\n- [otlLib] Replaced environment variable for GPOS compression level with an\n  equivalent option using the new config system.\n- [designspaceLib] Incremented format version to 5.0 (#2436).\n  Added discrete axes, variable fonts, STAT information, either design- or\n  user-space location on instances.\n  Added ``fontTools.designspaceLib.split`` module to split a designspace\n  into sub-spaces that interpolate and that represent the variable fonts\n  listed in the document.\n  Made instance names optional and allow computing them from STAT data instead.\n  Added ``fontTools.designspaceLib.statNames`` module.\n  Allow instances to have the same location as a previously defined STAT label.\n  Deprecated some attributes:\n  ``SourceDescriptor``: ``copyLib``, ``copyInfo``, ``copyGroups``, ``copyFeatures``.\n  ``InstanceDescriptor``: ``kerning``, ``info``; ``glyphs``: use rules or sparse\n  sources.\n  For both, ``location``: use the more explicit designLocation.\n  Note: all are soft deprecations and existing code should keep working.\n  Updated documentation for Python methods and the XML format.\n- [varLib] Added ``build_many`` to build several variable fonts from a single\n  designspace document (#2436).\n  Added ``fontTools.varLib.stat`` module to build STAT tables from a designspace\n  document.\n- [otBase] Try to use the Harfbuzz Repacker for packing GSUB/GPOS tables when\n  ``uharfbuzz`` python bindings are available (#2552). Disable it by setting the\n  \"fontTools.ttLib.tables.otBase:USE_HARFBUZZ_REPACKER\" config option to ``False``.\n  If the option is set explicitly to ``True`` but ``uharfbuzz`` can't be imported\n  or fails to serialize for any reasons, an error will be raised (ImportError or\n  uharfbuzz errors).\n- [CFF/T2] Ensure that ``pen.closePath()`` gets called for CFF2 charstrings (#2577).\n  Handle implicit CFF2 closePath within ``T2OutlineExtractor`` (#2580).\n\n4.32.0 (released 2022-04-08)\n----------------------------\n\n- [otlLib] Disable GPOS7 optimization to work around bug in Apple CoreText.\n  Always force Chaining GPOS8 for now (#2540).\n- [glifLib] Added ``outputImpliedClosingLine=False`` parameter to ``Glyph.draw()``,\n  to control behaviour of ``PointToSegmentPen`` (6b4e2e7).\n- [varLib.interpolatable] Check for wrong contour starting point (#2571).\n- [cffLib] Remove leftover ``GlobalState`` class and fix calls to ``TopDictIndex()``\n  (#2569, #2570).\n- [instancer] Clear ``AxisValueArray`` if it is empty after instantiating (#2563).\n\n4.31.2 (released 2022-03-22)\n----------------------------\n\n- [varLib] fix instantiation of GPOS SinglePos values (#2555).\n\n4.31.1 (released 2022-03-18)\n----------------------------\n\n- [subset] fix subsetting OT-SVG when glyph id attribute is on the root ``<svg>``\n  element (#2553).\n\n4.31.0 (released 2022-03-18)\n----------------------------\n\n- [ttCollection] Fixed 'ResourceWarning: unclosed file' warning (#2549).\n- [varLib.merger] Handle merging SinglePos with valueformat=0 (#2550).\n- [ttFont] Update glyf's glyphOrder when calling TTFont.setGlyphOrder() (#2544).\n- [ttFont] Added ``ensureDecompiled`` method to load all tables irrespective\n  of the ``lazy`` attribute (#2551).\n- [otBase] Added ``iterSubTable`` method to iterate over BaseTable's children of\n  type BaseTable; useful for traversing a tree of otTables (#2551).\n\n4.30.0 (released 2022-03-10)\n----------------------------\n\n- [varLib] Added debug logger showing the glyph name for which ``gvar`` is built (#2542).\n- [varLib.errors] Fixed undefined names in ``FoundANone`` and ``UnsupportedFormat``\n  exceptions (ac4d5611).\n- [otlLib.builder] Added ``windowsNames`` and ``macNames`` (bool) parameters to the\n  ``buildStatTabe`` function, so that one can select whether to only add one or both\n  of the two sets (#2528).\n- [t1Lib] Added the ability to recreate PostScript stream (#2504).\n- [name] Added ``getFirstDebugName``, ``getBest{Family,SubFamily,Full}Name`` methods (#2526).\n\n4.29.1 (released 2022-02-01)\n----------------------------\n\n- [colorLib] Fixed rounding issue with radial gradient's start/end circles inside\n  one another (#2521).\n- [freetypePen] Handle rotate/skew transform when auto-computing width/height of the\n  buffer; raise PenError wen missing moveTo (#2517)\n\n4.29.0 (released 2022-01-24)\n----------------------------\n\n- [ufoLib] Fixed illegal characters and expanded reserved filenames (#2506).\n- [COLRv1] Don't emit useless PaintColrLayers of lenght=1 in LayerListBuilder (#2513).\n- [ttx] Removed legacy ``waitForKeyPress`` method on Windows (#2509).\n- [pens] Added FreeTypePen that uses ``freetype-py`` and the pen protocol for\n  rasterizating outline paths (#2494).\n- [unicodedata] Updated the script direction list to Unicode 14.0 (#2484).\n  Bumped unicodedata2 dependency to 14.0 (#2499).\n- [psLib] Fixed type of ``fontName`` in ``suckfont`` (#2496).\n\n4.28.5 (released 2021-12-19)\n----------------------------\n\n- [svgPathPen] Continuation of #2471: make sure all occurrences of ``str()`` are now\n  replaced with user-defined ``ntos`` callable.\n- [merge] Refactored code into submodules, plus several bugfixes and improvements:\n  fixed duplicate-glyph-resolution GSUB-lookup generation code; use tolerance in glyph\n  comparison for empty glyph's width; ignore space of default ignorable glyphs;\n  downgrade duplicates-resolution missing-GSUB from assert to warn; added --drop-tables\n  option (#2473, #2475, #2476).\n\n4.28.4 (released 2021-12-15)\n----------------------------\n\n- [merge] Merge GDEF marksets in Lookups properly (#2474).\n- [feaLib] Have ``fontTools feaLib`` script exit with error code when build fails (#2459)\n- [svgPathPen] Added ``ntos`` option to customize number formatting (e.g. rounding) (#2471).\n- [subset] Speed up subsetting of large CFF fonts (#2467).\n- [otTables] Speculatively promote lookups to extension to speed up compilation. If the\n  offset to lookup N is too big to fit in a ushort, the offset to lookup N+1 is going to\n  be too big as well, so we promote to extension all lookups from lookup N onwards (#2465).\n\n4.28.3 (released 2021-12-03)\n----------------------------\n\n- [subset] Fixed bug while subsetting ``COLR`` table, whereby incomplete layer records\n  pointing to missing glyphs were being retained leading to ``struct.error`` upon\n  compiling. Make it so that ``glyf`` glyph closure, which follows the ``COLR`` glyph\n  closure, does not influence the ``COLR`` table subsetting (#2461, #2462).\n- [docs] Fully document the ``cmap`` and ``glyf`` tables (#2454, #2457).\n- [colorLib.unbuilder] Fixed CLI by deleting no longer existing parameter (180bb1867).\n\n4.28.2 (released 2021-11-22)\n----------------------------\n\n- [otlLib] Remove duplicates when building coverage (#2433).\n- [docs] Add interrogate configuration (#2443).\n- [docs] Remove comment about missing “start” optional argument to ``calcChecksum`` (#2448).\n- [cu2qu/cli] Adapt to the latest ufoLib2.\n- [subset] Support subsetting SVG table and remove it from the list of  drop by default tables (#534).\n- [subset] add ``--pretty-svg`` option to pretty print SVG table contents (#2452).\n- [merge] Support merging ``CFF`` tables (CID-keyed ``CFF`` is still not supported) (#2447).\n- [merge] Support ``--output-file`` (#2447).\n- [docs] Split table docs into individual pages (#2444).\n- [feaLib] Forbid empty classes (#2446).\n- [docs] Improve documentation for ``fontTools.ttLib.ttFont`` (#2442).\n\n4.28.1 (released 2021-11-08)\n----------------------------\n\n- [subset] Fixed AttributeError while traversing a color glyph's Paint graph when there is no\n  LayerList, which is optional (#2441).\n\n4.28.0 (released 2021-11-05)\n----------------------------\n\n- Dropped support for EOL Python 3.6, require Python 3.7 (#2417).\n- [ufoLib/glifLib] Make filename-clash checks faster by using a set instead of a list (#2422).\n- [subset] Don't crash if optional ClipList and LayerList are ``None`` (empty) (#2424, 2439).\n- [OT-SVG] Removed support for old deprecated version 1 and embedded color palettes,\n  which were never officially part of the OpenType SVG spec. Upon compile, reuse offsets\n  to SVG documents that are identical (#2430).\n- [feaLib] Added support for Variable Feature File syntax. This is experimental and subject\n  to change until it is finalized in the Adobe FEA spec (#2432).\n- [unicodedata] Update Scripts/ScriptExtensions/Blocks to UnicodeData 14.0 (#2437).\n\n4.27.1 (released 2021-09-23)\n----------------------------\n\n- [otlLib] Fixed error when chained contextual lookup builder overflows (#2404, #2411).\n- [bezierTools] Fixed two floating-point bugs: one when computing `t` for a point\n  lying on an almost horizontal/vertical line; another when computing the intersection\n  point between a curve and a line (#2413).\n\n4.27.0 (released 2021-09-14)\n----------------------------\n\n- [ttLib/otTables] Cleaned up virtual GID handling: allow virtual GIDs in ``Coverage``\n  and ``ClassDef`` readers; removed unused ``allowVID`` argument from ``TTFont``\n  constructor, and ``requireReal`` argument in ``TTFont.getGlyphID`` method.\n  Make ``TTFont.setGlyphOrder`` clear reverse glyphOrder map, and assume ``glyphOrder``\n  internal attribute is never modified outside setGlyphOrder; added ``TTFont.getGlyphNameMany``\n  and ``getGlyphIDMany`` (#1536, #1654, #2334, #2398).\n- [py23] Dropped internal use of ``fontTools.py23`` module to fix deprecation warnings\n  in client code that imports from fontTools (#2234, #2399, #2400).\n- [subset] Fix subsetting COLRv1 clip boxes when font is loaded lazily (#2408).\n\n4.26.2 (released 2021-08-09)\n----------------------------\n\n- [otTables] Added missing ``CompositeMode.PLUS`` operator (#2390).\n\n4.26.1 (released 2021-08-03)\n----------------------------\n\n- [transform] Added ``transformVector`` and ``transformVectors`` methods to the\n  ``Transform`` class. Similar to ``transformPoint`` but ignore the translation\n  part (#2386).\n\n4.26.0 (released 2021-08-03)\n----------------------------\n\n- [xmlWriter] Default to ``\"\\n\"`` for ``newlinestr`` instead of platform-specific\n  ``os.linesep`` (#2384).\n- [otData] Define COLRv1 ClipList and ClipBox (#2379).\n- [removeOverlaps/instancer] Added --ignore-overlap-errors option to work around\n  Skia PathOps.Simplify bug (#2382, #2363, google/fonts#3365).\n- NOTE: This will be the last version to support Python 3.6. FontTools will require\n  Python 3.7 or above from the next release (#2350)\n\n4.25.2 (released 2021-07-26)\n----------------------------\n\n- [COLRv1] Various changes to sync with the latest CORLv1 draft spec. In particular:\n  define COLR.VarIndexMap, remove/inline ColorIndex struct, add VarIndexBase to ``PaintVar*`` tables (#2372);\n  add reduced-precicion specialized transform Paints;\n  define Angle as fraction of half circle encoded as F2Dot14;\n  use FWORD (int16) for all Paint center coordinates;\n  change PaintTransform to have an offset to Affine2x3;\n- [ttLib] when importing XML, only set sfntVersion if the font has no reader and is empty (#2376)\n\n4.25.1 (released 2021-07-16)\n----------------------------\n\n- [ttGlyphPen] Fixed bug in ``TTGlyphPointPen``, whereby open contours (i.e. starting\n  with segmentType \"move\") would throw ``NotImplementedError``. They are now treated\n  as if they are closed, like with the ``TTGlyphPen`` (#2364, #2366).\n\n4.25.0 (released 2021-07-05)\n----------------------------\n\n- [tfmLib] Added new library for parsing TeX Font Metric (TFM) files (#2354).\n- [TupleVariation] Make shared tuples order deterministic on python < 3.7 where\n  Counter (subclass of dict) doesn't remember insertion order (#2351, #2353).\n- [otData] Renamed COLRv1 structs to remove 'v1' suffix and match the updated draft\n  spec: 'LayerV1List' -> 'LayerList', 'BaseGlyphV1List' -> 'BaseGlyphList',\n  'BaseGlyphV1Record' -> 'BaseGlyphPaintRecord' (#2346).\n  Added 8 new ``PaintScale*`` tables: with/without centers, uniform vs non-uniform.\n  Added ``*AroundCenter`` variants to ``PaintRotate`` and ``PaintSkew``: the default\n  versions no longer have centerX/Y, but default to origin.\n  ``PaintRotate``, ``PaintSkew`` and ``PaintComposite`` formats were re-numbered.\n  NOTE: these are breaking changes; clients using the experimental COLRv1 API will\n  have to be updated (#2348).\n- [pointPens] Allow ``GuessSmoothPointPen`` to accept a tolerance. Fixed call to\n  ``math.atan2`` with x/y parameters inverted. Sync the code with fontPens (#2344).\n- [post] Fixed parsing ``post`` table format 2.0 when it contains extra garbage\n  at the end of the stringData array (#2314).\n- [subset] drop empty features unless 'size' with FeatureParams table (#2324).\n- [otlLib] Added ``otlLib.optimize`` module; added GPOS compaction algorithm.\n  The compaction can be run on existing fonts with ``fonttools otlLib.optimize``\n  or using the snippet ``compact_gpos.py``. There's experimental support for\n  compacting fonts at compilation time using an environment variable, but that\n  might be removed later (#2326).\n\n4.24.4 (released 2021-05-25)\n----------------------------\n\n- [subset/instancer] Fixed ``AttributeError`` when instantiating a VF that\n  contains GPOS ValueRecords with ``Device`` tables but without the respective\n  non-Device values (e.g. ``XAdvDevice`` without ``XAdvance``). When not\n  explicitly set, the latter are assumed to be 0 (#2323).\n\n4.24.3 (released 2021-05-20)\n----------------------------\n\n- [otTables] Fixed ``AttributeError`` in methods that split LigatureSubst,\n  MultipleSubst and AlternateSubst subtables when an offset overflow occurs.\n  The ``Format`` attribute was removed in v4.22.0 (#2319).\n\n4.24.2 (released 2021-05-20)\n----------------------------\n\n- [ttGlyphPen] Fixed typing annotation of TTGlyphPen glyphSet parameter (#2315).\n- Fixed two instances of DeprecationWarning: invalid escape sequence (#2311).\n\n4.24.1 (released 2021-05-20)\n----------------------------\n\n- [subset] Fixed AttributeError when SinglePos subtable has None Value (ValueFormat 0)\n  (#2312, #2313).\n\n4.24.0 (released 2021-05-17)\n----------------------------\n\n- [pens] Add ``ttGlyphPen.TTGlyphPointPen`` similar to ``TTGlyphPen`` (#2205).\n\n4.23.1 (released 2021-05-14)\n----------------------------\n\n- [subset] Fix ``KeyError`` after subsetting ``COLR`` table that initially contains\n  both v0 and v1 color glyphs when the subset only requested v1 glyphs; we were\n  not pruning the v0 portion of the table (#2308).\n- [colorLib] Set ``LayerV1List`` attribute to ``None`` when empty, it's optional\n  in CORLv1 (#2308).\n\n4.23.0 (released 2021-05-13)\n----------------------------\n\n- [designspaceLib] Allow to use ``\\\\UNC`` absolute paths on Windows (#2299, #2306).\n- [varLib.merger] Fixed bug where ``VarLibMergeError`` was raised with incorrect\n  parameters (#2300).\n- [feaLib] Allow substituting a glyph class with ``NULL`` to delete multiple glyphs\n  (#2303).\n- [glyf] Fixed ``NameError`` exception in ``getPhantomPoints`` (#2295, #2305).\n- [removeOverlaps] Retry pathops.simplify after rounding path coordinates to integers\n  if it fails the first time using floats, to work around a rare and hard to debug\n  Skia bug (#2288).\n- [varLib] Added support for building, reading, writing and optimizing 32-bit\n  ``ItemVariationStore`` as used in COLRv1 table (#2285).\n- [otBase/otConverters] Add array readers/writers for int types (#2285).\n- [feaLib] Allow more than one lookahead glyph/class in contextual positioning with\n  \"value at end\" (#2293, #2294).\n- [COLRv1] Default varIdx should be 0xFFFFFFFF (#2297, #2298).\n- [pens] Make RecordingPointPen actually pass on identifiers; replace asserts with\n  explicit ``PenError`` exception (#2284).\n- [mutator] Round lsb for CF2 fonts as well (#2286).\n\n4.22.1 (released 2021-04-26)\n----------------------------\n\n- [feaLib] Skip references to named lookups if the lookup block definition\n  is empty, similarly to makeotf. This also fixes an ``AttributeError`` while\n  generating ``aalt`` feature (#2276, #2277).\n- [subset] Fixed bug with ``--no-hinting`` implementation for Device tables (#2272,\n  #2275). The previous code was alwyas dropping Device tables if no-hinting was\n  requested, but some Device tables (DeltaFormat=0x8000) are also used to encode\n  variation indices and need to be retained.\n- [otBase] Fixed bug in getting the ValueRecordSize when decompiling ``MVAR``\n  table with ``lazy=True`` (#2273, #2274).\n- [varLib/glyf/gvar] Optimized and simplified ``GlyphCoordinates`` and\n  ``TupleVariation`` classes, use ``bytearray`` where possible, refactored\n  phantom-points calculations. We measured about 30% speedup in total time\n  of loading master ttfs, building gvar, and saving (#2261, #2266).\n- [subset] Fixed ``AssertionError`` while pruning unused CPAL palettes when\n  ``0xFFFF`` is present (#2257, #2259).\n\n4.22.0 (released 2021-04-01)\n----------------------------\n\n- [ttLib] Remove .Format from Coverage, ClassDef, SingleSubst, LigatureSubst,\n  AlternateSubst, MultipleSubst (#2238).\n  ATTENTION: This will change your TTX dumps!\n- [misc.arrayTools] move Vector to its own submodule, and rewrite as a tuple\n  subclass (#2201).\n- [docs] Added a terminology section for varLib (#2209).\n- [varLib] Move rounding to VariationModel, to avoid error accumulation from\n  multiple deltas (#2214)\n- [varLib] Explain merge errors in more human-friendly terms (#2223, #2226)\n- [otlLib] Correct some documentation (#2225)\n- [varLib/otlLib] Allow merging into VariationFont without first saving GPOS\n  PairPos2 (#2229)\n- [subset] Improve PairPosFormat2 subsetting (#2221)\n- [ttLib] TTFont.save: create file on disk as late as possible (#2253)\n- [cffLib] Add missing CFF2 dict operators LanguageGroup and ExpansionFactor\n  (#2249)\n  ATTENTION: This will change your TTX dumps!\n\n4.21.1 (released 2021-02-26)\n----------------------------\n\n- [pens] Reverted breaking change that turned ``AbstractPen`` and ``AbstractPointPen``\n  into abstract base classes (#2164, #2198).\n\n4.21.0 (released 2021-02-26)\n----------------------------\n\n- [feaLib] Indent anchor statements in ``asFea()`` to make them more legible and\n  diff-able (#2193).\n- [pens] Turn ``AbstractPen`` and ``AbstractPointPen`` into abstract base classes\n  (#2164).\n- [feaLib] Added support for parsing and building ``STAT`` table from AFDKO feature\n  files (#2039).\n- [instancer] Added option to update name table of generated instance using ``STAT``\n  table's axis values (#2189).\n- [bezierTools] Added functions to compute bezier point-at-time, as well as line-line,\n  curve-line and curve-curve intersections (#2192).\n\n4.20.0 (released 2021-02-15)\n----------------------------\n\n- [COLRv1] Added ``unbuildColrV1`` to deconstruct COLRv1 otTables to raw json-able\n  data structure; it does the reverse of ``buildColrV1`` (#2171).\n- [feaLib] Allow ``sub X by NULL`` sequence to delete a glyph (#2170).\n- [arrayTools] Fixed ``Vector`` division (#2173).\n- [COLRv1] Define new ``PaintSweepGradient`` (#2172).\n- [otTables] Moved ``Paint.Format`` enum class outside of ``Paint`` class definition,\n  now named ``PaintFormat``. It was clashing with paint instance ``Format`` attribute\n  and thus was breaking lazy load of COLR table which relies on magic ``__getattr__``\n  (#2175).\n- [COLRv1] Replace hand-coded builder functions with otData-driven dynamic\n  implementation (#2181).\n- [COLRv1] Define additional static (non-variable) Paint formats (#2181).\n- [subset] Added support for subsetting COLR v1 and CPAL tables (#2174, #2177).\n- [fontBuilder] Allow ``setupFvar`` to optionally take ``designspaceLib.AxisDescriptor``\n  objects. Added new ``setupAvar`` method. Support localised names for axes and\n  named instances (#2185).\n\n4.19.1 (released 2021-01-28)\n----------------------------\n\n- [woff2] An initial off-curve point with an overlap flag now stays an off-curve\n  point after compression.\n\n4.19.0 (released 2021-01-25)\n----------------------------\n\n- [codecs] Handle ``errors`` parameter different from 'strict' for the custom\n  extended mac encodings (#2137, #2132).\n- [featureVars] Raise better error message when a script is missing the required\n  default language system (#2154).\n- [COLRv1] Avoid abrupt change caused by rounding ``PaintRadialGradient.c0`` when\n  the start circle almost touches the end circle's perimeter (#2148).\n- [COLRv1] Support building unlimited lists of paints as 255-ary trees of\n  ``PaintColrLayers`` tables (#2153).\n- [subset] Prune redundant format-12 cmap subtables when all non-BMP characters\n  are dropped (#2146).\n- [basePen] Raise ``MissingComponentError`` instead of bare ``KeyError`` when a\n  referenced component is missing (#2145).\n\n4.18.2 (released 2020-12-16)\n----------------------------\n\n- [COLRv1] Implemented ``PaintTranslate`` paint format (#2129).\n- [varLib.cff] Fixed unbound local variable error (#1787).\n- [otlLib] Don't crash when creating OpenType class definitions if some glyphs\n  occur more than once (#2125).\n\n4.18.1 (released 2020-12-09)\n----------------------------\n\n- [colorLib] Speed optimization for ``LayerV1ListBuilder`` (#2119).\n- [mutator] Fixed missing tab in ``interpolate_cff2_metrics`` (0957dc7a).\n\n4.18.0 (released 2020-12-04)\n----------------------------\n\n- [COLRv1] Update to latest draft: added ``PaintRotate`` and ``PaintSkew`` (#2118).\n- [woff2] Support new ``brotlicffi`` bindings for PyPy (#2117).\n- [glifLib] Added ``expectContentsFile`` parameter to ``GlyphSet``, for use when\n  reading existing UFOs, to comply with the specification stating that a\n  ``contents.plist`` file must exist in a glyph set (#2114).\n- [subset] Allow ``LangSys`` tags in ``--layout-scripts`` option (#2112). For example:\n  ``--layout-scripts=arab.dflt,arab.URD,latn``; this will keep ``DefaultLangSys``\n  and ``URD`` language for ``arab`` script, and all languages for ``latn`` script.\n- [varLib.interpolatable] Allow UFOs to be checked; report open paths, non existant\n  glyphs; add a ``--json`` option to produce a machine-readable list of\n  incompatibilities\n- [pens] Added ``QuartzPen`` to create ``CGPath`` from glyph outlines on macOS.\n  Requires pyobjc (#2107).\n- [feaLib] You can export ``FONTTOOLS_LOOKUP_DEBUGGING=1`` to enable feature file\n  debugging info stored in ``Debg`` table (#2106).\n- [otlLib] Build more efficient format 1 and format 2 contextual lookups whenever\n  possible (#2101).\n\n4.17.1 (released 2020-11-16)\n----------------------------\n\n- [colorLib] Fixed regression in 4.17.0 when building COLR v0 table; when color\n  layers are stored in UFO lib plist, we can't distinguish tuples from lists so\n  we need to accept either types (e5439eb9, googlefonts/ufo2ft/issues#426).\n\n4.17.0 (released 2020-11-12)\n----------------------------\n\n- [colorLib/otData] Updated to latest draft ``COLR`` v1 spec (#2092).\n- [svgLib] Fixed parsing error when arc commands' boolean flags are not separated\n  by space or comma (#2094).\n- [varLib] Interpret empty non-default glyphs as 'missing', if the default glyph is\n  not empty (#2082).\n- [feaLib.builder] Only stash lookup location for ``Debg`` if ``Builder.buildLookups_``\n  has cooperated (#2065, #2067).\n- [varLib] Fixed bug in VarStore optimizer (#2073, #2083).\n- [varLib] Add designspace lib key for custom feavar feature tag (#2080).\n- Add HashPointPen adapted from psautohint. With this pen, a hash value of a glyph\n  can be computed, which can later be used to detect glyph changes (#2005).\n\n4.16.1 (released 2020-10-05)\n----------------------------\n\n- [varLib.instancer] Fixed ``TypeError`` exception when instantiating a VF with\n  a GSUB table 1.1 in which ``FeatureVariations`` attribute is present but set to\n  ``None`` -- indicating that optional ``FeatureVariations`` is missing (#2077).\n- [glifLib] Make ``x`` and ``y`` attributes of the ``point`` element required\n  even when validation is turned off, and raise a meaningful ``GlifLibError``\n  message when that happens (#2075).\n\n4.16.0 (released 2020-09-30)\n----------------------------\n\n- [removeOverlaps] Added new module and ``removeOverlaps`` function that merges\n  overlapping contours and components in TrueType glyphs. It requires the\n  `skia-pathops <https://github.com/fonttools/skia-pathops>`__ module.\n  Note that removing overlaps invalidates the TrueType hinting (#2068).\n- [varLib.instancer] Added ``--remove-overlaps`` command-line option.\n  The ``overlap`` option in ``instantiateVariableFont`` now takes an ``OverlapMode``\n  enum: 0: KEEP_AND_DONT_SET_FLAGS, 1: KEEP_AND_SET_FLAGS (default), and 2: REMOVE.\n  The latter is equivalent to calling ``removeOverlaps`` on the generated static\n  instance. The option continues to accept ``bool`` value for backward compatibility.\n\n\n4.15.0 (released 2020-09-21)\n----------------------------\n\n- [plistlib] Added typing annotations to plistlib module. Set up mypy static\n  typechecker to run automatically on CI (#2061).\n- [ttLib] Implement private ``Debg`` table, a reverse-DNS namespaced JSON dict.\n- [feaLib] Optionally add an entry into the ``Debg`` table with the original\n  lookup name (if any), feature name / script / language combination (if any),\n  and original source filename and line location. Annotate the ttx output for\n  a lookup with the information from the Debg table (#2052).\n- [sfnt] Disabled checksum checking by default in ``SFNTReader`` (#2058).\n- [Docs] Document ``mtiLib`` module (#2027).\n- [varLib.interpolatable] Added checks for contour node count and operation type\n  of each node (#2054).\n- [ttLib] Added API to register custom table packer/unpacker classes (#2055).\n\n4.14.0 (released 2020-08-19)\n----------------------------\n\n- [feaLib] Allow anonymous classes in LookupFlags definitions (#2037).\n- [Docs] Better document DesignSpace rules processing order (#2041).\n- [ttLib] Fixed 21-year old bug in ``maxp.maxComponentDepth`` calculation (#2044,\n  #2045).\n- [varLib.models] Fixed misspelled argument name in CLI entry point (81d0042a).\n- [subset] When subsetting GSUB v1.1, fixed TypeError by checking whether the\n  optional FeatureVariations table is present (e63ecc5b).\n- [Snippets] Added snippet to show how to decompose glyphs in a TTF (#2030).\n- [otlLib] Generate GSUB type 5 and GPOS type 7 contextual lookups where appropriate\n  (#2016).\n\n4.13.0 (released 2020-07-10)\n----------------------------\n\n- [feaLib/otlLib] Moved lookup subtable builders from feaLib to otlLib; refactored\n  some common code (#2004, #2007).\n- [docs] Document otlLib module (#2009).\n- [glifLib] Fixed bug with some UFO .glif filenames clashing on case-insensitive\n  filesystems (#2001, #2002).\n- [colorLib] Updated COLRv1 implementation following changes in the draft spec:\n  (#2008, googlefonts/colr-gradients-spec#24).\n\n4.12.1 (released 2020-06-16)\n----------------------------\n\n- [_n_a_m_e] Fixed error in ``addMultilingualName`` with one-character names.\n  Only attempt to recovered malformed UTF-16 data from a ``bytes`` string,\n  not from unicode ``str`` (#1997, #1998).\n\n4.12.0 (released 2020-06-09)\n----------------------------\n\n- [otlLib/varLib] Ensure that the ``AxisNameID`` in the ``STAT`` and ``fvar``\n  tables is grater than 255 as per OpenType spec (#1985, #1986).\n- [docs] Document more modules in ``fontTools.misc`` package: ``filenames``,\n  ``fixedTools``, ``intTools``, ``loggingTools``, ``macCreatorType``, ``macRes``,\n  ``plistlib`` (#1981).\n- [OS/2] Don't calculate whole sets of unicode codepoints, use faster and more memory\n  efficient ranges and bisect lookups (#1984).\n- [voltLib] Support writing back abstract syntax tree as VOLT data (#1983).\n- [voltLib] Accept DO_NOT_TOUCH_CMAP keyword (#1987).\n- [subset/merge] Fixed a namespace clash involving a private helper class (#1955).\n\n4.11.0 (released 2020-05-28)\n----------------------------\n\n- [feaLib] Introduced ``includeDir`` parameter on Parser and IncludingLexer to\n  explicitly specify the directory to search when ``include()`` statements are\n  encountered (#1973).\n- [ufoLib] Silently delete duplicate glyphs within the same kerning group when reading\n  groups (#1970).\n- [ttLib] Set version of COLR table when decompiling COLRv1 (commit 9d8a7e2).\n\n4.10.2 (released 2020-05-20)\n----------------------------\n\n- [sfnt] Fixed ``NameError: SimpleNamespace`` while reading TTC header. The regression\n  was introduced with 4.10.1 after removing ``py23`` star import.\n\n4.10.1 (released 2020-05-19)\n----------------------------\n\n- [sfnt] Make ``SFNTReader`` pickleable even when TTFont is loaded with lazy=True\n  option and thus keeps a reference to an external file (#1962, #1967).\n- [feaLib.ast] Restore backward compatibility (broken in 4.10 with #1905) for\n  ``ChainContextPosStatement`` and ``ChainContextSubstStatement`` classes.\n  Make them accept either list of lookups or list of lists of lookups (#1961).\n- [docs] Document some modules in ``fontTools.misc`` package: ``arrayTools``,\n  ``bezierTools`` ``cliTools`` and ``eexec`` (#1956).\n- [ttLib._n_a_m_e] Fixed ``findMultilingualName()`` when name record's ``string`` is\n  encoded as bytes sequence (#1963).\n\n4.10.0 (released 2020-05-15)\n----------------------------\n\n- [varLib] Allow feature variations to be active across the entire space (#1957).\n- [ufoLib] Added support for ``formatVersionMinor`` in UFO's ``fontinfo.plist`` and for\n  ``formatMinor`` attribute in GLIF file as discussed in unified-font-object/ufo-spec#78.\n  No changes in reading or writing UFOs until an upcoming (non-0) minor update of the\n  UFO specification is published (#1786).\n- [merge] Fixed merging fonts with different versions of ``OS/2`` table (#1865, #1952).\n- [subset] Fixed ``AttributeError`` while subsetting ``ContextSubst`` and ``ContextPos``\n  Format 3 subtable (#1879, #1944).\n- [ttLib.table._m_e_t_a] if data happens to be ascii, emit comment in TTX (#1938).\n- [feaLib] Support multiple lookups per glyph position (#1905).\n- [psCharStrings] Use inheritance to avoid repeated code in initializer (#1932).\n- [Doc] Improved documentation for the following modules: ``afmLib`` (#1933), ``agl``\n  (#1934), ``cffLib`` (#1935), ``cu2qu`` (#1937), ``encodings`` (#1940), ``feaLib``\n  (#1941), ``merge`` (#1949).\n- [Doc] Split off developer-centric info to new page, making front page of docs more\n  user-focused. List all utilities and sub-modules with brief descriptions.\n  Make README more concise and focused (#1914).\n- [otlLib] Add function to build STAT table from high-level description (#1926).\n- [ttLib._n_a_m_e] Add ``findMultilingualName()`` method (#1921).\n- [unicodedata] Update ``RTL_SCRIPTS`` for Unicode 13.0 (#1925).\n- [gvar] Sort ``gvar`` XML output by glyph name, not glyph order (#1907, #1908).\n- [Doc] Added help options to ``fonttools`` command line tool (#1913, #1920).\n  Ensure all fonttools CLI tools have help documentation (#1948).\n- [ufoLib] Only write fontinfo.plist when there actually is content (#1911).\n\n4.9.0 (released 2020-04-29)\n---------------------------\n\n- [subset] Fixed subsetting of FeatureVariations table. The subsetter no longer drops\n  FeatureVariationRecords that have empty substitutions as that will keep the search\n  going and thus change the logic. It will only drop empty records that occur at the\n  end of the FeatureVariationRecords array (#1881).\n- [subset] Remove FeatureVariations table and downgrade GSUB/GPOS to version 0x10000\n  when FeatureVariations contain no FeatureVariationRecords after subsetting (#1903).\n- [agl] Add support for legacy Adobe Glyph List of glyph names in ``fontTools.agl``\n  (#1895).\n- [feaLib] Ignore superfluous script statements (#1883).\n- [feaLib] Hide traceback by default on ``fonttools feaLib`` command line.\n  Use ``--traceback`` option to show (#1898).\n- [feaLib] Check lookup index in chaining sub/pos lookups and print better error\n  message (#1896, #1897).\n- [feaLib] Fix building chained alt substitutions (#1902).\n- [Doc] Included all fontTools modules in the sphinx-generated documentation, and\n  published it to ReadTheDocs for continuous documentation of the fontTools project\n  (#1333). Check it out at https://fonttools.readthedocs.io/. Thanks to Chris Simpkins!\n- [transform] The ``Transform`` class is now subclass of ``typing.NamedTuple``. No\n  change in functionality (#1904).\n\n\n4.8.1 (released 2020-04-17)\n---------------------------\n\n- [feaLib] Fixed ``AttributeError: 'NoneType' has no attribute 'getAlternateGlyphs'``\n  when ``aalt`` feature references a chain contextual substitution lookup\n  (googlefonts/fontmake#648, #1878).\n\n4.8.0 (released 2020-04-16)\n---------------------------\n\n- [feaLib] If Parser is initialized without a ``glyphNames`` parameter, it cannot\n  distinguish between a glyph name containing an hyphen, or a range of glyph names;\n  instead of raising an error, it now interprets them as literal glyph names, while\n  also outputting a logging warning to alert user about the ambiguity (#1768, #1870).\n- [feaLib] When serializing AST to string, emit spaces around hyphens that denote\n  ranges. Also, fixed an issue with CID ranges when round-tripping AST->string->AST\n  (#1872).\n- [Snippets/otf2ttf] In otf2ttf.py script update LSB in hmtx to match xMin (#1873).\n- [colorLib] Added experimental support for building ``COLR`` v1 tables as per\n  the `colr-gradients-spec <https://github.com/googlefonts/colr-gradients-spec/blob/main/colr-gradients-spec.md>`__\n  draft proposal. **NOTE**: both the API and the XML dump of ``COLR`` v1 are\n  susceptible to change while the proposal is being discussed and formalized (#1822).\n\n4.7.0 (released 2020-04-03)\n---------------------------\n\n- [cu2qu] Added ``fontTools.cu2qu`` package, imported from the original\n  `cu2qu <https://github.com/googlefonts/cu2qu>`__ project. The ``cu2qu.pens`` module\n  was moved to ``fontTools.pens.cu2quPen``. The optional cu2qu extension module\n  can be compiled by installing `Cython <https://cython.org/>`__ before installing\n  fonttools from source (i.e. git repo or sdist tarball). The wheel package that\n  is published on PyPI (i.e. the one ``pip`` downloads, unless ``--no-binary``\n  option is used), will continue to be pure-Python for now (#1868).\n\n4.6.0 (released 2020-03-24)\n---------------------------\n\n- [varLib] Added support for building variable ``BASE`` table version 1.1 (#1858).\n- [CPAL] Added ``fromRGBA`` method to ``Color`` class (#1861).\n\n\n4.5.0 (released 2020-03-20)\n---------------------------\n\n- [designspaceLib] Added ``add{Axis,Source,Instance,Rule}Descriptor`` methods to\n  ``DesignSpaceDocument`` class, to initialize new descriptor objects using keyword\n  arguments, and at the same time append them to the current document (#1860).\n- [unicodedata] Update to Unicode 13.0 (#1859).\n\n4.4.3 (released 2020-03-13)\n---------------------------\n\n- [varLib] Always build ``gvar`` table for TrueType-flavored Variable Fonts,\n  even if it contains no variation data. The table is required according to\n  the OpenType spec (#1855, #1857).\n\n4.4.2 (released 2020-03-12)\n---------------------------\n\n- [ttx] Annotate ``LookupFlag`` in XML dump with comment explaining what bits\n  are set and what they mean (#1850).\n- [feaLib] Added more descriptive message to ``IncludedFeaNotFound`` error (#1842).\n\n4.4.1 (released 2020-02-26)\n---------------------------\n\n- [woff2] Skip normalizing ``glyf`` and ``loca`` tables if these are missing from\n  a font (e.g. in NotoColorEmoji using ``CBDT/CBLC`` tables).\n- [timeTools] Use non-localized date parsing in ``timestampFromString``, to fix\n  error when non-English ``LC_TIME`` locale is set (#1838, #1839).\n- [fontBuilder] Make sure the CFF table generated by fontBuilder can be used by varLib\n  without having to compile and decompile the table first. This was breaking in\n  converting the CFF table to CFF2 due to some unset attributes (#1836).\n\n4.4.0 (released 2020-02-18)\n---------------------------\n\n- [colorLib] Added ``fontTools.colorLib.builder`` module, initially with ``buildCOLR``\n  and ``buildCPAL`` public functions. More color font formats will follow (#1827).\n- [fontBuilder] Added ``setupCOLR`` and ``setupCPAL`` methods (#1826).\n- [ttGlyphPen] Quantize ``GlyphComponent.transform`` floats to ``F2Dot14`` to fix\n  round-trip issue when computing bounding boxes of transformed components (#1830).\n- [glyf] If a component uses reference points (``firstPt`` and ``secondPt``) for\n  alignment (instead of X and Y offsets), compute the effective translation offset\n  *after* having applied any transform (#1831).\n- [glyf] When all glyphs have zero contours, compile ``glyf`` table data as a single\n  null byte in order to pass validation by OTS and Windows (#1829).\n- [feaLib] Parsing feature code now ensures that referenced glyph names are part of\n  the known glyph set, unless a glyph set was not provided.\n- [varLib] When filling in the default axis value for a missing location of a source or\n  instance, correctly map the value forward.\n- [varLib] The avar table can now contain mapping output values that are greater than\n  OR EQUAL to the preceeding value, as the avar specification allows this.\n- [varLib] The errors of the module are now ordered hierarchically below VarLibError.\n  See #1821.\n\n4.3.0 (released 2020-02-03)\n---------------------------\n\n- [EBLC/CBLC] Fixed incorrect padding length calculation for Format 3 IndexSubTable\n  (#1817, #1818).\n- [varLib] Fixed error when merging OTL tables and TTFonts were loaded as ``lazy=True``\n  (#1808, #1809).\n- [varLib] Allow to use master fonts containing ``CFF2`` table when building VF (#1816).\n- [ttLib] Make ``recalcBBoxes`` option work also with ``CFF2`` table (#1816).\n- [feaLib] Don't reset ``lookupflag`` in lookups defined inside feature blocks.\n  They will now inherit the current ``lookupflag`` of the feature. This is what\n  Adobe ``makeotf`` also does in this case (#1815).\n- [feaLib] Fixed bug with mixed single/multiple substitutions. If a single substitution\n  involved a glyph class, we were incorrectly using only the first glyph in the class\n  (#1814).\n\n4.2.5 (released 2020-01-29)\n---------------------------\n\n- [feaLib] Do not fail on duplicate multiple substitutions, only warn (#1811).\n- [subset] Optimize SinglePos subtables to Format 1 if all ValueRecords are the same\n  (#1802).\n\n4.2.4 (released 2020-01-09)\n---------------------------\n\n- [unicodedata] Update RTL_SCRIPTS for Unicode 11 and 12.\n\n4.2.3 (released 2020-01-07)\n---------------------------\n\n- [otTables] Fixed bug when splitting `MarkBasePos` subtables as offsets overflow.\n  The mark class values in the split subtable were not being updated, leading to\n  invalid mark-base attachments (#1797, googlefonts/noto-source#145).\n- [feaLib] Only log a warning instead of error when features contain duplicate\n  substitutions (#1767).\n- [glifLib] Strip XML comments when parsing with lxml (#1784, #1785).\n\n4.2.2 (released 2019-12-12)\n---------------------------\n\n- [subset] Fixed issue with subsetting FeatureVariations table when the index\n  of features changes as features get dropped. The feature index need to be\n  remapped to point to index of the remaining features (#1777, #1782).\n- [fontBuilder] Added `addFeatureVariations` method to `FontBuilder` class. This\n  is a shorthand for calling `featureVars.addFeatureVariations` on the builder's\n  TTFont object (#1781).\n- [glyf] Fixed the flags bug in glyph.drawPoints() like we did for glyph.draw()\n  (#1771, #1774).\n\n4.2.1 (released 2019-12-06)\n---------------------------\n\n- [glyf] Use the ``flagOnCurve`` bit mask in ``glyph.draw()``, so that we ignore\n  the ``overlap`` flag that may be set when instantiating variable fonts (#1771).\n\n4.2.0 (released 2019-11-28)\n---------------------------\n\n- [pens] Added the following pens:\n\n  * ``roundingPen.RoundingPen``: filter pen that rounds coordinates and components'\n    offsets to integer;\n  * ``roundingPen.RoundingPointPen``: like the above, but using PointPen protocol.\n  * ``filterPen.FilterPointPen``: base class for filter point pens;\n  * ``transformPen.TransformPointPen``: filter point pen to apply affine transform;\n  * ``recordingPen.RecordingPointPen``: records and replays point-pen commands.\n\n- [ttGlyphPen] Always round float coordinates and component offsets to integers\n  (#1763).\n- [ufoLib] When converting kerning groups from UFO2 to UFO3, avoid confusing\n  groups with the same name as one of the glyphs (#1761, #1762,\n  unified-font-object/ufo-spec#98).\n\n4.1.0 (released 2019-11-18)\n---------------------------\n\n- [instancer] Implemented restricting axis ranges (level 3 partial instancing).\n  You can now pass ``{axis_tag: (min, max)}`` tuples as input to the\n  ``instantiateVariableFont`` function. Note that changing the default axis\n  position is not supported yet. The command-line script also accepts axis ranges\n  in the form of colon-separated float values, e.g. ``wght=400:700`` (#1753, #1537).\n- [instancer] Never drop STAT ``DesignAxis`` records, but only prune out-of-range\n  ``AxisValue`` records.\n- [otBase/otTables] Enforce that VarStore.RegionAxisCount == fvar.axisCount, even\n  when regions list is empty to appease OTS < v8.0 (#1752).\n- [designspaceLib] Defined new ``processing`` attribute for ``<rules>`` element,\n  with values \"first\" or \"last\", plus other editorial changes to DesignSpace\n  specification. Bumped format version to 4.1 (#1750).\n- [varLib] Improved error message when masters' glyph orders do not match (#1758,\n  #1759).\n- [featureVars] Allow to specify custom feature tag in ``addFeatureVariations``;\n  allow said feature to already exist, in which case we append new lookup indices\n  to existing features. Implemented ``<rules>`` attribute ``processing`` according to\n  DesignSpace specification update in #1750. Depending on this flag, we generate\n  either an 'rvrn' (always processed first) or a 'rclt' feature (follows lookup order,\n  therefore last) (#1747, #1625, #1371).\n- [ttCollection] Added support for context manager auto-closing via ``with`` statement\n  like with ``TTFont`` (#1751).\n- [unicodedata] Require unicodedata2 >= 12.1.0.\n- [py2.py3] Removed yet more PY2 vestiges (#1743).\n- [_n_a_m_e] Fixed issue when comparing NameRecords with different string types (#1742).\n- [fixedTools] Changed ``fixedToFloat`` to not do any rounding but simply return\n  ``value / (1 << precisionBits)``. Added ``floatToFixedToStr`` and\n  ``strToFixedToFloat`` functions to be used when loading from or dumping to XML.\n  Fixed values (e.g. fvar axes and instance coordinates, avar mappings, etc.) are\n  are now stored as un-rounded decimal floats upon decompiling (#1740, #737).\n- [feaLib] Fixed handling of multiple ``LigatureCaret`` statements for the same glyph.\n  Only the first rule per glyph is used, additional ones are ignored (#1733).\n\n4.0.2 (released 2019-09-26)\n---------------------------\n\n- [voltLib] Added support for ``ALL`` and ``NONE`` in ``PROCESS_MARKS`` (#1732).\n- [Silf] Fixed issue in ``Silf`` table compilation and decompilation regarding str vs\n  bytes in python3 (#1728).\n- [merge] Handle duplicate glyph names better: instead of appending font index to\n  all glyph names, use similar code like we use in ``post`` and ``CFF`` tables (#1729).\n\n4.0.1 (released 2019-09-11)\n---------------------------\n\n- [otTables] Support fixing offset overflows in ``MultipleSubst`` lookup subtables\n  (#1706).\n- [subset] Prune empty strikes in ``EBDT`` and ``CBDT`` table data (#1698, #1633).\n- [pens] Fixed issue in ``PointToSegmentPen`` when last point of closed contour has\n  same coordinates as the starting point and was incorrectly dropped (#1720).\n- [Graphite] Fixed ``Sill`` table output to pass OTS (#1705).\n- [name] Added ``removeNames`` method to ``table__n_a_m_e`` class (#1719).\n- [ttLib] Added aliases for renamed entries ``ascender`` and ``descender`` in\n  ``hhea`` table (#1715).\n\n4.0.0 (released 2019-08-22)\n---------------------------\n\n- NOTE: The v4.x version series only supports Python 3.6 or greater. You can keep\n  using fonttools 3.x if you need support for Python 2.\n- [py23] Removed all the python2-only code since it is no longer reachable, thus\n  unused; only the Python3 symbols were kept, but these are no-op. The module is now\n  DEPRECATED and will removed in the future.\n- [ttLib] Fixed UnboundLocalError for empty loca/glyph tables (#1680). Also, allow\n  the glyf table to be incomplete when dumping to XML (#1681).\n- [varLib.models] Fixed KeyError while sorting masters and there are no on-axis for\n  a given axis (38a8eb0e).\n- [cffLib] Make sure glyph names are unique (#1699).\n- [feaLib] Fix feature parser to correctly handle octal numbers (#1700).\n\n\\... see `here <https://github.com/fonttools/fonttools/blob/main/NEWS.rst>`__ for earlier changes\n",
        "description_content_type": "text/x-rst",
        "home_page": "http://github.com/fonttools/fonttools",
        "author": "Just van Rossum",
        "author_email": "just@letterror.com",
        "maintainer": "Behdad Esfahbod",
        "maintainer_email": "behdad@behdad.org",
        "license": "MIT",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Environment :: Console",
          "Environment :: Other Environment",
          "Intended Audience :: Developers",
          "Intended Audience :: End Users/Desktop",
          "Natural Language :: English",
          "Operating System :: OS Independent",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3",
          "Topic :: Text Processing :: Fonts",
          "Topic :: Multimedia :: Graphics",
          "Topic :: Multimedia :: Graphics :: Graphics Conversion"
        ],
        "requires_dist": [
          "lxml>=4.0; extra == \"lxml\"",
          "brotli>=1.0.1; platform_python_implementation == \"CPython\" and extra == \"woff\"",
          "brotlicffi>=0.8.0; platform_python_implementation != \"CPython\" and extra == \"woff\"",
          "zopfli>=0.1.4; extra == \"woff\"",
          "unicodedata2>=17.0.0; python_version <= \"3.14\" and extra == \"unicode\"",
          "lz4>=1.7.4.2; extra == \"graphite\"",
          "scipy; platform_python_implementation != \"PyPy\" and extra == \"interpolatable\"",
          "munkres; platform_python_implementation == \"PyPy\" and extra == \"interpolatable\"",
          "pycairo; extra == \"interpolatable\"",
          "matplotlib; extra == \"plot\"",
          "sympy; extra == \"symfont\"",
          "xattr; sys_platform == \"darwin\" and extra == \"type1\"",
          "skia-pathops>=0.5.0; extra == \"pathops\"",
          "uharfbuzz>=0.45.0; extra == \"repacker\"",
          "lxml>=4.0; extra == \"all\"",
          "brotli>=1.0.1; platform_python_implementation == \"CPython\" and extra == \"all\"",
          "brotlicffi>=0.8.0; platform_python_implementation != \"CPython\" and extra == \"all\"",
          "zopfli>=0.1.4; extra == \"all\"",
          "unicodedata2>=17.0.0; python_version <= \"3.14\" and extra == \"all\"",
          "lz4>=1.7.4.2; extra == \"all\"",
          "scipy; platform_python_implementation != \"PyPy\" and extra == \"all\"",
          "munkres; platform_python_implementation == \"PyPy\" and extra == \"all\"",
          "pycairo; extra == \"all\"",
          "matplotlib; extra == \"all\"",
          "sympy; extra == \"all\"",
          "xattr; sys_platform == \"darwin\" and extra == \"all\"",
          "skia-pathops>=0.5.0; extra == \"all\"",
          "uharfbuzz>=0.45.0; extra == \"all\""
        ],
        "requires_python": ">=3.10",
        "provides_extra": [
          "ufo",
          "lxml",
          "woff",
          "unicode",
          "graphite",
          "interpolatable",
          "plot",
          "symfont",
          "type1",
          "pathops",
          "repacker",
          "all"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/67/4e/a28359bf1c1ecf11eba22123168c138698f7cb576ac678f5a2e16cd5da08/hf_xet-1.6.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl",
        "archive_info": {
          "hash": "sha256=d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f",
          "hashes": {
            "sha256": "d62671bb130879cef0ee4c9ebe47a14af6c66ec53e6d84dc15936e5ffdfac82f"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "hf-xet",
        "version": "1.6.0",
        "summary": "Fast transfer of large files with the Hugging Face Hub.",
        "description": "<!---\nCopyright 2024 The HuggingFace Team. All rights reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n-->\n<p align=\"center\">\n    <a href=\"https://github.com/huggingface/xet-core/blob/main/LICENSE\"><img alt=\"License\" src=\"https://img.shields.io/github/license/huggingface/xet-core.svg?color=blue\"></a>\n    <a href=\"https://github.com/huggingface/xet-core/releases\"><img alt=\"GitHub release\" src=\"https://img.shields.io/github/release/huggingface/xet-core.svg\"></a>\n    <a href=\"https://github.com/huggingface/xet-core/blob/main/CODE_OF_CONDUCT.md\"><img alt=\"Contributor Covenant\" src=\"https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg\"></a>\n</p>\n\n<h3 align=\"center\">\n  <p>🤗 hf-xet - xet client tech, used in <a target=\"_blank\" href=\"https://github.com/huggingface/huggingface_hub/\">huggingface_hub</a></p>\n</h3>\n\n## Welcome\n\n`hf-xet` enables `huggingface_hub` to utilize xet storage for uploading and downloading to HF Hub. Xet storage provides chunk-based deduplication, efficient storage/retrieval with local disk caching, and backwards compatibility with Git LFS. This library is not meant to be used directly, and is instead intended to be used from [huggingface_hub](https://pypi.org/project/huggingface-hub).\n\n## Key features\n\n♻ **chunk-based deduplication implementation**: avoid transferring and storing chunks that are shared across binary files (models, datasets, etc).\n\n🤗 **Python bindings**: bindings for [huggingface_hub](https://github.com/huggingface/huggingface_hub/) package.\n\n↔ **network communications**: concurrent communication to HF Hub Xet backend services (CAS).\n\n🔖 **local disk caching**: chunk-based cache that sits alongside the existing [huggingface_hub disk cache](https://huggingface.co/docs/huggingface_hub/guides/manage-cache).\n\n## Installation\n\nInstall the `hf_xet` package with [pip](https://pypi.org/project/hf-xet/):\n\n```bash\npip install hf_xet\n```\n\n## Quick Start\n\n`hf_xet` is not intended to be run independently as it is expected to be used from `huggingface_hub`, so to get started with `huggingface_hub` check out the documentation [here](\"https://hf.co/docs/huggingface_hub\").\n\n## Contributions (feature requests, bugs, etc.) are encouraged & appreciated 💙💚💛💜🧡❤️\n\nPlease join us in making hf-xet better. We value everyone's contributions. Code is not the only way to help. Answering questions, helping each other, improving documentation, filing issues all help immensely. If you are interested in contributing (please do!), check out the [contribution guide](https://github.com/huggingface/xet-core/blob/main/CONTRIBUTING.md) for this repository.\n",
        "description_content_type": "text/markdown; charset=UTF-8; variant=GFM",
        "maintainer_email": "Rajat Arya <rajat@rajatarya.com>, Jared Sulzdorf <j.sulzdorf@gmail.com>, Di Xiao <di@huggingface.co>, Assaf Vayner <assaf@huggingface.co>, Hoyt Koepke <hoytak@gmail.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "License :: OSI Approved :: Apache Software License",
          "Programming Language :: Rust",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.8",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: Free Threading",
          "Programming Language :: Python :: Free Threading :: 2 - Beta",
          "Topic :: Scientific/Engineering :: Artificial Intelligence"
        ],
        "requires_dist": [
          "pytest ; extra == 'tests'"
        ],
        "requires_python": ">=3.8",
        "project_url": [
          "Documentation, https://huggingface.co/docs/hub/xet/index",
          "Homepage, https://github.com/huggingface/xet-core",
          "Issues, https://github.com/huggingface/xet-core/issues",
          "Repository, https://github.com/huggingface/xet-core.git"
        ],
        "provides_extra": [
          "tests"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/fc/f4/dadfec469313c7f428efa7e84b4aba9732f813c13ea7131a24b7b008ef57/kiwisolver-1.5.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl",
        "archive_info": {
          "hash": "sha256=34633ecf50d16187ab8e5528b7a2530f2feb4e23f300db4672538b51cfc5cd38",
          "hashes": {
            "sha256": "34633ecf50d16187ab8e5528b7a2530f2feb4e23f300db4672538b51cfc5cd38"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "kiwisolver",
        "version": "1.5.1",
        "dynamic": [
          "license-file"
        ],
        "summary": "A fast implementation of the Cassowary constraint solver",
        "description_content_type": "text/x-rst",
        "author_email": "The Nucleic Development Team <sccolbert@gmail.com>",
        "maintainer_email": "\"Matthieu C. Dartiailh\" <m.dartiailh@gmail.com>",
        "license": "=========================\n The Kiwi licensing terms\n=========================\nKiwi is licensed under the terms of the Modified BSD License (also known as\nNew or Revised BSD), as follows:\n\nCopyright (c) 2013-2026, Nucleic Development Team\n\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer.\n\nRedistributions in binary form must reproduce the above copyright notice, this\nlist of conditions and the following disclaimer in the documentation and/or\nother materials provided with the distribution.\n\nNeither the name of the Nucleic Development Team nor the names of its\ncontributors may be used to endorse or promote products derived from this\nsoftware without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nAbout Kiwi\n----------\nChris Colbert began the Kiwi project in December 2013 in an effort to\ncreate a blisteringly fast UI constraint solver. Chris is still the\nproject lead.\n\nThe Nucleic Development Team is the set of all contributors to the Nucleic\nproject and its subprojects.\n\nThe core team that coordinates development on GitHub can be found here:\nhttp://github.com/nucleic. The current team consists of:\n\n* Chris Colbert\n\nOur Copyright Policy\n--------------------\nNucleic uses a shared copyright model. Each contributor maintains copyright\nover their contributions to Nucleic. But, it is important to note that these\ncontributions are typically only changes to the repositories. Thus, the Nucleic\nsource code, in its entirety is not the copyright of any single person or\ninstitution. Instead, it is the collective copyright of the entire Nucleic\nDevelopment Team. If individual contributors want to maintain a record of what\nchanges/contributions they have specific copyright on, they should indicate\ntheir copyright in the commit message of the change, when they commit the\nchange to one of the Nucleic repositories.\n\nWith this in mind, the following banner should be used in any source code file\nto indicate the copyright and license terms:\n\n#------------------------------------------------------------------------------\n# Copyright (c) 2013-2026, Nucleic Development Team.\n#\n# Distributed under the terms of the Modified BSD License.\n#\n# The full license is in the file LICENSE, distributed with this software.\n#------------------------------------------------------------------------------\n",
        "classifier": [
          "License :: OSI Approved :: BSD License",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3.15",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Programming Language :: Python :: Implementation :: GraalPy"
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "homepage, https://github.com/nucleic/kiwi",
          "documentation, https://kiwisolver.readthedocs.io/en/latest/",
          "repository, https://github.com/nucleic/kiwi",
          "changelog, https://github.com/nucleic/kiwi/blob/main/releasenotes.rst"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a",
          "hashes": {
            "sha256": "9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "markdown-it-py",
        "version": "4.2.0",
        "summary": "Python port of markdown-it. Markdown parsing, done right!",
        "description": "# markdown-it-py\n\n[![Github-CI][github-ci]][github-link]\n[![Coverage Status][codecov-badge]][codecov-link]\n[![PyPI][pypi-badge]][pypi-link]\n[![Conda][conda-badge]][conda-link]\n[![PyPI - Downloads][install-badge]][install-link]\n\n<p align=\"center\">\n  <img alt=\"markdown-it-py icon\" src=\"https://raw.githubusercontent.com/executablebooks/markdown-it-py/master/docs/_static/markdown-it-py.svg\">\n</p>\n\n> Markdown parser done right.\n\n- Follows the __[CommonMark spec](http://spec.commonmark.org/)__ for baseline parsing\n- Configurable syntax: you can add new rules and even replace existing ones.\n- Pluggable: Adds syntax extensions to extend the parser (see the [plugin list][md-plugins]).\n- High speed (see our [benchmarking tests][md-performance])\n- Easy to configure for [security][md-security]\n- Member of [Google's Assured Open Source Software](https://cloud.google.com/assured-open-source-software/docs/supported-packages)\n\nThis is a Python port of [markdown-it], and some of its associated plugins.\nFor more details see: <https://markdown-it-py.readthedocs.io>.\n\nFor details on [markdown-it] itself, see:\n\n- The __[Live demo](https://markdown-it.github.io)__\n- [The markdown-it README][markdown-it-readme]\n\n**See also:** [markdown-it-pyrs](https://github.com/chrisjsewell/markdown-it-pyrs) for an experimental Rust binding,\nfor even more speed!\n\n## Installation\n\n### PIP\n\n```bash\npip install markdown-it-py[plugins]\n```\n\nor with extras\n\n```bash\npip install markdown-it-py[linkify,plugins]\n```\n\n### Conda\n\n```bash\nconda install -c conda-forge markdown-it-py\n```\n\nor with extras\n\n```bash\nconda install -c conda-forge markdown-it-py linkify-it-py mdit-py-plugins\n```\n\n## Usage\n\n### Python API Usage\n\nRender markdown to HTML with markdown-it-py and a custom configuration\nwith and without plugins and features:\n\n```python\nfrom markdown_it import MarkdownIt\nfrom mdit_py_plugins.front_matter import front_matter_plugin\nfrom mdit_py_plugins.footnote import footnote_plugin\n\nmd = (\n    MarkdownIt('commonmark', {'breaks':True,'html':True})\n    .use(front_matter_plugin)\n    .use(footnote_plugin)\n    .enable('table')\n)\ntext = (\"\"\"\n---\na: 1\n---\n\na | b\n- | -\n1 | 2\n\nA footnote [^1]\n\n[^1]: some details\n\"\"\")\ntokens = md.parse(text)\nhtml_text = md.render(text)\n\n## To export the html to a file, uncomment the lines below:\n# from pathlib import Path\n# Path(\"output.html\").write_text(html_text)\n```\n\n### Command-line Usage\n\nRender markdown to HTML with markdown-it-py from the\ncommand-line:\n\n```console\nusage: markdown-it [-h] [-v] [--stdin|filenames [filenames ...]]\n\nParse one or more markdown files, convert each to HTML, and print to stdout\n\npositional arguments:\n  --stdin        read source Markdown file from standard input\n  filenames      specify an optional list of files to convert\n\noptional arguments:\n  -h, --help     show this help message and exit\n  -v, --version  show program's version number and exit\n\nInteractive:\n\n  $ markdown-it\n  markdown-it-py [version 0.0.0] (interactive)\n  Type Ctrl-D to complete input, or Ctrl-C to exit.\n  >>> # Example\n  ... > markdown *input*\n  ...\n  <h1>Example</h1>\n  <blockquote>\n  <p>markdown <em>input</em></p>\n  </blockquote>\n\nBatch:\n\n  $ markdown-it README.md README.footer.md > index.html\n\n```\n\n## References / Thanks\n\nBig thanks to the authors of [markdown-it]:\n\n- Alex Kocharin [github/rlidwka](https://github.com/rlidwka)\n- Vitaly Puzrin [github/puzrin](https://github.com/puzrin)\n\nAlso [John MacFarlane](https://github.com/jgm) for his work on the CommonMark spec and reference implementations.\n\n[github-ci]: https://github.com/executablebooks/markdown-it-py/actions/workflows/tests.yml/badge.svg?branch=master\n[github-link]: https://github.com/executablebooks/markdown-it-py\n[pypi-badge]: https://img.shields.io/pypi/v/markdown-it-py.svg\n[pypi-link]: https://pypi.org/project/markdown-it-py\n[conda-badge]: https://anaconda.org/conda-forge/markdown-it-py/badges/version.svg\n[conda-link]: https://anaconda.org/conda-forge/markdown-it-py\n[codecov-badge]: https://codecov.io/gh/executablebooks/markdown-it-py/branch/master/graph/badge.svg\n[codecov-link]: https://codecov.io/gh/executablebooks/markdown-it-py\n[install-badge]: https://img.shields.io/pypi/dw/markdown-it-py?label=pypi%20installs\n[install-link]: https://pypistats.org/packages/markdown-it-py\n\n[CommonMark spec]: http://spec.commonmark.org/\n[markdown-it]: https://github.com/markdown-it/markdown-it\n[markdown-it-readme]: https://github.com/markdown-it/markdown-it/blob/master/README.md\n[md-security]: https://markdown-it-py.readthedocs.io/en/latest/security.html\n[md-performance]: https://markdown-it-py.readthedocs.io/en/latest/performance.html\n[md-plugins]: https://markdown-it-py.readthedocs.io/en/latest/plugins.html\n\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "markdown",
          "lexer",
          "parser",
          "commonmark",
          "markdown-it"
        ],
        "author_email": "Chris Sewell <chrisj_sewell@hotmail.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: MIT License",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Topic :: Text Processing :: Markup"
        ],
        "requires_dist": [
          "mdurl~=0.1",
          "psutil ; extra == \"benchmarking\"",
          "pytest ; extra == \"benchmarking\"",
          "pytest-benchmark ; extra == \"benchmarking\"",
          "commonmark~=0.9 ; extra == \"compare\"",
          "markdown~=3.4 ; extra == \"compare\"",
          "mistletoe~=1.0 ; extra == \"compare\"",
          "mistune~=3.0 ; extra == \"compare\"",
          "panflute~=2.3 ; extra == \"compare\"",
          "markdown-it-pyrs ; extra == \"compare\"",
          "linkify-it-py>=1,<3 ; extra == \"linkify\"",
          "mdit-py-plugins>=0.5.0 ; extra == \"plugins\"",
          "gprof2dot ; extra == \"profiling\"",
          "mdit-py-plugins>=0.5.0 ; extra == \"rtd\"",
          "myst-parser ; extra == \"rtd\"",
          "pyyaml ; extra == \"rtd\"",
          "sphinx ; extra == \"rtd\"",
          "sphinx-copybutton ; extra == \"rtd\"",
          "sphinx-design ; extra == \"rtd\"",
          "sphinx-book-theme~=1.0 ; extra == \"rtd\"",
          "jupyter_sphinx ; extra == \"rtd\"",
          "ipykernel ; extra == \"rtd\"",
          "coverage ; extra == \"testing\"",
          "pytest ; extra == \"testing\"",
          "pytest-cov ; extra == \"testing\"",
          "pytest-regressions ; extra == \"testing\"",
          "pytest-timeout ; extra == \"testing\"",
          "requests ; extra == \"testing\""
        ],
        "requires_python": ">=3.10",
        "project_url": [
          "Documentation, https://markdown-it-py.readthedocs.io",
          "Homepage, https://github.com/executablebooks/markdown-it-py"
        ],
        "provides_extra": [
          "benchmarking",
          "compare",
          "linkify",
          "plugins",
          "profiling",
          "rtd",
          "testing"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d",
          "hashes": {
            "sha256": "850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.4",
        "name": "pyparsing",
        "version": "3.3.2",
        "summary": "pyparsing - Classes and methods to define and execute parsing grammars",
        "description": "PyParsing -- A Python Parsing Module\n====================================\n\n|Version| |Build Status| |Coverage| |License| |Python Versions| |Snyk Score|\n\nIntroduction\n============\n\nThe pyparsing module is an alternative approach to creating and\nexecuting simple grammars, vs. the traditional lex/yacc approach, or the\nuse of regular expressions. The pyparsing module provides a library of\nclasses that client code uses to construct the grammar directly in\nPython code.\n\n*[Since first writing this description of pyparsing in late 2003, this\ntechnique for developing parsers has become more widespread, under the\nname Parsing Expression Grammars - PEGs. See more information on PEGs*\n`here <https://en.wikipedia.org/wiki/Parsing_expression_grammar>`__\n*.]*\n\nHere is a program to parse ``\"Hello, World!\"`` (or any greeting of the form\n``\"salutation, addressee!\"``):\n\n.. code:: python\n\n    from pyparsing import Word, alphas\n    greet = Word(alphas) + \",\" + Word(alphas) + \"!\"\n    hello = \"Hello, World!\"\n    print(hello, \"->\", greet.parse_string(hello))\n\nThe program outputs the following::\n\n    Hello, World! -> ['Hello', ',', 'World', '!']\n\nThe Python representation of the grammar is quite readable, owing to the\nself-explanatory class names, and the use of '+', '|' and '^' operator\ndefinitions.\n\nThe parsed results returned from ``parse_string()`` is a collection of type\n``ParseResults``, which can be accessed as a\nnested list, a dictionary, or an object with named attributes.\n\nThe pyparsing module handles some of the problems that are typically\nvexing when writing text parsers:\n\n- extra or missing whitespace (the above program will also handle ``\"Hello,World!\"``, ``\"Hello , World !\"``, etc.)\n- quoted strings\n- embedded comments\n\nThe examples directory includes a simple SQL parser, simple CORBA IDL\nparser, a config file parser, a chemical formula parser, and a four-\nfunction algebraic notation parser, among many others.\n\nDocumentation\n=============\n\nThere are many examples in the online docstrings of the classes\nand methods in pyparsing. You can find them compiled into `online docs <https://pyparsing-docs.readthedocs.io/en/latest/>`__. Additional\ndocumentation resources and project info are listed in the online\n`GitHub wiki <https://github.com/pyparsing/pyparsing/wiki>`__. An\nentire directory of examples can be found `here <https://github.com/pyparsing/pyparsing/tree/master/examples>`__.\n\nAI Instructions\n===============\n\nThere are also instructions for AI agents to use when helping you to create your parser. They can\nbe pulled from the GitHub project repository, at pyparsing/ai/best_practices.md. You can also tell\nthe AI to access them programmatically after installing pyparsing, either from the CLI with\n``python -m pyparsing.ai.show_best_practices`` or within python with\n``import pyparsing; pyparsing.show_best_practices()``.\n\n\nLicense\n=======\n\nMIT License. See header of the `pyparsing __init__.py <https://github.com/pyparsing/pyparsing/blob/master/pyparsing/__init__.py#L1-L23>`__ file.\n\nHistory\n=======\n\nSee `CHANGES <https://github.com/pyparsing/pyparsing/blob/master/CHANGES>`__ file.\n\n\nPerformance benchmarks\n======================\n\nFor usage instructions and details on the performance benchmark suite, see\n``tests/README.md`` in this repository.\n\n.. |Build Status| image:: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml/badge.svg\n   :target: https://github.com/pyparsing/pyparsing/actions/workflows/ci.yml\n\n.. |Coverage| image:: https://codecov.io/gh/pyparsing/pyparsing/branch/master/graph/badge.svg\n  :target: https://codecov.io/gh/pyparsing/pyparsing\n\n.. |Version| image:: https://img.shields.io/pypi/v/pyparsing?style=flat-square\n    :target: https://pypi.org/project/pyparsing/\n    :alt: Version\n\n.. |License| image:: https://img.shields.io/pypi/l/pyparsing.svg?style=flat-square\n    :target: https://pypi.org/project/pyparsing/\n    :alt: License\n\n.. |Python Versions| image:: https://img.shields.io/pypi/pyversions/pyparsing.svg?style=flat-square\n    :target: https://pypi.org/project/python-liquid/\n    :alt: Python versions\n\n.. |Snyk Score| image:: https://snyk.io//advisor/python/pyparsing/badge.svg\n   :target: https://snyk.io//advisor/python/pyparsing\n   :alt: pyparsing\n\n",
        "description_content_type": "text/x-rst",
        "author_email": "Paul McGuire <ptmcg.gm+pyparsing@gmail.com>",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "Intended Audience :: Information Technology",
          "Operating System :: OS Independent",
          "Programming Language :: Python",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Programming Language :: Python :: 3.13",
          "Programming Language :: Python :: 3.14",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Topic :: Software Development :: Compilers",
          "Topic :: Text Processing",
          "Typing :: Typed"
        ],
        "requires_dist": [
          "railroad-diagrams ; extra == \"diagrams\"",
          "jinja2 ; extra == \"diagrams\""
        ],
        "requires_python": ">=3.9",
        "project_url": [
          "Documentation, https://pyparsing-docs.readthedocs.io/en/latest/",
          "Homepage, https://github.com/pyparsing/pyparsing/",
          "Source, https://github.com/pyparsing/pyparsing.git"
        ],
        "provides_extra": [
          "diagrams"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427",
          "hashes": {
            "sha256": "a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "python-dateutil",
        "version": "2.9.0.post0",
        "summary": "Extensions to the standard Python datetime module",
        "description": "dateutil - powerful extensions to datetime\n==========================================\n\n|pypi| |support| |licence|\n\n|gitter| |readthedocs|\n\n|travis| |appveyor| |pipelines| |coverage|\n\n.. |pypi| image:: https://img.shields.io/pypi/v/python-dateutil.svg?style=flat-square\n    :target: https://pypi.org/project/python-dateutil/\n    :alt: pypi version\n\n.. |support| image:: https://img.shields.io/pypi/pyversions/python-dateutil.svg?style=flat-square\n    :target: https://pypi.org/project/python-dateutil/\n    :alt: supported Python version\n\n.. |travis| image:: https://img.shields.io/travis/dateutil/dateutil/master.svg?style=flat-square&label=Travis%20Build\n    :target: https://travis-ci.org/dateutil/dateutil\n    :alt: travis build status\n\n.. |appveyor| image:: https://img.shields.io/appveyor/ci/dateutil/dateutil/master.svg?style=flat-square&logo=appveyor\n    :target: https://ci.appveyor.com/project/dateutil/dateutil\n    :alt: appveyor build status\n\n.. |pipelines| image:: https://dev.azure.com/pythondateutilazure/dateutil/_apis/build/status/dateutil.dateutil?branchName=master\n    :target: https://dev.azure.com/pythondateutilazure/dateutil/_build/latest?definitionId=1&branchName=master\n    :alt: azure pipelines build status\n\n.. |coverage| image:: https://codecov.io/gh/dateutil/dateutil/branch/master/graphs/badge.svg?branch=master\n    :target: https://codecov.io/gh/dateutil/dateutil?branch=master\n    :alt: Code coverage\n\n.. |gitter| image:: https://badges.gitter.im/dateutil/dateutil.svg\n   :alt: Join the chat at https://gitter.im/dateutil/dateutil\n   :target: https://gitter.im/dateutil/dateutil\n\n.. |licence| image:: https://img.shields.io/pypi/l/python-dateutil.svg?style=flat-square\n    :target: https://pypi.org/project/python-dateutil/\n    :alt: licence\n\n.. |readthedocs| image:: https://img.shields.io/readthedocs/dateutil/latest.svg?style=flat-square&label=Read%20the%20Docs\n   :alt: Read the documentation at https://dateutil.readthedocs.io/en/latest/\n   :target: https://dateutil.readthedocs.io/en/latest/\n\nThe `dateutil` module provides powerful extensions to\nthe standard `datetime` module, available in Python.\n\nInstallation\n============\n`dateutil` can be installed from PyPI using `pip` (note that the package name is\ndifferent from the importable name)::\n\n    pip install python-dateutil\n\nDownload\n========\ndateutil is available on PyPI\nhttps://pypi.org/project/python-dateutil/\n\nThe documentation is hosted at:\nhttps://dateutil.readthedocs.io/en/stable/\n\nCode\n====\nThe code and issue tracker are hosted on GitHub:\nhttps://github.com/dateutil/dateutil/\n\nFeatures\n========\n\n* Computing of relative deltas (next month, next year,\n  next Monday, last week of month, etc);\n* Computing of relative deltas between two given\n  date and/or datetime objects;\n* Computing of dates based on very flexible recurrence rules,\n  using a superset of the `iCalendar <https://www.ietf.org/rfc/rfc2445.txt>`_\n  specification. Parsing of RFC strings is supported as well.\n* Generic parsing of dates in almost any string format;\n* Timezone (tzinfo) implementations for tzfile(5) format\n  files (/etc/localtime, /usr/share/zoneinfo, etc), TZ\n  environment string (in all known formats), iCalendar\n  format files, given ranges (with help from relative deltas),\n  local machine timezone, fixed offset timezone, UTC timezone,\n  and Windows registry-based time zones.\n* Internal up-to-date world timezone information based on\n  Olson's database.\n* Computing of Easter Sunday dates for any given year,\n  using Western, Orthodox or Julian algorithms;\n* A comprehensive test suite.\n\nQuick example\n=============\nHere's a snapshot, just to give an idea about the power of the\npackage. For more examples, look at the documentation.\n\nSuppose you want to know how much time is left, in\nyears/months/days/etc, before the next easter happening on a\nyear with a Friday 13th in August, and you want to get today's\ndate out of the \"date\" unix system command. Here is the code:\n\n.. code-block:: python3\n\n    >>> from dateutil.relativedelta import *\n    >>> from dateutil.easter import *\n    >>> from dateutil.rrule import *\n    >>> from dateutil.parser import *\n    >>> from datetime import *\n    >>> now = parse(\"Sat Oct 11 17:13:46 UTC 2003\")\n    >>> today = now.date()\n    >>> year = rrule(YEARLY,dtstart=now,bymonth=8,bymonthday=13,byweekday=FR)[0].year\n    >>> rdelta = relativedelta(easter(year), today)\n    >>> print(\"Today is: %s\" % today)\n    Today is: 2003-10-11\n    >>> print(\"Year with next Aug 13th on a Friday is: %s\" % year)\n    Year with next Aug 13th on a Friday is: 2004\n    >>> print(\"How far is the Easter of that year: %s\" % rdelta)\n    How far is the Easter of that year: relativedelta(months=+6)\n    >>> print(\"And the Easter of that year is: %s\" % (today+rdelta))\n    And the Easter of that year is: 2004-04-11\n\nBeing exactly 6 months ahead was **really** a coincidence :)\n\nContributing\n============\n\nWe welcome many types of contributions - bug reports, pull requests (code, infrastructure or documentation fixes). For more information about how to contribute to the project, see the ``CONTRIBUTING.md`` file in the repository.\n\n\nAuthor\n======\nThe dateutil module was written by Gustavo Niemeyer <gustavo@niemeyer.net>\nin 2003.\n\nIt is maintained by:\n\n* Gustavo Niemeyer <gustavo@niemeyer.net> 2003-2011\n* Tomi Pieviläinen <tomi.pievilainen@iki.fi> 2012-2014\n* Yaron de Leeuw <me@jarondl.net> 2014-2016\n* Paul Ganssle <paul@ganssle.io> 2015-\n\nStarting with version 2.4.1 and running until 2.8.2, all source and binary\ndistributions will be signed by a PGP key that has, at the very least, been\nsigned by the key which made the previous release. A table of release signing\nkeys can be found below:\n\n===========  ============================\nReleases     Signing key fingerprint\n===========  ============================\n2.4.1-2.8.2  `6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB`_\n===========  ============================\n\nNew releases *may* have signed tags, but binary and source distributions\nuploaded to PyPI will no longer have GPG signatures attached.\n\nContact\n=======\nOur mailing list is available at `dateutil@python.org <https://mail.python.org/mailman/listinfo/dateutil>`_. As it is hosted by the PSF, it is subject to the `PSF code of\nconduct <https://www.python.org/psf/conduct/>`_.\n\nLicense\n=======\n\nAll contributions after December 1, 2017 released under dual license - either `Apache 2.0 License <https://www.apache.org/licenses/LICENSE-2.0>`_ or the `BSD 3-Clause License <https://opensource.org/licenses/BSD-3-Clause>`_. Contributions before December 1, 2017 - except those those explicitly relicensed - are released only under the BSD 3-Clause License.\n\n\n.. _6B49 ACBA DCF6 BD1C A206 67AB CD54 FCE3 D964 BEFB:\n   https://pgp.mit.edu/pks/lookup?op=vindex&search=0xCD54FCE3D964BEFB\n",
        "description_content_type": "text/x-rst",
        "home_page": "https://github.com/dateutil/dateutil",
        "author": "Gustavo Niemeyer",
        "author_email": "gustavo@niemeyer.net",
        "maintainer": "Paul Ganssle",
        "maintainer_email": "dateutil@python.org",
        "license": "Dual License",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: BSD License",
          "License :: OSI Approved :: Apache Software License",
          "Programming Language :: Python",
          "Programming Language :: Python :: 2",
          "Programming Language :: Python :: 2.7",
          "Programming Language :: Python :: 3",
          "Programming Language :: Python :: 3.3",
          "Programming Language :: Python :: 3.4",
          "Programming Language :: Python :: 3.5",
          "Programming Language :: Python :: 3.6",
          "Programming Language :: Python :: 3.7",
          "Programming Language :: Python :: 3.8",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Topic :: Software Development :: Libraries"
        ],
        "requires_dist": [
          "six >=1.5"
        ],
        "requires_python": "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7",
        "project_url": [
          "Documentation, https://dateutil.readthedocs.io/en/stable/",
          "Source, https://github.com/dateutil/dateutil"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686",
          "hashes": {
            "sha256": "7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "shellingham",
        "version": "1.5.4",
        "summary": "Tool to Detect Surrounding Shell",
        "description": "=============================================\nShellingham: Tool to Detect Surrounding Shell\n=============================================\n\n.. image:: https://img.shields.io/pypi/v/shellingham.svg\n    :target: https://pypi.org/project/shellingham/\n\nShellingham detects what shell the current Python executable is running in.\n\n\nUsage\n=====\n\n.. code-block:: python\n\n    >>> import shellingham\n    >>> shellingham.detect_shell()\n    ('bash', '/bin/bash')\n\n``detect_shell`` pokes around the process's running environment to determine\nwhat shell it is run in. It returns a 2-tuple:\n\n* The shell name, always lowercased.\n* The command used to run the shell.\n\n``ShellDetectionFailure`` is raised if ``detect_shell`` fails to detect the\nsurrounding shell.\n\n\nNotes\n=====\n\n* The shell name is always lowercased.\n* On Windows, the shell name is the name of the executable, minus the file\n  extension.\n\n\nNotes for Application Developers\n================================\n\nRemember, your application's user is not necessarily using a shell.\nShellingham raises ``ShellDetectionFailure`` if there is no shell to detect,\nbut *your application should almost never do this to your user*.\n\nA practical approach to this is to wrap ``detect_shell`` in a try block, and\nprovide a sane default on failure\n\n.. code-block:: python\n\n    try:\n        shell = shellingham.detect_shell()\n    except shellingham.ShellDetectionFailure:\n        shell = provide_default()\n\n\nThere are a few choices for you to choose from.\n\n* The POSIX standard mandates the environment variable ``SHELL`` to refer to\n  \"the user's preferred command language interpreter\". This is always available\n  (even if the user is not in an interactive session), and likely the correct\n  choice to launch an interactive sub-shell with.\n* A command ``sh`` is almost guaranteed to exist, likely at ``/bin/sh``, since\n  several POSIX tools rely on it. This should be suitable if you want to run a\n  (possibly non-interactive) script.\n* All versions of DOS and Windows have an environment variable ``COMSPEC``.\n  This can always be used to launch a usable command prompt (e.g. `cmd.exe` on\n  Windows).\n\nHere's a simple implementation to provide a default shell\n\n.. code-block:: python\n\n    import os\n\n    def provide_default():\n        if os.name == 'posix':\n            return os.environ['SHELL']\n        elif os.name == 'nt':\n            return os.environ['COMSPEC']\n        raise NotImplementedError(f'OS {os.name!r} support not available')\n",
        "description_content_type": "text/x-rst",
        "keywords": [
          "shell"
        ],
        "home_page": "https://github.com/sarugaku/shellingham",
        "author": "Tzu-ping Chung",
        "author_email": "uranusjr@gmail.com",
        "license": "ISC License",
        "classifier": [
          "Development Status :: 3 - Alpha",
          "Environment :: Console",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: ISC License (ISCL)",
          "Operating System :: OS Independent",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.7",
          "Programming Language :: Python :: 3.8",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: 3.11",
          "Programming Language :: Python :: 3.12",
          "Topic :: Software Development :: Libraries :: Python Modules"
        ],
        "requires_python": ">=3.7"
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
          "hashes": {
            "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "mdurl",
        "version": "0.1.2",
        "summary": "Markdown URL utilities",
        "description": "# mdurl\n\n[![Build Status](https://github.com/executablebooks/mdurl/workflows/Tests/badge.svg?branch=master)](https://github.com/executablebooks/mdurl/actions?query=workflow%3ATests+branch%3Amaster+event%3Apush)\n[![codecov.io](https://codecov.io/gh/executablebooks/mdurl/branch/master/graph/badge.svg)](https://codecov.io/gh/executablebooks/mdurl)\n[![PyPI version](https://img.shields.io/pypi/v/mdurl)](https://pypi.org/project/mdurl)\n\nThis is a Python port of the JavaScript [mdurl](https://www.npmjs.com/package/mdurl) package.\nSee the [upstream README.md file](https://github.com/markdown-it/mdurl/blob/master/README.md) for API documentation.\n\n",
        "description_content_type": "text/markdown",
        "keywords": [
          "markdown",
          "commonmark"
        ],
        "author_email": "Taneli Hukkinen <hukkin@users.noreply.github.com>",
        "classifier": [
          "License :: OSI Approved :: MIT License",
          "Operating System :: MacOS",
          "Operating System :: Microsoft :: Windows",
          "Operating System :: POSIX :: Linux",
          "Programming Language :: Python :: 3 :: Only",
          "Programming Language :: Python :: 3.7",
          "Programming Language :: Python :: 3.8",
          "Programming Language :: Python :: 3.9",
          "Programming Language :: Python :: 3.10",
          "Programming Language :: Python :: Implementation :: CPython",
          "Programming Language :: Python :: Implementation :: PyPy",
          "Topic :: Software Development :: Libraries :: Python Modules",
          "Typing :: Typed"
        ],
        "requires_python": ">=3.7",
        "project_url": [
          "Homepage, https://github.com/executablebooks/mdurl"
        ]
      }
    },
    {
      "download_info": {
        "url": "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl",
        "archive_info": {
          "hash": "sha256=4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274",
          "hashes": {
            "sha256": "4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"
          }
        }
      },
      "is_direct": false,
      "is_yanked": false,
      "requested": false,
      "metadata": {
        "metadata_version": "2.1",
        "name": "six",
        "version": "1.17.0",
        "summary": "Python 2 and 3 compatibility utilities",
        "description": ".. image:: https://img.shields.io/pypi/v/six.svg\n   :target: https://pypi.org/project/six/\n   :alt: six on PyPI\n\n.. image:: https://readthedocs.org/projects/six/badge/?version=latest\n   :target: https://six.readthedocs.io/\n   :alt: six's documentation on Read the Docs\n\n.. image:: https://img.shields.io/badge/license-MIT-green.svg\n   :target: https://github.com/benjaminp/six/blob/master/LICENSE\n   :alt: MIT License badge\n\nSix is a Python 2 and 3 compatibility library.  It provides utility functions\nfor smoothing over the differences between the Python versions with the goal of\nwriting Python code that is compatible on both Python versions.  See the\ndocumentation for more information on what is provided.\n\nSix supports Python 2.7 and 3.3+.  It is contained in only one Python\nfile, so it can be easily copied into your project. (The copyright and license\nnotice must be retained.)\n\nOnline documentation is at https://six.readthedocs.io/.\n\nBugs can be reported to https://github.com/benjaminp/six.  The code can also\nbe found there.\n",
        "home_page": "https://github.com/benjaminp/six",
        "author": "Benjamin Peterson",
        "author_email": "benjamin@python.org",
        "license": "MIT",
        "classifier": [
          "Development Status :: 5 - Production/Stable",
          "Programming Language :: Python :: 2",
          "Programming Language :: Python :: 3",
          "Intended Audience :: Developers",
          "License :: OSI Approved :: MIT License",
          "Topic :: Software Development :: Libraries",
          "Topic :: Utilities"
        ],
        "requires_python": ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
      }
    }
  ],
  "environment": {
    "implementation_name": "cpython",
    "implementation_version": "3.12.3",
    "os_name": "posix",
    "platform_machine": "x86_64",
    "platform_release": "6.8.0-117-generic",
    "platform_system": "Linux",
    "platform_version": "#117-Ubuntu SMP PREEMPT_DYNAMIC Tue May  5 19:26:24 UTC 2026",
    "python_full_version": "3.12.3",
    "platform_python_implementation": "CPython",
    "python_version": "3.12",
    "sys_platform": "linux"
  }
}