Skip to content

Contributing

Thank you for being interested in contributing to Hishel. We appreciate your efforts. You can contribute by reviewing the pull requests, opening an issue, or adding a new feature.

Here I will describe the development process and the tricks that we use during the development.

Setting up

First, you should fork the Hishel so you can create your own branch and work on it.

Then you should git clone your fork and create a new branch for your pull request.

git clone https://github.com/username/hishel
cd hishel
git switch -c my-feature-name

Scripts

Hishel provides a script directory to simplify the development process. Here is what each command does.

  • scripts/install Set up the virtual environment and install all the necessary dependencies
  • scripts/lint Runs linter, formatter, and unasync to enforce code style
  • scripts/check Runs all the necessary checks, including linter, formatter, static type analyzer, and unasync checks
  • scripts/test Runs scripts/check + pytest over the coverage.

Example:

>>> ./scripts/install
>>> source ./venv/bin/activate
>>> ./scripts/test
+ ./scripts/check
+ ruff format tests hishel --diff
26 files left unchanged
+ ruff tests hishel
+ mypy tests hishel
Success: no issues found in 38 source files
+ python unasync.py --check
hishel/_async/_client.py -> hishel/_sync/_client.py
hishel/_async/_pool.py -> hishel/_sync/_pool.py
hishel/_async/_transports.py -> hishel/_sync/_transports.py
hishel/_async/_mock.py -> hishel/_sync/_mock.py
hishel/_async/_storages.py -> hishel/_sync/_storages.py
hishel/_async/__init__.py -> hishel/_sync/__init__.py
tests/_async/test_storages.py -> tests/_sync/test_storages.py
tests/_async/test_transport.py -> tests/_sync/test_transport.py
tests/_async/__init__.py -> tests/_sync/__init__.py
tests/_async/test_client.py -> tests/_sync/test_client.py
tests/_async/test_pool.py -> tests/_sync/test_pool.py
+ coverage run -m pytest tests
============================ test session starts =============================
platform linux -- Python 3.10.12, pytest-7.4.3, pluggy-1.3.0
rootdir: /home/test/programs/gitprojects/hishel
configfile: pyproject.toml
plugins: anyio-4.1.0, asyncio-0.21.1
asyncio: mode=stric`t
collected 158 items                                                          

tests/test_controller.py ..........................................    [ 26%]
tests/test_headers.py .....................                            [ 39%]
tests/test_lfu_cache.py ......                                         [ 43%]
tests/test_serializers.py .....                                        [ 46%]
tests/test_utils.py ........                                           [ 51%]
tests/_async/test_client.py ..                                         [ 53%]
tests/_async/test_pool.py ..................                           [ 64%]
tests/_async/test_storages.py ...........                              [ 71%]
tests/_async/test_transport.py ..................                      [ 82%]
tests/_sync/test_client.py .                                           [ 83%]
tests/_sync/test_pool.py .........                                     [ 89%]
tests/_sync/test_storages.py ........                                  [ 94%]
tests/_sync/test_transport.py .........                                [100%]

============================ 158 passed in 2.97s ============================= 

Note

Some tests may fail if you don't have all the necessary services. For example, you don't have Redis to pass the integration tests, so there is a Docker compose file in the root directory to start those services.

Async and Sync

Like HTTP Core, Hishel also uses the unasync strategy to support both async and sync code.

The idea behind unasync is that you are writing only async code and also using some logic that converts your async code to sync code rather than writing almost the same code twice.

In Hishel, there is a unasync.py script that converts an async directory to a sync one.

Warning

You should not write any code in the hishel/_sync directory. It is always generated by the unasync.py scripts, and after running CI, all your changes to that directory would be lost.

Unasync scripts would automatically be called from scripts/lint, so you should just write an async code and then call scripts/lint.