{"id":22942446,"url":"https://github.com/stardustdl/aexpy","last_synced_at":"2025-08-12T21:32:37.351Z","repository":{"id":62592811,"uuid":"521075255","full_name":"StardustDL/aexpy","owner":"StardustDL","description":"AexPy /eikspai/ is Api EXplorer in PYthon for detecting API breaking changes in Python packages.","archived":false,"fork":false,"pushed_at":"2024-06-10T02:57:51.000Z","size":9124,"stargazers_count":18,"open_issues_count":10,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-19T09:54:37.414Z","etag":null,"topics":["api","backward-compatibility","breaking-changes","package","pypi","python","semver"],"latest_commit_sha":null,"homepage":"https://aexpy.netlify.app/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/StardustDL.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATIONS.bib","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-04T00:45:42.000Z","updated_at":"2024-11-18T19:11:55.000Z","dependencies_parsed_at":"2024-04-01T09:36:43.007Z","dependency_job_id":"96552a41-b15e-404a-aa1f-b4d5631a71d5","html_url":"https://github.com/StardustDL/aexpy","commit_stats":{"total_commits":482,"total_committers":2,"mean_commits":241.0,"dds":"0.0020746887966804906","last_synced_commit":"21b8863ad2917611285d52a6740c1d0ed0607ea5"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StardustDL%2Faexpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StardustDL%2Faexpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StardustDL%2Faexpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/StardustDL%2Faexpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/StardustDL","download_url":"https://codeload.github.com/StardustDL/aexpy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":229710743,"owners_count":18111641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","backward-compatibility","breaking-changes","package","pypi","python","semver"],"created_at":"2024-12-14T13:47:51.329Z","updated_at":"2024-12-14T13:47:51.748Z","avatar_url":"https://github.com/StardustDL.png","language":"Python","readme":"# ![AexPy](https://socialify.git.ci/StardustDL/aexpy/image?description=1\u0026font=Bitter\u0026forks=1\u0026issues=1\u0026language=1\u0026owner=1\u0026pulls=1\u0026stargazers=1\u0026theme=Light \"AexPy\")\n\n[![CI](https://github.com/StardustDL/aexpy/actions/workflows/ci.yml/badge.svg)](https://github.com/StardustDL/aexpy/actions/workflows/ci.yml) [![](https://img.shields.io/github/license/StardustDL/aexpy.svg)](https://github.com/StardustDL/coxbuild/blob/master/LICENSE) [![](https://img.shields.io/pypi/v/aexpy)](https://pypi.org/project/aexpy/) [![Downloads](https://pepy.tech/badge/aexpy?style=flat)](https://pepy.tech/project/aexpy) [![](https://img.shields.io/docker/pulls/stardustdl/aexpy?style=flat)](https://hub.docker.com/r/stardustdl/aexpy)\n\n[AexPy](https://github.com/StardustDL/aexpy) */eɪkspaɪ/* is **A**pi **EX**plorer in **PY**thon for detecting API breaking changes in Python packages.\n\nExplore AexPy's [APIs](https://aexpy.netlify.app/projects/aexpy), and the [main](https://aexpy.netlify.app/view/?url=https://stardustdl.github.io/aexpy/main.json) branch on **AexPy** itself. AexPy also runs an [index project](https://github.com/StardustDL-Labs/aexpy-index) for some packages shown [here](https://aexpy.netlify.app/), trying to replace `pypi.org` to `aexpy.netlify.app` in the package PyPI URLs to explore their APIs.\n\n\u003e [!NOTE]\n\u003e AexPy is the prototype implementation of the conference paper \"**AexPy: Detecting API Breaking Changes in Python Packages**\" in Proceedings of the 33rd IEEE International Symposium on Software Reliability Engineering ([ISSRE 2022](https://issre2022.github.io/)), Charlotte, North Carolina, USA, October 31 - November 3, 2022.\n\u003e \n\u003e If you use our approach or results in your work, please cite it according to [the citation file](https://github.com/StardustDL/aexpy/blob/main/CITATIONS.bib).\n\u003e \n\u003e X. Du and J. Ma, \"AexPy: Detecting API Breaking Changes in Python Packages,\" 2022 IEEE 33rd International Symposium on Software Reliability Engineering (ISSRE), 2022, pp. 470-481, doi: 10.1109/ISSRE55969.2022.00052.\n\nhttps://user-images.githubusercontent.com/34736356/182772349-af0a5f20-d009-4daa-b4a9-593922ed66fe.mov\n\n- **How AexPy works?** Approach Design \u0026 Evaluation are in [AexPy's conference paper](https://ieeexplore.ieee.org/abstract/document/9978982), see also [talk](https://www.bilibili.com/video/BV1tv4y1D75F/) \u0026 [slides](https://stardustdl.github.io/assets/pdfs/aexpy/aexpy-slides.pdf).\n- **How we implement AexPy?** Source Code \u0026 Implemetation are in [AexPy's repository](https://github.com/StardustDL/aexpy), see also [design (zh-cn)](https://stardustdl.github.io/assets/pdfs/aexpy/aexpy-chinasoft.pdf).\n- **How to use AexPy?** Detailed Document \u0026 Data are in [AexPy's documents](https://aexpy-docs.netlify.app/), see also [video](https://www.bilibili.com/video/BV1PG411F77m/) and [online AexPy](https://aexpy.netlify.app/).\n\n```mermaid\ngraph LR;\n    Package--\u003eVersion-1;\n    Package--\u003eVersion-2;\n    Version-1--\u003ePreprocessing-1;\n    Version-2--\u003ePreprocessing-2;\n    Preprocessing-1--\u003eExtraction-1;\n    Preprocessing-2--\u003eExtraction-2;\n    Extraction-1--\u003eDifference;\n    Extraction-2--\u003eDifference;\n    Difference--\u003eEvaluation;\n    Evaluation--\u003eBreaking-Changes;\n```\n\nAexPy also provides a framework to process Python packages, extract APIs, and detect changes, which is designed for easily reusing and customizing. See the following \"Advanced Tools\" section and the source code for details.\n\n## Quick Start\n\nTake the package [generator-oj-problem](https://pypi.org/project/generator-oj-problem/) v0.0.1 and v0.0.2 as an example.\n\n- Save API descriptions to `cache/api1.json` and `cache/api2.json`\n- Output report to `report.txt`\n\n```sh\n# Install AexPy package and tool\npip install aexpy\n\n# Extract APIs from v0.0.1\necho generator-oj-problem@0.0.1 | aexpy extract - api1.json -r\n\n# Extract APIs from v0.0.1\necho generator-oj-problem@0.0.2 | aexpy extract - api2.json -r\n\n# Diff APIs between two versions\naexpy diff api1.json api2.json changes.json\n```\n\nView results on [online AexPy](https://aexpy.netlify.app/).\n\n- generator-oj-problem@0.0.1 [Distribution](https://aexpy.netlify.app/projects/generator-oj-problem/@0.0.1/) and [API](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1/)\n- generator-oj-problem@0.0.2 [Distribution](https://aexpy.netlify.app/projects/generator-oj-problem/@0.0.2/) and [API](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.2/)\n- [Changes](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1..0.0.2/) and [Report](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1\u00260.0.2/)\n\nSee also about [API Level](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.2/?tab=level), [Call Graph](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.2/?tab=callgraph), and [Inheritance Diagram](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.2/?tab=inheritance).\n\n## Features\n\n- Preprocessing\n  - Download packages and get source code, or use existing code base.\n  - Count package file sizes and lines of code.\n  - Read package metadata and detect top modules.\n- Extracting\n  - Extract APIs from Python packages, including modules, classes, functions, attributes.\n  - Collect detailed APIs, including parameters, instance attributes.\n  - Detect API aliases and build call graphs, inheritance diagrams.\n  - Enrich type information for APIs by static type analyzers.\n- Diffing\n  - Detect API changes after pairing APIs between two versions.\n  - Grade changes by their severities.\n- Reporting\n  - Generate a human-readable report for API change detection results.\n- Framework\n  - Customize processors and implementation details.\n  - Process Python packages in AexPy's general pipeline with logging and caching.\n  - Generate portable data in JSON for API descriptions, changes, and so on.\n  - Execute processing and view data by AexPy's command-line, with stdin/stdout supported.\n\n## Install\n\nWe provide the Python package on PyPI. Use pip to install the package.\n\n```sh\npython -m pip install --upgrade aexpy\naexpy --help\n```\n\n\u003e [!IMPORTANT]\n\u003e Please ensure your Python interpreter works in [UTF-8 mode](https://peps.python.org/pep-0540/).\n\nWe also provide the Docker image to avoid environment errors.\n\n```sh\ndocker pull stardustdl/aexpy:latest\ndocker run --rm stardustdl/aexpy:latest --help\n\n# or the image from the main branch\ndocker pull stardustdl/aexpy:main\n```\n\n## Usage\n\n\u003e [!TIP]\n\u003e - AexPy match commands by their prefixes, so you do not need to write the whole command name, but just a distinguishable prefix.\n\u003e   ```sh\n\u003e   # aexpy preprocess --help\n\u003e   aexpy pre --help\n\u003e   ```\n\u003e - All results produced by AexPy are in JSON format, so you could modify it in any text editor.\n\u003e - Pass `-` to I/O arguments to use stdin/stdout.\n\n\n### Preprocess\n\nPreprocess a distribution for a package release.\n\nAexPy provide four preprocessing modes:\n\n- `-s`, `--src`: (default) Use given distribution information (path to code, package name, modules)\n- `-r`, `--release`: download and unpack the package wheel and automatically load from dist-info\n- `-w`, `--wheel`: Unpack existing package wheel file and automatically load from dist-info\n- `-d`, `--dist`: Automatically load from unpacked wheel, and its dist-info\n\nAexPy will automatically load package name, version, top-level modules, and dependencies from dist-info.\n\nThere are also options to specify fields in the distribution:\n\n- `-p`, `--project`: Package name and its version, e.g. `project@version`.\n- `-m`, `--module`: (multiple) Top-level module names.\n- `-D`, `--depends`: (multiple) Package dependencies.\n- `-R`, `--requirements`: Package `requirements.txt` file path, to load dependencies.\n- `-P`, `--pyversion`: Specify Python version for this distribution, supported Python 3.8+.\n\n\u003e [!TIP]\n\u003e You could modify the generated distribution file in a text editor to change field values.\n\n```sh\n# download the package wheel and unpack into ./cache\n# output the distribution file to ./cache/distribution.json\naexpy preprocess -r -p generator-oj-problem@0.0.1 ./cache ./cache/distribution.json\n# or output the distribution file to stdout\naexpy preprocess -r -p generator-oj-problem@0.0.1 ./cache -\n\n# use existing wheel file\naexpy preprocess -w ./cache/generator_oj_problem-0.0.1-py3-none-any.whl ./cache/distribution.json\n\n# use existing unpacked wheel directory, auto load metadata from .dist-info directory\naexpy preprocess -d ./cache/generator_oj_problem-0.0.1-py3-none-any ./cache/distribution.json\n\n# use existing source code directory, given the package's name, version, and top-level modules\naexpy preprocess ./cache/generator_oj_problem-0.0.1-py3-none-any ./cache/distribution.json -p generator-oj-problem@0.0.1 -m generator_oj_problem\n```\n\n\u003e View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/@0.0.1/).\n\n### Extract\n\nExtract the API description from a distribution.\n\nAexPy provide four modes for the input distribution file:\n\n- `-j`, `--json`: (default) The file is the JSON file produced by AexPy (`preprocess` command)\n- `-r`, `--release`: The file is a text containing the release ID, e.g., `aexpy@0.1.0`\n- `-w`, `--wheel`: The file is a wheel, i.e., `.whl` file. when reading from stdin, please also give the wheel file name through `--wheel-name` option.\n- `-s`, `--src`: The file is a ZIP file that contains the package code directory\n  - Please ensure the directory is at the root of the ZIP archive\n\n\u003e [!IMPORTANT]\n\u003e **About Dependencies**\n\u003e AexPy would dynamically import the target module to detect all available APIs. So please ensure all dependencies have been installed in the extraction environment, or specify the `dependencies` field in the distribution, and AexPy will install them into the extraction environment.\n\u003e \n\u003e If the `wheelFile` field is valid (i.e. the target file exists), AexPy will firstly try to install the wheel and ignore the `dependencies` field (used when the wheel installation fails).\n\n\u003e [!TIP]\n\u003e **About Environment**\n\u003e AexPy use [micromamba](https://mamba.readthedocs.io/en/latest/installation/micromamba-installation.html) as default environment manager. Use `AEXPY_ENV_PROVIDER` environment variable to specify `conda`, `mamba`, or `micromamba` (if the variable hasn't been specified, AexPy will detect the environment manager automatically).\n\u003e \n\u003e - Use flag `--no-temp` to let AexPy use the current Python environment (as same as AexPy) as the extraction environment (the default behavior of the installed AexPy package).\n\u003e - Use flag `--temp` to let AexPy create a temporary mamba(conda) environment that matches the distribution's pyverion field (the default behavior of our docker image).\n\u003e - Use option `-e`, `--env` to specify an existing mamba(conda) env name as the extraction environment (will ignore the temp flag).\n\n```sh\naexpy extract ./cache/distribution.json ./cache/api.json\n# or input the distribution file from stdin\n# (this feature is also supported in other commands)\naexpy extract - ./cache/api.json\n# or output the api description file to stdout\naexpy extract ./cache/distribution.json -\n\n# extract from the target project release\necho aexpy@0.0.1 | aexpy extract - api.json -r\n# extract from the wheel file\naexpy extract ./temp/aexpy-0.1.0.whl api.json -w\ncat ./temp/aexpy-0.1.0.whl | aexpy extract - api.json -w --wheel-name aexpy-0.1.0.whl\n# extract from the project source code ZIP archive\nzip -r - ./project | aexpy extract - api.json -s\n\n# Use a env named demo-env\naexpy extract ./cache/distribution.json - -e demo-env\n# Create a temporary env\naexpy extract ./cache/distribution.json - --temp\n```\n\n\u003e View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1/).\n\n### Diff\n\nDiff two API descriptions and detect changes.\n\n```sh\naexpy diff ./cache/api1.json ./cache/api2.json ./cache/diff.json\n```\n\n\u003e View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1..0.0.2/).\n\n\u003e [!TIP]\n\u003e If you have both stdin for OLD and NEW, please split two API descriptions by a comma `,`.\n\u003e \n\u003e This situation only support for normal IO mode, not compressing IO mode.\n\u003e ```sh\n\u003e echo \",\" | cat ./api1.json - ./api2.json | aexpy diff - - ./changes.json\n\u003e ```\n\n### Report\n\nGenerate report from detect changes.\n\n```sh\naexpy report ./cache/diff.json ./cache/report.json\n```\n\n\u003e View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1\u00260.0.2/).\n\n### View\n\nView produced data.\n\n```sh\naexpy view ./cache/distribution1.json\naexpy view ./cache/distribution2.json\naexpy view ./cache/api1.json\naexpy view ./cache/api2.json\naexpy view ./cache/diff.json\naexpy view ./cache/report.json\n```\n\n### Docker Image\n\nThe docker image keeps the same command-line interface, but always use stdin/stdout for host-container data transferring.\n\n```sh\necho generator-oj-problem@0.0.1 | docker run -i aexpy/aexpy extract - - \u003e ./api.json\n\necho \",\" | cat ./api1.json - ./api2.json | docker run -i aexpy/aexpy diff - - - \u003e ./changes.json\n```\n\n\u003e [!TIP]\n\u003e If you want to write processed data to filesystem, not the standard IO, add a volume mapping to `/data` for file access.\n\u003e \n\u003e Please ensure using the same user as the owner of the mounted directory, to access mounted files.\n\u003e \n\u003e ```sh\n\u003e docker run -v $pwd/cache:/data -u $(id -u):$(id -g) aexpy/aexpy extract /data/distribution.json /data/api.json\n\u003e ```\n\nWhen you installed AexPy package, you could use `tool runimage` command for a quick runner of containers (if you have Docker installed).\n\n\u003e [!TIP]\n\u003e The volume directory will mount to `/data` in the container\n\u003e \n\u003e All file path arguments passed to container should use absolute paths with `/data` prefix or use a path relative to `/data`.\n\n```sh\n# Use the same version of the image as current AexPy version\n# Use current as mount directory\naexpy tool runimage -- --version\naexpy runimage -- --version\n\n# Extract from ./dist.json\naexpy runimage -- extract ./dist.json ./api.json\n\n# Use a specified image tag and mount directory\naexpy tool runimage -v ./mount -t stardustdl/aexpy:latest -- --version\n\n# Extract from ./mount/dist.json\naexpy runimage -v ./mount -- extract ./dist.json ./api.json\naexpy runimage -v ./mount -- extract /data/dist.json /data/api.json\n```\n\n## Advanced Tools\n\n### Logging\n\nThe processing may cost time, you can use multiple `-v` for verbose logs (which are outputed to stderr).\n\n```sh\naexpy -vvv view ./cache/report.json\n```\n\n### Compressed IO\n\nWhen the package is large, the JSON data produced by AexPy might be large, too. AexPy support gzip format to compress/decompress for IO streams, use `-z/--gzip` option or `AEXPY_GZIP_IO` environemnt variable to enable it.\n\n```sh\naexpy --gzip extract ./cache/distribution.json ./cache/api.json.gz\nAEXPY_GZIP_IO=1 aexpy extract ./cache/distribution.json.gz ./cache/api.json\naexpy view ./cache/api.json.gz\n```\n\n\u003e [!TIP]\n\u003e AexPy will detect input file format automatically, no matter compressed-IO enabled or not.\n\u003e \n\u003e When enabling compressed-IO mode, all output JSON streams will be regarded as gzip JSON streams.\n\n### Interactive\n\nAdd `-i` or `--interact` to enable interactive mode, every command will create an interactive Python shell after finishing processing. Here are some useful variable you could use in the interactive Python shell.\n\n- `result`: The produced data object\n- `context`: The producing context, use `exception` to access the exception if failing to process\n\n```sh\naexpy -i view ./cache/report.json\n```\n\n\u003e [!TIP]\n\u003e Feel free to use `locals()` and `dir()` to explore the interactive environment.\n\n### Statistics\n\nAexPy provides tools to count numbers from produced data in `aexpy.tools.stats` module.\nIt loads products from given files, runs builtin counters, and then records them as kay-value pairs of the release (or release pair).\n\n```sh\naexpy tool stat ./*.json ./stats.json\naexpy stat ./*.json ./stats.json\n\naexpy view ./stats.json\n```\n\n### Pipeline\n\nAexPy has four loosely-coupled stages in its pipeline. The adjacent stages transfer data by JSON, defined in [models](https://github.com/StardustDL/aexpy/blob/main/src/aexpy/models/) directory. You can easily write your own implementation for every stage, and combine your implementation into the pipeline.\n\nTo write your own services, copy from [aexpy/services.py](https://github.com/StardustDL/aexpy/blob/main/src/aexpy/services.py) and write your subclass of `ServiceProvider` and modify the `getService` function to return your service instance.\n\n```python\nfrom aexpy.services import ServiceProvider\n\nclass MyServiceProvider(ServiceProvider):\n    ...\n\ndef getService():\n    return MyServiceProvider()\n```\n\nThen you can load your service file by `-s/--service` option or `AEXPY_SERVICE` environment variable.\n\n```sh\naexpy -s services.py -vvv view --help\nAEXPY_SERVICE=services.py aexpy -vvv view --help\n```\n\nWe have implemented an image service provider, which replaces the default extractor, differ, and reporter by the container runner. See [aexpy/tools/runners/services.py](https://github.com/StardustDL/aexpy/blob/main/src/aexpy/tools/runners/services.py) for its implementation. Here is the demo service file to use the image service provider.\n\n```python\nfrom aexpy.tools.runners.services import DockerRunnerServiceProvider\n\n\ndef getService():\n    return DockerRunnerServiceProvider(tag=\"stardustdl/aexpy:latest\")\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstardustdl%2Faexpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstardustdl%2Faexpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstardustdl%2Faexpy/lists"}