Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stardustdl/aexpy
AexPy /eikspai/ is Api EXplorer in PYthon for detecting API breaking changes in Python packages.
https://github.com/stardustdl/aexpy
api backward-compatibility breaking-changes package pypi python semver
Last synced: 27 days ago
JSON representation
AexPy /eikspai/ is Api EXplorer in PYthon for detecting API breaking changes in Python packages.
- Host: GitHub
- URL: https://github.com/stardustdl/aexpy
- Owner: StardustDL
- License: mpl-2.0
- Created: 2022-08-04T00:45:42.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2024-06-10T02:57:51.000Z (7 months ago)
- Last Synced: 2024-11-19T09:54:37.414Z (about 2 months ago)
- Topics: api, backward-compatibility, breaking-changes, package, pypi, python, semver
- Language: Python
- Homepage: https://aexpy.netlify.app/
- Size: 8.7 MB
- Stars: 18
- Watchers: 1
- Forks: 5
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Citation: CITATIONS.bib
Awesome Lists containing this project
README
# ![AexPy](https://socialify.git.ci/StardustDL/aexpy/image?description=1&font=Bitter&forks=1&issues=1&language=1&owner=1&pulls=1&stargazers=1&theme=Light "AexPy")
[![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)
[AexPy](https://github.com/StardustDL/aexpy) */eɪkspaɪ/* is **A**pi **EX**plorer in **PY**thon for detecting API breaking changes in Python packages.
Explore 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.
> [!NOTE]
> 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.
>
> 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).
>
> 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.https://user-images.githubusercontent.com/34736356/182772349-af0a5f20-d009-4daa-b4a9-593922ed66fe.mov
- **How AexPy works?** Approach Design & Evaluation are in [AexPy's conference paper](https://ieeexplore.ieee.org/abstract/document/9978982), see also [talk](https://www.bilibili.com/video/BV1tv4y1D75F/) & [slides](https://stardustdl.github.io/assets/pdfs/aexpy/aexpy-slides.pdf).
- **How we implement AexPy?** Source Code & 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).
- **How to use AexPy?** Detailed Document & 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/).```mermaid
graph LR;
Package-->Version-1;
Package-->Version-2;
Version-1-->Preprocessing-1;
Version-2-->Preprocessing-2;
Preprocessing-1-->Extraction-1;
Preprocessing-2-->Extraction-2;
Extraction-1-->Difference;
Extraction-2-->Difference;
Difference-->Evaluation;
Evaluation-->Breaking-Changes;
```AexPy 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.
## Quick Start
Take the package [generator-oj-problem](https://pypi.org/project/generator-oj-problem/) v0.0.1 and v0.0.2 as an example.
- Save API descriptions to `cache/api1.json` and `cache/api2.json`
- Output report to `report.txt````sh
# Install AexPy package and tool
pip install aexpy# Extract APIs from v0.0.1
echo [email protected] | aexpy extract - api1.json -r# Extract APIs from v0.0.1
echo [email protected] | aexpy extract - api2.json -r# Diff APIs between two versions
aexpy diff api1.json api2.json changes.json
```View results on [online AexPy](https://aexpy.netlify.app/).
- [email protected] [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/)
- [email protected] [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/)
- [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&0.0.2/)See 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).
## Features
- Preprocessing
- Download packages and get source code, or use existing code base.
- Count package file sizes and lines of code.
- Read package metadata and detect top modules.
- Extracting
- Extract APIs from Python packages, including modules, classes, functions, attributes.
- Collect detailed APIs, including parameters, instance attributes.
- Detect API aliases and build call graphs, inheritance diagrams.
- Enrich type information for APIs by static type analyzers.
- Diffing
- Detect API changes after pairing APIs between two versions.
- Grade changes by their severities.
- Reporting
- Generate a human-readable report for API change detection results.
- Framework
- Customize processors and implementation details.
- Process Python packages in AexPy's general pipeline with logging and caching.
- Generate portable data in JSON for API descriptions, changes, and so on.
- Execute processing and view data by AexPy's command-line, with stdin/stdout supported.## Install
We provide the Python package on PyPI. Use pip to install the package.
```sh
python -m pip install --upgrade aexpy
aexpy --help
```> [!IMPORTANT]
> Please ensure your Python interpreter works in [UTF-8 mode](https://peps.python.org/pep-0540/).We also provide the Docker image to avoid environment errors.
```sh
docker pull stardustdl/aexpy:latest
docker run --rm stardustdl/aexpy:latest --help# or the image from the main branch
docker pull stardustdl/aexpy:main
```## Usage
> [!TIP]
> - AexPy match commands by their prefixes, so you do not need to write the whole command name, but just a distinguishable prefix.
> ```sh
> # aexpy preprocess --help
> aexpy pre --help
> ```
> - All results produced by AexPy are in JSON format, so you could modify it in any text editor.
> - Pass `-` to I/O arguments to use stdin/stdout.### Preprocess
Preprocess a distribution for a package release.
AexPy provide four preprocessing modes:
- `-s`, `--src`: (default) Use given distribution information (path to code, package name, modules)
- `-r`, `--release`: download and unpack the package wheel and automatically load from dist-info
- `-w`, `--wheel`: Unpack existing package wheel file and automatically load from dist-info
- `-d`, `--dist`: Automatically load from unpacked wheel, and its dist-infoAexPy will automatically load package name, version, top-level modules, and dependencies from dist-info.
There are also options to specify fields in the distribution:
- `-p`, `--project`: Package name and its version, e.g. `project@version`.
- `-m`, `--module`: (multiple) Top-level module names.
- `-D`, `--depends`: (multiple) Package dependencies.
- `-R`, `--requirements`: Package `requirements.txt` file path, to load dependencies.
- `-P`, `--pyversion`: Specify Python version for this distribution, supported Python 3.8+.> [!TIP]
> You could modify the generated distribution file in a text editor to change field values.```sh
# download the package wheel and unpack into ./cache
# output the distribution file to ./cache/distribution.json
aexpy preprocess -r -p [email protected] ./cache ./cache/distribution.json
# or output the distribution file to stdout
aexpy preprocess -r -p [email protected] ./cache -# use existing wheel file
aexpy preprocess -w ./cache/generator_oj_problem-0.0.1-py3-none-any.whl ./cache/distribution.json# use existing unpacked wheel directory, auto load metadata from .dist-info directory
aexpy preprocess -d ./cache/generator_oj_problem-0.0.1-py3-none-any ./cache/distribution.json# use existing source code directory, given the package's name, version, and top-level modules
aexpy preprocess ./cache/generator_oj_problem-0.0.1-py3-none-any ./cache/distribution.json -p [email protected] -m generator_oj_problem
```> View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/@0.0.1/).
### Extract
Extract the API description from a distribution.
AexPy provide four modes for the input distribution file:
- `-j`, `--json`: (default) The file is the JSON file produced by AexPy (`preprocess` command)
- `-r`, `--release`: The file is a text containing the release ID, e.g., `[email protected]`
- `-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.
- `-s`, `--src`: The file is a ZIP file that contains the package code directory
- Please ensure the directory is at the root of the ZIP archive> [!IMPORTANT]
> **About Dependencies**
> 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.
>
> 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).> [!TIP]
> **About Environment**
> 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).
>
> - 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).
> - 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).
> - Use option `-e`, `--env` to specify an existing mamba(conda) env name as the extraction environment (will ignore the temp flag).```sh
aexpy extract ./cache/distribution.json ./cache/api.json
# or input the distribution file from stdin
# (this feature is also supported in other commands)
aexpy extract - ./cache/api.json
# or output the api description file to stdout
aexpy extract ./cache/distribution.json -# extract from the target project release
echo [email protected] | aexpy extract - api.json -r
# extract from the wheel file
aexpy extract ./temp/aexpy-0.1.0.whl api.json -w
cat ./temp/aexpy-0.1.0.whl | aexpy extract - api.json -w --wheel-name aexpy-0.1.0.whl
# extract from the project source code ZIP archive
zip -r - ./project | aexpy extract - api.json -s# Use a env named demo-env
aexpy extract ./cache/distribution.json - -e demo-env
# Create a temporary env
aexpy extract ./cache/distribution.json - --temp
```> View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1/).
### Diff
Diff two API descriptions and detect changes.
```sh
aexpy diff ./cache/api1.json ./cache/api2.json ./cache/diff.json
```> View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1..0.0.2/).
> [!TIP]
> If you have both stdin for OLD and NEW, please split two API descriptions by a comma `,`.
>
> This situation only support for normal IO mode, not compressing IO mode.
> ```sh
> echo "," | cat ./api1.json - ./api2.json | aexpy diff - - ./changes.json
> ```### Report
Generate report from detect changes.
```sh
aexpy report ./cache/diff.json ./cache/report.json
```> View results at [AexPy Online](https://aexpy.netlify.app/projects/generator-oj-problem/0.0.1&0.0.2/).
### View
View produced data.
```sh
aexpy view ./cache/distribution1.json
aexpy view ./cache/distribution2.json
aexpy view ./cache/api1.json
aexpy view ./cache/api2.json
aexpy view ./cache/diff.json
aexpy view ./cache/report.json
```### Docker Image
The docker image keeps the same command-line interface, but always use stdin/stdout for host-container data transferring.
```sh
echo [email protected] | docker run -i aexpy/aexpy extract - - > ./api.jsonecho "," | cat ./api1.json - ./api2.json | docker run -i aexpy/aexpy diff - - - > ./changes.json
```> [!TIP]
> If you want to write processed data to filesystem, not the standard IO, add a volume mapping to `/data` for file access.
>
> Please ensure using the same user as the owner of the mounted directory, to access mounted files.
>
> ```sh
> docker run -v $pwd/cache:/data -u $(id -u):$(id -g) aexpy/aexpy extract /data/distribution.json /data/api.json
> ```When you installed AexPy package, you could use `tool runimage` command for a quick runner of containers (if you have Docker installed).
> [!TIP]
> The volume directory will mount to `/data` in the container
>
> All file path arguments passed to container should use absolute paths with `/data` prefix or use a path relative to `/data`.```sh
# Use the same version of the image as current AexPy version
# Use current as mount directory
aexpy tool runimage -- --version
aexpy runimage -- --version# Extract from ./dist.json
aexpy runimage -- extract ./dist.json ./api.json# Use a specified image tag and mount directory
aexpy tool runimage -v ./mount -t stardustdl/aexpy:latest -- --version# Extract from ./mount/dist.json
aexpy runimage -v ./mount -- extract ./dist.json ./api.json
aexpy runimage -v ./mount -- extract /data/dist.json /data/api.json
```## Advanced Tools
### Logging
The processing may cost time, you can use multiple `-v` for verbose logs (which are outputed to stderr).
```sh
aexpy -vvv view ./cache/report.json
```### Compressed IO
When 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.
```sh
aexpy --gzip extract ./cache/distribution.json ./cache/api.json.gz
AEXPY_GZIP_IO=1 aexpy extract ./cache/distribution.json.gz ./cache/api.json
aexpy view ./cache/api.json.gz
```> [!TIP]
> AexPy will detect input file format automatically, no matter compressed-IO enabled or not.
>
> When enabling compressed-IO mode, all output JSON streams will be regarded as gzip JSON streams.### Interactive
Add `-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.
- `result`: The produced data object
- `context`: The producing context, use `exception` to access the exception if failing to process```sh
aexpy -i view ./cache/report.json
```> [!TIP]
> Feel free to use `locals()` and `dir()` to explore the interactive environment.### Statistics
AexPy provides tools to count numbers from produced data in `aexpy.tools.stats` module.
It loads products from given files, runs builtin counters, and then records them as kay-value pairs of the release (or release pair).```sh
aexpy tool stat ./*.json ./stats.json
aexpy stat ./*.json ./stats.jsonaexpy view ./stats.json
```### Pipeline
AexPy 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.
To 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.
```python
from aexpy.services import ServiceProviderclass MyServiceProvider(ServiceProvider):
...def getService():
return MyServiceProvider()
```Then you can load your service file by `-s/--service` option or `AEXPY_SERVICE` environment variable.
```sh
aexpy -s services.py -vvv view --help
AEXPY_SERVICE=services.py aexpy -vvv view --help
```We 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.
```python
from aexpy.tools.runners.services import DockerRunnerServiceProviderdef getService():
return DockerRunnerServiceProvider(tag="stardustdl/aexpy:latest")
```