diff --git a/.github/workflows/check_urls.yml b/.github/workflows/check_urls.yml new file mode 100644 index 0000000..67d7731 --- /dev/null +++ b/.github/workflows/check_urls.yml @@ -0,0 +1,47 @@ +name: Check URLs + +on: + pull_request: + branches: [main] + schedule: + # ┌───────────── minute (0 - 59) + # │ ┌───────────── hour (0 - 23) + # │ │ ┌───────────── day of the month (1 - 31) + # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) + # │ │ │ │ │ + # │ │ │ │ │ + # │ │ │ │ │ + # * * * * * + - cron: '30 1 * * 0' + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: urls-checker-code + uses: urlstechie/urlchecker-action@master + with: + subfolder: onnx_array_api + file_types: .md,.py,.rst,.ipynb + print_all: false + timeout: 2 + retry_count# : 2 + # exclude_urls: https://dumps.wikimedia.org/other/pageviews/%Y/%Y-%m/pageviews-%Y%m%d-%H0000.gz,https://dumps.wikimedia.org/frwiki/latest/latest-all-titles-in-ns0.gz + exclude_patterns: https://dumps.wikimedia.org/ + # force_pass : true + + - name: urls-checker-docs + uses: urlstechie/urlchecker-action@master + with: + subfolder: _doc + file_types: .md,.py,.rst,.ipynb + print_all: false + timeout: 2 + retry_count# : 2 + exclude_urls: https://hal.archives-ouvertes.fr/hal-00990252/document + exclude_patterns: https://www.data.gouv.fr/fr/datasets/r/e3d83ab3-dc52-4c99-abaf-8a38050cc68c,https://dev.azure.com/ + # force_pass : true diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index dcc6d51..05b6a19 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -1,24 +1,15 @@ -name: Documentation +name: Documentation and Code Coverage on: push: - branches: [main] pull_request: - branches: [main] - schedule: - # ┌───────────── minute (0 - 59) - # │ ┌───────────── hour (0 - 23) - # │ │ ┌───────────── day of the month (1 - 31) - # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) - # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) - # │ │ │ │ │ - # │ │ │ │ │ - # │ │ │ │ │ - # * * * * * - - cron: '30 1 * * 0' + types: + - closed + branches: + - main jobs: - build_wheels: + run: name: Build documentation on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: @@ -33,17 +24,65 @@ jobs: with: python-version: '3.11' + - uses: tlylt/install-graphviz@v1 + + - name: Install pandoc + run: sudo apt-get install -y pandoc + - name: Install requirements run: python -m pip install -r requirements.txt - - name: Install requirements-dev.txt + - name: Install requirements dev run: python -m pip install -r requirements-dev.txt + - name: Cache pip + uses: actions/cache@v2 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements-dev.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + ${{ runner.os }}- + + - name: Generate coverage report + run: | + pip install pytest + pip install pytest-cov + export PYTHONPATH=. + pytest --cov=./onnx_array_api/ --cov-report=xml --durations=10 --ignore-glob=**LONG*.py --ignore-glob=**notebook*.py + export PYTHONPATH= + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + - name: Install - run: python -m pip install -e . + run: python setup.py install + + - name: Copy license, changelogs + run: | + cp LICENSE* ./_doc + cp CHANGELOGS* ./_doc - name: Documentation - run: python -m sphinx ./_doc ./dist/html + run: python -m sphinx ./_doc ./dist/html -n -w doc.txt + + - name: Summary + run: cat doc.txt + + - name: Check for errors and warnings + run: | + if [[ $(grep ERROR doc.txt) ]]; then + echo "Documentation produces errors." + grep ERROR doc.txt + exit 1 + fi + if [[ $(grep WARNING doc.txt) ]]; then + echo "Documentation produces warnings." + grep WARNING doc.txt + exit 1 + fi - uses: actions/upload-artifact@v3 with: diff --git a/CHANGELOGS.rst b/CHANGELOGS.rst index ec31997..554f796 100644 --- a/CHANGELOGS.rst +++ b/CHANGELOGS.rst @@ -8,6 +8,6 @@ Change Logs an array to a TensorProto, including bfloat16 and float 8 types * :pr:`24`: add ExtendedReferenceEvaluator to support scenario for the Array API onnx does not support -* :pr:`22`: support OrtValue in function :func:`ort_profile` +* :pr:`22`: support OrtValue in function *ort_profile* * :pr:`17`: implements ArrayAPI * :pr:`3`: fixes Array API with onnxruntime and scikit-learn diff --git a/README.rst b/README.rst index 790e838..9890a18 100644 --- a/README.rst +++ b/README.rst @@ -26,6 +26,9 @@ onnx-array-api: (Numpy) Array API for ONNX .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black +.. image:: https://codecov.io/gh/sdpython/onnx-array-api/branch/main/graph/badge.svg?token=Wb9ZGDta8J + :target: https://codecov.io/gh/sdpython/onnx-array-api + **onnx-array-api** implements a numpy API for ONNX. It gives the user the ability to convert functions written following the numpy API to convert that function into ONNX as diff --git a/_doc/api/array_api.rst b/_doc/api/array_api.rst index f07716a..9d06bee 100644 --- a/_doc/api/array_api.rst +++ b/_doc/api/array_api.rst @@ -3,5 +3,6 @@ onnx_array_api.array_api .. toctree:: - array_api_onnx_numpy - array_api_onnx_ort + array_api_numpy + array_api_ort + npx_array_api diff --git a/_doc/api/index.rst b/_doc/api/index.rst index a95b2f4..c39b7c0 100644 --- a/_doc/api/index.rst +++ b/_doc/api/index.rst @@ -7,9 +7,11 @@ API :maxdepth: 1 array_api + npx_core_api npx_functions - npx_jit + npx_jit_eager npx_numpy + npx_tensors npx_types npx_var onnx_tools @@ -17,3 +19,4 @@ API plotting reference tools + profiling diff --git a/_doc/api/npx_array_api.rst b/_doc/api/npx_array_api.rst new file mode 100644 index 0000000..7481e71 --- /dev/null +++ b/_doc/api/npx_array_api.rst @@ -0,0 +1,5 @@ +onnx_array_api.npx.npx_array_api +================================ + +.. automodule:: onnx_array_api.npx.npx_array_api.BaseArrayApi + :members: diff --git a/_doc/api/npx_jit.rst b/_doc/api/npx_core_api.rst similarity index 52% rename from _doc/api/npx_jit.rst rename to _doc/api/npx_core_api.rst index 05f6fbe..370c443 100644 --- a/_doc/api/npx_jit.rst +++ b/_doc/api/npx_core_api.rst @@ -1,31 +1,33 @@ -npx, jit and eager mode -======================= +============ +npx_core_api +============ - -API -+++ - -.. autofunction:: onnx_array_api.npx.npx_core_api.var +cst +=== .. autofunction:: onnx_array_api.npx.npx_core_api.cst -.. autofunction:: onnx_array_api.npx.npx_jit_eager.eager_onnx - -.. autofunction:: onnx_array_api.npx.npx_jit_eager.jit_onnx +make_tuple +========== .. autofunction:: onnx_array_api.npx.npx_core_api.make_tuple +tuple_var +========= + .. autofunction:: onnx_array_api.npx.npx_core_api.tuple_var +npxapi_inline +============= + .. autofunction:: onnx_array_api.npx.npx_core_api.npxapi_inline -.. autofunction:: onnx_array_api.npx.npx_core_api.npxapi_function +npxapi_function +=============== -JIT, Eager -++++++++++ +.. autofunction:: onnx_array_api.npx.npx_core_api.npxapi_function -.. autoclass:: onnx_array_api.npx.npx_jit_eager.JitEager - :members: +var +=== -.. autoclass:: onnx_array_api.npx.npx_jit_eager.JitOnnx - :members: +.. autofunction:: onnx_array_api.npx.npx_core_api.var diff --git a/_doc/api/npx_jit_eager.rst b/_doc/api/npx_jit_eager.rst new file mode 100644 index 0000000..f3faa08 --- /dev/null +++ b/_doc/api/npx_jit_eager.rst @@ -0,0 +1,31 @@ +============= +npx_jit_eager +============= + +eager_onnx +========== + +.. autofunction:: onnx_array_api.npx.npx_jit_eager.eager_onnx + +EagerOnnx +========= + +.. autoclass:: onnx_array_api.npx.npx_jit_eager.EagerOnnx + :members: + +JitEager +======== + +.. autoclass:: onnx_array_api.npx.npx_jit_eager.JitEager + :members: + +jit_onnx +======== + +.. autofunction:: onnx_array_api.npx.npx_jit_eager.jit_onnx + +JitOnnx +======= + +.. autoclass:: onnx_array_api.npx.npx_jit_eager.JitOnnx + :members: diff --git a/_doc/api/npx_numpy.rst b/_doc/api/npx_numpy.rst index deb8c99..11b752e 100644 --- a/_doc/api/npx_numpy.rst +++ b/_doc/api/npx_numpy.rst @@ -1,11 +1,20 @@ npx.npx_numpy_tensors ===================== +EagerNumpyTensor +++++++++++++++++ + .. autoclass:: onnx_array_api.npx.npx_numpy_tensors.EagerNumpyTensor :members: +JitNumpyTensor +++++++++++++++ + .. autoclass:: onnx_array_api.npx.npx_numpy_tensors.JitNumpyTensor :members: +NumpyTensor ++++++++++++ + .. autoclass:: onnx_array_api.npx.npx_numpy_tensors.NumpyTensor :members: \ No newline at end of file diff --git a/_doc/api/npx_tensors.rst b/_doc/api/npx_tensors.rst new file mode 100644 index 0000000..d86c252 --- /dev/null +++ b/_doc/api/npx_tensors.rst @@ -0,0 +1,10 @@ +=========== +npx_tensors +=========== + + +EagerTensor +=========== + +.. autoclass:: onnx_array_api.npx.npx_tensors.EagerTensor + :members: diff --git a/_doc/api/ort.rst b/_doc/api/ort.rst index 1a09e3d..2aadcdc 100644 --- a/_doc/api/ort.rst +++ b/_doc/api/ort.rst @@ -1,27 +1,35 @@ ort === -Optimization -++++++++++++ +ort_optimized_model ++++++++++++++++++++ .. autofunction:: onnx_array_api.ort.ort_optimizers.ort_optimized_model -OrtTensor -+++++++++ +EagerOrtTensor +++++++++++++++ .. autoclass:: onnx_array_api.ort.ort_tensors.EagerOrtTensor :members: +JitOrtTensor +++++++++++++ + .. autoclass:: onnx_array_api.ort.ort_tensors.JitOrtTensor :members: +OrtTensor ++++++++++ + .. autoclass:: onnx_array_api.ort.ort_tensors.OrtTensor :members: -Profiling -+++++++++ +merge_ort_profile ++++++++++++++++++ .. autofunction:: onnx_array_api.ort.ort_profile.merge_ort_profile -.. autofunction:: onnx_array_api.ort.ort_profile.ort_profile +ort_profile ++++++++++++ +.. autofunction:: onnx_array_api.ort.ort_profile.ort_profile diff --git a/_doc/api/profiling.rst b/_doc/api/profiling.rst new file mode 100644 index 0000000..7a20874 --- /dev/null +++ b/_doc/api/profiling.rst @@ -0,0 +1,17 @@ +profiling +========= + +ProfileNode ++++++++++++ + +.. autoclass:: onnx_array_api.profiling.ProfileNode + +profile ++++++++ + +.. autofunction:: onnx_array_api.profiling.profile + +profile2graph ++++++++++++++ + +.. autofunction:: onnx_array_api.profiling.profile2graph diff --git a/_doc/api/tools.rst b/_doc/api/tools.rst index b93d918..ef161e0 100644 --- a/_doc/api/tools.rst +++ b/_doc/api/tools.rst @@ -11,16 +11,6 @@ Examples .. autofunction:: onnx_array_api.ext_test_case.example_path -Profiling -+++++++++ - -.. autofunction:: onnx_array_api.profiling.profile - -.. autofunction:: onnx_array_api.profiling.profile2graph - -.. autofunction:: onnx_array_api.profiling.profile2df - - Unit tests ++++++++++ diff --git a/_doc/conf.py b/_doc/conf.py index 52f54b6..c58576c 100644 --- a/_doc/conf.py +++ b/_doc/conf.py @@ -1,24 +1,35 @@ import os import sys - +from sphinx_runpython.github_link import make_linkcode_resolve +from sphinx_runpython.conf_helper import has_dvipng, has_dvisvgm from onnx_array_api import __version__ extensions = [ "sphinx.ext.autodoc", - "sphinx.ext.intersphinx", - "sphinx.ext.todo", "sphinx.ext.coverage", - "sphinx.ext.mathjax", + "sphinx.ext.githubpages", "sphinx.ext.ifconfig", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", "sphinx.ext.viewcode", - "sphinx.ext.githubpages", + "sphinx.ext.todo", "sphinx_gallery.gen_gallery", + "sphinx_issues", "matplotlib.sphinxext.plot_directive", - "pyquickhelper.sphinxext.sphinx_epkg_extension", - "pyquickhelper.sphinxext.sphinx_gdot_extension", - "pyquickhelper.sphinxext.sphinx_runpython_extension", + "sphinx_runpython.epkg", + "sphinx_runpython.gdot", + "sphinx_runpython.runpython", ] +if has_dvisvgm(): + extensions.append("sphinx.ext.imgmath") + imgmath_image_format = "svg" +elif has_dvipng(): + extensions.append("sphinx.ext.pngmath") + imgmath_image_format = "png" +else: + extensions.append("sphinx.ext.mathjax") + templates_path = ["_templates"] html_logo = "_static/logo.png" source_suffix = ".rst" @@ -37,18 +48,59 @@ html_theme_path = ["_static"] html_theme_options = {} html_static_path = ["_static"] +html_sourcelink_suffix = "" + +issues_github_path = "sdpython/onnx-array-api" +# The following is used by sphinx.ext.linkcode to provide links to github +linkcode_resolve = make_linkcode_resolve( + "mlstatpy", + ( + "https://github.com/sdpython/onnx-array-api/" + "blob/{revision}/{package}/" + "{path}#L{lineno}" + ), +) + +latex_elements = { + "papersize": "a4", + "pointsize": "10pt", + "title": project, +} intersphinx_mapping = { - "onnx": ("https://onnx.ai/onnx/", None), "matplotlib": ("https://matplotlib.org/", None), "numpy": ("https://numpy.org/doc/stable", None), + "onnx": ("https://onnx.ai/onnx/", None), "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), "python": (f"https://docs.python.org/{sys.version_info.major}", None), "scipy": ("https://docs.scipy.org/doc/scipy/reference", None), + "sklearn": ("https://scikit-learn.org/stable/", None), + "sklearn-onnx": ("https://onnx.ai/sklearn-onnx/", None), "torch": ("https://pytorch.org/docs/stable/", None), } +# Check intersphinx reference targets exist +nitpicky = True +# See also scikit-learn/scikit-learn#26761 +nitpick_ignore = [ + ("py:class", "False"), + ("py:class", "True"), + ("py:class", "pipeline.Pipeline"), + ("py:class", "default=sklearn.utils.metadata_routing.UNCHANGED"), +] + +nitpick_ignore_regex = [ + ("py:func", ".*numpy[.].*"), + ("py:func", ".*scipy[.].*"), + ("py:class", ".*onnxruntime[.].*"), + ("py:class", ".*onnx_array_api.npx.npx_types.OptParTypeTupleType_.*"), + ("py:class", ".*onnx_array_api.npx.npx_types.ParType[a-z].*"), + ("py:class", ".*onnx_array_api.npx.npx_types.OptTensorType_.*"), + ("py:class", ".*onnx_array_api.npx.npx_types.TensorType_.*"), + ("py:class", ".*onnx_array_api.npx.npx_types.[ui].*"), +] + sphinx_gallery_conf = { # path to your examples scripts "examples_dirs": os.path.join(os.path.dirname(__file__), "examples"), @@ -78,4 +130,13 @@ "scipy": "https://scipy.org/", "sphinx-gallery": "https://github.com/sphinx-gallery/sphinx-gallery", "torch": "https://pytorch.org/docs/stable/torch.html", + # + "C_OrtValue": ( + "http://www.xavierdupre.fr/app/onnxcustom/helpsphinx/" + "api/onnxruntime_python/ortvalue.html#c-class-ortvalue-or-c-ortvalue" + ), + "OrtValue": ( + "http://www.xavierdupre.fr/app/onnxcustom/helpsphinx/" + "api/onnxruntime_python/ortvalue.html#onnxruntime.OrtValue" + ), } diff --git a/_doc/examples/plot_first_example.py b/_doc/examples/plot_first_example.py index 09d1b26..2c01f4e 100644 --- a/_doc/examples/plot_first_example.py +++ b/_doc/examples/plot_first_example.py @@ -87,9 +87,12 @@ def myloss(x, y): def l1_loss(x, y): + """ + err is a type inheriting from + :class:`EagerTensor `. + It needs to be converted to numpy first before any display. + """ err = absolute(x - y).sum() - # err is a type inheriting from :class:`EagerTensor`. - # It needs to be converted to numpy first before any display. print(f"l1_loss={err.numpy()}") return err @@ -105,10 +108,13 @@ def myloss(x, y): ################################# -# Eager mode is enabled by function :func:`eager_onnx`. +# Eager mode is enabled by function :func:`eager_onnx +# `. # It intercepts all calls to `my_loss`. On the first call, # it replaces a numpy array by a tensor corresponding to the -# selected runtime, here numpy as well through :class:`EagerNumpyTensor`. +# selected runtime, here numpy as well through +# :class:`EagerNumpyTensor +# `. eager_myloss = eager_onnx(myloss) x = np.array([[0.1, 0.2], [0.3, 0.4]], dtype=np.float32) diff --git a/_doc/index.rst b/_doc/index.rst index 30997b0..c782c8c 100644 --- a/_doc/index.rst +++ b/_doc/index.rst @@ -23,6 +23,9 @@ onnx-array-api: (Numpy) Array API for ONNX .. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black +.. image:: https://codecov.io/gh/sdpython/onnx-array-api/branch/main/graph/badge.svg?token=Wb9ZGDta8J + :target: https://codecov.io/gh/sdpython/onnx-array-api + **onnx-array-api** implements a numpy API for ONNX. It gives the user the ability to convert functions written following the numpy API to convert that function into ONNX as diff --git a/_doc/tech/aapi.rst b/_doc/tech/aapi.rst index ddb0bbe..0f96464 100644 --- a/_doc/tech/aapi.rst +++ b/_doc/tech/aapi.rst @@ -21,7 +21,8 @@ backend. It can be :epkg:`numpy`, :epkg:`onnxruntime` or any other backend. The generation of every graph takes a significant amount of time. It must be avoided. These graphs are cached. But a graph can be reused only if the inputs - by ONNX semantic - change. If a parameter change, -a new graph must be cached. Method :meth:`JitEager.make_key` +a new graph must be cached. Method :meth:`JitEager.make_key +` generates a unique key based on the input it receives, the signature of the function to call. If the key is the same, a cached onnx can be reused on the second call. @@ -53,9 +54,13 @@ Beside, from onnx point of view, argument dtype should be named. Tensor type +++++++++++ -An :class:`EagerTensor` must be used to represent any tensor. +An :class:`EagerTensor ` +must be used to represent any tensor. This class defines the backend to use as well. -`EagerNumpyTensor` for :epkg:`numpy`, `EagerOrtTensor` +:class:`EagerNumpyTensor +` +for :epkg:`numpy`, :class:`EagerOrtTensor +` for :epkg:`onnxruntime`. Since the Array API is new, existing packages do not fully support the API if they support it (:epkg:`scikit-learn`). Some numpy array may still be used. diff --git a/onnx_array_api/array_api/onnx_numpy.py b/onnx_array_api/array_api/onnx_numpy.py index cf39774..bf9eae6 100644 --- a/onnx_array_api/array_api/onnx_numpy.py +++ b/onnx_array_api/array_api/onnx_numpy.py @@ -1,6 +1,3 @@ -""" -Array API valid for an :class:`EagerNumpyTensor`. -""" from ..npx.npx_numpy_tensors import EagerNumpyTensor from . import _finalize_array_api diff --git a/onnx_array_api/array_api/onnx_ort.py b/onnx_array_api/array_api/onnx_ort.py index e1427e1..d285246 100644 --- a/onnx_array_api/array_api/onnx_ort.py +++ b/onnx_array_api/array_api/onnx_ort.py @@ -1,6 +1,3 @@ -""" -Array API valid for an :class:`EagerOrtTensor`. -""" from ..ort.ort_tensors import EagerOrtTensor from . import _finalize_array_api diff --git a/onnx_array_api/npx/npx_core_api.py b/onnx_array_api/npx/npx_core_api.py index 1249273..d6688cf 100644 --- a/onnx_array_api/npx/npx_core_api.py +++ b/onnx_array_api/npx/npx_core_api.py @@ -20,7 +20,8 @@ class args_tuple(tuple): def cst(*args, **kwargs): """ - Wraps a call to the building of class :class:`Cst`. + Wraps a call to the building of class + :class:`Cst `. """ return Cst(*args, **kwargs) @@ -52,7 +53,8 @@ def make_tuple( def var(*args: Sequence[Var], **kwargs: Dict[str, Any]) -> Var: """ - Wraps a call to the building of class :class:`Var`. + Wraps a call to the building of class + :class:`Var `. """ return Var(*args, **kwargs) diff --git a/onnx_array_api/npx/npx_functions.py b/onnx_array_api/npx/npx_functions.py index a8bb62a..db29ca2 100644 --- a/onnx_array_api/npx/npx_functions.py +++ b/onnx_array_api/npx/npx_functions.py @@ -30,7 +30,7 @@ def _cstv(x): @npxapi_inline def abs(x: TensorType[ElemType.numerics, "T"], /) -> TensorType[ElemType.numerics, "T"]: - "See :func:`numpy.abs`." + "See :func:`numpy.absolute`." return var(x, op="Abs") @@ -38,7 +38,7 @@ def abs(x: TensorType[ElemType.numerics, "T"], /) -> TensorType[ElemType.numeric def absolute( x: TensorType[ElemType.numerics, "T"], / ) -> TensorType[ElemType.numerics, "T"]: - "See :func:`numpy.abs`." + "See :func:`numpy.absolute`." return var(x, op="Abs") diff --git a/onnx_array_api/npx/npx_functions_test.py b/onnx_array_api/npx/npx_functions_test.py index 0a4d607..4d442dd 100644 --- a/onnx_array_api/npx/npx_functions_test.py +++ b/onnx_array_api/npx/npx_functions_test.py @@ -24,7 +24,6 @@ def _min_max( x: TensorType[ElemType.numerics, "T"] ) -> TupleType[TensorType[ElemType.numerics, "T"], TensorType[ElemType.numerics, "T"]]: - "See :func:`numpy.abs`." return tuple_var(var(x, op="ReduceMin"), var(x, op="ReduceMax")) @@ -32,7 +31,6 @@ def _min_max( def _min_max_inline( x: TensorType[ElemType.numerics, "T"] ) -> TupleType[TensorType[ElemType.numerics, "T"], TensorType[ElemType.numerics, "T"]]: - "See :func:`numpy.abs`." return tuple_var(var(x, op="ReduceMin"), var(x, op="ReduceMax")) @@ -40,7 +38,7 @@ def _min_max_inline( def absolute( x: TensorType[ElemType.numerics, "T"] ) -> TensorType[ElemType.numerics, "T"]: - "See :func:`numpy.abs`." + "See :func:`numpy.absolute`." return var(x, op="Abs") @@ -94,7 +92,7 @@ def log1p(x: TensorType[ElemType.floats, "T"]) -> TensorType[ElemType.floats, "T def negative( x: TensorType[ElemType.numerics, "T"] ) -> TensorType[ElemType.numerics, "T"]: - "See :func:`numpy.abs`." + "See :func:`numpy.negative`." return var(x, op="Neg") diff --git a/onnx_array_api/npx/npx_graph_builder.py b/onnx_array_api/npx/npx_graph_builder.py index b5333b5..53d2899 100644 --- a/onnx_array_api/npx/npx_graph_builder.py +++ b/onnx_array_api/npx/npx_graph_builder.py @@ -728,7 +728,9 @@ def to_onnx( """ Conversion to onnx. - :param output_vars: list of :class:`Var` holding the final outputs + :param output_vars: list of + :class:`Var ` + holding the final outputs :return: onnx graph """ # _GraphBuilder.to_onnx diff --git a/onnx_array_api/npx/npx_jit_eager.py b/onnx_array_api/npx/npx_jit_eager.py index 0cfe9f7..ef24af7 100644 --- a/onnx_array_api/npx/npx_jit_eager.py +++ b/onnx_array_api/npx/npx_jit_eager.py @@ -18,7 +18,7 @@ class JitEager: :param f: function to convert :param tensor_class: wrapper around a class defining the backend, - if None, it defaults to :class:`onnx.reference.ReferenceEvalutor` + if None, it defaults to :class:`onnx.reference.ReferenceEvaluator` :param target_opsets: dictionary `{opset: version}` :param output_types: shape and type inference cannot be run before the onnx graph is created and type is needed to do such, @@ -551,7 +551,7 @@ class JitOnnx(JitEager): :param f: function to convert :param tensor_class: wrapper around a class defining the backend, - if None, it defaults to :class:`onnx.reference.ReferenceEvalutor` + if None, it defaults to :class:`onnx.reference.ReferenceEvaluator` :param target_opsets: dictionary `{opset: version}` :param output_types: shape and type inference cannot be run before the onnx graph is created and type is needed to do such, @@ -608,7 +608,7 @@ class EagerOnnx(JitEager): :param f: function to convert :param tensor_class: wrapper around a class defining the backend, - if None, it defaults to :class:`onnx.reference.ReferenceEvalutor` + if None, it defaults to :class:`onnx.reference.ReferenceEvaluator` :param target_opsets: dictionary `{opset: version}` :param output_types: shape and type inference cannot be run before the onnx graph is created and type is needed to do such, @@ -801,6 +801,7 @@ def jit_onnx(*args, **kwargs): def eager_onnx(*args, **kwargs): """ - Returns an instance of :class:`EagerOnnx`. + Returns an instance of :class:`EagerOnnx + `. """ return EagerOnnx(*args, **kwargs) diff --git a/onnx_array_api/npx/npx_tensors.py b/onnx_array_api/npx/npx_tensors.py index b8f9637..3e4faa7 100644 --- a/onnx_array_api/npx/npx_tensors.py +++ b/onnx_array_api/npx/npx_tensors.py @@ -17,7 +17,8 @@ class EagerTensor(BaseArrayApi): """ Defines a value for a specific eager mode. An eager tensor must overwrite every call to a method listed in class - :class:`BaseArrayApi`. + :class:`BaseArrayApi + `. """ @classmethod diff --git a/onnx_array_api/npx/npx_types.py b/onnx_array_api/npx/npx_types.py index 54cc618..8284765 100644 --- a/onnx_array_api/npx/npx_types.py +++ b/onnx_array_api/npx/npx_types.py @@ -20,7 +20,7 @@ class DType(WrapperType): following the :epkg:`Array API`. :param code: element type based on onnx definition, - if str, it looks into class :class:`onnxTensorProto` + if str, it looks into class :class:`onnx.TensorProto` to retrieve the code """ diff --git a/onnx_array_api/npx/npx_var.py b/onnx_array_api/npx/npx_var.py index 3e77cc5..27f5455 100644 --- a/onnx_array_api/npx/npx_var.py +++ b/onnx_array_api/npx/npx_var.py @@ -87,7 +87,7 @@ def __ge__(self, x): class ManyIdentity: """ - Holds several instances of :class:`Var`. + Holds several instances of :class:`Var `. """ def __init__(self, *inputs, input_indices=None): @@ -930,7 +930,7 @@ def flatten(self) -> "Var": Flattens a matrix (see :meth:`numpy.ndarray.flatten`). :param axis: only flatten from axis to the end. - :return: :class:`Var` + :return: :class:`Var ` """ cst, var = Var.get_cst_var() @@ -964,7 +964,8 @@ def __getitem__(self, index: Any) -> "Var": * *index* is an integer or a slice, a tuple of integers and slices, example: `[0, 1]`, `[:5, :6]`, `[::2]` (**scenario 1**) * *index* is an *ONNX* object (more precisely an instance of - :class:`Var`), then the method assumes it is an array of + :class:`Var `), + then the method assumes it is an array of boolean to select a subset of the tensor along the first axis, example: `mat[mat == 0]` (**scenario 2**) """ diff --git a/onnx_array_api/ort/ort_tensors.py b/onnx_array_api/ort/ort_tensors.py index c78fccd..2117e3f 100644 --- a/onnx_array_api/ort/ort_tensors.py +++ b/onnx_array_api/ort/ort_tensors.py @@ -39,7 +39,7 @@ def from_array( Creates an instance of :class:`OrtTensor` from a numpy array. Relies on `ortvalue_from_numpy`. A copy of the data in the Numpy object is held by the - :class:`C_OrtValue` only if the device is **not cpu**. + :epkg:`C_OrtValue` only if the device is **not cpu**. Any expression such as `from_array(x.copy())`, or `from_array(x.astype(np.float32))`, ... creates an intermediate variable scheduled to be deleted by the garbage collector @@ -60,7 +60,7 @@ def from_array( def numpy(self) -> np.ndarray: """ - Converts the :class:`OrtValue` into numpy array. + Converts the :epkg:`OrtValue` into numpy array. """ return self._tensor.numpy() @@ -69,7 +69,8 @@ class Evaluator: Wraps class :class:`onnxruntime.InferenceSession` to have a signature closer to python function. - :param tensor_class: class tensor such as :class:`NumpyTensor` + :param tensor_class: class tensor such as :class:`NumpyTensor + ` :param input_names: input names :param onx: onnx model :param f: unused except in error messages diff --git a/onnx_array_api/plotting/_helper.py b/onnx_array_api/plotting/_helper.py index a4c1915..ddca631 100644 --- a/onnx_array_api/plotting/_helper.py +++ b/onnx_array_api/plotting/_helper.py @@ -90,10 +90,10 @@ def _extract_attribute_value( value = fct(att) return value if ref_att is None: - raise AttributeError( + raise AttributeError( # pragma: no cover f"Unable to convert attribute {att.name!r} type {att.type!r}." ) - raise AttributeError( + raise AttributeError( # pragma: no cover f"Unable to convert default value for {ref_att.name!r} " f"type {att.type!r}." ) @@ -115,7 +115,7 @@ def get_tensor_shape(obj): if isinstance(obj, ValueInfoProto): return get_tensor_shape(obj.type) elif not isinstance(obj, TypeProto): - raise TypeError(f"Unexpected type {type(obj)!r}.") + raise TypeError(f"Unexpected type {type(obj)!r}.") # pragma: no cover shape = [] for d in obj.tensor_type.shape.dim: v = d.dim_value if d.dim_value > 0 else d.dim_param @@ -161,7 +161,7 @@ def _get_type(obj0): obj = obj.tensor_type if hasattr(obj, "elem_type"): return tensor_dtype_to_np_dtype(obj.elem_type) - raise RuntimeError(f"Unable to guess type from {obj0!r}.") + raise RuntimeError(f"Unable to guess type from {obj0!r}.") # pragma: no cover def _get_shape(obj): @@ -183,11 +183,11 @@ def _get_shape(obj): if hasattr(obj, "raw_data") and len(obj.raw_data) > 0: arr = to_array(obj) return arr.shape - raise RuntimeError( + raise RuntimeError( # pragma: no cover f"Unable to guess type from {obj0!r}, " f"data_type is {obj.data_type!r}." ) if hasattr(obj, "type"): obj = obj.type if hasattr(obj, "tensor_type"): return get_tensor_shape(obj) - raise RuntimeError(f"Unable to guess type from {obj0!r}.") + raise RuntimeError(f"Unable to guess type from {obj0!r}.") # pragma: no cover diff --git a/onnx_array_api/plotting/stat_plot.py b/onnx_array_api/plotting/stat_plot.py index eaa6a70..4def331 100644 --- a/onnx_array_api/plotting/stat_plot.py +++ b/onnx_array_api/plotting/stat_plot.py @@ -23,7 +23,7 @@ def plot_ort_profile( See :ref:`l-example-ort-profiling` for an example. """ if ax0 is None: - ax0 = plt.gca() + ax0 = plt.gca() # pragma: no cover gr_dur = ( df[["dur", "args_op_name"]].groupby("args_op_name").sum().sort_values("dur") diff --git a/onnx_array_api/plotting/text_plot.py b/onnx_array_api/plotting/text_plot.py index d8976a9..8736d97 100644 --- a/onnx_array_api/plotting/text_plot.py +++ b/onnx_array_api/plotting/text_plot.py @@ -184,7 +184,9 @@ def iterate(nodes, node, depth=0, true_false=""): rows.extend(r) return "\n".join(rows) - raise NotImplementedError(f"Type {node.op_type!r} cannot be displayed.") + raise NotImplementedError( # pragma: no cover + f"Type {node.op_type!r} cannot be displayed." + ) def _append_succ_pred( @@ -401,7 +403,7 @@ def _find_sequence(node_name, known, done): ) if len(sequences) == 0: - raise RuntimeError( + raise RuntimeError( # pragma: no cover "Unexpected empty sequence (len(possibles)=%d, " "len(done)=%d, len(nodes)=%d). This is usually due to " "a name used both as result name and node node. " @@ -432,7 +434,7 @@ def _find_sequence(node_name, known, done): best = k if best is None: - raise RuntimeError( + raise RuntimeError( # pragma: no cover f"Wrong implementation (len(sequence)={len(sequences)})." ) if verbose: @@ -451,7 +453,7 @@ def _find_sequence(node_name, known, done): known |= set(v.output) if len(new_nodes) != len(nodes): - raise RuntimeError( + raise RuntimeError( # pragma: no cover "The returned new nodes are different. " "len(nodes=%d) != %d=len(new_nodes). done=\n%r" "\n%s\n----------\n%s" @@ -484,7 +486,7 @@ def _find_sequence(node_name, known, done): n0s = set(n.name for n in nodes) n1s = set(n.name for n in new_nodes) if n0s != n1s: - raise RuntimeError( + raise RuntimeError( # pragma: no cover "The returned new nodes are different.\n" "%r !=\n%r\ndone=\n%r" "\n----------\n%s\n----------\n%s" @@ -756,7 +758,7 @@ def str_node(indent, node): try: val = str(to_array(att.t).tolist()) except TypeError as e: - raise TypeError( + raise TypeError( # pragma: no cover "Unable to display tensor type %r.\n%s" % (att.type, str(att)) ) from e @@ -851,7 +853,9 @@ def str_node(indent, node): if isinstance(att, str): rows.append(f"attribute: {att!r}") else: - raise NotImplementedError("Not yet introduced in onnx.") + raise NotImplementedError( # pragma: no cover + "Not yet introduced in onnx." + ) # initializer if hasattr(model, "initializer"): @@ -890,7 +894,7 @@ def str_node(indent, node): try: nodes = reorder_nodes_for_display(model.node, verbose=verbose) - except RuntimeError as e: + except RuntimeError as e: # pragma: no cover if raise_exc: raise e else: @@ -920,7 +924,9 @@ def str_node(indent, node): indent = mi if previous_indent is not None and indent < previous_indent: if verbose: - print(f"[onnx_simple_text_plot] break2 {node.op_type}") + print( # pragma: no cover + f"[onnx_simple_text_plot] break2 {node.op_type}" + ) add_break = True if not add_break and previous_out is not None: if len(set(node.input) & previous_out) == 0: diff --git a/requirements-dev.txt b/requirements-dev.txt index 07fd7c3..bda3c19 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -19,9 +19,11 @@ pyquickhelper pytest pytest-cov rstcheck[sphinx,toml] +sphinx-issues +git+https://github.com/sdpython/sphinx-runpython.git ruff scikit-learn -skl2onnx +git+https://github.com/onnx/sklearn-onnx.git sphinx sphinx-gallery tomli