Skip to main content

An extremely fast Python linter, written in Rust.

Project description

ruff

Actions status PyPI version

An extremely fast Python linter, written in Rust.

Bar chart with benchmark results

Linting the CPython codebase from scratch.

  • ⚡️ 10-100x faster than existing linters
  • 🐍 Installable via pip
  • 🤝 Python 3.10 compatibility
  • 🛠️ pyproject.toml support
  • 📦 ESLint-inspired cache support
  • 🔧 ESLint-inspired --fix support
  • 👀 TypeScript-inspired --watch support

ruff is a proof-of-concept and not yet intended for production use. It supports only a small subset of the Flake8 rules, and may crash on your codebase.

Read the launch blog post.

Installation and usage

Installation

Available as ruff on PyPI:

pip install ruff

Usage

To run ruff, try any of the following:

ruff path/to/code/to/check.py
ruff path/to/code/
ruff path/to/code/*.py

You can run ruff in --watch mode to automatically re-run on-change:

ruff path/to/code/ --watch

ruff also works with Pre-Commit (requires Cargo on system):

repos:
- repo: https://github.com/charliermarsh/ruff
  rev: v0.0.28
  hooks:
    - id: lint

Configuration

ruff is configurable both via pyproject.toml and the command line.

For example, you could configure ruff to only enforce a subset of rules with:

[tool.ruff]
line-length = 88
select = [
    "F401",
    "F403",
]

Alternatively, on the command-line:

ruff path/to/code/ --select F401 F403

See ruff --help for more:

ruff (v0.0.28)
An extremely fast Python linter.

USAGE:
    ruff [OPTIONS] <FILES>...

ARGS:
    <FILES>...

OPTIONS:
    -e, --exit-zero             Exit with status code "0", even upon detecting errors
    -f, --fix                   Attempt to automatically fix lint errors
    -h, --help                  Print help information
        --ignore <IGNORE>...    Comma-separated list of error codes to ignore
    -n, --no-cache              Disable cache reads
    -q, --quiet                 Disable all logging (but still exit with status code "1" upon
                                detecting errors)
        --select <SELECT>...    Comma-separated list of error codes to enable
    -v, --verbose               Enable verbose logging
    -w, --watch                 Run in watch mode by re-running whenever files change

Compatibility with Black

ruff is intended to be compatible with Black, and should be compatible out-of-the-box as long as the line-length setting is consistent between the two.

As a project, ruff is designed to be used alongside Black and, as such, will defer implementing lint rules that are obviated by Black (e.g., stylistic rules).

Rules

Code Name Message
E402 ModuleImportNotAtTopOfFile Module level import not at top of file
E501 LineTooLong Line too long
E711 NoneComparison Comparison to None should be cond is None
E712 TrueFalseComparison Comparison to True should be cond is True
E713 NotInTest Test for membership should be not in
E714 NotIsTest Test for object identity should be is not
E731 DoNotAssignLambda Do not assign a lambda expression, use a def
E902 IOError No such file or directory: ...
F401 UnusedImport ... imported but unused
F403 ImportStarUsage Unable to detect undefined names
F541 FStringMissingPlaceholders f-string without any placeholders
F631 AssertTuple Assert test is a non-empty tuple, which is always True
F634 IfTuple If test is a tuple, which is always True
F704 YieldOutsideFunction a yield or yield from statement outside of a function/method
F706 ReturnOutsideFunction a return statement outside of a function/method
F707 DefaultExceptNotLast an except: block as not the last exception handler
F821 UndefinedName Undefined name ...
F822 UndefinedExport Undefined name ... in __all__
F823 UndefinedLocal Local variable ... referenced before assignment
F831 DuplicateArgumentName Duplicate argument name in function definition
F841 UnusedVariable Local variable ... is assigned to but never used
F901 RaiseNotImplemented raise NotImplemented should be raise NotImplementedError
R001 UselessObjectInheritance Class ... inherits from object
R002 NoAssertEquals assertEquals is deprecated, use assertEqual instead

Development

ruff is written in Rust (1.63.0). You'll need to install the Rust toolchain for development.

Assuming you have cargo installed, you can run:

cargo run resources/test/fixtures
cargo fmt
cargo clippy
cargo test

Deployment

ruff is distributed on PyPI, and published via maturin.

See: .github/workflows/release.yaml.

Benchmarking

First, clone CPython. It's a large and diverse Python codebase, which makes it a good target for benchmarking.

git clone --branch 3.10 https://github.com/python/cpython.git resources/test/cpython

Add this pyproject.toml to the CPython directory:

[tool.linter]
line-length = 88
exclude = [
    "Lib/lib2to3/tests/data/bom.py",
    "Lib/lib2to3/tests/data/crlf.py",
    "Lib/lib2to3/tests/data/different_encoding.py",
    "Lib/lib2to3/tests/data/false_encoding.py",
    "Lib/lib2to3/tests/data/py2_test_grammar.py",
    "Lib/test/bad_coding2.py",
    "Lib/test/badsyntax_3131.py",
    "Lib/test/badsyntax_pep3120.py",
    "Lib/test/encoded_modules/module_iso_8859_1.py",
    "Lib/test/encoded_modules/module_koi8_r.py",
    "Lib/test/test_fstring.py",
    "Lib/test/test_grammar.py",
    "Lib/test/test_importlib/test_util.py",
    "Lib/test/test_named_expressions.py",
    "Lib/test/test_patma.py",
    "Lib/test/test_source_encoding.py",
    "Tools/c-analyzer/c_parser/parser/_delim.py",
    "Tools/i18n/pygettext.py",
    "Tools/test2to3/maintest.py",
    "Tools/test2to3/setup.py",
    "Tools/test2to3/test/test_foo.py",
    "Tools/test2to3/test2to3/hello.py",
]

Next, to benchmark the release build:

cargo build --release

hyperfine --ignore-failure --warmup 1 \
  "./target/release/ruff ./resources/test/cpython/ --no-cache" \
  "./target/release/ruff ./resources/test/cpython/"

Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
  Time (mean ± σ):     353.6 ms ±   7.6 ms    [User: 2868.8 ms, System: 171.5 ms]
  Range (min  max):   344.4 ms  367.3 ms    10 runs

Benchmark 2: ./target/release/ruff ./resources/test/cpython/
  Time (mean ± σ):      59.6 ms ±   2.5 ms    [User: 36.4 ms, System: 345.6 ms]
  Range (min  max):    55.9 ms   67.0 ms    48 runs

To benchmark against the ecosystem's existing tools:

hyperfine --ignore-failure --warmup 5 \
  "./target/release/ruff ./resources/test/cpython/ --no-cache" \
  "pylint --recursive=y resources/test/cpython/" \
  "pyflakes resources/test/cpython" \
  "autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython" \
  "pycodestyle resources/test/cpython" \
  "pycodestyle --select E501 resources/test/cpython" \
  "flake8 resources/test/cpython" \
  "flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython" \
  "python -m scripts.run_flake8 resources/test/cpython" \
  "python -m scripts.run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501"

In order, these evaluate:

  • ruff
  • Pylint
  • PyFlakes
  • autoflake
  • pycodestyle
  • pycodestyle, limited to the checks supported by ruff
  • Flake8
  • Flake8, limited to the checks supported by ruff
  • Flake8, with a hack to enable multiprocessing on macOS
  • Flake8, with a hack to enable multiprocessing on macOS, limited to the checks supported by ruff

(You can poetry install from ./scripts to create a working environment for the above.)

Benchmark 1: ./target/release/ruff ./resources/test/cpython/ --no-cache
  Time (mean ± σ):     469.3 ms ±  16.3 ms    [User: 2663.0 ms, System: 972.5 ms]
  Range (min  max):   445.2 ms  494.8 ms    10 runs

Benchmark 2: pylint --recursive=y resources/test/cpython/
  Time (mean ± σ):     27.211 s ±  0.097 s    [User: 26.405 s, System: 0.799 s]
  Range (min  max):   27.056 s  27.349 s    10 runs

Benchmark 3: pyflakes resources/test/cpython
  Time (mean ± σ):     27.309 s ±  0.033 s    [User: 27.137 s, System: 0.169 s]
  Range (min  max):   27.267 s  27.372 s    10 runs

Benchmark 4: autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython
  Time (mean ± σ):      8.027 s ±  0.024 s    [User: 74.255 s, System: 0.953 s]
  Range (min  max):    7.969 s   8.052 s    10 runs

Benchmark 5: pycodestyle resources/test/cpython
  Time (mean ± σ):     41.666 s ±  0.266 s    [User: 41.531 s, System: 0.132 s]
  Range (min  max):   41.295 s  41.980 s    10 runs

Benchmark 6: pycodestyle --select E501 resources/test/cpython
  Time (mean ± σ):     14.547 s ±  0.077 s    [User: 14.466 s, System: 0.079 s]
  Range (min  max):   14.429 s  14.695 s    10 runs

Benchmark 7: flake8 resources/test/cpython
  Time (mean ± σ):     75.700 s ±  0.152 s    [User: 75.254 s, System: 0.440 s]
  Range (min  max):   75.513 s  76.014 s    10 runs

Benchmark 8: flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython
  Time (mean ± σ):     75.122 s ±  0.532 s    [User: 74.677 s, System: 0.440 s]
  Range (min  max):   74.130 s  75.606 s    10 runs

Benchmark 9: python -m scripts.run_flake8 resources/test/cpython
  Time (mean ± σ):     12.794 s ±  0.147 s    [User: 90.792 s, System: 0.738 s]
  Range (min  max):   12.606 s  13.030 s    10 runs

Benchmark 10: python -m scripts.run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501
  Time (mean ± σ):     12.487 s ±  0.118 s    [User: 90.052 s, System: 0.714 s]
  Range (min  max):   12.265 s  12.665 s    10 runs

Summary
  './target/release/ruff ./resources/test/cpython/ --no-cache' ran
   17.10 ± 0.60 times faster than 'autoflake --recursive --expand-star-imports --remove-all-unused-imports --remove-unused-variables --remove-duplicate-keys resources/test/cpython'
   26.60 ± 0.96 times faster than 'python -m scripts.run_flake8 resources/test/cpython --select=F831,F541,F634,F403,F706,F901,E501'
   27.26 ± 1.00 times faster than 'python -m scripts.run_flake8 resources/test/cpython'
   30.99 ± 1.09 times faster than 'pycodestyle --select E501 resources/test/cpython'
   57.98 ± 2.03 times faster than 'pylint --recursive=y resources/test/cpython/'
   58.19 ± 2.02 times faster than 'pyflakes resources/test/cpython'
   88.77 ± 3.14 times faster than 'pycodestyle resources/test/cpython'
  160.06 ± 5.68 times faster than 'flake8 --select=F831,F541,F634,F403,F706,F901,E501 resources/test/cpython'
  161.29 ± 5.61 times faster than 'flake8 resources/test/cpython'

License

MIT

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ruff-0.0.28.tar.gz (88.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ruff-0.0.28-py3-none-win_amd64.whl (2.5 MB view details)

Uploaded Python 3Windows x86-64

ruff-0.0.28-py3-none-win32.whl (2.4 MB view details)

Uploaded Python 3Windows x86

ruff-0.0.28-py3-none-musllinux_1_2_x86_64.whl (2.7 MB view details)

Uploaded Python 3musllinux: musl 1.2+ x86-64

ruff-0.0.28-py3-none-musllinux_1_2_i686.whl (2.6 MB view details)

Uploaded Python 3musllinux: musl 1.2+ i686

ruff-0.0.28-py3-none-musllinux_1_2_armv7l.whl (2.4 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARMv7l

ruff-0.0.28-py3-none-musllinux_1_2_aarch64.whl (2.5 MB view details)

Uploaded Python 3musllinux: musl 1.2+ ARM64

ruff-0.0.28-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl (2.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ s390x

ruff-0.0.28-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (2.0 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64le

ruff-0.0.28-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl (2.1 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ppc64

ruff-0.0.28-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (1.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARMv7l

ruff-0.0.28-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (2.5 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

ruff-0.0.28-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (2.6 MB view details)

Uploaded Python 3manylinux: glibc 2.12+ x86-64

ruff-0.0.28-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl (2.7 MB view details)

Uploaded Python 3manylinux: glibc 2.12+ i686

ruff-0.0.28-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl (5.0 MB view details)

Uploaded Python 3macOS 10.9+ universal2 (ARM64, x86-64)macOS 10.9+ x86-64macOS 11.0+ ARM64

ruff-0.0.28-py3-none-macosx_10_7_x86_64.whl (2.6 MB view details)

Uploaded Python 3macOS 10.7+ x86-64

File details

Details for the file ruff-0.0.28.tar.gz.

File metadata

  • Download URL: ruff-0.0.28.tar.gz
  • Upload date:
  • Size: 88.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.28.tar.gz
Algorithm Hash digest
SHA256 49aa08a2448033be5033b5fc349f4c9da763408e5e3a691f5dbe9d63a2a67401
MD5 13f1a60e04bded92c9c66019390b9724
BLAKE2b-256 002f9ccc6751cb3552eb08140fc8a78db9ea0de21a7bdf8345e506008ed9ea7c

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-win_amd64.whl.

File metadata

  • Download URL: ruff-0.0.28-py3-none-win_amd64.whl
  • Upload date:
  • Size: 2.5 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.28-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 88808a348ec133390584f4a1da4b2d3479dc14dc7a8369e1e0660e7d4347b0df
MD5 b35f1115ab58321a4a22f585d75ff5b0
BLAKE2b-256 273973bc6cba0245dac1474e66e5a24a7a86d6652884a638b944822cc94ff976

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-win32.whl.

File metadata

  • Download URL: ruff-0.0.28-py3-none-win32.whl
  • Upload date:
  • Size: 2.4 MB
  • Tags: Python 3, Windows x86
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.28-py3-none-win32.whl
Algorithm Hash digest
SHA256 093654dc8758721a7fed34ecf3f5482b80eecae46ae5e495b03d1d5027661860
MD5 520712608c6a73df187ae63b232f5f5e
BLAKE2b-256 bb220669f239834c16176e441e87aabee4fb08303619c205ff005d5c062daee6

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 54e7dd2d2c0c4825289539b0b6696d4ec9ee8de61dcb7fb36c85a4ea5b0178b1
MD5 47efeccbad0b622d7e4217bdc171b8e3
BLAKE2b-256 8e3d96d8f9353450ea056ba8e30eba305ae138b2b84c6a19431f74ba2899d902

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-musllinux_1_2_i686.whl.

File metadata

  • Download URL: ruff-0.0.28-py3-none-musllinux_1_2_i686.whl
  • Upload date:
  • Size: 2.6 MB
  • Tags: Python 3, musllinux: musl 1.2+ i686
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.8.10

File hashes

Hashes for ruff-0.0.28-py3-none-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 18ba549eaefe803542ffcacf71ffbebb1aa253ecee69efd63034aa9bc1a98d89
MD5 80d42165eabfe75f077aa059ada0cf6a
BLAKE2b-256 e3570f24abe39be7a09ba9399c72efbb47c883f895f2a2683345d30d65d29c41

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 a84e4bd7e06c240289f9c01b582a0b469037d3c16fcaaa8d2dcc4888d9724abc
MD5 c69aa4b10da3f47bd719c57fe2bfe970
BLAKE2b-256 29d58bfc027f1713347930ddee031c585444be0de25cfa3d715b91d207e6b7d0

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 7d48f932b89b97f0cd4656058d63054fe03d9bb86d77b7054be33ebadefeb61a
MD5 f2776639269d684676b9270018bbffcd
BLAKE2b-256 0da88717cdfe45792011c2e515f834372b48563c61015b4c7b27c73720580b7c

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 e5478c79668f639484dc6c2d2e2826451c930ddf6fa465c98dd241d1b55f2cfc
MD5 659ef5d2bda9aaf9c200e0f6754241f9
BLAKE2b-256 7bad66a16033654db9a28be9b9739a6da7e3d07151ac7613d34af54aa0ce2434

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 f442e183b311788a479ea1c3cabdda584f537844d940dcfecd42adc56f34a580
MD5 fdb4a8532cd1c3ac3cb4703e3c81e3f3
BLAKE2b-256 ce5b35985c1f4cd7983b719d0a5eb5486aa5ef9f5dad77f4ced5ed77a3f3bde0

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl
Algorithm Hash digest
SHA256 c65ea6c92084a0725a7ccb9ee210a5f8c87bc699204b07c931faa8539846ab12
MD5 126bc093dfe7665fc476c4ed8f696ab4
BLAKE2b-256 e8f6bae323e774d1075c2aefebf881e78dff81bfd1f2edb205265f2378c31fd1

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 43e5867dd19457aa2099746036c7575516568f540a2e31129317119e7f270910
MD5 0364633853296a7bc7285fc80cf53188
BLAKE2b-256 42a2f4a79523b6cdee129c074f3ff1a3560b9ab2b3b8a2008c9cef387c011169

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3edd00140a2b0737209e1de3334b99d38db9b2fa08922fd538b588a562efe2aa
MD5 96ecf2a2c3e7045f002930b41f9ee5c1
BLAKE2b-256 561e5089ebd0e1fae30d2ce6f954d90bb3d9fb8d393ea65de3c2acff41ddf543

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 3c2130f9afac92c42d9b15fe52a86ffd407368893e6800cd618ea87d0d481653
MD5 7aca6f42d01a1ee306f321f6bd99460a
BLAKE2b-256 c01d148cd81fe1fd2b76e8dc1b381f87ce9d15c03e12e9dcbbd4e5c4410c6f37

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl
Algorithm Hash digest
SHA256 f3c06ef55d524e7b12eb4ffae532d11b322c0efda62da28e2e74e705c8ca1afc
MD5 4a4d2b5fb94cf6a455612f7248c5f4f1
BLAKE2b-256 30bc86d52f17fd3688bcf2828b8a109d21671a46646bcc2e4b1e699883f61878

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-macosx_10_9_x86_64.macosx_11_0_arm64.macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 cf4ac372538d04a4b533be9a5475a9836a1c85248e399705369cc07338d02aa3
MD5 fef2f7869082461283967244d0494281
BLAKE2b-256 6dd5c620b3bd710f32d008880236dec1086f2019f773063808cc7b737673fc8e

See more details on using hashes here.

File details

Details for the file ruff-0.0.28-py3-none-macosx_10_7_x86_64.whl.

File metadata

File hashes

Hashes for ruff-0.0.28-py3-none-macosx_10_7_x86_64.whl
Algorithm Hash digest
SHA256 ef067a36e50463ee5c1c637e212ff3fc4c87fb6cb404e81226232e59ef772772
MD5 53da5678eb7f0d9d3e97e9775754877a
BLAKE2b-256 d29054cff1fef92902154aea46bd1a813daa5f905c57f562dd936909144ec6f3

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page