diff --git a/.circleci/config.yml b/.circleci/config.yml deleted file mode 100644 index 8c4d6892..00000000 --- a/.circleci/config.yml +++ /dev/null @@ -1,149 +0,0 @@ -# Python CircleCI 2.0 configuration file -# Check https://circleci.com/docs/2.0/language-python/ for more details -# -# References: -# # how to setup multiple python versions -# https://stackoverflow.com/questions/948354/default-behavior-of-git-push-without-a-branch-specified -# https://github.com/adambrenecki/virtualfish/blob/aa3d6271bcb86ad27b6d24f96b5bd386d176f588/.circleci/config.yml -# -# # Multiple files for a checksum -# https://discuss.circleci.com/t/cant-checksum-multiple-files-with-slashes-in-the-file-path/20667/2 -# -# # Auto Cancel Redundant Builds -# https://circleci.com/docs/2.0/skip-build/#steps-to-enable-auto-cancel-for-pipelines-triggered-by-pushes-to-github-or-the-api -# https://app.circleci.com/settings/project/github/pyutils/line_profiler/advanced?return-to=https%3A%2F%2Fapp.circleci.com%2Fpipelines%2Fgithub%2Fpyutils%2FPYPKG - - -# Note: Main CI is now in github actions - -version: 2 -workflows: - version: 2 - test: - jobs: - - test_full/cp39-cp39-manylinux2010 - - test_full/cp38-cp38-manylinux2010 - - test_full/cp37-cp37m-manylinux2010 - - test_full/cp36-cp36m-manylinux2010 - - -jobs: - - ########### - # TEMPLATES - ########### - - .common_template: &common_template - docker: - - image: cimg/python - steps: - - checkout - - - .test_full_template: &test_full_template - <<: - - *common_template - resource_class: small - steps: - - checkout - - setup_remote_docker - - run: - name: prepare_env - command: | - python -m venv venv - . venv/bin/activate - pip install --upgrade pip - - run: - name: build_wheel - command: | - . venv/bin/activate - VERSION=$(python -c "import setup; print(setup.VERSION)") - export CIBW_BUILD="${MB_PYTHON_TAG}-*" - docker info - pip install -r requirements/build.txt - cibuildwheel --platform=linux --arch=native - - persist_to_workspace: - root: . - paths: - - wheelhouse - - run: - name: install_wheel - command: | - . venv/bin/activate - VERSION=$(python -c "import setup; print(setup.VERSION)") - # Hack in the arch - BDIST_WHEEL_PATH=$(ls wheelhouse/*-$VERSION-$MB_PYTHON_TAG*manylinux*_x86_64.whl) - echo "BDIST_WHEEL_PATH=${BDIST_WHEEL_PATH}" - pip install ${BDIST_WHEEL_PATH}[all] - - run: - name: run_tests - command: | - . venv/bin/activate - python run_tests.py - - - ################################### - ### INHERIT FROM BASE TEMPLATES ### - ################################### - - # Define tests fo the other python verisons using the "test3.6" template - # and indicating what needs to be modified. - # - # All we need to do is change the base docker image so python is the - # version we want we can reuse everything else from the template - - test_full/cp39-cp39-manylinux2010: - <<: *test_full_template - environment: - - MB_PYTHON_TAG=cp39 - docker: - - image: cimg/python:3.9 - working_directory: ~/repo-full-cp39 - - test_full/cp38-cp38-manylinux2010: - <<: *test_full_template - environment: - - MB_PYTHON_TAG=cp38 - docker: - - image: cimg/python:3.8 - working_directory: ~/repo-full-cp38 - - test_full/cp37-cp37m-manylinux2010: - <<: *test_full_template - environment: - - MB_PYTHON_TAG=cp37 - docker: - - image: cimg/python:3.7 - working_directory: ~/repo-full-cp37 - - test_full/cp36-cp36m-manylinux2010: - <<: *test_full_template - environment: - - MB_PYTHON_TAG=cp36 - docker: - - image: cimg/python:3.6 - working_directory: ~/repo-full-cp36 - - -__scratch_work__: - docker: - - image: pypy:3 - working_directory: ~/dev-only-not-a-real-job - steps: - - | - __doc__=" - # Run circleci scripts on a local machine - # snap install circleci - mkdir -p $HOME/Downloads - curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | DESTDIR=$HOME/Downloads bash - - circleci update - circleci switch - - circleci config validate - circleci local execute --job test_full/cp39-cp39-manylinux2010 - circleci local execute --config .circleci/config.yml --job test_full/cp38-cp38-manylinux2010 - circleci local execute --config .circleci/config.yml - - circleci local execute --job test_full/cp38-cp38-manylinux2010 - " diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 55c3312d..a97ac696 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,9 +21,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.1 - name: Set up Python 3.12 for linting - uses: actions/setup-python@v4.7.1 + uses: actions/setup-python@v5.0.0 with: python-version: '3.12' - name: Install dependencies @@ -37,6 +37,7 @@ jobs: - name: Typecheck with mypy run: |- python -m pip install mypy + pip install -r requirements/runtime.txt mypy --install-types --non-interactive ./line_profiler mypy ./line_profiler build_and_test_sdist: @@ -48,9 +49,9 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.1 - name: Set up Python 3.12 - uses: actions/setup-python@v4.7.1 + uses: actions/setup-python@v5.0.0 with: python-version: '3.12' - name: Upgrade pip @@ -66,7 +67,7 @@ jobs: python -m build --sdist --outdir wheelhouse - name: Install sdist run: |- - ls -al ./wheelhouse + ls -al wheelhouse pip install --prefer-binary wheelhouse/line_profiler*.tar.gz -v - name: Test minimal loose sdist run: |- @@ -80,7 +81,7 @@ jobs: # Get path to installed package MOD_DPATH=$(python -c "import line_profiler, os; print(os.path.dirname(line_profiler.__file__))") echo "MOD_DPATH = $MOD_DPATH" - python -m pytest --verbose --cov={self.mod_name} $MOD_DPATH ../tests + python -m pytest --verbose --cov=line_profiler $MOD_DPATH ../tests cd .. - name: Test full loose sdist run: |- @@ -95,13 +96,13 @@ jobs: # Get path to installed package MOD_DPATH=$(python -c "import line_profiler, os; print(os.path.dirname(line_profiler.__file__))") echo "MOD_DPATH = $MOD_DPATH" - python -m pytest --verbose --cov={self.mod_name} $MOD_DPATH ../tests + python -m pytest --verbose --cov=line_profiler $MOD_DPATH ../tests cd .. - - name: Upload sdist artifact - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v3.1.3 + name: Upload sdist artifact with: - name: wheels - path: ./wheelhouse/*.tar.gz + name: sdist_wheels + path: wheelhouse/*.tar.gz build_binpy_wheels: ## # Build the binary wheels. Note: even though cibuildwheel will test @@ -111,6 +112,7 @@ jobs: name: ${{ matrix.os }}, arch=${{ matrix.arch }} runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: # Normally, xcookie generates explicit lists of platforms to build / test # on, but in this case cibuildwheel does that for us, so we need to just @@ -127,7 +129,7 @@ jobs: - auto steps: - name: Checkout source - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.1 - name: Enable MSVC 64bit uses: ilammy/msvc-dev-cmd@v1 if: matrix.os == 'windows-latest' && ${{ contains(matrix.cibw_skip, '*-win32') }} @@ -137,7 +139,7 @@ jobs: with: platforms: all - name: Build binary wheels - uses: pypa/cibuildwheel@v2.16.2 + uses: pypa/cibuildwheel@v2.17.0 with: output-dir: wheelhouse config-file: pyproject.toml @@ -148,7 +150,7 @@ jobs: shell: bash run: ls -la wheelhouse - name: Set up Python 3.12 to combine coverage - uses: actions/setup-python@v4.7.1 + uses: actions/setup-python@v5.0.0 if: runner.os == 'Linux' with: python-version: '3.12' @@ -167,11 +169,12 @@ jobs: echo '### The cwd should now have a coverage.xml' ls -altr pwd - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4.0.1 name: Codecov Upload with: file: ./coverage.xml - - uses: actions/upload-artifact@v3 + token: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/upload-artifact@v3.1.3 name: Upload wheels artifact with: name: wheels @@ -183,10 +186,12 @@ jobs: # environment. ## name: ${{ matrix.python-version }} on ${{ matrix.os }}, arch=${{ matrix.arch }} with ${{ matrix.install-extras }} + if: "! startsWith(github.event.ref, 'refs/heads/release')" runs-on: ${{ matrix.os }} needs: - build_binpy_wheels strategy: + fail-fast: false matrix: # Xcookie generates an explicit list of environments that will be used # for testing instead of using the more concise matrix notation. @@ -197,7 +202,7 @@ jobs: arch: auto - python-version: '3.6' install-extras: tests-strict,runtime-strict - os: macOS-latest + os: macos-13 arch: auto - python-version: '3.6' install-extras: tests-strict,runtime-strict @@ -217,7 +222,7 @@ jobs: arch: auto - python-version: '3.12' install-extras: tests - os: windows-latest + os: macOS-latest arch: auto - python-version: '3.12' install-extras: tests @@ -225,59 +230,59 @@ jobs: arch: auto - python-version: '3.6' install-extras: tests,optional - os: windows-latest + os: ubuntu-20.04 arch: auto - python-version: '3.7' install-extras: tests,optional - os: windows-latest + os: ubuntu-latest arch: auto - python-version: '3.8' install-extras: tests,optional - os: windows-latest + os: ubuntu-latest arch: auto - python-version: '3.9' install-extras: tests,optional - os: windows-latest + os: ubuntu-latest arch: auto - python-version: '3.10' install-extras: tests,optional - os: windows-latest + os: ubuntu-latest arch: auto - python-version: '3.11' install-extras: tests,optional - os: windows-latest + os: ubuntu-latest arch: auto - python-version: '3.12' install-extras: tests,optional - os: windows-latest + os: ubuntu-latest arch: auto - python-version: '3.6' install-extras: tests,optional - os: windows-latest + os: macos-13 arch: auto - python-version: '3.7' install-extras: tests,optional - os: windows-latest + os: macos-13 arch: auto - python-version: '3.8' install-extras: tests,optional - os: windows-latest + os: macOS-latest arch: auto - python-version: '3.9' install-extras: tests,optional - os: windows-latest + os: macOS-latest arch: auto - python-version: '3.10' install-extras: tests,optional - os: windows-latest + os: macOS-latest arch: auto - python-version: '3.11' install-extras: tests,optional - os: windows-latest + os: macOS-latest arch: auto - python-version: '3.12' install-extras: tests,optional - os: windows-latest + os: macOS-latest arch: auto - python-version: '3.6' install-extras: tests,optional @@ -309,7 +314,7 @@ jobs: arch: auto steps: - name: Checkout source - uses: actions/checkout@v4 + uses: actions/checkout@v4.1.1 - name: Enable MSVC 64bit uses: ilammy/msvc-dev-cmd@v1 if: matrix.os == 'windows-latest' @@ -319,10 +324,10 @@ jobs: with: platforms: all - name: Setup Python - uses: actions/setup-python@v4.7.1 + uses: actions/setup-python@v5.0.0 with: python-version: ${{ matrix.python-version }} - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v2.1.1 name: Download wheels with: name: wheels @@ -339,6 +344,9 @@ jobs: pip install tomli pkginfo export WHEEL_FPATH=$(python -c "import pathlib; print(str(sorted(pathlib.Path('wheelhouse').glob('line_profiler*.whl'))[-1]).replace(chr(92), chr(47)))") export MOD_VERSION=$(python -c "from pkginfo import Wheel; print(Wheel('$WHEEL_FPATH').version)") + echo "$WHEEL_FPATH=WHEEL_FPATH" + echo "$INSTALL_EXTRAS=INSTALL_EXTRAS" + echo "$MOD_VERSION=MOD_VERSION" pip install --prefer-binary "line_profiler[$INSTALL_EXTRAS]==$MOD_VERSION" -f wheelhouse echo "Install finished." - name: Test wheel ${{ matrix.install-extras }} @@ -356,6 +364,7 @@ jobs: ls -altr # Get the path to the installed package and run the tests export MOD_DPATH=$(python -c "import line_profiler, os; print(os.path.dirname(line_profiler.__file__))") + export MOD_NAME=line_profiler echo " --- MOD_DPATH = $MOD_DPATH @@ -363,7 +372,7 @@ jobs: running the pytest command inside the workspace --- " - python -m pytest --verbose -p pytester -p no:doctest --xdoctest --cov-config ../pyproject.toml --cov-report term --cov="line_profiler" "$MOD_DPATH" ../tests + python -m pytest --verbose -p pytester -p no:doctest --xdoctest --cov-config ../pyproject.toml --cov-report term --durations=100 --cov="$MOD_NAME" "$MOD_DPATH" ../tests echo "pytest command finished, moving the coverage file to the repo root" ls -al # Move coverage file to a new name @@ -386,26 +395,31 @@ jobs: echo '### The cwd should now have a coverage.xml' ls -altr pwd - - uses: codecov/codecov-action@v3 + - uses: codecov/codecov-action@v4.0.1 name: Codecov Upload with: file: ./coverage.xml + token: ${{ secrets.CODECOV_TOKEN }} test_deploy: name: Uploading Test to PyPi runs-on: ubuntu-latest if: github.event_name == 'push' && ! startsWith(github.event.ref, 'refs/tags') && ! startsWith(github.event.ref, 'refs/heads/release') needs: - - build_and_test_sdist - build_binpy_wheels - - test_binpy_wheels + - build_and_test_sdist steps: - name: Checkout source - uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 - name: Download wheels and sdist + uses: actions/checkout@v4.1.1 + - uses: actions/download-artifact@v2.1.1 + name: Download wheels with: name: wheels path: wheelhouse + - uses: actions/download-artifact@v2.1.1 + name: Download sdist + with: + name: sdist_wheels + path: wheelhouse - name: Show files to upload shell: bash run: ls -la wheelhouse @@ -433,23 +447,53 @@ jobs: pip install urllib3 requests[security] twine GPG_KEYID=$(cat dev/public_gpg_key) echo "GPG_KEYID = '$GPG_KEYID'" - DO_GPG=True GPG_KEYID=$GPG_KEYID TWINE_REPOSITORY_URL=${TWINE_REPOSITORY_URL} TWINE_PASSWORD=$TWINE_PASSWORD TWINE_USERNAME=$TWINE_USERNAME GPG_EXECUTABLE=$GPG_EXECUTABLE DO_UPLOAD=True DO_TAG=False ./publish.sh + GPG_SIGN_CMD="$GPG_EXECUTABLE --batch --yes --detach-sign --armor --local-user $GPG_KEYID" + WHEEL_PATHS=(wheelhouse/*.whl wheelhouse/*.tar.gz) + WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_PATHS[@]}") + echo "$WHEEL_PATHS_STR" + for WHEEL_PATH in "${WHEEL_PATHS[@]}" + do + echo "------" + echo "WHEEL_PATH = $WHEEL_PATH" + $GPG_SIGN_CMD --output $WHEEL_PATH.asc $WHEEL_PATH + $GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH || echo "hack, the first run of gpg very fails" + $GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH + done + ls -la wheelhouse + pip install opentimestamps-client + ots stamp wheelhouse/*.whl wheelhouse/*.tar.gz wheelhouse/*.asc + ls -la wheelhouse + twine upload --username __token__ --password "$TWINE_PASSWORD" --repository-url "$TWINE_REPOSITORY_URL" wheelhouse/*.whl wheelhouse/*.tar.gz --skip-existing --verbose || { echo "failed to twine upload" ; exit 1; } + - uses: actions/upload-artifact@v3.1.3 + name: Upload deploy artifacts + with: + name: deploy_artifacts + path: |- + wheelhouse/*.whl + wheelhouse/*.zip + wheelhouse/*.tar.gz + wheelhouse/*.asc + wheelhouse/*.ots live_deploy: name: Uploading Live to PyPi runs-on: ubuntu-latest if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || startsWith(github.event.ref, 'refs/heads/release')) needs: - - build_and_test_sdist - build_binpy_wheels - - test_binpy_wheels + - build_and_test_sdist steps: - name: Checkout source - uses: actions/checkout@v4 - - uses: actions/download-artifact@v3 - name: Download wheels and sdist + uses: actions/checkout@v4.1.1 + - uses: actions/download-artifact@v2.1.1 + name: Download wheels with: name: wheels path: wheelhouse + - uses: actions/download-artifact@v2.1.1 + name: Download sdist + with: + name: sdist_wheels + path: wheelhouse - name: Show files to upload shell: bash run: ls -la wheelhouse @@ -477,6 +521,77 @@ jobs: pip install urllib3 requests[security] twine GPG_KEYID=$(cat dev/public_gpg_key) echo "GPG_KEYID = '$GPG_KEYID'" - DO_GPG=True GPG_KEYID=$GPG_KEYID TWINE_REPOSITORY_URL=${TWINE_REPOSITORY_URL} TWINE_PASSWORD=$TWINE_PASSWORD TWINE_USERNAME=$TWINE_USERNAME GPG_EXECUTABLE=$GPG_EXECUTABLE DO_UPLOAD=True DO_TAG=False ./publish.sh + GPG_SIGN_CMD="$GPG_EXECUTABLE --batch --yes --detach-sign --armor --local-user $GPG_KEYID" + WHEEL_PATHS=(wheelhouse/*.whl wheelhouse/*.tar.gz) + WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_PATHS[@]}") + echo "$WHEEL_PATHS_STR" + for WHEEL_PATH in "${WHEEL_PATHS[@]}" + do + echo "------" + echo "WHEEL_PATH = $WHEEL_PATH" + $GPG_SIGN_CMD --output $WHEEL_PATH.asc $WHEEL_PATH + $GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH || echo "hack, the first run of gpg very fails" + $GPG_EXECUTABLE --verify $WHEEL_PATH.asc $WHEEL_PATH + done + ls -la wheelhouse + pip install opentimestamps-client + ots stamp wheelhouse/*.whl wheelhouse/*.tar.gz wheelhouse/*.asc + ls -la wheelhouse + twine upload --username __token__ --password "$TWINE_PASSWORD" --repository-url "$TWINE_REPOSITORY_URL" wheelhouse/*.whl wheelhouse/*.tar.gz --skip-existing --verbose || { echo "failed to twine upload" ; exit 1; } + - uses: actions/upload-artifact@v3.1.3 + name: Upload deploy artifacts + with: + name: deploy_artifacts + path: |- + wheelhouse/*.whl + wheelhouse/*.zip + wheelhouse/*.tar.gz + wheelhouse/*.asc + wheelhouse/*.ots + release: + name: Create Github Release + if: github.event_name == 'push' && (startsWith(github.event.ref, 'refs/tags') || startsWith(github.event.ref, 'refs/heads/release')) + runs-on: ubuntu-latest + permissions: + contents: write + needs: + - live_deploy + steps: + - name: Checkout source + uses: actions/checkout@v4.1.1 + - uses: actions/download-artifact@v2.1.1 + name: Download artifacts + with: + name: deploy_artifacts + path: wheelhouse + - name: Show files to release + shell: bash + run: ls -la wheelhouse + - run: 'echo "Automatic Release Notes. TODO: improve" > ${{ github.workspace }}-CHANGELOG.txt' + - name: Tag Release Commit + if: (startsWith(github.event.ref, 'refs/heads/release')) + run: |- + export VERSION=$(python -c "import setup; print(setup.VERSION)") + git tag "v$VERSION" + git push origin "v$VERSION" + - uses: softprops/action-gh-release@v1 + name: Create Release + id: create_release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + body_path: ${{ github.workspace }}-CHANGELOG.txt + tag_name: ${{ github.ref }} + name: Release ${{ github.ref }} + body: Automatic Release + generate_release_notes: true + draft: true + prerelease: false + files: |- + wheelhouse/*.whl + wheelhouse/*.asc + wheelhouse/*.ots + wheelhouse/*.zip + wheelhouse/*.tar.gz diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c99bc496..1f8207ae 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,14 +1,17 @@ Changes ======= +4.1.3 +~~~~~ + 4.1.2 -~~~~ +~~~~~ * ENH: Add support for Python 3.12 #246 * ENH: Add osx universal2 and arm64 wheels #251 * ENH: Fix issue with integer overflow on 32 bit systems #249 4.1.1 -~~~~ +~~~~~ * FIX: ``get_stats`` is no longer slowed down when profiling many code sections #236 4.1.0 @@ -24,7 +27,7 @@ Changes * ENH: Added readthedocs integration: https://kernprof.readthedocs.io/en/latest/index.html 4.0.3 -~~~~ +~~~~~ * FIX: Stop requiring bleeding-edge Cython unless necesasry (for Python 3.12). #206 4.0.2 diff --git a/build_wheels.sh b/build_wheels.sh index bc16f81f..09db509c 100755 --- a/build_wheels.sh +++ b/build_wheels.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash __doc__=" Runs cibuildwheel to create linux binary wheels. diff --git a/dev/ci_public_gpg_key.pgp.enc b/dev/ci_public_gpg_key.pgp.enc index 9e36203a..4e4fd721 100644 --- a/dev/ci_public_gpg_key.pgp.enc +++ b/dev/ci_public_gpg_key.pgp.enc @@ -1,31 +1,31 @@ -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 diff --git a/dev/ci_secret_gpg_subkeys.pgp.enc b/dev/ci_secret_gpg_subkeys.pgp.enc index fcc81faa..532a3a1c 100644 --- a/dev/ci_secret_gpg_subkeys.pgp.enc +++ b/dev/ci_secret_gpg_subkeys.pgp.enc @@ -1,24 +1,24 @@ -U2FsdGVkX1/pRjQeonOw8CdJoiHMQzb6Cv4CEJKTf1q5JaEcwQgfz+2Z7bNKr7yQ -YvW4ydsaRVEuJ09NWqhdg+C46yJvJrQ9CAd7Flp4TLVxtczdY+YVoe2zejPAJbDR -Rm/B/1egxwmFoKbiFy1DH6cZiZlpqwlX9nnY257Vquyu/4xv/w3ziOF3A0knQFwF -3RjEMbnZXd1/zh5JdF9W3oAdn0dSfjDDf/jJZVyHb7riPnTyDN+NEgKRnqgLSm2x -EUcJufhu2AiQQLhIZ2xu9ckHh0XXYrtsbvaEJgYbyvcyY4xDTIsjzH7MBs17Zjl8 -I6GyGQtYwLc4zEeC4Icna2WyyxNhP+D3G1hhFotXFzzWrDHOdCgeWmkKtE4xrpI5 -qa0FPJ6xIxoqZ5WOQMowRtERjB3dzCgRrp5wLPEBGkco/AKFd24ZT7qqv6Q438rA -Q/Mza4i0JfCkUFn8weaAq6sAyDZ/ji9qJU3iNGc/lxQHbhRg1nuJOUNzy0NT/u0Q -B5Ai0cj4xR1L3RWD5l6mHZAuXjSSHJyRpV9eSxpl1H+croqjujoCvtpDkXFBKJir -/myY5DKW7eXcX9RWstv466SBKYJe25Ebpah60u0VnbBrnklQK0n6xVIrqzDQ19Oh -lT7doHpPnKWfpbwkCrg+8RFpE38Us0Q6P4devpTo1oCR7wJt+r0uaefTI69eEnQR -pSoW4f/0of1ITQOSx8s5Hna+gZNWUzD9rfMB3q3t0wC8JY5erj1FfjHVDv1UwxpD -ATRqTYtQFutZPGs63TD0nXCkRf6SxGOQYkswo+e42WYqx+NBJcyGAi8Bu3hXZfBX -5dDvfWTATinNs89K7TV2lb5VpGXN+dFNxx8GYKjOj/p40PB71/6+RCjn+JLEXoom -V3xeJf5uxaX+F9bEN4YLiKND3b9zd08XuSsr6Ye3qZpkdl75x21jJfHS1A1wp1Nu -yjsAFHphc489LkMG1QfmCVqgQ/gEzLrtfNNazgpotxiM5RHxtsLsep4V1yVn8kwG -lBLxgIgsjiCI5SPGkI2NyimYASaewpvt8MO4G+GVydS+639x+1Y1oDqpbVASYr1J -cqAShtKjdo6F4AsVLJXww89Mueq6dkIh5RzZRkdXFFhElXjAxaU6iq9KnZ26f2AF -z6weArFd0isU/2fHm6Ll+tpZWI7FqsZkmAY73n6e8wFJA8wJHXufZH+t3YykgB9+ -NJtkxYGnfea33vJ7vzcS9GtTfFeaOv15X9tA7N4NHVupWXLE8Uy5YjuBek+Tyt8D -K3Bs2n9naSowPp2Uhu4NXtpjFB1MrkarcwZw95y49mk/489FuBwDtPNWXpQ9iyAp -+OLr9IJCWU6XVIzZptx7WmrjBdOzFFXhMniNtj1hdyQ4cdrFtgvQqrBjitp9MpWk -gj+8L/ZoqzPxXtUyh9utdKwgAsfSb0fa8mV9h8FFxIjfuerqjYyof9Tw33w5kgel -pw0jmKBIZJ1WWHqLjHDo2Q== +U2FsdGVkX1815MoM9p0PN0YcxcByf4Whx7zYwgnsZhqXLrD07u+oE314+Hbzfexo +NVrdl3iPWjaXOZECKOWpBrq7RWmfCuY1GR8QM46U+CK0cHEMPFXSOD77RSwGI1W4 +e2Czl5fF074JaRNaPH1oJWCUwkshvnSC6tCGTmlUNxETSh4Bvor3gWn2odpo2DDn +0RgrHOP5qabPxHZSMOwdam1mrfLHp2yKeFAUzsHYI+YuzyUCYJUjx/pQYspXAX+q +843w5aMT7NkWXF02/wHYMT6RVk6DDTWE/4jJLqsIosey48Yb906s8eboTVRGOZaz +DEhEmh/5a4GB4SZxinT8d2fmLqdRl4mwkHyxC5iYjG6io0+6RDSpr+qpF/Ew0nQk +b9hQ6e/LR7Q2Q/0kyjsMtLaozAx/xo2HOSo0EGwKLa1LIcTmmXdzVe/bm2Tf46Z1 ++5AGPQb3FW3Sttnm5y7dj0c3d7sJmm0c2e5co8dloldXilEMAfWe2HUJ8cj3P30N +y/MbPdIJSVpEqucwx0+VUAOKc5lcjcXbB0bMGEl3AtnkkwYAVXC2+fHViHxu6Gy2 +klTwB6idzFm7I0C/iVwMbeusMXhyDIxOABfLNr6ODTHt1blfMq3rf2+d6L2dQ3KW +HHimNTMxGCjPf7FnLO+1fP9x/xUN1eLO8EYJBqgeEf1dJcbFgaTvQ2N4txpJiXrr +MXawuTNBBVSmeCh3F95cCXkd0MpGj8Dq/NIAnZygs7hhS9BPwo2V3r/PLgBqsPWZ +v0HOhUjjRwQAUvZBRBxZr0rZUifFMBErmLVpsqvVdIwGox1GVJvctI31Ik7xarne +jt4XDoQI8s1Mo3oveu/2UNWsm6jtjonnROjMIWUCCKdq2mVQvJhJq4gZHjZThWLl +DTQCGnHSs09nmaFe5z8egRPWqZkF06ypjI1ycQ0JmqdZtFCftLnTWoACM65Drgz+ +vq1CvpqEjs0oLQWHcHBJDlMY1BU8MZ/55z5o/DgUEjUHmRoOqj5LF/DS0c5Vk3FS ++nekrkXhiERqI42Qo2It1Qq8egXcSRma91ufKVVX5Kz4UplNyvTDVIoA01ZYkKcB +wNW5QKsjzsIPUcxcOt1LOxoDkUyh/js+wZjh/UFoGahzn9JIJmxzLEg/ZBGu4Shp +M8f+4pFkufdNihLXOEX8OoT58a4A2TdOxnswtkEgfRXMRTzFrH3p2HIeYGsQ3l8l +lTE1GyRbWqWgbm0cDBv5++EOEqcKjc+FeLW9pkB3WFUGRZ76zN3Ha8heVJ95g/xs +EuKCyiq15hIYn2hs1LjmzvaXDwPJKJ/u9PFQwL2ixkC4byyE3ez3xCbO5O/TLwqn +ZgfLKwiW16+PK+DA2koyElPVOD6W/XRp1dEPFEzBSz3C7y3OmqpN2xNQs76sTZEm +HczxjEyCRenq3029aPM2Y+MdvzekM78/h5g0JlaNMTr25Rwy6u6I5wvtlDZMMnev ++CWwEjqbpR2lUnZuUyMgeg== diff --git a/dev/gpg_owner_trust.enc b/dev/gpg_owner_trust.enc index 4a230aaa..1d3961ec 100644 --- a/dev/gpg_owner_trust.enc +++ b/dev/gpg_owner_trust.enc @@ -1,11 +1,8 @@ -U2FsdGVkX1/VV/oZL+0zJuZbiNgyUZSW8rfYJBPwP5miuereqn/I62Ya0Yd7QQAD -Y+eb/PTMAHRTYrb6nGCig9WztCS5gdaYs2V7RwkGdfQOqeMOdm8tWOSRH21EVtc7 -zyg2EqSTjLyJQReWjf2c1U8AOM1HAp6ZzCnoZkqXIXC2vUDPPipLlTICzlMzytKD -xxpuyl99N7ZIrpHo28Hy8LV9HTidx+OqV6PmzhoSxjiVG23FtflfSrsWh5zxTW8f -ZsDrNielzg63V+IPjzRTP+KLrIxAWvuymKm5QDY/IbSxTuQbI5g8Dny9uOw0BzEW -fHmOZjhEwLECJAhOONUh9VxFlc9SqvfOBMlaLd/HjTtD8pTwD11Zhv5YYdvbhIjw -fgYLF/y6LExpS1B4qanYLvSx35h6c3COeB6AKjVPPBLNYBHBuGKifF1nWeYaSC8s -SiaQ52I6rJdhHAzHR+5FyXlwALKPzGHIYL+chyYHt8g8mIZd131Wu/+6VQtkxb3r -QcKZ8hYACJDTZBuqk11jWiOiFqRH0yOzyq1KUzVV72q4hmp+RLqFPOvTUB1iL7H9 -PsIC2D5+R5Mc2D1dCCbsFSRGYMRsaiORROJQEeZK+WpK0sN8zQTiP3/XomhWGUDF -eWCqjUSYcxv3gVVzksJkbQ== +U2FsdGVkX1+4PZRvEPTWDI49GG9yUC89Zfid9ZHwX/jxhNN0Aps30cn0xoIXlIBF +lkvsRA3071ZEQ4d/udQrlU+FeUCyvR6+hc7r+HFU6kwZ503p6Oc27azbxsVSXmrV +ozW9dbeGiJTyB628NP/efmH5VviTP55ezx2eRHdllAYmqvogar43T8J8eOff6ZkE +QHaGtcW6YJtIRCzwiBenE87ppS45MlqXERW/05yaKlY/cEouQUL/YsZ1Xr1MTEUY +ygQx3gbdsdI1eoXnWuQqc4pNc5lIZIPXlCg41aQNXm3sykpK+gBfeOMvMjddGf+a +2/RgAJZoSuwgsoDN38eZGmv3GYkrvz/kqytxSB0Z6eyZu30NepgGRPcpaAi+yrbU +DSgtJzChyUI03VJYl7asHq9AtdB3mDUlv869J2Yd2nGgDDvJ8yDs2GeWDtXFpBTt +Z2qhsFNbIUBaDB8vGQP247Ji13nmoSwdn3vVJdoigKo= diff --git a/dev/setup_secrets.sh b/dev/setup_secrets.sh index 7b994cae..6321e5ac 100644 --- a/dev/setup_secrets.sh +++ b/dev/setup_secrets.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash __doc__=' ============================ SETUP CI SECRET INSTRUCTIONS diff --git a/docs/source/kernprof.rst b/docs/source/auto/kernprof.rst similarity index 100% rename from docs/source/kernprof.rst rename to docs/source/auto/kernprof.rst diff --git a/docs/source/line_profiler.__main__.rst b/docs/source/auto/line_profiler.__main__.rst similarity index 100% rename from docs/source/line_profiler.__main__.rst rename to docs/source/auto/line_profiler.__main__.rst diff --git a/docs/source/line_profiler._line_profiler.rst b/docs/source/auto/line_profiler._line_profiler.rst similarity index 100% rename from docs/source/line_profiler._line_profiler.rst rename to docs/source/auto/line_profiler._line_profiler.rst diff --git a/docs/source/line_profiler.autoprofile.ast_profle_transformer.rst b/docs/source/auto/line_profiler.autoprofile.ast_profle_transformer.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.ast_profle_transformer.rst rename to docs/source/auto/line_profiler.autoprofile.ast_profle_transformer.rst diff --git a/docs/source/line_profiler.autoprofile.ast_tree_profiler.rst b/docs/source/auto/line_profiler.autoprofile.ast_tree_profiler.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.ast_tree_profiler.rst rename to docs/source/auto/line_profiler.autoprofile.ast_tree_profiler.rst diff --git a/docs/source/line_profiler.autoprofile.autoprofile.rst b/docs/source/auto/line_profiler.autoprofile.autoprofile.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.autoprofile.rst rename to docs/source/auto/line_profiler.autoprofile.autoprofile.rst diff --git a/docs/source/line_profiler.autoprofile.line_profiler_utils.rst b/docs/source/auto/line_profiler.autoprofile.line_profiler_utils.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.line_profiler_utils.rst rename to docs/source/auto/line_profiler.autoprofile.line_profiler_utils.rst diff --git a/docs/source/line_profiler.autoprofile.profmod_extractor.rst b/docs/source/auto/line_profiler.autoprofile.profmod_extractor.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.profmod_extractor.rst rename to docs/source/auto/line_profiler.autoprofile.profmod_extractor.rst diff --git a/docs/source/line_profiler.autoprofile.rst b/docs/source/auto/line_profiler.autoprofile.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.rst rename to docs/source/auto/line_profiler.autoprofile.rst diff --git a/docs/source/line_profiler.autoprofile.util_static.rst b/docs/source/auto/line_profiler.autoprofile.util_static.rst similarity index 100% rename from docs/source/line_profiler.autoprofile.util_static.rst rename to docs/source/auto/line_profiler.autoprofile.util_static.rst diff --git a/docs/source/line_profiler.explicit_profiler.rst b/docs/source/auto/line_profiler.explicit_profiler.rst similarity index 100% rename from docs/source/line_profiler.explicit_profiler.rst rename to docs/source/auto/line_profiler.explicit_profiler.rst diff --git a/docs/source/line_profiler.ipython_extension.rst b/docs/source/auto/line_profiler.ipython_extension.rst similarity index 100% rename from docs/source/line_profiler.ipython_extension.rst rename to docs/source/auto/line_profiler.ipython_extension.rst diff --git a/docs/source/line_profiler.line_profiler.rst b/docs/source/auto/line_profiler.line_profiler.rst similarity index 100% rename from docs/source/line_profiler.line_profiler.rst rename to docs/source/auto/line_profiler.line_profiler.rst diff --git a/docs/source/line_profiler.rst b/docs/source/auto/line_profiler.rst similarity index 100% rename from docs/source/line_profiler.rst rename to docs/source/auto/line_profiler.rst diff --git a/docs/source/auto/line_profiler.timers.rst b/docs/source/auto/line_profiler.timers.rst new file mode 100644 index 00000000..40bee47d --- /dev/null +++ b/docs/source/auto/line_profiler.timers.rst @@ -0,0 +1,8 @@ +line\_profiler.timers module +============================ + +.. automodule:: line_profiler.timers + :members: + :undoc-members: + :show-inheritance: + :private-members: diff --git a/docs/source/auto/line_profiler.unset_trace.rst b/docs/source/auto/line_profiler.unset_trace.rst new file mode 100644 index 00000000..5b595182 --- /dev/null +++ b/docs/source/auto/line_profiler.unset_trace.rst @@ -0,0 +1,8 @@ +line\_profiler.unset\_trace module +================================== + +.. automodule:: line_profiler.unset_trace + :members: + :undoc-members: + :show-inheritance: + :private-members: diff --git a/docs/source/auto/modules.rst b/docs/source/auto/modules.rst new file mode 100644 index 00000000..a6ff2cbc --- /dev/null +++ b/docs/source/auto/modules.rst @@ -0,0 +1,7 @@ +line_profiler +============= + +.. toctree:: + :maxdepth: 4 + + line_profiler diff --git a/docs/source/conf.py b/docs/source/conf.py index 21d3094a..596d0eb1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,7 +1,7 @@ """ Notes: Based on template code in: - ~/code/xcookie/xcookie/builders/docs_conf.py + ~/code/xcookie/xcookie/builders/docs.py ~/code/xcookie/xcookie/rc/conf_ext.py http://docs.readthedocs.io/en/latest/getting_started.html @@ -17,10 +17,13 @@ # need to edit the conf.py cd ~/code/line_profiler/docs - sphinx-apidoc --private -f -o ~/code/line_profiler/docs/source ~/code/line_profiler/line_profiler --separate + sphinx-apidoc --private --separate -f -o ~/code/line_profiler/docs/source/auto ~/code/line_profiler/line_profiler + + # Note: the module should importable before running this + # (e.g. install it in developer mode or munge the PYTHONPATH) make html - git add source/*.rst + git add source/auto/*.rst Also: To turn on PR checks @@ -34,31 +37,54 @@ ### For gitlab - The user will need to enable the repo on their readthedocs account: - https://readthedocs.org/dashboard/import/manual/? - To enable the read-the-docs go to https://readthedocs.org/dashboard/ and login - Make sure you have a .readthedocs.yml file + The user will need to enable the repo on their readthedocs account: + https://readthedocs.org/dashboard/import/manual/? - Click import project: (for github you can select, but gitlab you need to import manually) + Enter the following information: Set the Repository NAME: line_profiler Set the Repository URL: https://github.com/pyutils/line_profiler + Make sure you have a .readthedocs.yml file + For gitlab you also need to setup an integrations. Navigate to: https://readthedocs.org/dashboard/line-profiler/integrations/create/ Then add gitlab incoming webhook and copy the URL (make sure - you copy the real url and not the text so https is included). + you copy the real url and not the text so https is included), + specifically: + + In the "Integration type:" dropdown menu, select + "Gitlab incoming webhook" + + Click "Add integration" + + Copy the text in the "Webhook URL" box to be used later. + + Copy the text in the "Secret" box to be used later. Then go to https://github.com/pyutils/line_profiler/hooks - and add the URL + Click "Add new webhook". - select push, tag, and merge request + Copy the text previously saved from the "Webhook URL" box + in the readthedocs form into the "URL" box in the gitlab + form. + + Copy the text previously saved from the "Secret" box + in the readthedocs form into the "Secret token" box in the + gitlab form. + + For trigger permissions select the following checkboxes: + push events, + tag push events, + merge request events + + Click the "Add webhook" button. See Docs for more details https://docs.readthedocs.io/en/stable/integrations.html @@ -110,14 +136,19 @@ def visit_Assign(self, node): return visitor.version project = 'line_profiler' -copyright = '2023, Robert Kern' +copyright = '2024, Robert Kern' author = 'Robert Kern' modname = 'line_profiler' -modpath = join(dirname(dirname(dirname(__file__))), 'line_profiler', '__init__.py') +repo_dpath = dirname(dirname(dirname(__file__))) +mod_dpath = join(repo_dpath, 'line_profiler') +src_dpath = dirname(mod_dpath) +modpath = join(mod_dpath, '__init__.py') release = parse_version(modpath) version = '.'.join(release.split('.')[0:2]) +# Hack to ensure the module is importable +# sys.path.insert(0, os.path.abspath(src_dpath)) # -- General configuration --------------------------------------------------- @@ -136,8 +167,8 @@ def visit_Assign(self, node): 'sphinx.ext.napoleon', 'sphinx.ext.todo', 'sphinx.ext.viewcode', - # 'myst_parser', # TODO - + 'myst_parser', # For markdown docs + 'sphinx.ext.imgconverter', # For building latexpdf 'sphinx.ext.githubpages', # 'sphinxcontrib.redirects', 'sphinx_reredirects', @@ -148,8 +179,21 @@ def visit_Assign(self, node): napoleon_use_param = False napoleon_use_ivar = True +#autoapi_type = 'python' +#autoapi_dirs = [mod_dpath] + autodoc_inherit_docstrings = False +# Hack for geowatch, todo configure +autosummary_mock_imports = [ + 'geowatch.utils.lightning_ext._jsonargparse_ext_ge_4_24_and_lt_4_xx', + 'geowatch.utils.lightning_ext._jsonargparse_ext_ge_4_22_and_lt_4_24', + 'geowatch.utils.lightning_ext._jsonargparse_ext_ge_4_21_and_lt_4_22', + 'geowatch.tasks.fusion.datamodules.temporal_sampling.affinity_sampling', + 'geowatch.tasks.depth_pcd.model', + 'geowatch.tasks.cold.export_change_map', +] + autodoc_member_order = 'bysource' autoclass_content = 'both' # autodoc_mock_imports = ['torch', 'torchvision', 'visdom'] @@ -163,6 +207,9 @@ def visit_Assign(self, node): # autoapi_dirs = [f'../../src/{modname}'] # autoapi_keep_files = True +# References: +# https://stackoverflow.com/questions/21538983/specifying-targets-for-intersphinx-links-to-numpy-scipy-and-matplotlib + intersphinx_mapping = { # 'pytorch': ('http://pytorch.org/docs/master/', None), 'python': ('https://docs.python.org/3', None), @@ -181,10 +228,20 @@ def visit_Assign(self, node): 'scriptconfig': ('https://scriptconfig.readthedocs.io/en/latest/', None), 'rich': ('https://rich.readthedocs.io/en/latest/', None), + 'numpy': ('https://numpy.org/doc/stable/', None), + 'sympy': ('https://docs.sympy.org/latest/', None), + 'scikit-learn': ('https://scikit-learn.org/stable/', None), + 'pandas': ('https://pandas.pydata.org/docs/', None), + 'matplotlib': ('https://matplotlib.org/stable/', None), + 'pytest': ('https://docs.pytest.org/en/latest/', None), + 'platformdirs': ('https://platformdirs.readthedocs.io/en/latest/', None), + + 'timerit': ('https://timerit.readthedocs.io/en/latest/', None), + 'progiter': ('https://progiter.readthedocs.io/en/latest/', None), + 'dateutil': ('https://dateutil.readthedocs.io/en/latest/', None), # 'pytest._pytest.doctest': ('https://docs.pytest.org/en/latest/_modules/_pytest/doctest.html', None), # 'colorama': ('https://pypi.org/project/colorama/', None), - # 'numpy': ('http://docs.scipy.org/doc/numpy/', None), # 'cv2' : ('http://docs.opencv.org/2.4/', None), # 'h5py' : ('http://docs.h5py.org/en/latest/', None) } @@ -246,6 +303,7 @@ def visit_Assign(self, node): html_theme_options = { 'collapse_navigation': False, 'display_version': True, + 'navigation_depth': -1, # 'logo_only': True, } # html_logo = '.static/line_profiler.svg' @@ -275,6 +333,21 @@ def visit_Assign(self, node): # -- Options for LaTeX output ------------------------------------------------ +# References: +# https://tex.stackexchange.com/questions/546246/centos-8-the-font-freeserif-cannot-be-found + +""" +# https://www.sphinx-doc.org/en/master/usage/builders/index.html#sphinx.builders.latex.LaTeXBuilder +# https://tex.stackexchange.com/a/570691/83399 +sudo apt install fonts-freefont-otf texlive-luatex texlive-latex-extra texlive-fonts-recommended texlive-latex-recommended tex-gyre latexmk +make latexpdf LATEXMKOPTS="-shell-escape --synctex=-1 -src-specials -interaction=nonstopmode" +make latexpdf LATEXMKOPTS="-lualatex -interaction=nonstopmode" +make LATEXMKOPTS="-lualatex -interaction=nonstopmode" + +""" +# latex_engine = 'lualatex' +# latex_engine = 'xelatex' + latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # @@ -330,15 +403,28 @@ def visit_Assign(self, node): from typing import Any, List # NOQA +# HACK TO PREVENT EXCESSIVE TIME. +# TODO: FIXME FOR REAL +MAX_TIME_MINUTES = None +if MAX_TIME_MINUTES: + import ubelt # NOQA + TIMER = ubelt.Timer() + TIMER.tic() + + class PatchedPythonDomain(PythonDomain): """ References: https://github.com/sphinx-doc/sphinx/issues/3866 """ def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode): - # TODO: can use this to resolve references nicely - # if target.startswith('ub.'): - # target = 'ubelt.' + target[3] + """ + Helps to resolves cross-references + """ + if target.startswith('ub.'): + target = 'ubelt.' + target[3] + if target.startswith('xdoc.'): + target = 'xdoctest.' + target[3] return_value = super(PatchedPythonDomain, self).resolve_xref( env, fromdocname, builder, typ, target, node, contnode) return return_value @@ -351,6 +437,7 @@ class GoogleStyleDocstringProcessor: """ def __init__(self, autobuild=1): + self.debug = 0 self.registry = {} if autobuild: self._register_builtins() @@ -405,7 +492,7 @@ def benchmark(lines): redone = new_text.split('\n') new_lines.extend(redone) # import ubelt as ub - # print('new_lines = {}'.format(ub.repr2(new_lines, nl=1))) + # print('new_lines = {}'.format(ub.urepr(new_lines, nl=1))) # new_lines.append('') return new_lines @@ -419,6 +506,17 @@ def text_art(lines): new_lines.extend(lines[1:]) return new_lines + # @self.register_section(tag='TODO', alias=['.. todo::']) + # def todo_section(lines): + # """ + # Fixup todo sections + # """ + # import xdev + # xdev.embed() + # import ubelt as ub + # print('lines = {}'.format(ub.urepr(lines, nl=1))) + # return new_lines + @self.register_section(tag='Ignore') def ignore(lines): return [] @@ -529,10 +627,12 @@ def process_docstring_callback(self, app, what_: str, name: str, obj: Any, https://www.sphinx-doc.org/en/1.5.1/_modules/sphinx/ext/autodoc.html https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html """ - # print(f'name={name}') + if self.debug: + print(f'ProcessDocstring: name={name}, what_={what_}, num_lines={len(lines)}') + # print('BEFORE:') # import ubelt as ub - # print('lines = {}'.format(ub.repr2(lines, nl=1))) + # print('lines = {}'.format(ub.urepr(lines, nl=1))) self.process(lines) @@ -545,8 +645,12 @@ def process_docstring_callback(self, app, what_: str, name: str, obj: Any, # import xdev # xdev.embed() - RENDER_IMAGES = 1 - if RENDER_IMAGES: + render_doc_images = 0 + + if MAX_TIME_MINUTES and TIMER.toc() > (60 * MAX_TIME_MINUTES): + render_doc_images = False # FIXME too slow on RTD + + if render_doc_images: # DEVELOPING if any('REQUIRES(--show)' in line for line in lines): # import xdev @@ -608,7 +712,7 @@ def process_docstring_callback(self, app, what_: str, name: str, obj: Any, lines[edit_slice] = new_lines # print('AFTER:') - # print('lines = {}'.format(ub.repr2(lines, nl=1))) + # print('lines = {}'.format(ub.urepr(lines, nl=1))) # if name == 'kwimage.Affine.translate': # import sys @@ -856,27 +960,74 @@ class Skipped(Exception): insert_index = end_index else: raise KeyError(INSERT_AT) - lines.insert(insert_index, '.. image:: {}'.format(rel_to_root_fpath)) + lines.insert(insert_index, '.. image:: {}'.format('..' / rel_to_root_fpath)) + # lines.insert(insert_index, '.. image:: {}'.format(rel_to_root_fpath)) # lines.insert(insert_index, '.. image:: {}'.format(rel_to_static_fpath)) lines.insert(insert_index, '') +def postprocess_hyperlinks(app, doctree, docname): + """ + Extension to fixup hyperlinks. + This should be connected to the Sphinx application's + "autodoc-process-docstring" event. + """ + # Your hyperlink postprocessing logic here + from docutils import nodes + import pathlib + for node in doctree.traverse(nodes.reference): + if 'refuri' in node.attributes: + refuri = node.attributes['refuri'] + if '.rst' in refuri: + if 'source' in node.document: + fpath = pathlib.Path(node.document['source']) + parent_dpath = fpath.parent + if (parent_dpath / refuri).exists(): + node.attributes['refuri'] = refuri.replace('.rst', '.html') + else: + raise AssertionError + + +def fix_rst_todo_section(lines): + new_lines = [] + for line in lines: + ... + ... + + def setup(app): import sphinx app : sphinx.application.Sphinx = app app.add_domain(PatchedPythonDomain, override=True) + + app.connect("doctree-resolved", postprocess_hyperlinks) + docstring_processor = GoogleStyleDocstringProcessor() # https://stackoverflow.com/questions/26534184/can-sphinx-ignore-certain-tags-in-python-docstrings app.connect('autodoc-process-docstring', docstring_processor.process_docstring_callback) + def copy(src, dst): + import shutil + print(f'Copy {src} -> {dst}') + assert src.exists() + if not dst.parent.exists(): + dst.parent.mkdir() + shutil.copy(src, dst) + ### Hack for kwcoco: TODO: figure out a way for the user to configure this. HACK_FOR_KWCOCO = 0 if HACK_FOR_KWCOCO: import pathlib - import shutil - doc_outdir = pathlib.Path(app.outdir) - doc_srcdir = pathlib.Path(app.srcdir) - schema_src = (doc_srcdir / '../../kwcoco/coco_schema.json') - shutil.copy(schema_src, doc_outdir / 'coco_schema.json') - shutil.copy(schema_src, doc_srcdir / 'coco_schema.json') + doc_outdir = pathlib.Path(app.outdir) / 'auto' + doc_srcdir = pathlib.Path(app.srcdir) / 'auto' + + mod_dpath = doc_srcdir / '../../../kwcoco' + + src_fpath = (mod_dpath / 'coco_schema.json') + copy(src_fpath, doc_outdir / src_fpath.name) + copy(src_fpath, doc_srcdir / src_fpath.name) + + src_fpath = (mod_dpath / 'coco_schema_informal.rst') + copy(src_fpath, doc_outdir / src_fpath.name) + copy(src_fpath, doc_srcdir / src_fpath.name) return app diff --git a/docs/source/index.rst b/docs/source/index.rst index 47c4057b..d46ed0ab 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,8 +6,10 @@ :maxdepth: 8 :caption: Package Layout - line_profiler - kernprof + auto/line_profiler + auto/line_profiler.autoprofile + auto/line_profiler.explicit_profiler + auto/kernprof Indices and tables diff --git a/kernprof.py b/kernprof.py index e9b1a861..29496655 100755 --- a/kernprof.py +++ b/kernprof.py @@ -91,7 +91,7 @@ def main(): # NOTE: This version needs to be manually maintained in # line_profiler/line_profiler.py and line_profiler/__init__.py as well -__version__ = '4.1.2' +__version__ = '4.1.3' # Guard the import of cProfile such that 3.x people # without lsprof can still use this script. diff --git a/line_profiler/__init__.py b/line_profiler/__init__.py index 3069bb2b..5c090cb2 100644 --- a/line_profiler/__init__.py +++ b/line_profiler/__init__.py @@ -159,7 +159,7 @@ def main(): # from .line_profiler import __version__ # NOTE: This needs to be in sync with ../kernprof.py and line_profiler.py -__version__ = '4.1.2' +__version__ = '4.1.3' from .line_profiler import (LineProfiler, load_ipython_extension, load_stats, main, diff --git a/line_profiler/line_profiler.py b/line_profiler/line_profiler.py index 4dd0bb08..daaca49a 100755 --- a/line_profiler/line_profiler.py +++ b/line_profiler/line_profiler.py @@ -22,7 +22,7 @@ ) # NOTE: This needs to be in sync with ../kernprof.py and __init__.py -__version__ = '4.1.2' +__version__ = '4.1.3' def load_ipython_extension(ip): diff --git a/publish.sh b/publish.sh index 6a1d9c67..237ee0d8 100755 --- a/publish.sh +++ b/publish.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash __doc__=' Script to publish a new version of this library on PyPI. @@ -24,6 +24,10 @@ Args: If True, sign the packages with a GPG key specified by `GPG_KEYID`. defaults to auto. + DO_OTS (bool) : + If True, make an opentimestamp for the package and signature (if + available) + DO_UPLOAD (bool) : If True, upload the packages to the pypi server specified by `TWINE_REPOSITORY_URL`. @@ -138,11 +142,21 @@ DO_UPLOAD=${DO_UPLOAD:=$ARG_1} DO_TAG=${DO_TAG:=$ARG_1} DO_GPG=${DO_GPG:="auto"} -# Verify that we want to build if [ "$DO_GPG" == "auto" ]; then DO_GPG="True" fi +DO_OTS=${DO_OTS:="auto"} +if [ "$DO_OTS" == "auto" ]; then + # Do opentimestamp if it is available + # python -m pip install opentimestamps-client + if type ots ; then + DO_OTS="True" + else + DO_OTS="False" + fi +fi + DO_BUILD=${DO_BUILD:="auto"} # Verify that we want to build if [ "$DO_BUILD" == "auto" ]; then @@ -150,6 +164,7 @@ if [ "$DO_BUILD" == "auto" ]; then fi DO_GPG=$(normalize_boolean "$DO_GPG") +DO_OTS=$(normalize_boolean "$DO_OTS") DO_BUILD=$(normalize_boolean "$DO_BUILD") DO_UPLOAD=$(normalize_boolean "$DO_UPLOAD") DO_TAG=$(normalize_boolean "$DO_TAG") @@ -237,6 +252,7 @@ GPG_KEYID = '$GPG_KEYID' DO_UPLOAD=${DO_UPLOAD} DO_TAG=${DO_TAG} DO_GPG=${DO_GPG} +DO_OTS=${DO_OTS} DO_BUILD=${DO_BUILD} MODE_LIST_STR=${MODE_LIST_STR} " @@ -375,7 +391,7 @@ ls_array(){ } -WHEEL_PATHS=() +WHEEL_FPATHS=() for _MODE in "${MODE_LIST[@]}" do if [[ "$_MODE" == "sdist" ]]; then @@ -393,32 +409,32 @@ do for new_item in "${_NEW_WHEEL_PATHS[@]}" do if [[ "$new_item" != "" ]]; then - WHEEL_PATHS+=("$new_item") + WHEEL_FPATHS+=("$new_item") fi done done # Dedup the paths -readarray -t WHEEL_PATHS < <(printf '%s\n' "${WHEEL_PATHS[@]}" | sort -u) +readarray -t WHEEL_FPATHS < <(printf '%s\n' "${WHEEL_FPATHS[@]}" | sort -u) -WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_PATHS[@]}") +WHEEL_PATHS_STR=$(printf '"%s" ' "${WHEEL_FPATHS[@]}") echo "WHEEL_PATHS_STR = $WHEEL_PATHS_STR" echo " MODE=$MODE VERSION='$VERSION' -WHEEL_PATHS='$WHEEL_PATHS_STR' +WHEEL_FPATHS='$WHEEL_PATHS_STR' " - +WHEEL_SIGNATURE_FPATHS=() if [ "$DO_GPG" == "True" ]; then echo " === === " - for WHEEL_FPATH in "${WHEEL_PATHS[@]}" + for WHEEL_FPATH in "${WHEEL_FPATHS[@]}" do echo "WHEEL_FPATH = $WHEEL_FPATH" check_variable WHEEL_FPATH @@ -439,6 +455,8 @@ if [ "$DO_GPG" == "True" ]; then echo "Verifying wheels" $GPG_EXECUTABLE --verify "$WHEEL_FPATH".asc "$WHEEL_FPATH" || { echo 'could not verify wheels' ; exit 1; } + + WHEEL_SIGNATURE_FPATHS+=("$WHEEL_FPATH".asc) done echo " === === @@ -448,6 +466,27 @@ else fi + +if [ "$DO_OTS" == "True" ]; then + + echo " + === === + " + if [ "$DO_GPG" == "True" ]; then + # Stamp the wheels and the signatures + ots stamp "${WHEEL_FPATHS[@]}" "${WHEEL_SIGNATURE_FPATHS[@]}" + else + # Stamp only the wheels + ots stamp "${WHEEL_FPATHS[@]}" + fi + echo " + === === + " +else + echo "DO_OTS=False, Skipping OTS sign" +fi + + if [[ "$DO_TAG" == "True" ]]; then TAG_NAME="v${VERSION}" # if we messed up we can delete the tag @@ -467,7 +506,7 @@ if [[ "$DO_UPLOAD" == "True" ]]; then check_variable TWINE_USERNAME check_variable TWINE_PASSWORD "hide" - for WHEEL_FPATH in "${WHEEL_PATHS[@]}" + for WHEEL_FPATH in "${WHEEL_FPATHS[@]}" do twine upload --username "$TWINE_USERNAME" "--password=$TWINE_PASSWORD" \ --repository-url "$TWINE_REPOSITORY_URL" \ @@ -496,3 +535,39 @@ else !!! FINISH: DRY RUN !!! """ fi + +__devel__=' +# Checking to see how easy it is to upload packages to gitlab. +# This logic should go in the CI script, not sure if it belongs here. + + +export HOST=https://gitlab.kitware.com +export GROUP_NAME=computer-vision +export PROJECT_NAME=geowatch +PROJECT_VERSION=$(geowatch --version) +echo "$PROJECT_VERSION" + +load_secrets +export PRIVATE_GITLAB_TOKEN=$(git_token_for "$HOST") +TMP_DIR=$(mktemp -d -t ci-XXXXXXXXXX) + +curl --header "PRIVATE-TOKEN: $PRIVATE_GITLAB_TOKEN" "$HOST/api/v4/groups" > "$TMP_DIR/all_group_info" +GROUP_ID=$(cat "$TMP_DIR/all_group_info" | jq ". | map(select(.name==\"$GROUP_NAME\")) | .[0].id") +echo "GROUP_ID = $GROUP_ID" + +curl --header "PRIVATE-TOKEN: $PRIVATE_GITLAB_TOKEN" "$HOST/api/v4/groups/$GROUP_ID" > "$TMP_DIR/group_info" +PROJ_ID=$(cat "$TMP_DIR/group_info" | jq ".projects | map(select(.name==\"$PROJECT_NAME\")) | .[0].id") +echo "PROJ_ID = $PROJ_ID" + +ls_array DIST_FPATHS "dist/*" + +for FPATH in "${DIST_FPATHS[@]}" +do + FNAME=$(basename $FPATH) + echo $FNAME + curl --header "PRIVATE-TOKEN: $PRIVATE_GITLAB_TOKEN" \ + --upload-file $FPATH \ + "https://gitlab.kitware.com/api/v4/projects/$PROJ_ID/packages/generic/$PROJECT_NAME/$PROJECT_VERSION/$FNAME" +done + +' diff --git a/pyproject.toml b/pyproject.toml index 86f2ddf7..f504262b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,8 +38,9 @@ omit =[ build = "cp36-* cp37-* cp38-* cp39-* cp310-* cp311-* cp312-*" build-frontend = "build" build-verbosity = 1 -test-requires = [ "-r requirements/tests.txt",] +#test-requires = [ "-r requirements/tests-strict.txt",] test-command = "python {project}/run_tests.py" +test-extras = ["tests-strict", "runtime-strict"] # https://cibuildwheel.readthedocs.io/en/stable/options/#archs [tool.cibuildwheel.macos] @@ -72,8 +73,8 @@ console_scripts = [ [tool.pytest.ini_options] -addopts = "--ignore-glob=setup.py --ignore-glob=dev" -norecursedirs = ".git ignore build __pycache__ dev _skbuild" +addopts = "--ignore-glob=setup.py --ignore-glob=dev --ignore-glob=setup.py --ignore-glob=docs --ignore-glob=agentx" +norecursedirs = ".git ignore build __pycache__ dev _skbuild docs agentx" filterwarnings = [ "default", ] diff --git a/requirements/tests.txt b/requirements/tests.txt index 00379c53..1936d1a2 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -1,16 +1,20 @@ -pytest>=6.2.5 ; python_version >= '3.10.0' # Python 3.10+ -pytest>=4.6.0 ; python_version < '3.10.0' and python_version >= '3.7.0' # Python 3.7-3.9 -pytest>=4.6.0 ; python_version < '3.7.0' and python_version >= '3.6.0' # Python 3.6 -pytest>=4.6.0, <= 6.1.2 ; python_version < '3.6.0' and python_version >= '3.5.0' # Python 3.5 -pytest>=4.6.0, <= 4.6.11 ; python_version < '3.5.0' and python_version >= '3.4.0' # Python 3.4 -pytest>=4.6.0, <= 4.6.11 ; python_version < '2.8.0' and python_version >= '2.7.0' # Python 2.7 +pytest>=7.4.4 ; python_version < '4.0' and python_version >= '3.13' # Python 3.13+ +pytest>=7.4.4 ; python_version < '3.13' and python_version >= '3.12' # Python 3.12 +pytest>=7.4.4 ; python_version < '3.12' and python_version >= '3.11' # Python 3.11 +pytest>=7.4.4 ; python_version < '3.11' and python_version >= '3.10' # Python 3.10 +pytest>=7.4.4 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9 +pytest>=7.4.4 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8 +pytest>=7.4.4 ; python_version < '3.8' and python_version >= '3.7' # Python 3.7 +pytest>=6.2.5 ; python_version < '3.7' and python_version >= '3.6' # Python 3.6 pytest-cov>=3.0.0 ; python_version >= '3.6.0' # Python 3.6+ -pytest-cov>=2.9.0 ; python_version < '3.6.0' and python_version >= '3.5.0' # Python 3.5 -pytest-cov>=2.8.1 ; python_version < '3.5.0' and python_version >= '3.4.0' # Python 3.4 -pytest-cov>=2.8.1 ; python_version < '2.8.0' and python_version >= '2.7.0' # Python 2.7 -coverage[toml] >= 5.3 -ubelt >= 1.3.4 +coverage[toml]>=7.3.0 ; python_version < '4.0' and python_version >= '3.12' # Python 3.12 +coverage[toml]>=6.5.0 ; python_version < '3.12' and python_version >= '3.10' # Python 3.10-3.11 +coverage[toml]>=6.5.0 ; python_version < '3.10' and python_version >= '3.9' # Python 3.9 +coverage[toml]>=6.5.0 ; python_version < '3.9' and python_version >= '3.8' # Python 3.8 +coverage[toml]>=6.5.0 ; python_version < '3.8' and python_version >= '3.7' # Python 3.7 +coverage[toml]>=6.1.1 ; python_version < '3.7' and python_version >= '3.6' # Python 3.6 -xdoctest >= 1.1.2 +ubelt >= 1.3.4 +xdoctest >= 1.1.3 diff --git a/run_tests.py b/run_tests.py index cdd835aa..627c46fc 100755 --- a/run_tests.py +++ b/run_tests.py @@ -1,8 +1,10 @@ #!/usr/bin/env python -from os.path import dirname, join, abspath +""" +Based on template in rc/run_tests.binpy.py.in +""" +import os import sqlite3 import sys -import os import re @@ -11,18 +13,17 @@ def is_cibuildwheel(): return 'CIBUILDWHEEL' in os.environ -def temp_rename_kernprof(repo_dir): - """ - Hacky workaround so kernprof.py doesn't get covered twice (installed and local). - This needed to combine the .coverage files, since file paths need to be unique. - - """ - original_path = repo_dir + '/kernprof.py' - tmp_path = original_path + '.tmp' - if os.path.isfile(original_path): - os.rename(original_path, tmp_path) - elif os.path.isfile(tmp_path): - os.rename(tmp_path, original_path) +# def temp_rename_kernprof(repo_dir): +# """ +# Hacky workaround so kernprof.py doesn't get covered twice (installed and local). +# This needed to combine the .coverage files, since file paths need to be unique. +# """ +# original_path = repo_dir + '/kernprof.py' +# tmp_path = original_path + '.tmp' +# if os.path.isfile(original_path): +# os.rename(original_path, tmp_path) +# elif os.path.isfile(tmp_path): +# os.rename(tmp_path, original_path) def replace_docker_path(path, runner_project_dir): @@ -76,13 +77,22 @@ def copy_coverage_cibuildwheel_docker(runner_project_dir): os.rename(coverage_path, '/output/.coverage.{}'.format(env_hash)) -if __name__ == '__main__': - cwd = os.getcwd() - repo_dir = abspath(dirname(__file__)) - test_dir = join(repo_dir, 'tests') - print('cwd = {!r}'.format(cwd)) +def main(): + import pathlib + orig_cwd = os.getcwd() + repo_dir = pathlib.Path(__file__).parent.absolute() + test_dir = repo_dir / 'tests' + print('[run_tests] cwd = {!r}'.format(orig_cwd)) + + print('[run_tests] Changing dirs to test_dir={!r}'.format(test_dir)) + os.chdir(test_dir) - import pytest + testdir_contents = list(pathlib.Path(test_dir).glob('*')) + pyproject_fpath = repo_dir / 'pyproject.toml' + + print(f'[run_tests] repo_dir = {repo_dir}') + print(f'[run_tests] pyproject_fpath = {pyproject_fpath}') + print(f'[run_tests] test_dir={test_dir}') # Prefer testing the installed version, but fallback to testing the # development version. @@ -91,43 +101,74 @@ def copy_coverage_cibuildwheel_docker(runner_project_dir): except ImportError: print('running this test script requires ubelt') raise + + print(f'[run_tests] testdir_contents = {ub.urepr(testdir_contents, nl=1)}') + print(f'[run_tests] sys.path = {ub.urepr(sys.path, nl=1)}') + package_name = 'line_profiler' # Statically check if ``package_name`` is installed outside of the repo. # To do this, we make a copy of PYTHONPATH, remove the repodir, and use # ubelt to check to see if ``package_name`` can be resolved to a path. - temp_path = list(map(abspath, sys.path)) - if repo_dir in temp_path: - temp_path.remove(repo_dir) - modpath = ub.modname_to_modpath(package_name, sys_path=temp_path) + temp_path = [pathlib.Path(p).resolve() for p in sys.path] + _resolved_repo_dir = repo_dir.resolve() + print(f'[run_tests] Searching for installed version of {package_name}.') + try: + _idx = temp_path.index(_resolved_repo_dir) + except IndexError: + print('[run_tests] Confirmed repo dir is not in sys.path') + else: + print(f'[run_tests] Removing _resolved_repo_dir={_resolved_repo_dir} from search path') + del temp_path[_idx] + if is_cibuildwheel(): + # Remove from sys.path to prevent the import mechanism from testing + # the source repo rather than the installed wheel. + print(f'[run_tests] Removing _resolved_repo_dir={_resolved_repo_dir} from sys.path to ensure wheels are tested') + del sys.path[_idx] + print(f'[run_tests] sys.path = {ub.urepr(sys.path, nl=1)}') + + _temp_path = [os.fspath(p) for p in temp_path] + print(f'[run_tests] Search Paths: {ub.urepr(_temp_path, nl=1)}') + modpath = ub.modname_to_modpath(package_name, sys_path=_temp_path) if modpath is not None: # If it does, then import it. This should cause the installed version # to be used on further imports even if the repo_dir is in the path. - print(f'Using installed version of {package_name}') - module = ub.import_module_from_path(modpath, index=0) - print('Installed module = {!r}'.format(module)) + print(f'[run_tests] Found installed version of {package_name}') + print(f'[run_tests] modpath={modpath}') + modpath_contents = list(pathlib.Path(modpath).glob('*')) + print(f'[run_tests] modpath_contents = {ub.urepr(modpath_contents, nl=1)}') + # module = ub.import_module_from_path(modpath, index=0) + # print(f'[run_tests] Installed module = {module!r}') else: - print(f'No installed version of {package_name} found') + print(f'[run_tests] No installed version of {package_name} found') try: - print('Changing dirs to test_dir={!r}'.format(test_dir)) - os.chdir(test_dir) - + import pytest pytest_args = [ - '--cov-config', '../pyproject.toml', + '--cov-config', os.fspath(pyproject_fpath), '--cov-report', 'html', '--cov-report', 'term', '--cov-report', 'xml', '--cov=' + package_name, - modpath, '.' + os.fspath(modpath), os.fspath(test_dir) ] if is_cibuildwheel(): pytest_args.append('--cov-append') pytest_args = pytest_args + sys.argv[1:] - sys.exit(pytest.main(pytest_args)) + print(f'[run_tests] Exec pytest with args={pytest_args}') + retcode = pytest.main(pytest_args) + print(f'[run_tests] pytest returned ret={retcode}') + except Exception as ex: + print(f'[run_tests] pytest exception: {ex}') + retcode = 1 finally: - os.chdir(cwd) + os.chdir(orig_cwd) if is_cibuildwheel(): # for CIBW under linux copy_coverage_cibuildwheel_docker(f'/home/runner/work/{package_name}/{package_name}') - print('Restoring cwd = {!r}'.format(cwd)) + print('[run_tests] Restoring cwd = {!r}'.format(orig_cwd)) + return retcode + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tests/test_cli.py b/tests/test_cli.py index 56721bcf..033ee0b0 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -57,8 +57,27 @@ def test_version_agreement(): info1 = ub.cmd(f'{executable} -m line_profiler --version') info2 = ub.cmd(f'{executable} -m kernprof --version') + if info1['ret'] != 0: + print(f'Error querying line-profiler version: {info1}') + + if info2['ret'] != 0: + print(f'Error querying kernprof version: {info2}') + # Strip local version suffixes version1 = info1['out'].strip().split('+')[0] version2 = info2['out'].strip().split('+')[0] - assert version2 == version1, 'kernprof and line_profiler must be in sync' + if version2 != version1: + raise AssertionError( + 'Version Mismatch: kernprof and line_profiler must be in sync. ' + f'kernprof.line_profiler = {version1}. ' + f'kernprof.__version__ = {version2}. ' + ) + + +if __name__ == '__main__': + """ + CommandLine: + python ~/code/line_profiler/tests/test_cli.py + """ + test_version_agreement()