diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..a1bbad5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,62 @@ +name: Bug Report +description: File a bug report +title: "[Bug]: " +labels: ["bug"] +assignees: + - octocat +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + - type: input + id: contact + attributes: + label: Contact Details + description: How can we get in touch with you if we need more info? + placeholder: ex. email@example.com + validations: + required: false + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what you see! + value: "A bug happened!" + validations: + required: true + + - type: textarea + id: version + attributes: + label: Version + description: What version of our software are you running? + validations: + required: true + + - type: dropdown + id: platform + attributes: + label: What platform are you working on? + multiple: true + options: + - Mac Intel + - Linux + - Windows + - Mac M + - type: textarea + id: logs + attributes: + label: Relevant log output + description: Please copy and paste any relevant log output in trace log mode. This will be automatically formatted into code, so no need for backticks. + render: bash + + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/ylab-hi/ScanNLS/blob/main/CODE_OF_CONDUCT.md) + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..2bc5d5f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "" +labels: "" +assignees: "" +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 32e2534..5a848ff 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,3 +8,8 @@ updates: # Prefix all commit messages with "deps: ", which should be # accepted as a conventional commit and trigger release-please prefix: "deps" + + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: daily diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 0000000..f7f83aa --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,66 @@ +--- +# Labels names are important as they are used by Release Drafter to decide +# regarding where to record them in changelog or if to skip them. +# +# The repository labels will be automatically configured using this file and +# the GitHub Action https://github.com/marketplace/actions/github-labeler. +- name: breaking + description: Breaking Changes + color: bfd4f2 +- name: bug + description: Something isn't working + color: d73a4a +- name: build + description: Build System and Dependencies + color: bfdadc +- name: ci + description: Continuous Integration + color: 4a97d6 +- name: dependencies + description: Pull requests that update a dependency file + color: 0366d6 +- name: documentation + description: Improvements or additions to documentation + color: 0075ca +- name: duplicate + description: This issue or pull request already exists + color: cfd3d7 +- name: enhancement + description: New feature or request + color: a2eeef +- name: github_actions + description: Pull requests that update Github_actions code + color: "000000" +- name: good first issue + description: Good for newcomers + color: 7057ff +- name: help wanted + description: Extra attention is needed + color: 008672 +- name: invalid + description: This doesn't seem right + color: e4e669 +- name: performance + description: Performance + color: "016175" +- name: python + description: Pull requests that update Python code + color: 2b67c6 +- name: question + description: Further information is requested + color: d876e3 +- name: refactoring + description: Refactoring + color: ef67c4 +- name: removal + description: Removals and Deprecations + color: 9ae7ea +- name: style + description: Style + color: c120e5 +- name: testing + description: Testing + color: b1fc6f +- name: wontfix + description: This will not be worked on + color: ffffff diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..9054eec --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,20 @@ +name: Labeler + +on: + push: + branches: + - main + +jobs: + labeler: + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Run Labeler + uses: crazy-max/ghaction-github-labeler@v5.0.0 + with: + skip-delete: true diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml new file mode 100644 index 0000000..6bf2512 --- /dev/null +++ b/.github/workflows/release-python.yml @@ -0,0 +1,76 @@ +name: release-python + +# ref https://github.com/pola-rs/polars/blob/main/.github/workflows/release-python.yml +on: + push: + branches: + - release + pull_request: + branches: + - release + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: PyO3/maturin-action@v1 + with: + manylinux: auto + command: build + args: --release --sdist -o dist --find-interpreter + - name: Upload wheels + uses: actions/upload-artifact@v3 + with: + name: wheels + path: dist + + windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + - uses: PyO3/maturin-action@v1 + with: + command: build + args: --release -o dist --find-interpreter + - name: Upload wheels + uses: actions/upload-artifact@v3 + with: + name: wheels + path: dist + + macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + - uses: PyO3/maturin-action@v1 + with: + command: build + args: --release -o dist --universal2 --find-interpreter + - name: Upload wheels + uses: actions/upload-artifact@v3 + with: + name: wheels + path: dist + + release: + name: Release + runs-on: ubuntu-latest + if: "startsWith(github.ref, 'refs/tags/')" + needs: [macos, windows, linux] + steps: + - uses: actions/download-artifact@v3 + with: + name: wheels + - name: Publish to PyPI + uses: PyO3/maturin-action@v1 + env: + MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + with: + command: upload + args: --skip-existing * diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3995e60..0644462 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,10 +1,31 @@ -name: CI +name: CI-rust on: push: - branches: [master] + branches: + - main + paths: + - src/** + - examples/** + - Cargo.toml + - .github/workflows/test.yml + pull_request: - branches: [master] + branches: + - main + paths: + - src/** + - examples/** + - Cargo.toml + - .github/workflows/test.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +#ref https://github.com/pola-rs/polars/blob/main/.github/workflows/test-rust.yml +env: + RUSTFLAGS: -C debuginfo=0 # Do not produce debug symbols to keep memory usage down jobs: Formatting: @@ -12,6 +33,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v2 + with: + fetch-depth: 1 - name: Install stable toolchain uses: actions-rs/toolchain@v1 @@ -63,7 +86,9 @@ jobs: rust: stable steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 + with: + fetch-depth: 1 - uses: actions-rs/toolchain@v1 with: @@ -86,10 +111,12 @@ jobs: needs: Formatting runs-on: ubuntu-latest env: - MSRV_VERSION: 1.62.0 + MSRV_VERSION: 1.70.0 steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 + with: + fetch-depth: 1 - name: Install MSRV toolchain uses: actions-rs/toolchain@v1 @@ -100,37 +127,8 @@ jobs: - name: check if README matches MSRV defined here run: grep $MSRV_VERSION README.md - - name: pin dependency versions for MSRV - run: | - cargo update -p indexmap --precise 1.8.2 - - name: Run tests uses: actions-rs/cargo@v1 with: command: test args: --all --no-fail-fast - - Coverage: - needs: Formatting - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Install nightly toolchain - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - override: true - - - name: Install and run cargo-tarpaulin - uses: actions-rs/tarpaulin@v0.1 - with: - version: "0.26.0" - args: "--workspace --all-features --run-types Tests,Doctests --out Lcov --timeout 300" - - - name: Upload coverage - uses: coverallsapp/github-action@v1 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: ./lcov.info diff --git a/.gitignore b/.gitignore index 3038700..1dc7204 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,78 @@ bench/random-bench.csv bench/random-cov-bench.csv bench/*.bed data/ + +# idea +.idea/ + +# Python binding ignore +# Byte-compiled / optimized / DLL files +__pycache__/ +.pytest_cache/ +*.py[cod] + +# C extensions +*.so + +# Distribution / packaging +.Python +.venv/ +env/ +bin/ +build/ +develop-eggs/ +dist/ +eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +include/ +man/ +venv/ +*.egg-info/ +.installed.cfg +*.egg + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt +pip-selfcheck.json + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.cache +nosetests.xml +coverage.xml + +# Translations +*.mo + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# Rope +.ropeproject + +# Django stuff: +*.log +*.pot + +.DS_Store + +# Sphinx documentation +docs/_build/ + +# PyCharm +.idea/ + +# VSCode +.vscode/ + +# Pyenv +.python-version diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bd60306..da146d1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: check-yaml stages: [commit] @@ -14,15 +14,22 @@ repos: stages: [commit] - id: detect-private-key stages: [commit] - - - repo: https://github.com/crate-ci/committed - rev: v1.0.18 - hooks: - - id: committed - stages: [commit-msg] + - id: check-added-large-files + args: ["--maxkb=150000"] + - id: end-of-file-fixer + - id: trailing-whitespace - repo: https://github.com/doublify/pre-commit-rust rev: v1.0 hooks: - id: fmt - id: cargo-check + + - repo: https://github.com/charliermarsh/ruff-pre-commit + rev: "v0.1.5" + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix, --unsafe-fixes] + files: ^py-coitrees/ + - id: ruff-format + files: ^py-coitrees/ diff --git a/README.md b/README.md index 11205a0..8126a37 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,3 @@ - # COITrees: Cache Oblivious Interval Trees COITrees implements a data structure for very fast overlap queries of a @@ -24,15 +23,17 @@ variants are implemented to exploit AVX2 instructions on x86-64 cpus type is oppurtunistically defined to one of these types if the right instruction set is detected. Typically it's necessary to compile with the environment variable `RUSTFLAGS="-Ctarget-cpu=native"` set for this to work. The fallback -implemntation (`BasicCOITree`) supports any platform rust compiles to and +implementation (`BasicCOITree`) supports any platform rust compiles to and remains highly efficient. # Trying Out +The Minimum Supported Rust Version (MSRV) is 1.70.0. This is primary a library for use in other programs, but for benchmarking purposes it includes a program for intersecting BED files. To try out, just clone this repo and run: + ```shell cargo run --release --example bed-intersect -- test1.bed test2.bed > intersections.bed ``` @@ -45,51 +46,50 @@ million lines of `B`. ## Intervals in sorted order -| | A vs B | B vs A | A vs A | B' vs B' | -| ----------------------------------- | ---------: | ---------: | -------: | ---------: | -| coitrees AVX | 11.8s | **3.7s** | 0.7 | 5.3s | -| coitrees AVX (`--sorted`) | 6.4s | 4.2s | **0.6s** | **0.5s** | -| coitrees | 11.4s | 5.2s | 0.8s | 8.3s | -| coitrees (`--sorted`) | **5.8s** | 5.4s | **0.6s** | **0.5s** | -| cgranges (`bedcov-cr -c`) | 35.4s | 6.6s | 2.0s | 17.6s | -| AIList | 13.8s | 10.1s | 1.1s | 18.4s | -| CITree | 20.1s | 13.5s | 1.6s | 45.7s | -| NCList | 22.5s | 16.8s | 1.9s | 39.8s | -| AITree | 23.8s | 26.3s | 2.1s | 63.4s | -| `bedtools coverage -counts -sorted` | 257.5s | 295.6s | 71.6s | 2130.9s | -| `bedtools coverage -counts` | 322.4s | 378.5s | 75.0s | 3595.9s | +| | A vs B | B vs A | A vs A | B' vs B' | +| ----------------------------------- | -------: | -------: | -------: | -------: | +| coitrees AVX | 11.8s | **3.7s** | 0.7 | 5.3s | +| coitrees AVX (`--sorted`) | 6.4s | 4.2s | **0.6s** | **0.5s** | +| coitrees | 11.4s | 5.2s | 0.8s | 8.3s | +| coitrees (`--sorted`) | **5.8s** | 5.4s | **0.6s** | **0.5s** | +| cgranges (`bedcov-cr -c`) | 35.4s | 6.6s | 2.0s | 17.6s | +| AIList | 13.8s | 10.1s | 1.1s | 18.4s | +| CITree | 20.1s | 13.5s | 1.6s | 45.7s | +| NCList | 22.5s | 16.8s | 1.9s | 39.8s | +| AITree | 23.8s | 26.3s | 2.1s | 63.4s | +| `bedtools coverage -counts -sorted` | 257.5s | 295.6s | 71.6s | 2130.9s | +| `bedtools coverage -counts` | 322.4s | 378.5s | 75.0s | 3595.9s | ### With coverage -| | A vs B | B vs A | A vs A | B' vs B' | -| ----------------------------------- | ---------: | ---------: | -------: | ---------: | -| coitrees AVX | 18.2s | **4.8s** | 1.1s | 16.0s | -| coitrees | **14.6s** | 5.7s | **1.0s** | **12.0s** | -| cgranges | 38.4s | 8.1s | 2.2s | 31.0s | -| CITree | 23.2s | 25.6s | 2.0s | 160.4s | +| | A vs B | B vs A | A vs A | B' vs B' | +| ------------ | --------: | -------: | -------: | --------: | +| coitrees AVX | 18.2s | **4.8s** | 1.1s | 16.0s | +| coitrees | **14.6s** | 5.7s | **1.0s** | **12.0s** | +| cgranges | 38.4s | 8.1s | 2.2s | 31.0s | +| CITree | 23.2s | 25.6s | 2.0s | 160.4s | ## Intervals in randomized order -| | A vs B | B vs A | A vs A | B' vs B' | -| ----------------------------------- | ---------: | ---------: | -------: | --------: | -| coitrees AVX | **23.9s** | **7.2s** | **1.6s** | **6.1s** | -| coitrees | 24.2s | 8.9s | 1.9s | 9.4s | -| cgranges (`bedcov-cr -c`) | 55.7s | 11.1s | 3.3s | 19.6s | -| AIList | 31.2s | 18.2s | 2.3s | 19.3s | -| CITree | 39.4s | 19.0s | 2.9s | 47.1s | -| NCList | 42.7s | 23.8s | 3.4s | 44.0s | -| AITree | 225.3s | 134.8s | 14.7s | 921.6s | -| `bedtools coverage -counts` | 1160.4s | 849.6s | 104.5s | 9254.6s | +| | A vs B | B vs A | A vs A | B' vs B' | +| --------------------------- | --------: | -------: | -------: | -------: | +| coitrees AVX | **23.9s** | **7.2s** | **1.6s** | **6.1s** | +| coitrees | 24.2s | 8.9s | 1.9s | 9.4s | +| cgranges (`bedcov-cr -c`) | 55.7s | 11.1s | 3.3s | 19.6s | +| AIList | 31.2s | 18.2s | 2.3s | 19.3s | +| CITree | 39.4s | 19.0s | 2.9s | 47.1s | +| NCList | 42.7s | 23.8s | 3.4s | 44.0s | +| AITree | 225.3s | 134.8s | 14.7s | 921.6s | +| `bedtools coverage -counts` | 1160.4s | 849.6s | 104.5s | 9254.6s | ### With coverage -| | A vs B | B vs A | A vs A | B' vs B' | -| ----------------------------------- | ---------: | ---------: | -------: | ---------: | -| coitrees AVX | 34.3s | **8.8s** | **2.2s** | 16.3s | -| coitrees | **29.6s** | 9.7s | 2.3s | **13.1s** | -| cgranges | 57.6s | 12.5s | 3.6s | 32.6s | -| CITree | 50.0s | 32.5s | 3.8s | 170.4s | - +| | A vs B | B vs A | A vs A | B' vs B' | +| ------------ | --------: | -------: | -------: | --------: | +| coitrees AVX | 34.3s | **8.8s** | **2.2s** | 16.3s | +| coitrees | **29.6s** | 9.7s | 2.3s | **13.1s** | +| cgranges | 57.6s | 12.5s | 3.6s | 32.6s | +| CITree | 50.0s | 32.5s | 3.8s | 170.4s | All benchmarks run on a ryzen 5950x. diff --git a/bench/CITree b/bench/CITree index 27171b1..e19ce28 100755 --- a/bench/CITree +++ b/bench/CITree @@ -1,4 +1,3 @@ #!/bin/sh ~/src/cgranges/test/bedcov-itree-nocov $1 $2 - diff --git a/bench/CITree-cov b/bench/CITree-cov index 56587ee..69bd6dd 100755 --- a/bench/CITree-cov +++ b/bench/CITree-cov @@ -1,4 +1,3 @@ #!/bin/sh ~/src/cgranges/test/bedcov-itree $1 $2 - diff --git a/bench/bedtools b/bench/bedtools index 8f525ab..d48b2ca 100755 --- a/bench/bedtools +++ b/bench/bedtools @@ -1,4 +1,3 @@ #!/bin/sh bedtools coverage -counts -a $1 -b $2 - diff --git a/bench/bedtools-sorted b/bench/bedtools-sorted index f8abfc4..d3e31b4 100755 --- a/bench/bedtools-sorted +++ b/bench/bedtools-sorted @@ -1,4 +1,3 @@ #!/bin/sh bedtools coverage -counts -sorted -a $1 -b $2 - diff --git a/bench/cgranges b/bench/cgranges index 3200914..4134f76 100755 --- a/bench/cgranges +++ b/bench/cgranges @@ -1,4 +1,3 @@ #!/bin/sh ~/src/cgranges/test/bedcov-cr -c $1 $2 - diff --git a/bench/cgranges-cov b/bench/cgranges-cov index 36d8a66..d78d2f0 100755 --- a/bench/cgranges-cov +++ b/bench/cgranges-cov @@ -1,4 +1,3 @@ #!/bin/sh ~/src/cgranges/test/bedcov-cr $1 $2 - diff --git a/bench/coitrees b/bench/coitrees index b2a4ee6..d20870c 100755 --- a/bench/coitrees +++ b/bench/coitrees @@ -1,4 +1,3 @@ #!/bin/sh ../target/release/examples/bed-intersect $1 $2 - diff --git a/bench/coitrees-cov b/bench/coitrees-cov index 640661f..36dfd53 100755 --- a/bench/coitrees-cov +++ b/bench/coitrees-cov @@ -1,4 +1,3 @@ #!/bin/sh ../target/release/examples/bed-intersect --coverage $1 $2 - diff --git a/bench/coitrees-sorted b/bench/coitrees-sorted index 01937ab..77e2628 100755 --- a/bench/coitrees-sorted +++ b/bench/coitrees-sorted @@ -1,4 +1,3 @@ #!/bin/sh ../target/release/examples/bed-intersect --sorted $1 $2 - diff --git a/bench/coitrees-tvt b/bench/coitrees-tvt index 24105f4..c736e27 100755 --- a/bench/coitrees-tvt +++ b/bench/coitrees-tvt @@ -1,4 +1,3 @@ #!/bin/sh ../target/release/examples/bed-intersect --tree-vs-tree $1 $2 - diff --git a/py-coitrees/Cargo.toml b/py-coitrees/Cargo.toml new file mode 100644 index 0000000..7a44e5a --- /dev/null +++ b/py-coitrees/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "py-coitrees" +version = "0.3.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +name = "coitrees" +crate-type = ["cdylib"] + +[dependencies] +pyo3 = { version = "0.20.0", features = ["abi3-py38", "extension-module"] } +coitrees = { path = ".." } diff --git a/py-coitrees/LICENSE b/py-coitrees/LICENSE new file mode 100644 index 0000000..4f88f81 --- /dev/null +++ b/py-coitrees/LICENSE @@ -0,0 +1 @@ +../LICENSE diff --git a/py-coitrees/Makefile b/py-coitrees/Makefile new file mode 100644 index 0000000..23deef8 --- /dev/null +++ b/py-coitrees/Makefile @@ -0,0 +1,70 @@ +SHELL := /bin/bash + +ts := $(shell date -u +"%Y-%m-%dT%H:%M:%SZ") + +.PHONY: help +help: ## This help message + @echo -e "$$(grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | sed -e 's/:.*##\s*/:/' -e 's/^\(.\+\):\(.*\)/\\x1b[36m\1\\x1b[m:\2/' | column -c2 -t -s :)" + +.PHONY: build +build: dev-packages ## Builds Rust code and Python modules + maturin build + +.PHONY: build-release +build-release: dev-packages ## Build module in release mode + maturin build --release + +.PHONY: nightly +nightly: ## Set rust compiler to nightly version + rustup override set nightly + +.PHONY: install +install: dev-packages ## Install module into current virtualenv + maturin develop --release + +.PHONY: publish +publish: ## Publish crate on Pypi + poetry run maturin publish + +.PHONY: clean +clean: ## Clean up build artifacts + cargo clean + find . \( -type f -name "*.py[co]" -o -type d -name "__pycache__" \) -delete && echo "Removed pycs and __pycache__" + rm -f data/*log + +.PHONY: dev-packages +dev-packages: ## Install Python development packages for project + poetry install + +.PHONY: cargo-test +cargo-test: ## Run cargo tests only + cargo test + +.PHONY: test +test: cargo-test dev-packages install quicktest ## Install rscannls module and run tests + +.PHONY: quicktest +quicktest: ## Run tests on already installed hyperjson module + poetry run pytest tests + +.PHONY: bench +bench: ## Run benchmarks + poetry run pytest benchmarks + +.PHONY: bench-compare +bench-compare: nightly dev-packages install ## Run benchmarks and compare results with other JSON encoders + poetry run pytest benchmarks --compare + +.PHONY: build-profile +build-profile: ## Builds binary for profiling + cd profiling && poetry run cargo build --release + +# Setup instructions here: +# https://gist.github.com/dlaehnemann/df31787c41bd50c0fe223df07cf6eb89 +.PHONY: profile +profile: OUTPUT_PATH = measurements/flame-$(ts).svg +profile: FLAGS=booleans --iterations 10000 +profile: nightly build-profile ## Run perf-based profiling (only works on Linux!) + perf record --call-graph dwarf,16384 -e cpu-clock -F 997 target/release/profiling $(FLAGS) + time perf script | stackcollapse-perf.pl | c++filt | flamegraph.pl > $(OUTPUT_PATH) + @echo "$(OUTPUT_PATH)" diff --git a/py-coitrees/README.md b/py-coitrees/README.md new file mode 100644 index 0000000..94389ae --- /dev/null +++ b/py-coitrees/README.md @@ -0,0 +1 @@ +../README.md diff --git a/py-coitrees/coitrees/__init__.py b/py-coitrees/coitrees/__init__.py new file mode 100644 index 0000000..b607082 --- /dev/null +++ b/py-coitrees/coitrees/__init__.py @@ -0,0 +1,7 @@ +"""coitrees package.""" +from .coitrees import sum_as_string + + +def sum_as_string_add_2(a, b): + """Add 2 to the result of sum_as_string.""" + return sum_as_string(a, b) + "2" diff --git a/py-coitrees/coitrees/__main___.py b/py-coitrees/coitrees/__main___.py new file mode 100644 index 0000000..e69de29 diff --git a/py-coitrees/coitrees/coitrees.py b/py-coitrees/coitrees/coitrees.py new file mode 100644 index 0000000..ae2a29a --- /dev/null +++ b/py-coitrees/coitrees/coitrees.py @@ -0,0 +1,44 @@ +class Interval: + """Interval class for Coitree.""" + + def __init__(self, low, high): + """Initialize interval.""" + self.low = low + self.high = high + + +class CoitreeNode: + """Coitree node class.""" + + def __init__(self, interval, data): + """Initialize node.""" + self.key = interval + self.data = data + + +class Coitree: + """Coitree class.""" + + def __init__(self): + """Initialize Coitree.""" + raise NotImplementedError + + def insert(self, node): + raise NotImplementedError + + def delete(self, key): + raise NotImplementedError + + def search(self, key): + raise NotImplementedError + + def build(self, node_list): + raise NotImplementedError + + def find_overlap(self, key): + raise NotImplementedError + + def __repr__(self) -> str: + raise NotImplementedError + + __str__ = __repr__ diff --git a/py-coitrees/coitrees/py.typed b/py-coitrees/coitrees/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/py-coitrees/poetry.lock b/py-coitrees/poetry.lock new file mode 100644 index 0000000..1dec902 --- /dev/null +++ b/py-coitrees/poetry.lock @@ -0,0 +1,473 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = "*" +files = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] + +[[package]] +name = "asttokens" +version = "2.4.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +optional = false +python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "executing" +version = "2.0.0" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = "*" +files = [ + {file = "executing-2.0.0-py2.py3-none-any.whl", hash = "sha256:06df6183df67389625f4e763921c6cf978944721abf3e714000200aab95b0657"}, + {file = "executing-2.0.0.tar.gz", hash = "sha256:0ff053696fdeef426cda5bd18eacd94f82c91f49823a2e9090124212ceea9b08"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "ipdb" +version = "0.13.13" +description = "IPython-enabled pdb" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4"}, + {file = "ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726"}, +] + +[package.dependencies] +decorator = {version = "*", markers = "python_version > \"3.6\""} +ipython = {version = ">=7.31.1", markers = "python_version > \"3.6\""} +tomli = {version = "*", markers = "python_version > \"3.6\" and python_version < \"3.11\""} + +[[package]] +name = "ipython" +version = "8.12.3" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipython-8.12.3-py3-none-any.whl", hash = "sha256:b0340d46a933d27c657b211a329d0be23793c36595acf9e6ef4164bc01a1804c"}, + {file = "ipython-8.12.3.tar.gz", hash = "sha256:3910c4b54543c2ad73d06579aa771041b7d5707b033bd488669b4cf544e3b363"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} + +[package.extras] +all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] + +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +optional = false +python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.39" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-sugar" +version = "0.9.7" +description = "pytest-sugar is a plugin for pytest that changes the default look and feel of pytest (e.g. progressbar, show tests that fail instantly)." +optional = false +python-versions = "*" +files = [ + {file = "pytest-sugar-0.9.7.tar.gz", hash = "sha256:f1e74c1abfa55f7241cf7088032b6e378566f16b938f3f08905e2cf4494edd46"}, + {file = "pytest_sugar-0.9.7-py2.py3-none-any.whl", hash = "sha256:8cb5a4e5f8bbcd834622b0235db9e50432f4cbd71fef55b467fe44e43701e062"}, +] + +[package.dependencies] +packaging = ">=21.3" +pytest = ">=6.2.0" +termcolor = ">=2.1.0" + +[package.extras] +dev = ["black", "flake8", "pre-commit"] + +[[package]] +name = "ruff" +version = "0.1.3" +description = "An extremely fast Python linter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.3-py3-none-macosx_10_7_x86_64.whl", hash = "sha256:b46d43d51f7061652eeadb426a9e3caa1e0002470229ab2fc19de8a7b0766901"}, + {file = "ruff-0.1.3-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl", hash = "sha256:b8afeb9abd26b4029c72adc9921b8363374f4e7edb78385ffaa80278313a15f9"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca3cf365bf32e9ba7e6db3f48a4d3e2c446cd19ebee04f05338bc3910114528b"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4874c165f96c14a00590dcc727a04dca0cfd110334c24b039458c06cf78a672e"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eec2dd31eed114e48ea42dbffc443e9b7221976554a504767ceaee3dd38edeb8"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:dc3ec4edb3b73f21b4aa51337e16674c752f1d76a4a543af56d7d04e97769613"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e3de9ed2e39160800281848ff4670e1698037ca039bda7b9274f849258d26ce"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c595193881922cc0556a90f3af99b1c5681f0c552e7a2a189956141d8666fe8"}, + {file = "ruff-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f75e670d529aa2288cd00fc0e9b9287603d95e1536d7a7e0cafe00f75e0dd9d"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:76dd49f6cd945d82d9d4a9a6622c54a994689d8d7b22fa1322983389b4892e20"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:918b454bc4f8874a616f0d725590277c42949431ceb303950e87fef7a7d94cb3"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d8859605e729cd5e53aa38275568dbbdb4fe882d2ea2714c5453b678dca83784"}, + {file = "ruff-0.1.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:0b6c55f5ef8d9dd05b230bb6ab80bc4381ecb60ae56db0330f660ea240cb0d4a"}, + {file = "ruff-0.1.3-py3-none-win32.whl", hash = "sha256:3e7afcbdcfbe3399c34e0f6370c30f6e529193c731b885316c5a09c9e4317eef"}, + {file = "ruff-0.1.3-py3-none-win_amd64.whl", hash = "sha256:7a18df6638cec4a5bd75350639b2bb2a2366e01222825562c7346674bdceb7ea"}, + {file = "ruff-0.1.3-py3-none-win_arm64.whl", hash = "sha256:12fd53696c83a194a2db7f9a46337ce06445fb9aa7d25ea6f293cf75b21aca9f"}, + {file = "ruff-0.1.3.tar.gz", hash = "sha256:3ba6145369a151401d5db79f0a47d50e470384d0d89d0d6f7fab0b589ad07c34"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "termcolor" +version = "2.3.0" +description = "ANSI color formatting for output in terminal" +optional = false +python-versions = ">=3.7" +files = [ + {file = "termcolor-2.3.0-py3-none-any.whl", hash = "sha256:3afb05607b89aed0ffe25202399ee0867ad4d3cb4180d98aaf8eefa6a5f7d475"}, + {file = "termcolor-2.3.0.tar.gz", hash = "sha256:b5b08f68937f138fe92f6c089b99f1e2da0ae56c52b78bf7075fd95420fd9a5a"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "traitlets" +version = "5.12.0" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.12.0-py3-none-any.whl", hash = "sha256:81539f07f7aebcde2e4b5ab76727f53eabf18ad155c6ed7979a681411602fa47"}, + {file = "traitlets-5.12.0.tar.gz", hash = "sha256:833273bf645d8ce31dcb613c56999e2e055b1ffe6d09168a164bcd91c36d5d35"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "typing-extensions" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, +] + +[[package]] +name = "wcwidth" +version = "0.2.8" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.8-py2.py3-none-any.whl", hash = "sha256:77f719e01648ed600dfa5402c347481c0992263b81a027344f3e1ba25493a704"}, + {file = "wcwidth-0.2.8.tar.gz", hash = "sha256:8705c569999ffbb4f6a87c6d1b80f324bd6db952f5eb0b95bc07517f4c1813d4"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.8" +content-hash = "3221317cd8d9477e81c0470dd8c2e965b2a6e42ec12030eb72054650a18a9cd9" diff --git a/py-coitrees/pyproject.toml b/py-coitrees/pyproject.toml new file mode 100644 index 0000000..6919ff3 --- /dev/null +++ b/py-coitrees/pyproject.toml @@ -0,0 +1,228 @@ +[build-system] +requires = ["maturin>=1.2.1,<2"] +build-backend = "maturin" + + +[tool.poetry] +name = "coitrees" +version = "0.3.0" +description = "Blazingly fast interval tree library" +authors = [ + "Yangyang Li ", + "Daniel C. Jones ", +] + +[project] +name = "coitrees" +description = "Blazingly fast interval tree library" +authors = [ + { name = "Yangyang Li", email = "yangyang.li@northwestern.edu" }, + { name = "Daniel C. Jones", email = "djones3@fredhutch.org" }, +] +readme = "README.md" +requires-python = ">=3.8" +license = { file = "LICENSE" } +keywords = ["interval tree", "find overlap", "rust", "blazingly fast"] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Rust", + "Topic :: Scientific/Engineering", +] + + +[tool.poetry.dependencies] +python = "^3.8" + +[tool.poetry.group.dev.dependencies] +pytest-sugar = "^0.9.7" +pytest = "^7.4.3" +ruff = "^0.1.3" +ipdb = "^0.13.13" + + +[project.urls] +homepage = "https://github.com/dcjones/coitrees" +documentation = "https://github.com/dcjones/coitrees" +repository = "https://github.com/dcjones/coitrees" +changelog = "https://github.com/dcjones/coitrees/README.md" + +[tool.ruff] +target-version = "py38" +line-length = 120 +fix = true +fixable = ["ALL"] +select = [ + "ANN", + "D", + "A", + "F", + "E", + "W", + "C90", + "I", + "UP", + "N", + "YTT", + "TID", + "S", + "BLE", + "FBT", + "PLR", + "B", + "B9", + "A", + "C4", + "T10", + "EM", + "ICN", + "T20", + "Q", + "RET", + "SIM", + "ARG", + "DTZ", + "ERA", + "PD", + "PGH", + "PLC", + "PLE", + "PLW", + "RUF", + "PL", + "TD", + "FIX", + "PTH", + "TCH", + "SLOT", + "PT", + "PYI", + "PIE", + "ISC", + "FA", + "EXE", + # "CPY", + "COM", +] +ignore = [ + "E501", + "D203", + "D100", + "D401", + "ANN101", + "ANN102", + "ANN001", + "ANN002", + "ANN003", + "ANN201", + "ANN202", + "ANN204", + "ANN205", + "ANN206", + "PGH003", + "N802", + "N803", + "N806", + "N815", + "EM101", + # formater conflict + 'COM812', + 'COM819', + 'D206', + 'ISC001', + 'Q000', + 'Q001', + 'Q002', + 'Q003', + 'W191', +] +exclude = [ + "tests/*", + "scripts/*", + "docs/conf.py", + + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".mypy_cache", + ".nox", + ".pants.d", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "venv", + +] + + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" +# Like Black, respect magic trailing commas. +# magic-trailing-comma = "respect" +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +[tool.ruff.flake8-bugbear] +extend-immutable-calls = ["typer.Argument", "typer.Option"] + +[tool.ruff.flake8-annotations] +allow-star-arg-any = true + +[tool.ruff.per-file-ignores] + +[tool.ruff.pydocstyle] +convention = 'google' + +[tool.coverage.paths] +source = ["coitrees", "*/site-packages"] +tests = ["tests", "*/tests"] + +[tool.coverage.run] +branch = true +source = ["coitrees"] +omit = ["tests/*"] + +[tool.coverage.report] +show_missing = true +fail_under = 40 +ignore_errors = true + +[tool.mypy] +strict = false +warn_unreachable = true +pretty = true +show_column_numbers = true +show_error_codes = true +show_error_context = true +ignore_missing_imports = true + +[tool.pytest.ini_options] +markers = [ + "smoke: a quick smoke test", + "failing: failing tests", + "imports: importing tests", +] diff --git a/py-coitrees/src/lib.rs b/py-coitrees/src/lib.rs new file mode 100644 index 0000000..8ba564b --- /dev/null +++ b/py-coitrees/src/lib.rs @@ -0,0 +1,15 @@ +use pyo3::prelude::*; + +/// Formats the sum of two numbers as string. +#[pyfunction] +fn sum_as_string(a: usize, b: usize) -> PyResult { + println!("hello world from rust"); + Ok((a + b).to_string()) +} + +/// A Python module implemented in Rust. +#[pymodule] +fn coitrees(_py: Python, m: &PyModule) -> PyResult<()> { + m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; + Ok(()) +} diff --git a/py-coitrees/tests/.gitkeep b/py-coitrees/tests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/py-coitrees/tests/test_coitrees.py b/py-coitrees/tests/test_coitrees.py new file mode 100644 index 0000000..a73e7aa --- /dev/null +++ b/py-coitrees/tests/test_coitrees.py @@ -0,0 +1,6 @@ +from coitrees import sum_as_string_add_2 + +def test_sum_as_string_add_2(): + """Test sum_as_string function.""" + result = sum_as_string_add_2(1, 2) + assert result == "32" diff --git a/src/avx.rs b/src/avx.rs index 2a2ec52..36a66c7 100644 --- a/src/avx.rs +++ b/src/avx.rs @@ -484,7 +484,7 @@ where self.nodes.is_empty() } - // /// Find intervals in the set overlaping the query `[first, last]` and call `visit` on every overlapping node + // /// Find intervals in the set overlapping the query `[first, last]` and call `visit` on every overlapping node fn query(&'a self, first: i32, last: i32, mut visit: F) where F: FnMut(&Interval<&'a T>), @@ -611,8 +611,8 @@ where let node = &self.nodes[self.i]; if self.j < 8 { let ret = Some(Interval { - first: node.first(self.j), - last: node.last(self.j), + first: node.first(self.j) + 1, + last: node.last(self.j) - 1, metadata: &node.metadata[self.j], }); self.count += 1; @@ -651,8 +651,8 @@ where let node = &self.nodes[self.i]; self.count += 1; Some(Interval { - first: node.first(self.j), - last: node.last(self.j), + first: node.first(self.j) + 1, + last: node.last(self.j) - 1, metadata: &node.metadata[self.j], }) } @@ -901,7 +901,7 @@ where return; } - // not overlaping or preceding + // not overlapping or preceding if first < self.prev_first || first > self.prev_last { // no overlap with previous query. have to resort to regular query strategy self.overlapping_intervals.clear(); diff --git a/src/lib.rs b/src/lib.rs index 14d3c59..867254d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,7 +11,7 @@ //! structs which store integer, end-inclusive intervals along with associated //! metadata. The tree can be queried directly for coverage or overlaps, or //! through the intermediary `SortedQuerenty` which keeps track of some state -//! to accelerate overlaping queries. +//! to accelerate overlapping queries. mod interval; pub use interval::*; diff --git a/src/neon.rs b/src/neon.rs index 00a5b30..3c5a072 100644 --- a/src/neon.rs +++ b/src/neon.rs @@ -381,7 +381,7 @@ where self.nodes.is_empty() } - // /// Find intervals in the set overlaping the query `[first, last]` and call `visit` on every overlapping node + // /// Find intervals in the set overlapping the query `[first, last]` and call `visit` on every overlapping node fn query(&'a self, first: i32, last: i32, mut visit: F) where F: FnMut(&Interval<&'a T>), @@ -508,8 +508,8 @@ where let node = &self.nodes[self.i]; if self.j < LANE_SIZE { let ret = Some(Interval { - first: node.first(self.j), - last: node.last(self.j), + first: node.first(self.j) + 1, + last: node.last(self.j) - 1, metadata: &node.metadata[self.j], }); self.count += 1; @@ -548,8 +548,8 @@ where let node = &self.nodes[self.i]; self.count += 1; Some(Interval { - first: node.first(self.j), - last: node.last(self.j), + first: node.first(self.j) + 1, + last: node.last(self.j) - 1, metadata: &node.metadata[self.j], }) } @@ -798,7 +798,7 @@ where return; } - // not overlaping or preceding + // not overlapping or preceding if first < self.prev_first || first > self.prev_last { // no overlap with previous query. have to resort to regular query strategy self.overlapping_intervals.clear(); diff --git a/src/nosimd.rs b/src/nosimd.rs index 4fe1f35..9186a77 100644 --- a/src/nosimd.rs +++ b/src/nosimd.rs @@ -11,7 +11,7 @@ //! structs which store integer, end-inclusive intervals along with associated //! metadata. The tree can be queried directly for coverage or overlaps, or //! through the intermediary `SortedQuerent` which keeps track of some state -//! to accelerate overlaping queries. +//! to accelerate overlapping queries. use super::interval::{GenericInterval, IntWithMax, Interval, IntervalTree, SortedQuerent}; use std::cmp::Ordering; @@ -190,7 +190,7 @@ where self.nodes.is_empty() } - /// Find intervals in the set overlaping the query `[first, last]` and call `visit` on every overlapping node + /// Find intervals in the set overlapping the query `[first, last]` and call `visit` on every overlapping node fn query(&'a self, first: i32, last: i32, mut visit: F) where F: FnMut(&IntervalNode), @@ -547,7 +547,7 @@ where return; } - // not overlaping or preceding + // not overlapping or preceding if first < self.prev_first || first > self.prev_last { // no overlap with previous query. have to resort to regular query strategy self.overlapping_intervals.clear();