├── .coveragerc ├── .editorconfig ├── .gitignore ├── .readthedocs.yaml ├── .travis.yml ├── AUTHORS ├── CONTRIBUTING.md ├── EURUSD60.csv ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.md ├── README.rst ├── config.cfg ├── docs ├── Makefile ├── conf.py ├── index.rst └── make.bat ├── pyproject.toml ├── tapy ├── __init__.py ├── indicators.py └── utils.py ├── test ├── __init__.py ├── conftest.py └── test_tapy.py ├── tox.ini └── uv.lock /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = tapy 3 | 4 | [report] 5 | show_missing = True 6 | fail_under = 50 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.py] 13 | indent_size = 4 14 | # Docstrings and comments should have max_line_length = 80. 15 | max_line_length = 90 16 | 17 | [*.{md,rst}] 18 | trim_trailing_whitespace = false 19 | max_line_length = 80 20 | 21 | [Makefile] 22 | indent_style = tab 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | .idea 106 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # Read the Docs configuration file for Sphinx projects 2 | 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | 6 | # Required 7 | 8 | version: 2 9 | 10 | 11 | # Set the OS, Python version and other tools you might need 12 | 13 | build: 14 | 15 | os: ubuntu-22.04 16 | 17 | tools: 18 | 19 | python: "3.12" 20 | 21 | # You can also specify other tool versions: 22 | 23 | # nodejs: "20" 24 | 25 | # rust: "1.70" 26 | 27 | # golang: "1.20" 28 | 29 | 30 | # Build documentation in the "docs/" directory with Sphinx 31 | 32 | sphinx: 33 | 34 | configuration: docs/conf.py 35 | 36 | # You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs 37 | 38 | # builder: "dirhtml" 39 | 40 | # Fail on all warnings to avoid broken references 41 | 42 | # fail_on_warning: true 43 | 44 | 45 | # Optionally build your docs in additional formats such as PDF and ePub 46 | 47 | # formats: 48 | 49 | # - pdf 50 | 51 | # - epub 52 | 53 | 54 | # Optional but recommended, declare the Python requirements required 55 | 56 | # to build your documentation 57 | 58 | # See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html 59 | 60 | # python: 61 | 62 | # install: 63 | 64 | # - requirements: docs/requirements.txt 65 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | dist: xenial 3 | 4 | python: 5 | - "3.5" 6 | - "3.6" 7 | - "3.7" 8 | - "3.8-dev" 9 | 10 | matrix: 11 | allow_failures: 12 | - python: "3.8-dev" 13 | 14 | before_install: 15 | - travis_retry pip install -U pip wheel setuptools 16 | 17 | install: 18 | - travis_retry pip install -e 19 | 20 | stages: 21 | - lint 22 | - rst 23 | - test 24 | 25 | # Used in the `test` stage. 26 | before_script: 27 | - travis_retry pip install -e ".[dev-test]" 28 | script: 29 | - make test 30 | 31 | jobs: 32 | include: 33 | - stage: lint 34 | name: "Linting" 35 | python: "3.7" 36 | before_script: 37 | - travis_retry pip install -e ".[dev-lint]" 38 | script: 39 | - make lint 40 | 41 | - stage: rst 42 | name: "RST (README.rst + docs) syntax check" 43 | python: "3.7" 44 | before_script: 45 | - travis_retry pip install -e ".[dev-docs]" 46 | script: 47 | - make rst_check 48 | 49 | # The `test` stage using the `python` matrix above is included implicitly. 50 | 51 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Dmitrii Kurlov 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to tapy 2 | 3 | ## Reporting issues 4 | 5 | - Please note that the issue tracker is not for questions. 6 | 7 | - If possible, before submitting an issue report try to verify that the issue 8 | haven't already been fixed and is not a duplicate. 9 | 10 | 11 | ## Submitting patches 12 | 13 | If you contribute code to tapy, you agree to license your code under the MIT. 14 | 15 | The new code should follow [PEP8](https://pep8.org/) coding style (except 16 | the line length limit, which is 90) and adhere to the style of 17 | the surrounding code. 18 | 19 | You must document any functionality using Sphinx-compatible RST, and 20 | implement tests for any functionality in the `test` directory. 21 | 22 | In your Pull Requests there's no need to fill the changelog or AUTHORS, 23 | this is a maintainer's responsibility. 24 | 25 | ### Setup 26 | 27 | 1. Create a virtualenv 28 | 2. Install `tapy` in editable mode along with dev dependencies: 29 | 30 | pip install -e ".[dev]" 31 | 32 | 3. Ensure that tests pass 33 | 34 | make test 35 | 36 | 37 | ### Running tests 38 | 39 | To run the full test suite: 40 | 41 | make test 42 | 43 | Or simply: 44 | 45 | pytest 46 | 47 | Before pushing your code, make sure that linting passes, otherwise Travis 48 | build would fail: 49 | 50 | make lint 51 | 52 | 53 | ### Building docs 54 | 55 | make docs 56 | 57 | Open `docs/_build/html/index.html` with a browser to see the docs. On macOS you 58 | can use the following command for that: 59 | 60 | open docs/_build/html/index.html 61 | 62 | 63 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dmitrii K 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include AUTHORS 2 | include LICENSE 3 | include README.rst 4 | recursive-exclude test * 5 | global-exclude __pycache__ 6 | global-exclude *.py[co] 7 | global-exclude .DS_Store 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | version := $(shell python -c 'from tapy import __version__; print(__version__)') 2 | 3 | .PHONY: format 4 | format: 5 | ruff format tapy 6 | ruff check tapy --select I --fix 7 | 8 | .PHONY: test 9 | test: 10 | pytest --cov=tapy -vv test/ 11 | 12 | .PHONY: clean 13 | clean: 14 | find . -name "*.pyc" -print0 | xargs -0 rm -f 15 | rm -Rf dist 16 | rm -Rf *.egg-info 17 | 18 | .PHONY: docs 19 | docs: 20 | cd docs && make html 21 | 22 | .PHONY: authors 23 | authors: 24 | git log --format='%aN <%aE>' `git describe --abbrev=0 --tags`..@ | sort | uniq >> AUTHORS 25 | cat AUTHORS | sort --ignore-case | uniq >> AUTHORS_ 26 | mv AUTHORS_ AUTHORS 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tapy 2 | Technical Indicators for the Pandas' Dataframes 3 | 4 | Documentation: https://pandastechindicators.readthedocs.io/en/latest/ 5 | 6 | ## Installation 7 | ``` 8 | pip install -U tapy 9 | ``` 10 | 11 | ## Example 12 | ``` 13 | >>> import pandas as pd 14 | >>> from tapy import Indicators 15 | >>> df = pd.read_csv('EURUSD60.csv') 16 | >>> i= Indicators(df) 17 | >>> i.accelerator_oscillator(column_name='AC') 18 | >>> i.sma() 19 | >>> df = i.df 20 | >>> df.tail() 21 | Date Time Open High Low Close Volume AC sma 22 | 3723 2019.09.20 16:00 1.10022 1.10105 1.10010 1.10070 2888 -0.001155 1.101296 23 | 3724 2019.09.20 17:00 1.10068 1.10193 1.10054 1.10184 6116 -0.000820 1.101158 24 | 3725 2019.09.20 18:00 1.10186 1.10194 1.10095 1.10144 3757 -0.000400 1.101056 25 | 3726 2019.09.20 19:00 1.10146 1.10215 1.10121 1.10188 3069 0.000022 1.101216 26 | 3727 2019.09.20 20:00 1.10184 1.10215 1.10147 1.10167 1224 0.000388 1.101506 27 | ``` 28 | 29 | ## Available Indicators 30 | 31 | 1. Accelerator Oscillator (AC) 32 | 2. Accumulation/Distribution (A/D) 33 | 3. Alligator 34 | 4. Average True Range (ATR) 35 | 5. Awesome Oscillator (AO) 36 | 6. Bears Power 37 | 7. Bollinger Bands 38 | 8. Bulls Power 39 | 9. Commodity Channel Index (CCI) 40 | 10. DeMarker (DeM) 41 | 11. Exponential Moving Average (EMA) 42 | 12. Force Index (FRC) 43 | 13. Fractals 44 | 14. Gator Oscillator 45 | 15. Ichimoku Kinko Hyo 46 | 16. Market Facilitation Index (BW MFI) 47 | 17. Momentum 48 | 18. Money Flow Index (MFI) 49 | 19. Moving Average Convergence/Divergence (MACD) 50 | 20. Simple Moving Average (SMA) 51 | 21. Smoothed Moving Average (SMMA) 52 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | tapy 2 | ==== 3 | 4 | Technical Indicators for the Pandas' Dataframes 5 | 6 | Documentation: https://pandastechindicators.readthedocs.io/en/latest/ 7 | 8 | Installation 9 | ------------ 10 | 11 | :: 12 | 13 | pip install -U tapy 14 | 15 | Example 16 | ------- 17 | 18 | :: 19 | 20 | 21 | >>> import pandas as pd 22 | >>> from tapy import Indicators 23 | >>> df = pd.read_csv('EURUSD60.csv') 24 | >>> i= Indicators(df) 25 | >>> i.accelerator_oscillator(column_name='AC') 26 | >>> i.sma() 27 | >>> df = i.df 28 | >>> df.tail() 29 | Date Time Open High Low Close Volume AC sma 30 | 3723 2019.09.20 16:00 1.10022 1.10105 1.10010 1.10070 2888 -0.001155 1.101296 31 | 3724 2019.09.20 17:00 1.10068 1.10193 1.10054 1.10184 6116 -0.000820 1.101158 32 | 3725 2019.09.20 18:00 1.10186 1.10194 1.10095 1.10144 3757 -0.000400 1.101056 33 | 3726 2019.09.20 19:00 1.10146 1.10215 1.10121 1.10188 3069 0.000022 1.101216 34 | 3727 2019.09.20 20:00 1.10184 1.10215 1.10147 1.10167 1224 0.000388 1.101506 35 | 36 | 37 | Available Indicators 38 | -------------------- 39 | 40 | 1. Accelerator Oscillator (AC) 41 | 2. Accumulation/Distribution (A/D) 42 | 3. Alligator 43 | 4. Average True Range (ATR) 44 | 5. Awesome Oscillator (AO) 45 | 6. Bears Power 46 | 7. Bollinger Bands 47 | 8. Bulls Power 48 | 9. Commodity Channel Index (CCI) 49 | 10. DeMarker (DeM) 50 | 11. Exponential Moving Average (EMA) 51 | 12. Force Index (FRC) 52 | 13. Fractals 53 | 14. Gator Oscillator 54 | 15. Ichimoku Kinko Hyo 55 | 16. Market Facilitation Index (BW MFI) 56 | 17. Momentum 57 | 18. Money Flow Index (MFI) 58 | 19. Moving Average Convergence/Divergence (MACD) 59 | 20. Simple Moving Average (SMA) 60 | 21. Smoothed Moving Average (SMMA) 61 | 62 | -------------------------------------------------------------------------------- /config.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 3 | 4 | [flake8] 5 | max-complexity = 24 6 | max-line-length = 90 7 | exclude = 8 | .git, 9 | .tox, 10 | .venv, 11 | __pycache__, 12 | build, 13 | dist, 14 | docs, 15 | geopy.egg-info 16 | 17 | [isort] 18 | ; https://github.com/timothycrosley/isort#multi-line-output-modes 19 | combine_as_imports = True 20 | force_grid_wrap = 0 21 | include_trailing_comma = True 22 | known_first_party = test 23 | line_length = 88 24 | multi_line_output = 3 25 | not_skip = __init__.py 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | sys.path.insert(0, os.path.abspath('../')) 16 | from tapy import __version__ 17 | autodoc_mock_imports = ['pandas'] 18 | 19 | # -- Project information ----------------------------------------------------- 20 | 21 | project = 'tapy' 22 | copyright = '2019, Dmitrii Kurlov' 23 | author = 'Dmitrii Kurlov' 24 | 25 | # -- General configuration --------------------------------------------------- 26 | 27 | # Add any Sphinx extension module names here, as strings. They can be 28 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 29 | # ones. 30 | extensions = [ 31 | 'sphinx.ext.autodoc', 32 | 'sphinx.ext.doctest', 33 | 'sphinx.ext.intersphinx', 34 | ] 35 | 36 | # Add any paths that contain templates here, relative to this directory. 37 | templates_path = ['_templates'] 38 | 39 | source_suffix = '.rst' 40 | master_doc = 'index' 41 | 42 | version = __version__ 43 | release = __version__ 44 | 45 | # List of patterns, relative to source directory, that match files and 46 | # directories to ignore when looking for source files. 47 | # This pattern also affects html_static_path and html_extra_path. 48 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] 49 | 50 | # -- Options for HTML output ------------------------------------------------- 51 | 52 | # The theme to use for HTML and HTML Help pages. See the documentation for 53 | # a list of builtin themes. 54 | # 55 | html_theme = 'sphinx_rtd_theme' 56 | 57 | # Add any paths that contain custom static files (such as style sheets) here, 58 | # relative to this directory. They are copied after the builtin static files, 59 | # so a file named "default.css" will overwrite the builtin "default.css". 60 | html_static_path = ['_static'] 61 | 62 | pygments_style = 'default' 63 | 64 | htmlhelp_basename = 'TaPyDoc' 65 | 66 | latex_documents = [ 67 | ('index', 'TaPy.tex', 'TaPy Documentation', 68 | 'TaPy Contributors', 'manual'), 69 | ] 70 | 71 | intersphinx_mapping = {'http://docs.python.org/': None} 72 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. tapy documentation master file, created by 2 | sphinx-quickstart on Mon Sep 23 02:03:02 2019. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to tapy's documentation! 7 | ================================ 8 | 9 | :Source Code: https://github.com/dmitriiweb/tapy 10 | :Issue Tracker: https://github.com/dmitriiweb/tapy/issues 11 | :PyPi: https://pypi.org/project/tapy/ 12 | 13 | .. automodule:: tapy 14 | :members: __doc__ 15 | 16 | .. toctree:: 17 | :maxdepth: 3 18 | :caption: Contents 19 | 20 | index 21 | 22 | Installation 23 | ============ 24 | :: 25 | 26 | pip install tapy 27 | 28 | Indicators 29 | ========== 30 | .. autoclass:: tapy.Indicators 31 | .. automodule:: __init__ 32 | 33 | .. automodule:: tapy.Indicators.accelerator_oscillator 34 | .. automodule:: tapy.Indicators.accumulation_distribution 35 | .. automodule:: tapy.Indicators.alligator 36 | .. automodule:: tapy.Indicators.atr 37 | .. automodule:: tapy.Indicators.awesome_oscillator 38 | .. automodule:: tapy.Indicators.bears_power 39 | .. automodule:: tapy.Indicators.bollinger_bands 40 | .. automodule:: tapy.Indicators.bulls_power 41 | .. automodule:: tapy.Indicators.cci 42 | .. automodule:: tapy.Indicators.de_marker 43 | .. automodule:: tapy.Indicators.ema 44 | .. automodule:: tapy.Indicators.force_index 45 | .. automodule:: tapy.Indicators.fractals 46 | .. automodule:: tapy.Indicators.gator 47 | .. automodule:: tapy.Indicators.ichimoku_kinko_hyo 48 | .. automodule:: tapy.Indicators.bw_mfi 49 | .. automodule:: tapy.Indicators.momentum 50 | .. automodule:: tapy.Indicators.mfi 51 | .. automodule:: tapy.Indicators.macd 52 | .. automodule:: tapy.Indicators.sma 53 | .. automodule:: tapy.Indicators.smma 54 | .. automodule:: tapy.Indicators.alma -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "tapy" 3 | version = "1.11.0" 4 | description = "Technical Indicators for the Pandas' Dataframes" 5 | authors = [{ name = "Dmitrii K", email = "dmitriik@proton.me" }] 6 | license = { text = "MIT" } 7 | readme = "README.md" 8 | requires-python = ">=3.11,<4" 9 | dependencies = ["pandas>=2.2"] 10 | classifiers = [ 11 | "Development Status :: 5 - Production/Stable", 12 | "Intended Audience :: Developers", 13 | "Intended Audience :: Financial and Insurance Industry", 14 | "License :: OSI Approved :: MIT License", 15 | "Operating System :: OS Independent", 16 | "Programming Language :: Python", 17 | "Topic :: Software Development :: Libraries :: Python Modules", 18 | "Programming Language :: Python :: 3", 19 | "Programming Language :: Python :: 3.11", 20 | "Programming Language :: Python :: 3.12", 21 | "Programming Language :: Python :: 3.13", 22 | "Programming Language :: Python :: Implementation :: CPython", 23 | ] 24 | 25 | [dependency-groups] 26 | dev = ["pytest>=8.2.2", "pytest-cov>=5.0.0", "tox>=4.16.0"] 27 | dev-docs = ["readme-renderer>=43.0", "sphinx>=7.3.7", "sphinx-rtd-theme>=2.0.0"] 28 | dev-linters = ["ruff>=0.4.9"] 29 | 30 | [project.scripts] 31 | smart-weather = "smart_weather.cli:main" 32 | 33 | [project.urls] 34 | Homepage = "https://github.com/dmitriiweb/tapy" 35 | 36 | [build-system] 37 | requires = ["hatchling"] 38 | build-backend = "hatchling.build" 39 | -------------------------------------------------------------------------------- /tapy/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | tapy is a Python3 library which provides 3 | various technical indicators for the Pandas' data frames 4 | """ 5 | 6 | from tapy.indicators import Indicators, __version__ 7 | -------------------------------------------------------------------------------- /tapy/indicators.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | import numpy as np 4 | 5 | from .utils import ( 6 | calculate_alma, 7 | calculate_ao, 8 | calculate_sma, 9 | calculate_smma, 10 | mad, 11 | ) 12 | 13 | __version__ = "1.11.0" 14 | 15 | 16 | class Indicators: 17 | """Add technical indicators data to a pandas data frame. 18 | 19 | Example: 20 | ~~~~~~~~ 21 | >>> import pandas as pd 22 | >>> from tapy import Indicators 23 | >>> df = pd.read_csv('EURUSD60.csv') 24 | >>> i= Indicators(df) 25 | >>> i.accelerator_oscillator(column_name='AC') 26 | >>> i.sma() 27 | >>> df = i.df 28 | >>> df.tail() 29 | Date Time Open High Low Close Volume AC sma 30 | 3723 2019.09.20 16:00 1.10022 1.10105 1.10010 1.10070 2888 -0.001155 1.101296 31 | 3724 2019.09.20 17:00 1.10068 1.10193 1.10054 1.10184 6116 -0.000820 1.101158 32 | 3725 2019.09.20 18:00 1.10186 1.10194 1.10095 1.10144 3757 -0.000400 1.101056 33 | 3726 2019.09.20 19:00 1.10146 1.10215 1.10121 1.10188 3069 0.000022 1.101216 34 | 3727 2019.09.20 20:00 1.10184 1.10215 1.10147 1.10167 1224 0.000388 1.101506 35 | """ 36 | 37 | def __init__( 38 | self, 39 | df, 40 | open_col="Open", 41 | high_col="High", 42 | low_col="Low", 43 | close_col="Close", 44 | volume_col="Volume", 45 | ): 46 | """Initiate Indicators object. 47 | 48 | :param pandas data frame df: Should contain OHLC columns and 49 | Volume column 50 | :param str open_col: Name of Open column in df 51 | :param str high_col: Name of High column in df 52 | :param str low_col: Name of Low column in df 53 | :param str close_col: Name of Close column in df 54 | :param str volume_col: Name of Volume column in df. This column 55 | is optional and require only if indicator use this data. 56 | """ 57 | self.df = df 58 | self._columns = { 59 | "Open": open_col, 60 | "High": high_col, 61 | "Low": low_col, 62 | "Close": close_col, 63 | "Volume": volume_col, 64 | } 65 | 66 | def sma(self, period=5, column_name="sma", apply_to="Close"): 67 | """ 68 | Simple Moving Average (SMA) 69 | --------------------- 70 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/moving_average#simple_moving_average 71 | 72 | >>> Indicators.sma(period=5, column_name='sma', apply_to='Close') 73 | 74 | :param int period: the number of calculation periods, default: 5 75 | :param str column_name: Column name, default: sma 76 | :param str apply_to: Which column use for calculation. 77 | Can be *"Open"*, *"High"*, *"Low"* and *"Close"*. 78 | **Default**: Close 79 | :return: None 80 | 81 | """ 82 | calculate_sma(self.df, period, column_name, apply_to) 83 | 84 | def smma(self, period=5, column_name="smma", apply_to="Close"): 85 | """ 86 | Smoothed Moving Average (SMMA) 87 | --------------------- 88 | https://www.metatrader4.com/ru/trading-platform/help/analytics/tech_indicators/moving_average#smoothed_moving_average 89 | 90 | >>> Indicators.smma(period=5, column_name='smma', apply_to='Close') 91 | 92 | :param int period: the number of calculation periods, default: 5 93 | :param str column_name: Column name, default: smma 94 | :param str apply_to: Which column use for calculation. 95 | Can be *"Open"*, *"High"*, *"Low"* and *"Close"*. 96 | **Default**: Close 97 | :return: None 98 | 99 | """ 100 | df_smma = calculate_smma(self.df, period, column_name, apply_to) 101 | self.df = self.df.merge(df_smma, left_index=True, right_index=True) 102 | 103 | def ema(self, period=5, column_name="ema", apply_to="Close"): 104 | """ 105 | Exponential Moving Average (EMA) 106 | --------------------- 107 | 108 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/moving_average#exponential_moving_average 109 | 110 | >>> Indicators.ema(period=5, column_name='ema', apply_to='Close') 111 | 112 | :param int period: the number of calculation periods, default: 5 113 | :param str column_name: Column name, default: ema 114 | :param str apply_to: Which column use for calculation. 115 | Can be *"Open"*, *"High"*, *"Low"* and *"Close"*. 116 | **Default**: Close 117 | :return: None 118 | 119 | """ 120 | self.df[column_name] = ( 121 | self.df[self._columns[apply_to]].ewm(span=period, adjust=False).mean() 122 | ) 123 | 124 | def alma( 125 | self, 126 | period=5, 127 | offset=0.85, 128 | sigma=6, 129 | apply_to="Close", 130 | column_name="alma", 131 | ): 132 | """ 133 | Arnaud Legoux Moving Average (ALMA) 134 | ---------------------------- 135 | 136 | https://realtrading.com/trading-blog/arnaud-legoux-moving-average/ 137 | 138 | >>> Indicators.alma(period=5, offset=0.85, sigma=6, apply_to='Close') 139 | 140 | :param int period: No of calculation period. Defaults to 5. 141 | :offset (float, optional): N. Defaults to 0.85. 142 | :sigma (int, optional): No.of standard deviation. Defaults to 6. 143 | :apply_to (str, optional): Which column use for calculation. 144 | Can be *"Open"*, *"High"*, *"Low"* and *"Close"*.. Defaults to "Close". 145 | :column_name (str, optional): Column name in datafram. Defaults to "alma". 146 | """ 147 | self.df = calculate_alma(self.df, period, offset, sigma, apply_to, column_name) 148 | 149 | def awesome_oscillator(self, column_name="ao"): 150 | """ 151 | Awesome Oscillator (AO) 152 | ----------------------- 153 | 154 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/awesome_oscillator 155 | 156 | >>> Indicators.awesome_oscillator(column_name='ao') 157 | 158 | :param str column_name: Column name, default: ao 159 | :return: None 160 | """ 161 | # Data frame for storing temporary data 162 | 163 | df_tmp = pd.DataFrame() 164 | df_tmp["High"] = self.df[self._columns["High"]] 165 | df_tmp["Low"] = self.df[self._columns["Low"]] 166 | 167 | # Calculate Awesome Oscillator 168 | 169 | calculate_ao(df_tmp, column_name) 170 | df_tmp = df_tmp[[column_name]] 171 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 172 | 173 | def accelerator_oscillator(self, column_name="ac"): 174 | """ 175 | Accelerator Oscillator (AC) 176 | ----------------------- 177 | 178 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/accelerator_decelerator 179 | 180 | >>> Indicators.accelerator_oscillator(column_name='ac') 181 | 182 | :param str column_name: Column name, default: ac 183 | :return: None 184 | """ 185 | pass 186 | # Data frame for storing temporary data 187 | 188 | df_tmp = pd.DataFrame() 189 | df_tmp["High"] = self.df[self._columns["High"]] 190 | df_tmp["Low"] = self.df[self._columns["Low"]] 191 | 192 | # Calculate Awesome Oscillator 193 | 194 | calculate_ao(df_tmp, "ao") 195 | 196 | # Calculate SMA for Awesome Oscillator 197 | 198 | calculate_sma(df_tmp, 5, "sma_ao", "ao") 199 | 200 | # Calculate Accelerator Oscillator 201 | 202 | df_tmp[column_name] = df_tmp["ao"] - df_tmp["sma_ao"] 203 | df_tmp = df_tmp[[column_name]] 204 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 205 | 206 | def accumulation_distribution(self, column_name="a/d"): 207 | """ 208 | Accumulation/Distribution (A/D) 209 | --------------------- 210 | 211 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/accumulation_distribution 212 | 213 | >>> Indicators.accumulation_distribution(column_name='a/d') 214 | 215 | :param str column_name: Column name, default: a/d 216 | :return: None 217 | 218 | """ 219 | # Temporary df 220 | 221 | df_tmp = pd.DataFrame() 222 | df_tmp["close"] = self.df[self._columns["Close"]] 223 | df_tmp["high"] = self.df[self._columns["High"]] 224 | df_tmp["low"] = self.df[self._columns["Low"]] 225 | df_tmp["volume"] = self.df[self._columns["Volume"]] 226 | 227 | df_tmp["calc"] = ( 228 | ((df_tmp["close"] - df_tmp["low"]) - (df_tmp["high"] - df_tmp["close"])) 229 | * df_tmp["volume"] 230 | / (df_tmp["high"] - df_tmp["low"]) 231 | ) 232 | 233 | df_tmp[column_name] = df_tmp["calc"].explode().sum() 234 | df_tmp = df_tmp[[column_name]] 235 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 236 | 237 | def alligator( 238 | self, 239 | period_jaws=13, 240 | period_teeth=8, 241 | period_lips=5, 242 | shift_jaws=8, 243 | shift_teeth=5, 244 | shift_lips=3, 245 | column_name_jaws="alligator_jaws", 246 | column_name_teeth="alligator_teeth", 247 | column_name_lips="alligator_lips", 248 | ): 249 | """ 250 | Alligator 251 | ------------------ 252 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/alligator 253 | 254 | >>> Indicators.alligator(period_jaws=13, period_teeth=8, period_lips=5, shift_jaws=8, shift_teeth=5, shift_lips=3, column_name_jaws='alligator_jaw', column_name_teeth='alligator_teeth', column_name_lips='alligator_lips') 255 | 256 | :param int period_jaws: Period for Alligator' Jaws, default: 13 257 | :param int period_teeth: Period for Alligator' Teeth, default: 8 258 | :param int period_lips: Period for Alligator' Lips, default: 5 259 | :param int shift_jaws: Period for Alligator' Jaws, default: 8 260 | :param int shift_teeth: Period for Alligator' Teeth, default: 5 261 | :param int shift_lips: Period for Alligator' Lips, default: 3 262 | :param str column_name_jaws: Column Name for Alligator' Jaws, default: alligator_jaws 263 | :param str column_name_teeth: Column Name for Alligator' Teeth, default: alligator_teeth 264 | :param str column_name_lips: Column Name for Alligator' Lips, default: alligator_lips 265 | :return: None 266 | """ 267 | df_median = self.df[[self._columns["High"], self._columns["Low"]]] 268 | median_col = "median_col" 269 | df_median = df_median.assign( 270 | median_col=lambda x: (x[self._columns["High"]] + x[self._columns["Low"]]) 271 | / 2 272 | ) 273 | df_j = calculate_smma(df_median, period_jaws, column_name_jaws, median_col) 274 | df_t = calculate_smma(df_median, period_teeth, column_name_teeth, median_col) 275 | df_l = calculate_smma(df_median, period_lips, column_name_lips, median_col) 276 | 277 | # Shift SMMAs 278 | 279 | df_j[column_name_jaws] = df_j[column_name_jaws].shift(shift_jaws) 280 | df_t[column_name_teeth] = df_t[column_name_teeth].shift(shift_teeth) 281 | df_l[column_name_lips] = df_l[column_name_lips].shift(shift_lips) 282 | 283 | self.df = self.df.merge(df_j, left_index=True, right_index=True) 284 | self.df = self.df.merge(df_t, left_index=True, right_index=True) 285 | self.df = self.df.merge(df_l, left_index=True, right_index=True) 286 | 287 | def atr(self, period=14, column_name="atr"): 288 | """ 289 | Average True Range (ATR) 290 | ------------------------ 291 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/average_true_range 292 | 293 | >>> Indicators.atr(period=14, column_name='atr') 294 | 295 | :param int period: Period, default: 14 296 | :param str column_name: Column name, default: atr 297 | :return: None 298 | """ 299 | df_tmp = self.df[ 300 | [ 301 | self._columns["High"], 302 | self._columns["Low"], 303 | self._columns["Close"], 304 | ] 305 | ] 306 | df_tmp = df_tmp.assign( 307 | max_min=df_tmp[self._columns["High"]] - df_tmp[self._columns["Low"]] 308 | ) 309 | df_tmp["prev_close-high"] = ( 310 | df_tmp[self._columns["Close"]].shift(1) - df_tmp[self._columns["High"]] 311 | ) 312 | df_tmp["prev_close-min"] = ( 313 | df_tmp[self._columns["Close"]].shift(1) - df_tmp[self._columns["Low"]] 314 | ) 315 | df_tmp["max_val"] = df_tmp.apply( 316 | lambda x: max([x["max_min"], x["prev_close-high"], x["prev_close-min"]]), 317 | axis=1, 318 | ) 319 | calculate_sma(df_tmp, period, column_name, "max_val") 320 | df_tmp = df_tmp[[column_name]] 321 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 322 | 323 | def bears_power(self, period=13, column_name="bears_power"): 324 | """ 325 | Bears Power 326 | ------------------------ 327 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/bears_power 328 | 329 | >>> Indicators.bears_power(period=13, column_name='bears_power') 330 | 331 | :param int period: Period, default: 13 332 | :param str column_name: Column name, default: bears_power 333 | :return: None 334 | """ 335 | df_tmp = self.df[[self._columns["Close"], self._columns["Low"]]] 336 | df_tmp = df_tmp.assign( 337 | ema=df_tmp[self._columns["Close"]].ewm(span=period, adjust=False).mean() 338 | ) 339 | df_tmp[column_name] = df_tmp["ema"] - df_tmp[self._columns["Low"]] 340 | df_tmp = df_tmp[[column_name]] 341 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 342 | 343 | def bollinger_bands( 344 | self, 345 | period=20, 346 | deviation=2, 347 | column_name_top="bollinger_top", 348 | column_name_mid="bollinger_mid", 349 | column_name_bottom="bollinger_bottom", 350 | ): 351 | """ 352 | Bollinger Bands 353 | --------------- 354 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/bollinger_bands 355 | 356 | >>> Indicators.bollinger_bands(self, period=20, deviation=2, column_name_top='bollinger_up', column_name_mid='bollinger_mid', column_name_bottom='bollinger_bottom') 357 | 358 | :param int period: Period, default 20 359 | :param int deviation: Number of Standard Deviations, default 2 360 | :param str column_name_top: default bollinger_up 361 | :param str column_name_mid: default bollinger_mid 362 | :param str column_name_bottom: default bollinger_down 363 | :return: None 364 | """ 365 | df_tmp = self.df[[self._columns["Close"]]] 366 | df_tmp = df_tmp.assign( 367 | mid=df_tmp[self._columns["Close"]].rolling(window=period).mean() 368 | ) 369 | df_tmp = df_tmp.assign( 370 | stdev=df_tmp[self._columns["Close"]].rolling(window=period).std(ddof=0) 371 | ) 372 | df_tmp = df_tmp.assign(tl=df_tmp.mid + deviation * df_tmp.stdev) 373 | df_tmp = df_tmp.assign(bl=df_tmp.mid - deviation * df_tmp.stdev) 374 | 375 | df_tmp = df_tmp[["mid", "tl", "bl"]] 376 | df_tmp = df_tmp.rename( 377 | columns={ 378 | "mid": column_name_mid, 379 | "tl": column_name_top, 380 | "bl": column_name_bottom, 381 | } 382 | ) 383 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 384 | 385 | def bulls_power(self, period=13, column_name="bulls_power"): 386 | """ 387 | Bulls Power 388 | ------------------------ 389 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/bulls_power 390 | 391 | >>> Indicators.bulls_power(period=13, column_name='bulls_power') 392 | 393 | :param int period: Period, default: 13 394 | :param str column_name: Column name, default: bulls_power 395 | :return: None 396 | """ 397 | df_tmp = self.df[[self._columns["Close"], self._columns["High"]]] 398 | df_tmp = df_tmp.assign( 399 | ema=df_tmp[self._columns["Close"]].ewm(span=period, adjust=False).mean() 400 | ) 401 | df_tmp[column_name] = df_tmp[self._columns["High"]] - df_tmp["ema"] 402 | df_tmp = df_tmp[[column_name]] 403 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 404 | 405 | def cci(self, period=14, column_name="cci"): 406 | """ 407 | Commodity Channel Index (CCI) 408 | ----------------------------- 409 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/commodity_channel_index 410 | 411 | >>> Indicators.cci(period=14, column_name='cci') 412 | 413 | :param int period: Period, default: 14 414 | :param str column_name: Column name, default: cci 415 | :return: None 416 | """ 417 | pd.set_option("display.max_columns", 500) 418 | df_tmp = self.df[ 419 | [ 420 | self._columns["High"], 421 | self._columns["Low"], 422 | self._columns["Close"], 423 | ] 424 | ] 425 | df_tmp = df_tmp.assign( 426 | tp=( 427 | df_tmp[self._columns["High"]] 428 | + df_tmp[self._columns["Low"]] 429 | + df_tmp[self._columns["Close"]] 430 | ) 431 | / 3 432 | ) 433 | 434 | df_tmp = df_tmp.assign(tp_sma=df_tmp.tp.rolling(window=period).mean()) 435 | df_tmp = df_tmp.assign( 436 | tp_mad=df_tmp.tp.rolling(window=period).apply(mad, raw=False) 437 | ) 438 | df_tmp = df_tmp.assign(tp_min_sma=df_tmp.tp - df_tmp.tp_sma) 439 | df_tmp = df_tmp.assign(cci=(1 / 0.015) * (df_tmp.tp_min_sma / df_tmp.tp_mad)) 440 | df_tmp = df_tmp[["cci"]] 441 | df_tmp = df_tmp.rename(columns={"cci": column_name}) 442 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 443 | 444 | def de_marker(self, period=14, column_name="dem"): 445 | """ 446 | DeMarker (DeM) 447 | -------------- 448 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/demarker 449 | 450 | >>> Indicators.de_marker(period=14, column_name='dem') 451 | 452 | :param int period: Period, default: 14 453 | :param str column_name: Column name, default: dem 454 | :return: None 455 | """ 456 | df_tmp = self.df[[self._columns["High"], self._columns["Low"]]] 457 | 458 | df_tmp = df_tmp.assign( 459 | hdif=( 460 | df_tmp[self._columns["High"]] > df_tmp[self._columns["High"]].shift(1) 461 | ).astype(int) 462 | ) 463 | df_tmp = df_tmp.assign( 464 | hsub=df_tmp[self._columns["High"]] - df_tmp[self._columns["High"]].shift(1) 465 | ) 466 | df_tmp = df_tmp.assign(demax=np.where(df_tmp.hdif == 0, 0, df_tmp.hsub)) 467 | 468 | df_tmp = df_tmp.assign( 469 | ldif=( 470 | df_tmp[self._columns["Low"]] < df_tmp[self._columns["Low"]].shift(1) 471 | ).astype(int) 472 | ) 473 | df_tmp = df_tmp.assign( 474 | lsub=df_tmp[self._columns["Low"]].shift(1) - df_tmp[self._columns["Low"]] 475 | ) 476 | df_tmp = df_tmp.assign(demin=np.where(df_tmp.ldif == 0, 0, df_tmp.lsub)) 477 | 478 | df_tmp["sma_demax"] = df_tmp["demax"].rolling(window=period).mean() 479 | df_tmp["sma_demin"] = df_tmp["demin"].rolling(window=period).mean() 480 | 481 | df_tmp = df_tmp.assign( 482 | dem=df_tmp.sma_demax / (df_tmp.sma_demax + df_tmp.sma_demin) 483 | ) 484 | 485 | df_tmp = df_tmp[["dem"]] 486 | df_tmp = df_tmp.rename(columns={"dem": column_name}) 487 | 488 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 489 | 490 | def force_index(self, period=13, method="sma", apply_to="Close", column_name="frc"): 491 | """ 492 | Force Index (FRC) 493 | ------------------ 494 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/force_index 495 | 496 | >>> Indicators.force_index(period=13, method='sma', apply_to='Close', column_name='frc') 497 | 498 | :param int period: Period, default: 13 499 | :param str method: Moving average method. Can be 'sma', 'smma' or 'ema'. Default: sma 500 | :param str apply_to: Apply indicator to column, default: Close 501 | :param str column_name: Column name, default: frc 502 | :return: None 503 | """ 504 | df_tmp = self.df[[apply_to, self._columns["Volume"]]] 505 | if method == "sma": 506 | df_tmp = df_tmp.assign(ma=df_tmp[apply_to].rolling(window=period).mean()) 507 | elif method == "smma": 508 | df_tmp_smma = calculate_smma(df_tmp, period, "ma", apply_to) 509 | df_tmp = df_tmp.merge(df_tmp_smma, left_index=True, right_index=True) 510 | elif method == "ema": 511 | df_tmp = df_tmp.assign( 512 | ma=df_tmp[apply_to].ewm(span=period, adjust=False).mean() 513 | ) 514 | else: 515 | raise ValueError('The "method" can be only "sma", "ema" or "smma"') 516 | df_tmp = df_tmp.assign( 517 | frc=(df_tmp.ma - df_tmp.ma.shift(1)) * df_tmp[self._columns["Volume"]] 518 | ) 519 | df_tmp = df_tmp[["frc"]] 520 | df_tmp = df_tmp.rename(columns={"frc": column_name}) 521 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 522 | 523 | def fractals( 524 | self, column_name_high="fractals_high", column_name_low="fractals_low" 525 | ): 526 | """ 527 | Fractals 528 | --------- 529 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/fractals 530 | 531 | >>> Indicators.fractals(column_name_high='fractals_high', column_name_low='fractals_low') 532 | 533 | :param str column_name_high: Column name for High values, default: fractals_high 534 | :param str column_name_low: Column name for Low values, default: fractals_low 535 | :return: None 536 | """ 537 | df_tmp = self.df[[self._columns["High"], self._columns["Low"]]] 538 | df_tmp = df_tmp.assign( 539 | fh=np.where( 540 | (df_tmp[self._columns["High"]] > df_tmp[self._columns["High"]].shift(1)) 541 | & ( 542 | df_tmp[self._columns["High"]] 543 | > df_tmp[self._columns["High"]].shift(2) 544 | ) 545 | & ( 546 | df_tmp[self._columns["High"]] 547 | > df_tmp[self._columns["High"]].shift(-1) 548 | ) 549 | & ( 550 | df_tmp[self._columns["High"]] 551 | > df_tmp[self._columns["High"]].shift(-2) 552 | ), 553 | True, 554 | False, 555 | ) 556 | ) 557 | df_tmp = df_tmp.assign( 558 | fl=np.where( 559 | (df_tmp[self._columns["Low"]] < df_tmp[self._columns["Low"]].shift(1)) 560 | & (df_tmp[self._columns["Low"]] < df_tmp[self._columns["Low"]].shift(2)) 561 | & ( 562 | df_tmp[self._columns["Low"]] 563 | < df_tmp[self._columns["Low"]].shift(-1) 564 | ) 565 | & ( 566 | df_tmp[self._columns["Low"]] 567 | < df_tmp[self._columns["Low"]].shift(-2) 568 | ), 569 | True, 570 | False, 571 | ) 572 | ) 573 | df_tmp = df_tmp[["fh", "fl"]] 574 | df_tmp = df_tmp.rename(columns={"fh": column_name_high, "fl": column_name_low}) 575 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 576 | 577 | def gator( 578 | self, 579 | period_jaws=13, 580 | period_teeth=8, 581 | period_lips=5, 582 | shift_jaws=8, 583 | shift_teeth=5, 584 | shift_lips=3, 585 | column_name_val1="value1", 586 | column_name_val2="value2", 587 | ): 588 | """ 589 | Gator Oscillator 590 | ----------------- 591 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/gator_oscillator 592 | 593 | >>> Indicators.gator(period_jaws=13, period_teeth=8, period_lips=5, shift_jaws=8, shift_teeth=5, shift_lips=3, column_name_val1='value1', column_name_val2='value2') 594 | 595 | :param int period_jaws: Jaws period, default: 13 596 | :param int period_teeth: Teeth period, default: 8 597 | :param int period_lips: Lips period, default: 5 598 | :param int shift_jaws: Jaws shift, default: 8 599 | :param int shift_teeth: Teeth shift, default: 5 600 | :param int shift_lips: Lips shift, default: 3 601 | :param str column_name_val1: Column name for Value1, default value1 602 | :param str column_name_val2: Column name for Value2, default value2 603 | :return: None 604 | """ 605 | df_tmp = self.df[[self._columns["High"], self._columns["Low"]]] 606 | df_tmp = df_tmp.assign( 607 | hc=(df_tmp[self._columns["High"]] + df_tmp[self._columns["Low"]]) / 2 608 | ) 609 | df_j = calculate_smma(df_tmp, period_jaws, "jaws", "hc") 610 | df_t = calculate_smma(df_tmp, period_teeth, "teeth", "hc") 611 | df_l = calculate_smma(df_tmp, period_lips, "lips", "hc") 612 | 613 | # Shift SMMAs 614 | 615 | df_j["jaws"] = df_j["jaws"].shift(shift_jaws) 616 | df_t["teeth"] = df_t["teeth"].shift(shift_teeth) 617 | df_l["lips"] = df_l["lips"].shift(shift_lips) 618 | 619 | df_tmp = df_tmp.merge(df_j, left_index=True, right_index=True) 620 | df_tmp = df_tmp.merge(df_t, left_index=True, right_index=True) 621 | df_tmp = df_tmp.merge(df_l, left_index=True, right_index=True) 622 | 623 | df_tmp = df_tmp.assign(val1=df_tmp["jaws"] - df_tmp["teeth"]) 624 | df_tmp = df_tmp.assign(val2=-(df_tmp["teeth"] - df_tmp["lips"])) 625 | 626 | df_tmp = df_tmp[["val1", "val2"]] 627 | df_tmp = df_tmp.rename( 628 | columns={"val1": column_name_val1, "val2": column_name_val2} 629 | ) 630 | 631 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 632 | 633 | def ichimoku_kinko_hyo( 634 | self, 635 | period_tenkan_sen=9, 636 | period_kijun_sen=26, 637 | period_senkou_span_b=52, 638 | column_name_chikou_span="chikou_span", 639 | column_name_tenkan_sen="tenkan_sen", 640 | column_name_kijun_sen="kijun_sen", 641 | column_name_senkou_span_a="senkou_span_a", 642 | column_name_senkou_span_b="senkou_span_b", 643 | ): 644 | """ 645 | Ichimoku Kinko Hyo 646 | ------------------ 647 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/ichimoku 648 | 649 | >>> Indicators.ichimoku_kinko_hyo(period_tenkan_sen=9, period_kijun_sen=26, period_senkou_span_b=52, column_name_chikou_span='chikou_span', column_name_tenkan_sen='tenkan_sen', column_name_kijun_sen='kijun_sen', column_name_senkou_span_a='senkou_span_a', column_name_senkou_span_b='senkou_span_b') 650 | 651 | :param int period_tenkan_sen: Period for Tenkan-sen, default: 9 652 | :param int period_kijun_sen: Period for Kijun-sen, default: 26 653 | :param int period_senkou_span_b: Period for Senkou-span, default: 52 654 | :param str column_name_chikou_span: Column name for Chikou-span, default: chikou_span 655 | :param str column_name_tenkan_sen: Column name for Tenkan-sen, default: tenkan_sen 656 | :param str column_name_kijun_sen: Column name for Kijun-sen, default: kijun_sen 657 | :param str column_name_senkou_span_a: Column name for Senkou Span A, default: senkou_span_a 658 | :param str column_name_senkou_span_b: Column name for Senkou Span B, default: senkou_span_b 659 | :return: None 660 | """ 661 | df_tmp = self.df[ 662 | [ 663 | self._columns["High"], 664 | self._columns["Low"], 665 | self._columns["Close"], 666 | ] 667 | ] 668 | 669 | df_tmp = df_tmp.assign( 670 | tenkan_h=df_tmp[self._columns["High"]] 671 | .rolling(window=period_tenkan_sen) 672 | .max() 673 | ) 674 | df_tmp = df_tmp.assign( 675 | tenkan_l=df_tmp[self._columns["Low"]] 676 | .rolling(window=period_tenkan_sen) 677 | .min() 678 | ) 679 | df_tmp = df_tmp.assign(tenkan=(df_tmp.tenkan_h + df_tmp.tenkan_l) / 2) 680 | del df_tmp["tenkan_h"] 681 | del df_tmp["tenkan_l"] 682 | 683 | df_tmp = df_tmp.assign( 684 | kijun_h=df_tmp[self._columns["High"]].rolling(window=period_kijun_sen).max() 685 | ) 686 | df_tmp = df_tmp.assign( 687 | kijun_l=df_tmp[self._columns["Low"]].rolling(window=period_kijun_sen).min() 688 | ) 689 | df_tmp = df_tmp.assign(kijun=(df_tmp.kijun_h + df_tmp.kijun_l) / 2) 690 | del df_tmp["kijun_h"] 691 | del df_tmp["kijun_l"] 692 | 693 | df_tmp = df_tmp.assign( 694 | ssa=((df_tmp.tenkan + df_tmp.kijun) / 2).shift(period_kijun_sen) 695 | ) 696 | 697 | df_tmp = df_tmp.assign( 698 | ssb_h=df_tmp[self._columns["High"]] 699 | .rolling(window=period_senkou_span_b) 700 | .max() 701 | ) 702 | df_tmp = df_tmp.assign( 703 | ssb_l=df_tmp[self._columns["Low"]] 704 | .rolling(window=period_senkou_span_b) 705 | .min() 706 | ) 707 | df_tmp = df_tmp.assign( 708 | ssb=((df_tmp.ssb_h + df_tmp.ssb_l) / 2).shift(period_kijun_sen) 709 | ) 710 | del df_tmp["ssb_h"] 711 | del df_tmp["ssb_l"] 712 | 713 | df_tmp = df_tmp.assign( 714 | chikou=df_tmp[self._columns["Close"]].shift(-period_kijun_sen) 715 | ) 716 | 717 | df_tmp = df_tmp[["tenkan", "kijun", "ssa", "ssb", "chikou"]] 718 | df_tmp = df_tmp.rename( 719 | columns={ 720 | "tenkan": column_name_tenkan_sen, 721 | "kijun": column_name_kijun_sen, 722 | "ssa": column_name_senkou_span_a, 723 | "ssb": column_name_senkou_span_b, 724 | "chikou": column_name_chikou_span, 725 | } 726 | ) 727 | 728 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 729 | 730 | def bw_mfi(self, column_name="bw_mfi"): 731 | """ 732 | Market Facilitation Index (BW MFI) 733 | ---------------------------------- 734 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/market_facilitation_index 735 | 736 | >>> Indicators.bw_mfi(column_name='bw_mfi') 737 | 738 | :param str column_name: Column name, default: bw_mfi 739 | :return: None 740 | """ 741 | df_tmp = self.df[ 742 | [ 743 | self._columns["High"], 744 | self._columns["Low"], 745 | self._columns["Volume"], 746 | ] 747 | ] 748 | df_tmp = df_tmp.assign( 749 | bw=(df_tmp[self._columns["High"]] - df_tmp[self._columns["Low"]]) 750 | / df_tmp[self._columns["Volume"]] 751 | * 100000 752 | ) 753 | df_tmp = df_tmp[["bw"]] 754 | df_tmp = df_tmp.rename(columns={"bw": column_name}) 755 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 756 | 757 | def momentum(self, period=14, column_name="momentum"): 758 | """ 759 | Momentum 760 | -------- 761 | https://www.metatrader4.com/ru/trading-platform/help/analytics/tech_indicators/momentum 762 | 763 | >>> Indicators.momentum(period=14, column_name='momentum') 764 | 765 | :param int period: Period, default: 14 766 | :param strr column_name: Column name, default: momentum 767 | :return: 768 | """ 769 | close = self._columns["Close"] 770 | df_tmp = self.df[[close]] 771 | df_tmp = df_tmp.assign(m=df_tmp[close] / df_tmp[close].shift(period) * 100) 772 | df_tmp = df_tmp[["m"]] 773 | df_tmp = df_tmp.rename(columns={"m": column_name}) 774 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 775 | 776 | def mfi(self, period=5, column_name="mfi"): 777 | """ 778 | Money Flow Index (MFI) 779 | ----------------------- 780 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/money_flow_index 781 | 782 | >>> Indicators.mfi(period=5, column_name='mfi') 783 | :param int period: Period, default: 5 784 | :param str column_name: Column name, default: mfi 785 | :return: None 786 | """ 787 | high, low, close, volume = ( 788 | self._columns["High"], 789 | self._columns["Low"], 790 | self._columns["Close"], 791 | self._columns["Volume"], 792 | ) 793 | df_tmp = self.df[[high, low, close, volume]] 794 | 795 | df_tmp = df_tmp.assign(tp=(df_tmp[high] + df_tmp[low] + df_tmp[close]) / 3) 796 | df_tmp = df_tmp.assign(mf=df_tmp["tp"] * df_tmp[volume]) 797 | 798 | df_tmp = df_tmp.assign( 799 | pmf=np.where(df_tmp["tp"] > df_tmp["tp"].shift(1), df_tmp["mf"], 0.0) 800 | ) 801 | df_tmp = df_tmp.assign( 802 | nmf=np.where(df_tmp["tp"] < df_tmp["tp"].shift(1), df_tmp["mf"], 0.0) 803 | ) 804 | 805 | df_tmp["pmfs"] = df_tmp.pmf.rolling(window=period).sum() 806 | df_tmp["nmfs"] = df_tmp.nmf.rolling(window=period).sum() 807 | 808 | del df_tmp["tp"] 809 | del df_tmp["mf"] 810 | del df_tmp["pmf"] 811 | del df_tmp["nmf"] 812 | 813 | df_tmp = df_tmp.round(decimals=10) 814 | df_tmp = df_tmp.assign(mr=df_tmp.pmfs / df_tmp.nmfs) 815 | df_tmp = df_tmp.assign(mfi=100 - (100 / (1 + df_tmp.mr))) 816 | 817 | df_tmp = df_tmp[["mfi"]] 818 | df_tmp = df_tmp.rename(columns={"mfi": column_name}) 819 | 820 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 821 | 822 | def macd( 823 | self, 824 | period_fast=12, 825 | period_slow=26, 826 | period_signal=9, 827 | column_name_value="macd_value", 828 | column_name_signal="macd_signal", 829 | ): 830 | """ 831 | Moving Average Convergence/Divergence (MACD) 832 | -------------------------------------------- 833 | https://www.metatrader4.com/en/trading-platform/help/analytics/tech_indicators/macd 834 | 835 | >>> Indicators.macd(self, period_fast=12, period_slow=26, period_signal=9, column_name_value='macd_value', column_name_signal='macd_signal') 836 | 837 | :param int period_fast: Period for Fast EMA, default: 12 838 | :param int period_slow: Period for Slow EMA, default: 26 839 | :param int period_signal: Period for Signal Line, default 9 840 | :param str column_name_value: Column name for MACD Value, default macd_value 841 | :param str column_name_signal: Column name for MACD Signal, default macd_signal 842 | :return: None 843 | """ 844 | close = self._columns["Close"] 845 | df_tmp = self.df[[close]] 846 | 847 | df_tmp = df_tmp.assign( 848 | fast=df_tmp[close].ewm(span=period_fast, adjust=False).mean() 849 | ) 850 | df_tmp = df_tmp.assign( 851 | slow=df_tmp[close].ewm(span=period_slow, adjust=False).mean() 852 | ) 853 | df_tmp = df_tmp.assign(value=df_tmp["fast"] - df_tmp["slow"]) 854 | df_tmp = df_tmp.assign( 855 | signal=df_tmp["value"].rolling(window=period_signal).mean() 856 | ) 857 | 858 | df_tmp = df_tmp[["value", "signal"]] 859 | df_tmp = df_tmp.rename( 860 | columns={"value": column_name_value, "signal": column_name_signal} 861 | ) 862 | 863 | self.df = self.df.merge(df_tmp, left_index=True, right_index=True) 864 | -------------------------------------------------------------------------------- /tapy/utils.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | from numpy import mean, absolute 4 | 5 | 6 | def calculate_sma(df, period, column_name, apply_to): 7 | """Calculate Simple Moving Averaga.""" 8 | df[column_name] = df[apply_to].rolling(window=period).mean() 9 | 10 | 11 | def calculate_ao(df, column_name): 12 | """Calculate Awesome Oscillator.""" 13 | # Data frame for storing temporary data 14 | df_tmp = pd.DataFrame() 15 | 16 | mp_col = "_median_price" 17 | df_tmp[mp_col] = (df["High"] + df["Low"]) / 2 18 | 19 | sma5_col = "_sma5" 20 | calculate_sma(df_tmp, 5, sma5_col, mp_col) 21 | 22 | sma34_col = "_sma34" 23 | calculate_sma(df_tmp, 34, sma34_col, mp_col) 24 | 25 | # Calculate Awesome Oscillator 26 | df[column_name] = df_tmp[sma5_col] - df_tmp[sma34_col] 27 | 28 | 29 | def calculate_smma(df, period, column_name, apply_to): 30 | """Calculate Smoothed Moving Average.""" 31 | df_tmp = df[[apply_to]] 32 | first_val = df_tmp[apply_to].iloc[:period].mean() 33 | df_tmp = df_tmp.assign(column_name=None) 34 | df_tmp.at[period, column_name] = first_val 35 | for index, row in df_tmp.iterrows(): 36 | if index > period: 37 | smma_val = ( 38 | df_tmp.at[index - 1, column_name] * (period - 1) 39 | + row[apply_to] 40 | ) / period 41 | df_tmp.at[index, column_name] = smma_val 42 | df_tmp = df_tmp[[column_name]] 43 | return df_tmp 44 | 45 | 46 | def mad(data, axis=None): 47 | """Calculate Average absolute deviation.""" 48 | return mean(absolute(data - mean(data, axis)), axis) 49 | 50 | 51 | def calculate_alma(df, period, offset, sigma, apply_to, column_name): 52 | m = offset * (period - 1) 53 | s = period / sigma 54 | 55 | # Gaussian distribution weight calculation 56 | weights = np.exp(-((np.arange(period) - m) ** 2) / (2 * s * s)) 57 | weights /= np.sum(weights) 58 | 59 | # Apply the weights to the specified column 60 | alma = ( 61 | df[apply_to] 62 | .rolling(window=period) 63 | .apply(lambda x: np.sum(weights * x), raw=True) 64 | ) 65 | 66 | df[column_name] = alma 67 | return df 68 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmitriiweb/tapy/6149677c3ee1f1dc7e0bdf496b7d5edc069f7424/test/__init__.py -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import pandas as pd 3 | 4 | 5 | from tapy import Indicators 6 | 7 | 8 | @pytest.fixture() 9 | def indicators() -> Indicators: 10 | df = pd.read_csv("EURUSD60.csv") 11 | indicators = Indicators(df) 12 | return indicators 13 | -------------------------------------------------------------------------------- /test/test_tapy.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from tapy import Indicators 4 | 5 | 6 | def get_val(df, column, val_index, round_to): 7 | val = round(df[column].tolist()[val_index], round_to) 8 | return val 9 | 10 | 11 | def test_sma(indicators: Indicators): 12 | col = "sma" 13 | indicators.sma(period=5, column_name=col) 14 | df = indicators.df 15 | val = get_val(df, col, -1, 5) 16 | assert val == 1.10151 17 | 18 | 19 | def test_ema(indicators: Indicators): 20 | col = "ema" 21 | indicators.ema(period=5, column_name=col) 22 | df = indicators.df 23 | val = get_val(df, col, -1, 5) 24 | assert val == 1.10164 25 | 26 | 27 | def test_awesome_oscillator(indicators: Indicators): 28 | col = "ao" 29 | indicators.awesome_oscillator(column_name=col) 30 | df = indicators.df 31 | val = get_val(df, col, -1, 6) 32 | assert val == -0.002834 33 | 34 | 35 | def test_accelerator_oscillator(indicators: Indicators): 36 | col = "ac" 37 | indicators.accelerator_oscillator(column_name=col) 38 | df = indicators.df 39 | val = get_val(df, col, -1, 7) 40 | assert val == 0.0003882 41 | 42 | 43 | def test_accumulation_distribution(indicators: Indicators): 44 | col = "a/d" 45 | indicators.accumulation_distribution(column_name=col) 46 | df = indicators.df 47 | val = get_val(df, col, -1, 0) 48 | assert val == -51439.0 49 | 50 | 51 | def test_smma(indicators: Indicators): 52 | col = "smma" 53 | indicators.smma(period=5, column_name=col) 54 | df = indicators.df 55 | val = get_val(df, col, -1, 5) 56 | assert val == 1.10192 57 | 58 | 59 | def test_alligator(indicators: Indicators): 60 | col_jaws = "jaws" 61 | col_teeth = "teeth" 62 | col_lips = "lips" 63 | indicators.alligator( 64 | column_name_jaws=col_jaws, 65 | column_name_teeth=col_teeth, 66 | column_name_lips=col_lips, 67 | ) 68 | df = indicators.df 69 | val_jaws = get_val(df, col_jaws, -1, 5) 70 | val_teeth = get_val(df, col_teeth, -1, 5) 71 | val_lips = get_val(df, col_lips, -1, 5) 72 | 73 | assert val_jaws == 1.10478 74 | assert val_teeth == 1.10352 75 | assert val_lips == 1.10214 76 | 77 | 78 | def test_atr(indicators: Indicators): 79 | col = "atr" 80 | indicators.atr(column_name=col) 81 | df = indicators.df 82 | val_atr = get_val(df, col, -1, 4) 83 | assert val_atr == 0.0013 84 | 85 | 86 | def test_bears_power(indicators: Indicators): 87 | col = "bears" 88 | indicators.bears_power(column_name=col) 89 | df = indicators.df 90 | val_bears = get_val(df, col, -1, 5) 91 | assert val_bears == 0.00083 92 | 93 | 94 | def test_bollinger_bands(indicators: Indicators): 95 | col_up = "bollinger_up" 96 | col_mid = "bollinger_mid" 97 | col_down = "bollinger_down" 98 | indicators.bollinger_bands( 99 | column_name_top=col_up, column_name_mid=col_mid, column_name_bottom=col_down 100 | ) 101 | df = indicators.df 102 | val_up = get_val(df, col_up, -1, 5) 103 | val_mid = get_val(df, col_mid, -1, 5) 104 | val_down = get_val(df, col_down, -1, 5) 105 | 106 | assert val_up == 1.10733 107 | assert val_mid == 1.10346 108 | assert val_down == 1.09959 109 | 110 | 111 | def test_bulls_power(indicators: Indicators): 112 | col = "bulls" 113 | indicators.bulls_power(column_name=col) 114 | df = indicators.df 115 | val_bulls = get_val(df, col, -1, 5) 116 | assert val_bulls == -0.00015 117 | 118 | 119 | def test_cci(indicators: Indicators): 120 | col = "cci" 121 | indicators.cci(column_name=col) 122 | df = indicators.df 123 | val_cci = get_val(df, col, -1, 4) 124 | assert val_cci == -38.4801 125 | 126 | 127 | def test_de_marker(indicators: Indicators, period=14, column_name="dem"): 128 | col = "dem" 129 | indicators.de_marker(column_name=col) 130 | df = indicators.df 131 | val_dem = get_val(df, col, -1, 4) 132 | assert val_dem == 0.1967 133 | 134 | 135 | def test_force_index_error(indicators: Indicators): 136 | col = "frc" 137 | with pytest.raises(Exception) as exception: 138 | indicators.force_index(column_name=col, method="blah") 139 | 140 | assert str(exception.value) == 'The "method" can be only "sma", "ema" or "smma"' 141 | 142 | 143 | def test_force_index(indicators: Indicators): 144 | col_sma = "frc_sma" 145 | col_ema = "ema" 146 | col_smma = "smma" 147 | indicators.force_index(column_name=col_sma) 148 | indicators.force_index(column_name=col_ema, method="ema") 149 | indicators.force_index(column_name=col_smma, method="smma") 150 | indicators.force_index() 151 | df = indicators.df 152 | val_frc_sma = get_val(df, col_sma, -1, 4) 153 | val_frc_ema = get_val(df, col_ema, -1, 4) 154 | val_frc_smma = get_val(df, col_smma, -1, 4) 155 | 156 | assert val_frc_sma == -0.3154 157 | assert val_frc_ema == -0.1294 158 | assert val_frc_smma == -0.1495 159 | 160 | 161 | def test_fractals(indicators: Indicators): 162 | col_high = "fh" 163 | col_low = "fl" 164 | indicators.fractals(column_name_high=col_high, column_name_low=col_low) 165 | df = indicators.df 166 | fractal_low = df.iloc[-6][col_low] 167 | fractal_high = df.iloc[-14][col_high] 168 | print(f"{df.iloc[-5][col_low]=}") 169 | 170 | assert fractal_low is not None 171 | assert fractal_high is not None 172 | assert df.iloc[-5][col_low] == False 173 | 174 | 175 | def test_gator(indicators: Indicators): 176 | col_val1 = "val1" 177 | col_val2 = "val2" 178 | indicators.gator(column_name_val1=col_val1, column_name_val2=col_val2) 179 | df = indicators.df 180 | val1 = get_val(df, col_val1, -1, 6) 181 | val2 = get_val(df, col_val2, -1, 6) 182 | assert val1 == 0.001263 183 | assert val2 == -0.001376 184 | 185 | 186 | def test_ichimoku_kinko_hyo(indicators: Indicators): 187 | col_chikou = "chikou" 188 | col_tenkan = "tenkan" 189 | col_kijun = "kijun" 190 | col_sb = "sb" 191 | col_sa = "sa" 192 | indicators.ichimoku_kinko_hyo( 193 | column_name_chikou_span=col_chikou, 194 | column_name_tenkan_sen=col_tenkan, 195 | column_name_kijun_sen=col_kijun, 196 | column_name_senkou_span_b=col_sb, 197 | column_name_senkou_span_a=col_sa, 198 | ) 199 | df = indicators.df 200 | val_chikou = get_val(df, col_chikou, -27, 5) 201 | val_tenkan = get_val(df, col_tenkan, -1, 5) 202 | val_kijun = get_val(df, col_kijun, -1, 5) 203 | val_sb = get_val(df, col_sb, -1, 5) 204 | val_sa = get_val(df, col_sa, -1, 5) 205 | assert val_chikou == 1.10167 206 | assert val_tenkan == 1.10147 207 | assert val_kijun == 1.10316 208 | assert val_sb == 1.10442 209 | assert val_sa == 1.10494 210 | 211 | 212 | def test_bw_mfi(indicators: Indicators): 213 | col = "bw" 214 | indicators.bw_mfi(column_name=col) 215 | df = indicators.df 216 | val_bw = get_val(df, col, -1, 4) 217 | assert val_bw == 0.0556 218 | 219 | 220 | def test_momentum(indicators: Indicators): 221 | col = "mom" 222 | indicators.momentum(column_name=col) 223 | df = indicators.df 224 | val = get_val(df, col, -1, 4) 225 | assert val == 99.6094 226 | 227 | 228 | def test_mfi(indicators: Indicators): 229 | col = "mfi" 230 | indicators.mfi(column_name=col) 231 | df = indicators.df 232 | val = get_val(df, col, -2, 4) 233 | assert val == 70.6982 234 | 235 | 236 | def test_macd(indicators: Indicators): 237 | col_val = "val" 238 | col_signal = "signal" 239 | indicators.macd(column_name_value=col_val, column_name_signal=col_signal) 240 | df = indicators.df 241 | value = get_val(df, col_val, -1, 6) 242 | signal = get_val(df, col_signal, -1, 6) 243 | assert value == -0.000973 244 | assert signal == -0.000827 245 | 246 | 247 | def test_alma(indicators: Indicators): 248 | col = "alma" 249 | indicators.alma(column_name=col) 250 | df = indicators.df 251 | value = get_val(df, col, -1, 6) 252 | assert value == 1.101739 253 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist=py{311,312,313} 3 | 4 | [testenv] 5 | extras = 6 | dev-test 7 | allowlist_externals= make 8 | commands = make test 9 | -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | requires-python = ">=3.11, <4" 3 | resolution-markers = [ 4 | "python_full_version >= '3.12'", 5 | "python_full_version < '3.12'", 6 | ] 7 | 8 | [[package]] 9 | name = "alabaster" 10 | version = "1.0.0" 11 | source = { registry = "https://pypi.org/simple" } 12 | sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 } 13 | wheels = [ 14 | { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 }, 15 | ] 16 | 17 | [[package]] 18 | name = "babel" 19 | version = "2.17.0" 20 | source = { registry = "https://pypi.org/simple" } 21 | sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } 22 | wheels = [ 23 | { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, 24 | ] 25 | 26 | [[package]] 27 | name = "cachetools" 28 | version = "5.5.2" 29 | source = { registry = "https://pypi.org/simple" } 30 | sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380 } 31 | wheels = [ 32 | { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080 }, 33 | ] 34 | 35 | [[package]] 36 | name = "certifi" 37 | version = "2025.1.31" 38 | source = { registry = "https://pypi.org/simple" } 39 | sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } 40 | wheels = [ 41 | { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, 42 | ] 43 | 44 | [[package]] 45 | name = "chardet" 46 | version = "5.2.0" 47 | source = { registry = "https://pypi.org/simple" } 48 | sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618 } 49 | wheels = [ 50 | { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385 }, 51 | ] 52 | 53 | [[package]] 54 | name = "charset-normalizer" 55 | version = "3.4.1" 56 | source = { registry = "https://pypi.org/simple" } 57 | sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } 58 | wheels = [ 59 | { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 }, 60 | { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 }, 61 | { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 }, 62 | { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 }, 63 | { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 }, 64 | { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 }, 65 | { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 }, 66 | { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 }, 67 | { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 }, 68 | { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 }, 69 | { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 }, 70 | { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 }, 71 | { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 }, 72 | { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, 73 | { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, 74 | { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, 75 | { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, 76 | { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, 77 | { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, 78 | { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, 79 | { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, 80 | { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, 81 | { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, 82 | { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, 83 | { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, 84 | { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, 85 | { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, 86 | { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, 87 | { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, 88 | { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, 89 | { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, 90 | { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, 91 | { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, 92 | { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, 93 | { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, 94 | { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, 95 | { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, 96 | { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, 97 | { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, 98 | { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, 99 | ] 100 | 101 | [[package]] 102 | name = "colorama" 103 | version = "0.4.6" 104 | source = { registry = "https://pypi.org/simple" } 105 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } 106 | wheels = [ 107 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, 108 | ] 109 | 110 | [[package]] 111 | name = "coverage" 112 | version = "7.7.0" 113 | source = { registry = "https://pypi.org/simple" } 114 | sdist = { url = "https://files.pythonhosted.org/packages/02/36/465f5492443265e1278f9a82ffe6aeed3f1db779da0d6e7d4611a5cfb6af/coverage-7.7.0.tar.gz", hash = "sha256:cd879d4646055a573775a1cec863d00c9ff8c55860f8b17f6d8eee9140c06166", size = 809969 } 115 | wheels = [ 116 | { url = "https://files.pythonhosted.org/packages/e8/ec/9e0c9358a3bd56b1ddbf266b889ea9d51ee29e58fb72712d5600663fa806/coverage-7.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a0a207c87a9f743c8072d059b4711f8d13c456eb42dac778a7d2e5d4f3c253a7", size = 210722 }, 117 | { url = "https://files.pythonhosted.org/packages/be/bd/7b47a4302423a13960ee30682900d7ca20cee15c978b1d9ea9594d59d352/coverage-7.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2d673e3add00048215c2cc507f1228a7523fd8bf34f279ac98334c9b07bd2656", size = 211154 }, 118 | { url = "https://files.pythonhosted.org/packages/c6/7c/ae54d9022440196bf9f3fad535388678a3db186980ff58a4956ddeb849a2/coverage-7.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f81fe93dc1b8e5673f33443c0786c14b77e36f1025973b85e07c70353e46882b", size = 243787 }, 119 | { url = "https://files.pythonhosted.org/packages/2d/21/913a2a2d89a2221f4410fbea4ff84e64ddf4367a4b9eb2c328bd01a1a401/coverage-7.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8c7524779003d59948c51b4fcbf1ca4e27c26a7d75984f63488f3625c328b9b", size = 241473 }, 120 | { url = "https://files.pythonhosted.org/packages/40/f1/5ae36fffd542fb86ab3b2d5e012af0840265f3dd001ad0ffabe9e4dbdcf6/coverage-7.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c124025430249118d018dcedc8b7426f39373527c845093132196f2a483b6dd", size = 243259 }, 121 | { url = "https://files.pythonhosted.org/packages/47/1b/abc87bad7f606a4df321bd8300413fe13700099a163e7d63453c7c70c1b2/coverage-7.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e7f559c36d5cdc448ee13e7e56ed7b6b5d44a40a511d584d388a0f5d940977ba", size = 242904 }, 122 | { url = "https://files.pythonhosted.org/packages/e0/b3/ff0cf15f5709996727dda2fa00af6f4da92ea3e16168400346f2f742341a/coverage-7.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:37cbc7b0d93dfd133e33c7ec01123fbb90401dce174c3b6661d8d36fb1e30608", size = 241079 }, 123 | { url = "https://files.pythonhosted.org/packages/05/c9/fcad82aad05b1eb8040e6c25ae7a1303716cc05718d4dd326e0fab31aa14/coverage-7.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7d2a65876274acf544703e943c010b60bd79404e3623a1e5d52b64a6e2728de5", size = 241617 }, 124 | { url = "https://files.pythonhosted.org/packages/59/9f/d1efe149afa5c3a459c08bf04f7e6917ef4ee8e3440df5c3e87d6b972870/coverage-7.7.0-cp311-cp311-win32.whl", hash = "sha256:f5a2f71d6a91238e7628f23538c26aa464d390cbdedf12ee2a7a0fb92a24482a", size = 213372 }, 125 | { url = "https://files.pythonhosted.org/packages/88/d2/4b58f03e399185b01fb3168d4b870882de9c7a10e273f99c8f25ec690302/coverage-7.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:ae8006772c6b0fa53c33747913473e064985dac4d65f77fd2fdc6474e7cd54e4", size = 214285 }, 126 | { url = "https://files.pythonhosted.org/packages/b7/47/f7b870caa26082ff8033be074ac61dc175a6b0c965adf7b910f92a6d7cfe/coverage-7.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:056d3017ed67e7ddf266e6f57378ece543755a4c9231e997789ab3bd11392c94", size = 210907 }, 127 | { url = "https://files.pythonhosted.org/packages/ea/eb/40b39bdc6c1da403257f0fcb2c1b2fd81ff9f66c13abbe3862f42780e1c1/coverage-7.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33c1394d8407e2771547583b66a85d07ed441ff8fae5a4adb4237ad39ece60db", size = 211162 }, 128 | { url = "https://files.pythonhosted.org/packages/53/08/42a2db41b4646d6261122773e222dd7105e2306526f2d7846de6fee808ec/coverage-7.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fbb7a0c3c21908520149d7751cf5b74eb9b38b54d62997b1e9b3ac19a8ee2fe", size = 245223 }, 129 | { url = "https://files.pythonhosted.org/packages/78/2a/0ceb328a7e67e8639d5c7800b8161d4b5f489073ac8d5ac33b11eadee218/coverage-7.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb356e7ae7c2da13f404bf8f75be90f743c6df8d4607022e759f5d7d89fe83f8", size = 242114 }, 130 | { url = "https://files.pythonhosted.org/packages/ba/68/42b13b849d40af1581830ff06c60f4ec84649764f4a58d5c6e20ae11cbd4/coverage-7.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce730d484038e97f27ea2dbe5d392ec5c2261f28c319a3bb266f6b213650135", size = 244371 }, 131 | { url = "https://files.pythonhosted.org/packages/68/66/ab7c3b9fdbeb8bdd322f5b67b1886463834dba2014a534caba60fb0075ea/coverage-7.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa4dff57fc21a575672176d5ab0ef15a927199e775c5e8a3d75162ab2b0c7705", size = 244134 }, 132 | { url = "https://files.pythonhosted.org/packages/01/74/b833d299a479681957d6b238e16a0725586e1d56ec1e43658f3184550bb0/coverage-7.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b667b91f4f714b17af2a18e220015c941d1cf8b07c17f2160033dbe1e64149f0", size = 242353 }, 133 | { url = "https://files.pythonhosted.org/packages/f9/c5/0ed656d65da39bbab8e8fc367dc3d465a7501fea0f2b1caccfb4f6361c9f/coverage-7.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:693d921621a0c8043bfdc61f7d4df5ea6d22165fe8b807cac21eb80dd94e4bbd", size = 243543 }, 134 | { url = "https://files.pythonhosted.org/packages/87/b5/142bcff3828e4cce5d4c9ddc9222de1664464263acca09638e4eb0dbda7c/coverage-7.7.0-cp312-cp312-win32.whl", hash = "sha256:52fc89602cde411a4196c8c6894afb384f2125f34c031774f82a4f2608c59d7d", size = 213543 }, 135 | { url = "https://files.pythonhosted.org/packages/29/74/99d226985def03284bad6a9aff27a1079a8881ec7523b5980b00a5260527/coverage-7.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0ce8cf59e09d31a4915ff4c3b94c6514af4c84b22c4cc8ad7c3c546a86150a92", size = 214344 }, 136 | { url = "https://files.pythonhosted.org/packages/45/2f/df6235ec963b9eb6b6b2f3c24f70448f1ffa13b9a481c155a6caff176395/coverage-7.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4545485fef7a8a2d8f30e6f79ce719eb154aab7e44217eb444c1d38239af2072", size = 210934 }, 137 | { url = "https://files.pythonhosted.org/packages/f3/85/ff19510bf642e334845318ddb73a550d2b17082831fa9ae053ce72288be7/coverage-7.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1393e5aa9441dafb0162c36c8506c648b89aea9565b31f6bfa351e66c11bcd82", size = 211212 }, 138 | { url = "https://files.pythonhosted.org/packages/2d/6a/af6582a419550d35eacc3e1bf9f4a936dda0ae559632a0bc4e3aef694ac8/coverage-7.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:316f29cc3392fa3912493ee4c83afa4a0e2db04ff69600711f8c03997c39baaa", size = 244727 }, 139 | { url = "https://files.pythonhosted.org/packages/55/62/7c49526111c91f3d7d27e111c22c8d08722f5b661c3f031b625b4d7bc4d9/coverage-7.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ffde1d6bc2a92f9c9207d1ad808550873748ac2d4d923c815b866baa343b3f", size = 241768 }, 140 | { url = "https://files.pythonhosted.org/packages/62/4b/2dc27700782be9795cbbbe98394dd19ef74815d78d5027ed894972cd1b4a/coverage-7.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:416e2a8845eaff288f97eaf76ab40367deafb9073ffc47bf2a583f26b05e5265", size = 243790 }, 141 | { url = "https://files.pythonhosted.org/packages/d3/11/9cc1ae56d3015edca69437f3121c2b44de309f6828980b29e4cc9b13246d/coverage-7.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5efdeff5f353ed3352c04e6b318ab05c6ce9249c25ed3c2090c6e9cadda1e3b2", size = 243861 }, 142 | { url = "https://files.pythonhosted.org/packages/db/e4/2398ed93edcf42ff43002d91c37be11514d825cec382606654fd44f4b8fa/coverage-7.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:57f3bd0d29bf2bd9325c0ff9cc532a175110c4bf8f412c05b2405fd35745266d", size = 241942 }, 143 | { url = "https://files.pythonhosted.org/packages/ec/fe/b6bd35b17a2b8d26bdb21d5ea4351a837ec01edf552655e833629af05b90/coverage-7.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3ab7090f04b12dc6469882ce81244572779d3a4b67eea1c96fb9ecc8c607ef39", size = 243228 }, 144 | { url = "https://files.pythonhosted.org/packages/6d/06/d8701bae1e5d865edeb00a6c2a71bd7659ca6af349789271c6fd16a57909/coverage-7.7.0-cp313-cp313-win32.whl", hash = "sha256:180e3fc68ee4dc5af8b33b6ca4e3bb8aa1abe25eedcb958ba5cff7123071af68", size = 213572 }, 145 | { url = "https://files.pythonhosted.org/packages/d7/c1/7e67780bfcaed6bed20100c9e1b2645e3414577b4bdad169578325249045/coverage-7.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:55143aa13c49491f5606f05b49ed88663446dce3a4d3c5d77baa4e36a16d3573", size = 214372 }, 146 | { url = "https://files.pythonhosted.org/packages/ed/25/50b0447442a415ad3da33093c589d9ef945dd6933225f1ce0ac97476397e/coverage-7.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:cc41374d2f27d81d6558f8a24e5c114580ffefc197fd43eabd7058182f743322", size = 211774 }, 147 | { url = "https://files.pythonhosted.org/packages/13/cc/3daddc707e934d3c0aafaa4a9b217f53fcf4133d4e40cc6ae63aa51243b8/coverage-7.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:89078312f06237417adda7c021c33f80f7a6d2db8572a5f6c330d89b080061ce", size = 211995 }, 148 | { url = "https://files.pythonhosted.org/packages/98/99/c92f43355d3d67f6bf8c946a350f2174e18f9ea7c8a1e36c9eb84ab7d20b/coverage-7.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b2f144444879363ea8834cd7b6869d79ac796cb8f864b0cfdde50296cd95816", size = 256226 }, 149 | { url = "https://files.pythonhosted.org/packages/25/62/65f0f33c08e0a1632f1e487b9c2d252e8bad6a77a942836043972b0ba6d2/coverage-7.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60e6347d1ed882b1159ffea172cb8466ee46c665af4ca397edbf10ff53e9ffaf", size = 251937 }, 150 | { url = "https://files.pythonhosted.org/packages/b2/10/99a9565aaeb159aade178c6509c8324a9c9e825b01f02242a37c2a8869f8/coverage-7.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb203c0afffaf1a8f5b9659a013f8f16a1b2cad3a80a8733ceedc968c0cf4c57", size = 254276 }, 151 | { url = "https://files.pythonhosted.org/packages/a7/12/206196edbf0b82250b11bf5c252fe25ebaa2b7c8d66edb0c194e7b3403fe/coverage-7.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:ad0edaa97cb983d9f2ff48cadddc3e1fb09f24aa558abeb4dc9a0dbacd12cbb4", size = 255366 }, 152 | { url = "https://files.pythonhosted.org/packages/a5/82/a2abb8d4cdd99c6a443ab6682c0eee5797490a2113a45ffaa8b6b31c5dcc/coverage-7.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c5f8a5364fc37b2f172c26a038bc7ec4885f429de4a05fc10fdcb53fb5834c5c", size = 253536 }, 153 | { url = "https://files.pythonhosted.org/packages/4d/7d/3747e000e60ad5dd8157bd978f99979967d56cb35c55235980c85305db86/coverage-7.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c4e09534037933bf6eb31d804e72c52ec23219b32c1730f9152feabbd7499463", size = 254344 }, 154 | { url = "https://files.pythonhosted.org/packages/45/56/7c33f8a6de1b3b079374d2ae490ccf76fb7c094a23f72d10f071989fc3ef/coverage-7.7.0-cp313-cp313t-win32.whl", hash = "sha256:1b336d06af14f8da5b1f391e8dec03634daf54dfcb4d1c4fb6d04c09d83cef90", size = 214284 }, 155 | { url = "https://files.pythonhosted.org/packages/95/ab/657bfa6171800a67bd1c005402f06d6b78610820ef1364ea4f85b04bbb5b/coverage-7.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b54a1ee4c6f1905a436cbaa04b26626d27925a41cbc3a337e2d3ff7038187f07", size = 215445 }, 156 | { url = "https://files.pythonhosted.org/packages/cb/69/6a5eac32d2e8721274ef75df1b9fd6a8f7e8231e41ff7bc5501f19835f25/coverage-7.7.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:3b0e6e54591ae0d7427def8a4d40fca99df6b899d10354bab73cd5609807261c", size = 202813 }, 157 | { url = "https://files.pythonhosted.org/packages/2a/ac/60f409a448e5b0e9b8539716f683568aa5848c1be903cdbbc805a552cdf8/coverage-7.7.0-py3-none-any.whl", hash = "sha256:708f0a1105ef2b11c79ed54ed31f17e6325ac936501fc373f24be3e6a578146a", size = 202803 }, 158 | ] 159 | 160 | [package.optional-dependencies] 161 | toml = [ 162 | { name = "tomli", marker = "python_full_version <= '3.11'" }, 163 | ] 164 | 165 | [[package]] 166 | name = "distlib" 167 | version = "0.3.9" 168 | source = { registry = "https://pypi.org/simple" } 169 | sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } 170 | wheels = [ 171 | { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, 172 | ] 173 | 174 | [[package]] 175 | name = "docutils" 176 | version = "0.21.2" 177 | source = { registry = "https://pypi.org/simple" } 178 | sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 } 179 | wheels = [ 180 | { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 }, 181 | ] 182 | 183 | [[package]] 184 | name = "filelock" 185 | version = "3.18.0" 186 | source = { registry = "https://pypi.org/simple" } 187 | sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075 } 188 | wheels = [ 189 | { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215 }, 190 | ] 191 | 192 | [[package]] 193 | name = "idna" 194 | version = "3.10" 195 | source = { registry = "https://pypi.org/simple" } 196 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } 197 | wheels = [ 198 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, 199 | ] 200 | 201 | [[package]] 202 | name = "imagesize" 203 | version = "1.4.1" 204 | source = { registry = "https://pypi.org/simple" } 205 | sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 } 206 | wheels = [ 207 | { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 }, 208 | ] 209 | 210 | [[package]] 211 | name = "iniconfig" 212 | version = "2.0.0" 213 | source = { registry = "https://pypi.org/simple" } 214 | sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } 215 | wheels = [ 216 | { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, 217 | ] 218 | 219 | [[package]] 220 | name = "isort" 221 | version = "6.0.1" 222 | source = { registry = "https://pypi.org/simple" } 223 | sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955 } 224 | wheels = [ 225 | { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186 }, 226 | ] 227 | 228 | [[package]] 229 | name = "jinja2" 230 | version = "3.1.6" 231 | source = { registry = "https://pypi.org/simple" } 232 | dependencies = [ 233 | { name = "markupsafe" }, 234 | ] 235 | sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } 236 | wheels = [ 237 | { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, 238 | ] 239 | 240 | [[package]] 241 | name = "markupsafe" 242 | version = "3.0.2" 243 | source = { registry = "https://pypi.org/simple" } 244 | sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } 245 | wheels = [ 246 | { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, 247 | { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, 248 | { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, 249 | { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, 250 | { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, 251 | { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, 252 | { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, 253 | { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, 254 | { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, 255 | { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, 256 | { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, 257 | { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, 258 | { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, 259 | { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, 260 | { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, 261 | { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, 262 | { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, 263 | { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, 264 | { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, 265 | { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, 266 | { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, 267 | { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, 268 | { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, 269 | { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, 270 | { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, 271 | { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, 272 | { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, 273 | { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, 274 | { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, 275 | { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, 276 | { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, 277 | { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, 278 | { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, 279 | { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, 280 | { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, 281 | { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, 282 | { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, 283 | { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, 284 | { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, 285 | { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, 286 | ] 287 | 288 | [[package]] 289 | name = "nh3" 290 | version = "0.2.21" 291 | source = { registry = "https://pypi.org/simple" } 292 | sdist = { url = "https://files.pythonhosted.org/packages/37/30/2f81466f250eb7f591d4d193930df661c8c23e9056bdc78e365b646054d8/nh3-0.2.21.tar.gz", hash = "sha256:4990e7ee6a55490dbf00d61a6f476c9a3258e31e711e13713b2ea7d6616f670e", size = 16581 } 293 | wheels = [ 294 | { url = "https://files.pythonhosted.org/packages/7f/81/b83775687fcf00e08ade6d4605f0be9c4584cb44c4973d9f27b7456a31c9/nh3-0.2.21-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:fcff321bd60c6c5c9cb4ddf2554e22772bb41ebd93ad88171bbbb6f271255286", size = 1297678 }, 295 | { url = "https://files.pythonhosted.org/packages/22/ee/d0ad8fb4b5769f073b2df6807f69a5e57ca9cea504b78809921aef460d20/nh3-0.2.21-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31eedcd7d08b0eae28ba47f43fd33a653b4cdb271d64f1aeda47001618348fde", size = 733774 }, 296 | { url = "https://files.pythonhosted.org/packages/ea/76/b450141e2d384ede43fe53953552f1c6741a499a8c20955ad049555cabc8/nh3-0.2.21-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d426d7be1a2f3d896950fe263332ed1662f6c78525b4520c8e9861f8d7f0d243", size = 760012 }, 297 | { url = "https://files.pythonhosted.org/packages/97/90/1182275db76cd8fbb1f6bf84c770107fafee0cb7da3e66e416bcb9633da2/nh3-0.2.21-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9d67709bc0d7d1f5797b21db26e7a8b3d15d21c9c5f58ccfe48b5328483b685b", size = 923619 }, 298 | { url = "https://files.pythonhosted.org/packages/29/c7/269a7cfbec9693fad8d767c34a755c25ccb8d048fc1dfc7a7d86bc99375c/nh3-0.2.21-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:55823c5ea1f6b267a4fad5de39bc0524d49a47783e1fe094bcf9c537a37df251", size = 1000384 }, 299 | { url = "https://files.pythonhosted.org/packages/68/a9/48479dbf5f49ad93f0badd73fbb48b3d769189f04c6c69b0df261978b009/nh3-0.2.21-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:818f2b6df3763e058efa9e69677b5a92f9bc0acff3295af5ed013da544250d5b", size = 918908 }, 300 | { url = "https://files.pythonhosted.org/packages/d7/da/0279c118f8be2dc306e56819880b19a1cf2379472e3b79fc8eab44e267e3/nh3-0.2.21-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b3b5c58161e08549904ac4abd450dacd94ff648916f7c376ae4b2c0652b98ff9", size = 909180 }, 301 | { url = "https://files.pythonhosted.org/packages/26/16/93309693f8abcb1088ae143a9c8dbcece9c8f7fb297d492d3918340c41f1/nh3-0.2.21-cp313-cp313t-win32.whl", hash = "sha256:637d4a10c834e1b7d9548592c7aad760611415fcd5bd346f77fd8a064309ae6d", size = 532747 }, 302 | { url = "https://files.pythonhosted.org/packages/a2/3a/96eb26c56cbb733c0b4a6a907fab8408ddf3ead5d1b065830a8f6a9c3557/nh3-0.2.21-cp313-cp313t-win_amd64.whl", hash = "sha256:713d16686596e556b65e7f8c58328c2df63f1a7abe1277d87625dcbbc012ef82", size = 528908 }, 303 | { url = "https://files.pythonhosted.org/packages/ba/1d/b1ef74121fe325a69601270f276021908392081f4953d50b03cbb38b395f/nh3-0.2.21-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a772dec5b7b7325780922dd904709f0f5f3a79fbf756de5291c01370f6df0967", size = 1316133 }, 304 | { url = "https://files.pythonhosted.org/packages/b8/f2/2c7f79ce6de55b41e7715f7f59b159fd59f6cdb66223c05b42adaee2b645/nh3-0.2.21-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d002b648592bf3033adfd875a48f09b8ecc000abd7f6a8769ed86b6ccc70c759", size = 758328 }, 305 | { url = "https://files.pythonhosted.org/packages/6d/ad/07bd706fcf2b7979c51b83d8b8def28f413b090cf0cb0035ee6b425e9de5/nh3-0.2.21-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2a5174551f95f2836f2ad6a8074560f261cf9740a48437d6151fd2d4d7d617ab", size = 747020 }, 306 | { url = "https://files.pythonhosted.org/packages/75/99/06a6ba0b8a0d79c3d35496f19accc58199a1fb2dce5e711a31be7e2c1426/nh3-0.2.21-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b8d55ea1fc7ae3633d758a92aafa3505cd3cc5a6e40470c9164d54dff6f96d42", size = 944878 }, 307 | { url = "https://files.pythonhosted.org/packages/79/d4/dc76f5dc50018cdaf161d436449181557373869aacf38a826885192fc587/nh3-0.2.21-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ae319f17cd8960d0612f0f0ddff5a90700fa71926ca800e9028e7851ce44a6f", size = 903460 }, 308 | { url = "https://files.pythonhosted.org/packages/cd/c3/d4f8037b2ab02ebf5a2e8637bd54736ed3d0e6a2869e10341f8d9085f00e/nh3-0.2.21-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:63ca02ac6f27fc80f9894409eb61de2cb20ef0a23740c7e29f9ec827139fa578", size = 839369 }, 309 | { url = "https://files.pythonhosted.org/packages/11/a9/1cd3c6964ec51daed7b01ca4686a5c793581bf4492cbd7274b3f544c9abe/nh3-0.2.21-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5f77e62aed5c4acad635239ac1290404c7e940c81abe561fd2af011ff59f585", size = 739036 }, 310 | { url = "https://files.pythonhosted.org/packages/fd/04/bfb3ff08d17a8a96325010ae6c53ba41de6248e63cdb1b88ef6369a6cdfc/nh3-0.2.21-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:087ffadfdcd497658c3adc797258ce0f06be8a537786a7217649fc1c0c60c293", size = 768712 }, 311 | { url = "https://files.pythonhosted.org/packages/9e/aa/cfc0bf545d668b97d9adea4f8b4598667d2b21b725d83396c343ad12bba7/nh3-0.2.21-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ac7006c3abd097790e611fe4646ecb19a8d7f2184b882f6093293b8d9b887431", size = 930559 }, 312 | { url = "https://files.pythonhosted.org/packages/78/9d/6f5369a801d3a1b02e6a9a097d56bcc2f6ef98cffebf03c4bb3850d8e0f0/nh3-0.2.21-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:6141caabe00bbddc869665b35fc56a478eb774a8c1dfd6fba9fe1dfdf29e6efa", size = 1008591 }, 313 | { url = "https://files.pythonhosted.org/packages/a6/df/01b05299f68c69e480edff608248313cbb5dbd7595c5e048abe8972a57f9/nh3-0.2.21-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:20979783526641c81d2f5bfa6ca5ccca3d1e4472474b162c6256745fbfe31cd1", size = 925670 }, 314 | { url = "https://files.pythonhosted.org/packages/3d/79/bdba276f58d15386a3387fe8d54e980fb47557c915f5448d8c6ac6f7ea9b/nh3-0.2.21-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a7ea28cd49293749d67e4fcf326c554c83ec912cd09cd94aa7ec3ab1921c8283", size = 917093 }, 315 | { url = "https://files.pythonhosted.org/packages/e7/d8/c6f977a5cd4011c914fb58f5ae573b071d736187ccab31bfb1d539f4af9f/nh3-0.2.21-cp38-abi3-win32.whl", hash = "sha256:6c9c30b8b0d291a7c5ab0967ab200598ba33208f754f2f4920e9343bdd88f79a", size = 537623 }, 316 | { url = "https://files.pythonhosted.org/packages/23/fc/8ce756c032c70ae3dd1d48a3552577a325475af2a2f629604b44f571165c/nh3-0.2.21-cp38-abi3-win_amd64.whl", hash = "sha256:bb0014948f04d7976aabae43fcd4cb7f551f9f8ce785a4c9ef66e6c2590f8629", size = 535283 }, 317 | ] 318 | 319 | [[package]] 320 | name = "numpy" 321 | version = "2.2.4" 322 | source = { registry = "https://pypi.org/simple" } 323 | sdist = { url = "https://files.pythonhosted.org/packages/e1/78/31103410a57bc2c2b93a3597340a8119588571f6a4539067546cb9a0bfac/numpy-2.2.4.tar.gz", hash = "sha256:9ba03692a45d3eef66559efe1d1096c4b9b75c0986b5dff5530c378fb8331d4f", size = 20270701 } 324 | wheels = [ 325 | { url = "https://files.pythonhosted.org/packages/16/fb/09e778ee3a8ea0d4dc8329cca0a9c9e65fed847d08e37eba74cb7ed4b252/numpy-2.2.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e9e0a277bb2eb5d8a7407e14688b85fd8ad628ee4e0c7930415687b6564207a4", size = 21254989 }, 326 | { url = "https://files.pythonhosted.org/packages/a2/0a/1212befdbecab5d80eca3cde47d304cad986ad4eec7d85a42e0b6d2cc2ef/numpy-2.2.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9eeea959168ea555e556b8188da5fa7831e21d91ce031e95ce23747b7609f8a4", size = 14425910 }, 327 | { url = "https://files.pythonhosted.org/packages/2b/3e/e7247c1d4f15086bb106c8d43c925b0b2ea20270224f5186fa48d4fb5cbd/numpy-2.2.4-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bd3ad3b0a40e713fc68f99ecfd07124195333f1e689387c180813f0e94309d6f", size = 5426490 }, 328 | { url = "https://files.pythonhosted.org/packages/5d/fa/aa7cd6be51419b894c5787a8a93c3302a1ed4f82d35beb0613ec15bdd0e2/numpy-2.2.4-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cf28633d64294969c019c6df4ff37f5698e8326db68cc2b66576a51fad634880", size = 6967754 }, 329 | { url = "https://files.pythonhosted.org/packages/d5/ee/96457c943265de9fadeb3d2ffdbab003f7fba13d971084a9876affcda095/numpy-2.2.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fa8fa7697ad1646b5c93de1719965844e004fcad23c91228aca1cf0800044a1", size = 14373079 }, 330 | { url = "https://files.pythonhosted.org/packages/c5/5c/ceefca458559f0ccc7a982319f37ed07b0d7b526964ae6cc61f8ad1b6119/numpy-2.2.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4162988a360a29af158aeb4a2f4f09ffed6a969c9776f8f3bdee9b06a8ab7e5", size = 16428819 }, 331 | { url = "https://files.pythonhosted.org/packages/22/31/9b2ac8eee99e001eb6add9fa27514ef5e9faf176169057a12860af52704c/numpy-2.2.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:892c10d6a73e0f14935c31229e03325a7b3093fafd6ce0af704be7f894d95687", size = 15881470 }, 332 | { url = "https://files.pythonhosted.org/packages/f0/dc/8569b5f25ff30484b555ad8a3f537e0225d091abec386c9420cf5f7a2976/numpy-2.2.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db1f1c22173ac1c58db249ae48aa7ead29f534b9a948bc56828337aa84a32ed6", size = 18218144 }, 333 | { url = "https://files.pythonhosted.org/packages/5e/05/463c023a39bdeb9bb43a99e7dee2c664cb68d5bb87d14f92482b9f6011cc/numpy-2.2.4-cp311-cp311-win32.whl", hash = "sha256:ea2bb7e2ae9e37d96835b3576a4fa4b3a97592fbea8ef7c3587078b0068b8f09", size = 6606368 }, 334 | { url = "https://files.pythonhosted.org/packages/8b/72/10c1d2d82101c468a28adc35de6c77b308f288cfd0b88e1070f15b98e00c/numpy-2.2.4-cp311-cp311-win_amd64.whl", hash = "sha256:f7de08cbe5551911886d1ab60de58448c6df0f67d9feb7d1fb21e9875ef95e91", size = 12947526 }, 335 | { url = "https://files.pythonhosted.org/packages/a2/30/182db21d4f2a95904cec1a6f779479ea1ac07c0647f064dea454ec650c42/numpy-2.2.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a7b9084668aa0f64e64bd00d27ba5146ef1c3a8835f3bd912e7a9e01326804c4", size = 20947156 }, 336 | { url = "https://files.pythonhosted.org/packages/24/6d/9483566acfbda6c62c6bc74b6e981c777229d2af93c8eb2469b26ac1b7bc/numpy-2.2.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:dbe512c511956b893d2dacd007d955a3f03d555ae05cfa3ff1c1ff6df8851854", size = 14133092 }, 337 | { url = "https://files.pythonhosted.org/packages/27/f6/dba8a258acbf9d2bed2525cdcbb9493ef9bae5199d7a9cb92ee7e9b2aea6/numpy-2.2.4-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:bb649f8b207ab07caebba230d851b579a3c8711a851d29efe15008e31bb4de24", size = 5163515 }, 338 | { url = "https://files.pythonhosted.org/packages/62/30/82116199d1c249446723c68f2c9da40d7f062551036f50b8c4caa42ae252/numpy-2.2.4-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:f34dc300df798742b3d06515aa2a0aee20941c13579d7a2f2e10af01ae4901ee", size = 6696558 }, 339 | { url = "https://files.pythonhosted.org/packages/0e/b2/54122b3c6df5df3e87582b2e9430f1bdb63af4023c739ba300164c9ae503/numpy-2.2.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3f7ac96b16955634e223b579a3e5798df59007ca43e8d451a0e6a50f6bfdfba", size = 14084742 }, 340 | { url = "https://files.pythonhosted.org/packages/02/e2/e2cbb8d634151aab9528ef7b8bab52ee4ab10e076509285602c2a3a686e0/numpy-2.2.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f92084defa704deadd4e0a5ab1dc52d8ac9e8a8ef617f3fbb853e79b0ea3592", size = 16134051 }, 341 | { url = "https://files.pythonhosted.org/packages/8e/21/efd47800e4affc993e8be50c1b768de038363dd88865920439ef7b422c60/numpy-2.2.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4e84a6283b36632e2a5b56e121961f6542ab886bc9e12f8f9818b3c266bfbb", size = 15578972 }, 342 | { url = "https://files.pythonhosted.org/packages/04/1e/f8bb88f6157045dd5d9b27ccf433d016981032690969aa5c19e332b138c0/numpy-2.2.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:11c43995255eb4127115956495f43e9343736edb7fcdb0d973defd9de14cd84f", size = 17898106 }, 343 | { url = "https://files.pythonhosted.org/packages/2b/93/df59a5a3897c1f036ae8ff845e45f4081bb06943039ae28a3c1c7c780f22/numpy-2.2.4-cp312-cp312-win32.whl", hash = "sha256:65ef3468b53269eb5fdb3a5c09508c032b793da03251d5f8722b1194f1790c00", size = 6311190 }, 344 | { url = "https://files.pythonhosted.org/packages/46/69/8c4f928741c2a8efa255fdc7e9097527c6dc4e4df147e3cadc5d9357ce85/numpy-2.2.4-cp312-cp312-win_amd64.whl", hash = "sha256:2aad3c17ed2ff455b8eaafe06bcdae0062a1db77cb99f4b9cbb5f4ecb13c5146", size = 12644305 }, 345 | { url = "https://files.pythonhosted.org/packages/2a/d0/bd5ad792e78017f5decfb2ecc947422a3669a34f775679a76317af671ffc/numpy-2.2.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cf4e5c6a278d620dee9ddeb487dc6a860f9b199eadeecc567f777daace1e9e7", size = 20933623 }, 346 | { url = "https://files.pythonhosted.org/packages/c3/bc/2b3545766337b95409868f8e62053135bdc7fa2ce630aba983a2aa60b559/numpy-2.2.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1974afec0b479e50438fc3648974268f972e2d908ddb6d7fb634598cdb8260a0", size = 14148681 }, 347 | { url = "https://files.pythonhosted.org/packages/6a/70/67b24d68a56551d43a6ec9fe8c5f91b526d4c1a46a6387b956bf2d64744e/numpy-2.2.4-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:79bd5f0a02aa16808fcbc79a9a376a147cc1045f7dfe44c6e7d53fa8b8a79392", size = 5148759 }, 348 | { url = "https://files.pythonhosted.org/packages/1c/8b/e2fc8a75fcb7be12d90b31477c9356c0cbb44abce7ffb36be39a0017afad/numpy-2.2.4-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:3387dd7232804b341165cedcb90694565a6015433ee076c6754775e85d86f1fc", size = 6683092 }, 349 | { url = "https://files.pythonhosted.org/packages/13/73/41b7b27f169ecf368b52533edb72e56a133f9e86256e809e169362553b49/numpy-2.2.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f527d8fdb0286fd2fd97a2a96c6be17ba4232da346931d967a0630050dfd298", size = 14081422 }, 350 | { url = "https://files.pythonhosted.org/packages/4b/04/e208ff3ae3ddfbafc05910f89546382f15a3f10186b1f56bd99f159689c2/numpy-2.2.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bce43e386c16898b91e162e5baaad90c4b06f9dcbe36282490032cec98dc8ae7", size = 16132202 }, 351 | { url = "https://files.pythonhosted.org/packages/fe/bc/2218160574d862d5e55f803d88ddcad88beff94791f9c5f86d67bd8fbf1c/numpy-2.2.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:31504f970f563d99f71a3512d0c01a645b692b12a63630d6aafa0939e52361e6", size = 15573131 }, 352 | { url = "https://files.pythonhosted.org/packages/a5/78/97c775bc4f05abc8a8426436b7cb1be806a02a2994b195945600855e3a25/numpy-2.2.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:81413336ef121a6ba746892fad881a83351ee3e1e4011f52e97fba79233611fd", size = 17894270 }, 353 | { url = "https://files.pythonhosted.org/packages/b9/eb/38c06217a5f6de27dcb41524ca95a44e395e6a1decdc0c99fec0832ce6ae/numpy-2.2.4-cp313-cp313-win32.whl", hash = "sha256:f486038e44caa08dbd97275a9a35a283a8f1d2f0ee60ac260a1790e76660833c", size = 6308141 }, 354 | { url = "https://files.pythonhosted.org/packages/52/17/d0dd10ab6d125c6d11ffb6dfa3423c3571befab8358d4f85cd4471964fcd/numpy-2.2.4-cp313-cp313-win_amd64.whl", hash = "sha256:207a2b8441cc8b6a2a78c9ddc64d00d20c303d79fba08c577752f080c4007ee3", size = 12636885 }, 355 | { url = "https://files.pythonhosted.org/packages/fa/e2/793288ede17a0fdc921172916efb40f3cbc2aa97e76c5c84aba6dc7e8747/numpy-2.2.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8120575cb4882318c791f839a4fd66161a6fa46f3f0a5e613071aae35b5dd8f8", size = 20961829 }, 356 | { url = "https://files.pythonhosted.org/packages/3a/75/bb4573f6c462afd1ea5cbedcc362fe3e9bdbcc57aefd37c681be1155fbaa/numpy-2.2.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a761ba0fa886a7bb33c6c8f6f20213735cb19642c580a931c625ee377ee8bd39", size = 14161419 }, 357 | { url = "https://files.pythonhosted.org/packages/03/68/07b4cd01090ca46c7a336958b413cdbe75002286295f2addea767b7f16c9/numpy-2.2.4-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ac0280f1ba4a4bfff363a99a6aceed4f8e123f8a9b234c89140f5e894e452ecd", size = 5196414 }, 358 | { url = "https://files.pythonhosted.org/packages/a5/fd/d4a29478d622fedff5c4b4b4cedfc37a00691079623c0575978d2446db9e/numpy-2.2.4-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:879cf3a9a2b53a4672a168c21375166171bc3932b7e21f622201811c43cdd3b0", size = 6709379 }, 359 | { url = "https://files.pythonhosted.org/packages/41/78/96dddb75bb9be730b87c72f30ffdd62611aba234e4e460576a068c98eff6/numpy-2.2.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f05d4198c1bacc9124018109c5fba2f3201dbe7ab6e92ff100494f236209c960", size = 14051725 }, 360 | { url = "https://files.pythonhosted.org/packages/00/06/5306b8199bffac2a29d9119c11f457f6c7d41115a335b78d3f86fad4dbe8/numpy-2.2.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2f085ce2e813a50dfd0e01fbfc0c12bbe5d2063d99f8b29da30e544fb6483b8", size = 16101638 }, 361 | { url = "https://files.pythonhosted.org/packages/fa/03/74c5b631ee1ded596945c12027649e6344614144369fd3ec1aaced782882/numpy-2.2.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:92bda934a791c01d6d9d8e038363c50918ef7c40601552a58ac84c9613a665bc", size = 15571717 }, 362 | { url = "https://files.pythonhosted.org/packages/cb/dc/4fc7c0283abe0981e3b89f9b332a134e237dd476b0c018e1e21083310c31/numpy-2.2.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ee4d528022f4c5ff67332469e10efe06a267e32f4067dc76bb7e2cddf3cd25ff", size = 17879998 }, 363 | { url = "https://files.pythonhosted.org/packages/e5/2b/878576190c5cfa29ed896b518cc516aecc7c98a919e20706c12480465f43/numpy-2.2.4-cp313-cp313t-win32.whl", hash = "sha256:05c076d531e9998e7e694c36e8b349969c56eadd2cdcd07242958489d79a7286", size = 6366896 }, 364 | { url = "https://files.pythonhosted.org/packages/3e/05/eb7eec66b95cf697f08c754ef26c3549d03ebd682819f794cb039574a0a6/numpy-2.2.4-cp313-cp313t-win_amd64.whl", hash = "sha256:188dcbca89834cc2e14eb2f106c96d6d46f200fe0200310fc29089657379c58d", size = 12739119 }, 365 | ] 366 | 367 | [[package]] 368 | name = "packaging" 369 | version = "24.2" 370 | source = { registry = "https://pypi.org/simple" } 371 | sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } 372 | wheels = [ 373 | { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, 374 | ] 375 | 376 | [[package]] 377 | name = "pandas" 378 | version = "2.2.3" 379 | source = { registry = "https://pypi.org/simple" } 380 | dependencies = [ 381 | { name = "numpy" }, 382 | { name = "python-dateutil" }, 383 | { name = "pytz" }, 384 | { name = "tzdata" }, 385 | ] 386 | sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 } 387 | wheels = [ 388 | { url = "https://files.pythonhosted.org/packages/a8/44/d9502bf0ed197ba9bf1103c9867d5904ddcaf869e52329787fc54ed70cc8/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:66108071e1b935240e74525006034333f98bcdb87ea116de573a6a0dccb6c039", size = 12602222 }, 389 | { url = "https://files.pythonhosted.org/packages/52/11/9eac327a38834f162b8250aab32a6781339c69afe7574368fffe46387edf/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7c2875855b0ff77b2a64a0365e24455d9990730d6431b9e0ee18ad8acee13dbd", size = 11321274 }, 390 | { url = "https://files.pythonhosted.org/packages/45/fb/c4beeb084718598ba19aa9f5abbc8aed8b42f90930da861fcb1acdb54c3a/pandas-2.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cd8d0c3be0515c12fed0bdbae072551c8b54b7192c7b1fda0ba56059a0179698", size = 15579836 }, 391 | { url = "https://files.pythonhosted.org/packages/cd/5f/4dba1d39bb9c38d574a9a22548c540177f78ea47b32f99c0ff2ec499fac5/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c124333816c3a9b03fbeef3a9f230ba9a737e9e5bb4060aa2107a86cc0a497fc", size = 13058505 }, 392 | { url = "https://files.pythonhosted.org/packages/b9/57/708135b90391995361636634df1f1130d03ba456e95bcf576fada459115a/pandas-2.2.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:63cc132e40a2e084cf01adf0775b15ac515ba905d7dcca47e9a251819c575ef3", size = 16744420 }, 393 | { url = "https://files.pythonhosted.org/packages/86/4a/03ed6b7ee323cf30404265c284cee9c65c56a212e0a08d9ee06984ba2240/pandas-2.2.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:29401dbfa9ad77319367d36940cd8a0b3a11aba16063e39632d98b0e931ddf32", size = 14440457 }, 394 | { url = "https://files.pythonhosted.org/packages/ed/8c/87ddf1fcb55d11f9f847e3c69bb1c6f8e46e2f40ab1a2d2abadb2401b007/pandas-2.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:3fc6873a41186404dad67245896a6e440baacc92f5b716ccd1bc9ed2995ab2c5", size = 11617166 }, 395 | { url = "https://files.pythonhosted.org/packages/17/a3/fb2734118db0af37ea7433f57f722c0a56687e14b14690edff0cdb4b7e58/pandas-2.2.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b1d432e8d08679a40e2a6d8b2f9770a5c21793a6f9f47fdd52c5ce1948a5a8a9", size = 12529893 }, 396 | { url = "https://files.pythonhosted.org/packages/e1/0c/ad295fd74bfac85358fd579e271cded3ac969de81f62dd0142c426b9da91/pandas-2.2.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a5a1595fe639f5988ba6a8e5bc9649af3baf26df3998a0abe56c02609392e0a4", size = 11363475 }, 397 | { url = "https://files.pythonhosted.org/packages/c6/2a/4bba3f03f7d07207481fed47f5b35f556c7441acddc368ec43d6643c5777/pandas-2.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5de54125a92bb4d1c051c0659e6fcb75256bf799a732a87184e5ea503965bce3", size = 15188645 }, 398 | { url = "https://files.pythonhosted.org/packages/38/f8/d8fddee9ed0d0c0f4a2132c1dfcf0e3e53265055da8df952a53e7eaf178c/pandas-2.2.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fffb8ae78d8af97f849404f21411c95062db1496aeb3e56f146f0355c9989319", size = 12739445 }, 399 | { url = "https://files.pythonhosted.org/packages/20/e8/45a05d9c39d2cea61ab175dbe6a2de1d05b679e8de2011da4ee190d7e748/pandas-2.2.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dfcb5ee8d4d50c06a51c2fffa6cff6272098ad6540aed1a76d15fb9318194d8", size = 16359235 }, 400 | { url = "https://files.pythonhosted.org/packages/1d/99/617d07a6a5e429ff90c90da64d428516605a1ec7d7bea494235e1c3882de/pandas-2.2.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:062309c1b9ea12a50e8ce661145c6aab431b1e99530d3cd60640e255778bd43a", size = 14056756 }, 401 | { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 }, 402 | { url = "https://files.pythonhosted.org/packages/64/22/3b8f4e0ed70644e85cfdcd57454686b9057c6c38d2f74fe4b8bc2527214a/pandas-2.2.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f00d1345d84d8c86a63e476bb4955e46458b304b9575dcf71102b5c705320015", size = 12477643 }, 403 | { url = "https://files.pythonhosted.org/packages/e4/93/b3f5d1838500e22c8d793625da672f3eec046b1a99257666c94446969282/pandas-2.2.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3508d914817e153ad359d7e069d752cdd736a247c322d932eb89e6bc84217f28", size = 11281573 }, 404 | { url = "https://files.pythonhosted.org/packages/f5/94/6c79b07f0e5aab1dcfa35a75f4817f5c4f677931d4234afcd75f0e6a66ca/pandas-2.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:22a9d949bfc9a502d320aa04e5d02feab689d61da4e7764b62c30b991c42c5f0", size = 15196085 }, 405 | { url = "https://files.pythonhosted.org/packages/e8/31/aa8da88ca0eadbabd0a639788a6da13bb2ff6edbbb9f29aa786450a30a91/pandas-2.2.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3a255b2c19987fbbe62a9dfd6cff7ff2aa9ccab3fc75218fd4b7530f01efa24", size = 12711809 }, 406 | { url = "https://files.pythonhosted.org/packages/ee/7c/c6dbdb0cb2a4344cacfb8de1c5808ca885b2e4dcfde8008266608f9372af/pandas-2.2.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:800250ecdadb6d9c78eae4990da62743b857b470883fa27f652db8bdde7f6659", size = 16356316 }, 407 | { url = "https://files.pythonhosted.org/packages/57/b7/8b757e7d92023b832869fa8881a992696a0bfe2e26f72c9ae9f255988d42/pandas-2.2.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6374c452ff3ec675a8f46fd9ab25c4ad0ba590b71cf0656f8b6daa5202bca3fb", size = 14022055 }, 408 | { url = "https://files.pythonhosted.org/packages/3b/bc/4b18e2b8c002572c5a441a64826252ce5da2aa738855747247a971988043/pandas-2.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:61c5ad4043f791b61dd4752191d9f07f0ae412515d59ba8f005832a532f8736d", size = 11481175 }, 409 | { url = "https://files.pythonhosted.org/packages/76/a3/a5d88146815e972d40d19247b2c162e88213ef51c7c25993942c39dbf41d/pandas-2.2.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3b71f27954685ee685317063bf13c7709a7ba74fc996b84fc6821c59b0f06468", size = 12615650 }, 410 | { url = "https://files.pythonhosted.org/packages/9c/8c/f0fd18f6140ddafc0c24122c8a964e48294acc579d47def376fef12bcb4a/pandas-2.2.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:38cf8125c40dae9d5acc10fa66af8ea6fdf760b2714ee482ca691fc66e6fcb18", size = 11290177 }, 411 | { url = "https://files.pythonhosted.org/packages/ed/f9/e995754eab9c0f14c6777401f7eece0943840b7a9fc932221c19d1abee9f/pandas-2.2.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ba96630bc17c875161df3818780af30e43be9b166ce51c9a18c1feae342906c2", size = 14651526 }, 412 | { url = "https://files.pythonhosted.org/packages/25/b0/98d6ae2e1abac4f35230aa756005e8654649d305df9a28b16b9ae4353bff/pandas-2.2.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db71525a1538b30142094edb9adc10be3f3e176748cd7acc2240c2f2e5aa3a4", size = 11871013 }, 413 | { url = "https://files.pythonhosted.org/packages/cc/57/0f72a10f9db6a4628744c8e8f0df4e6e21de01212c7c981d31e50ffc8328/pandas-2.2.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:15c0e1e02e93116177d29ff83e8b1619c93ddc9c49083f237d4312337a61165d", size = 15711620 }, 414 | { url = "https://files.pythonhosted.org/packages/ab/5f/b38085618b950b79d2d9164a711c52b10aefc0ae6833b96f626b7021b2ed/pandas-2.2.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ad5b65698ab28ed8d7f18790a0dc58005c7629f227be9ecc1072aa74c0c1d43a", size = 13098436 }, 415 | ] 416 | 417 | [[package]] 418 | name = "platformdirs" 419 | version = "4.3.6" 420 | source = { registry = "https://pypi.org/simple" } 421 | sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } 422 | wheels = [ 423 | { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, 424 | ] 425 | 426 | [[package]] 427 | name = "pluggy" 428 | version = "1.5.0" 429 | source = { registry = "https://pypi.org/simple" } 430 | sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } 431 | wheels = [ 432 | { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, 433 | ] 434 | 435 | [[package]] 436 | name = "pygments" 437 | version = "2.19.1" 438 | source = { registry = "https://pypi.org/simple" } 439 | sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } 440 | wheels = [ 441 | { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, 442 | ] 443 | 444 | [[package]] 445 | name = "pyproject-api" 446 | version = "1.9.0" 447 | source = { registry = "https://pypi.org/simple" } 448 | dependencies = [ 449 | { name = "packaging" }, 450 | ] 451 | sdist = { url = "https://files.pythonhosted.org/packages/7e/66/fdc17e94486836eda4ba7113c0db9ac7e2f4eea1b968ee09de2fe75e391b/pyproject_api-1.9.0.tar.gz", hash = "sha256:7e8a9854b2dfb49454fae421cb86af43efbb2b2454e5646ffb7623540321ae6e", size = 22714 } 452 | wheels = [ 453 | { url = "https://files.pythonhosted.org/packages/b0/1d/92b7c765df46f454889d9610292b0ccab15362be3119b9a624458455e8d5/pyproject_api-1.9.0-py3-none-any.whl", hash = "sha256:326df9d68dea22d9d98b5243c46e3ca3161b07a1b9b18e213d1e24fd0e605766", size = 13131 }, 454 | ] 455 | 456 | [[package]] 457 | name = "pytest" 458 | version = "8.3.5" 459 | source = { registry = "https://pypi.org/simple" } 460 | dependencies = [ 461 | { name = "colorama", marker = "sys_platform == 'win32'" }, 462 | { name = "iniconfig" }, 463 | { name = "packaging" }, 464 | { name = "pluggy" }, 465 | ] 466 | sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } 467 | wheels = [ 468 | { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, 469 | ] 470 | 471 | [[package]] 472 | name = "pytest-cov" 473 | version = "6.0.0" 474 | source = { registry = "https://pypi.org/simple" } 475 | dependencies = [ 476 | { name = "coverage", extra = ["toml"] }, 477 | { name = "pytest" }, 478 | ] 479 | sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 } 480 | wheels = [ 481 | { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 }, 482 | ] 483 | 484 | [[package]] 485 | name = "python-dateutil" 486 | version = "2.9.0.post0" 487 | source = { registry = "https://pypi.org/simple" } 488 | dependencies = [ 489 | { name = "six" }, 490 | ] 491 | sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } 492 | wheels = [ 493 | { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, 494 | ] 495 | 496 | [[package]] 497 | name = "pytz" 498 | version = "2025.1" 499 | source = { registry = "https://pypi.org/simple" } 500 | sdist = { url = "https://files.pythonhosted.org/packages/5f/57/df1c9157c8d5a05117e455d66fd7cf6dbc46974f832b1058ed4856785d8a/pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e", size = 319617 } 501 | wheels = [ 502 | { url = "https://files.pythonhosted.org/packages/eb/38/ac33370d784287baa1c3d538978b5e2ea064d4c1b93ffbd12826c190dd10/pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57", size = 507930 }, 503 | ] 504 | 505 | [[package]] 506 | name = "readme-renderer" 507 | version = "44.0" 508 | source = { registry = "https://pypi.org/simple" } 509 | dependencies = [ 510 | { name = "docutils" }, 511 | { name = "nh3" }, 512 | { name = "pygments" }, 513 | ] 514 | sdist = { url = "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1", size = 32056 } 515 | wheels = [ 516 | { url = "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151", size = 13310 }, 517 | ] 518 | 519 | [[package]] 520 | name = "requests" 521 | version = "2.32.3" 522 | source = { registry = "https://pypi.org/simple" } 523 | dependencies = [ 524 | { name = "certifi" }, 525 | { name = "charset-normalizer" }, 526 | { name = "idna" }, 527 | { name = "urllib3" }, 528 | ] 529 | sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } 530 | wheels = [ 531 | { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, 532 | ] 533 | 534 | [[package]] 535 | name = "roman-numerals-py" 536 | version = "3.1.0" 537 | source = { registry = "https://pypi.org/simple" } 538 | sdist = { url = "https://files.pythonhosted.org/packages/30/76/48fd56d17c5bdbdf65609abbc67288728a98ed4c02919428d4f52d23b24b/roman_numerals_py-3.1.0.tar.gz", hash = "sha256:be4bf804f083a4ce001b5eb7e3c0862479d10f94c936f6c4e5f250aa5ff5bd2d", size = 9017 } 539 | wheels = [ 540 | { url = "https://files.pythonhosted.org/packages/53/97/d2cbbaa10c9b826af0e10fdf836e1bf344d9f0abb873ebc34d1f49642d3f/roman_numerals_py-3.1.0-py3-none-any.whl", hash = "sha256:9da2ad2fb670bcf24e81070ceb3be72f6c11c440d73bd579fbeca1e9f330954c", size = 7742 }, 541 | ] 542 | 543 | [[package]] 544 | name = "ruff" 545 | version = "0.11.0" 546 | source = { registry = "https://pypi.org/simple" } 547 | sdist = { url = "https://files.pythonhosted.org/packages/77/2b/7ca27e854d92df5e681e6527dc0f9254c9dc06c8408317893cf96c851cdd/ruff-0.11.0.tar.gz", hash = "sha256:e55c620690a4a7ee6f1cccb256ec2157dc597d109400ae75bbf944fc9d6462e2", size = 3799407 } 548 | wheels = [ 549 | { url = "https://files.pythonhosted.org/packages/48/40/3d0340a9e5edc77d37852c0cd98c5985a5a8081fc3befaeb2ae90aaafd2b/ruff-0.11.0-py3-none-linux_armv6l.whl", hash = "sha256:dc67e32bc3b29557513eb7eeabb23efdb25753684b913bebb8a0c62495095acb", size = 10098158 }, 550 | { url = "https://files.pythonhosted.org/packages/ec/a9/d8f5abb3b87b973b007649ac7bf63665a05b2ae2b2af39217b09f52abbbf/ruff-0.11.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38c23fd9bdec4eb437b4c1e3595905a0a8edfccd63a790f818b28c78fe345639", size = 10879071 }, 551 | { url = "https://files.pythonhosted.org/packages/ab/62/aaa198614c6211677913ec480415c5e6509586d7b796356cec73a2f8a3e6/ruff-0.11.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7c8661b0be91a38bd56db593e9331beaf9064a79028adee2d5f392674bbc5e88", size = 10247944 }, 552 | { url = "https://files.pythonhosted.org/packages/9f/52/59e0a9f2cf1ce5e6cbe336b6dd0144725c8ea3b97cac60688f4e7880bf13/ruff-0.11.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b6c0e8d3d2db7e9f6efd884f44b8dc542d5b6b590fc4bb334fdbc624d93a29a2", size = 10421725 }, 553 | { url = "https://files.pythonhosted.org/packages/a6/c3/dcd71acc6dff72ce66d13f4be5bca1dbed4db678dff2f0f6f307b04e5c02/ruff-0.11.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c3156d3f4b42e57247275a0a7e15a851c165a4fc89c5e8fa30ea6da4f7407b8", size = 9954435 }, 554 | { url = "https://files.pythonhosted.org/packages/a6/9a/342d336c7c52dbd136dee97d4c7797e66c3f92df804f8f3b30da59b92e9c/ruff-0.11.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:490b1e147c1260545f6d041c4092483e3f6d8eba81dc2875eaebcf9140b53905", size = 11492664 }, 555 | { url = "https://files.pythonhosted.org/packages/84/35/6e7defd2d7ca95cc385ac1bd9f7f2e4a61b9cc35d60a263aebc8e590c462/ruff-0.11.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:1bc09a7419e09662983b1312f6fa5dab829d6ab5d11f18c3760be7ca521c9329", size = 12207856 }, 556 | { url = "https://files.pythonhosted.org/packages/22/78/da669c8731bacf40001c880ada6d31bcfb81f89cc996230c3b80d319993e/ruff-0.11.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcfa478daf61ac8002214eb2ca5f3e9365048506a9d52b11bea3ecea822bb844", size = 11645156 }, 557 | { url = "https://files.pythonhosted.org/packages/ee/47/e27d17d83530a208f4a9ab2e94f758574a04c51e492aa58f91a3ed7cbbcb/ruff-0.11.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6fbb2aed66fe742a6a3a0075ed467a459b7cedc5ae01008340075909d819df1e", size = 13884167 }, 558 | { url = "https://files.pythonhosted.org/packages/9f/5e/42ffbb0a5d4b07bbc642b7d58357b4e19a0f4774275ca6ca7d1f7b5452cd/ruff-0.11.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c0c1ff014351c0b0cdfdb1e35fa83b780f1e065667167bb9502d47ca41e6db", size = 11348311 }, 559 | { url = "https://files.pythonhosted.org/packages/c8/51/dc3ce0c5ce1a586727a3444a32f98b83ba99599bb1ebca29d9302886e87f/ruff-0.11.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e4fd5ff5de5f83e0458a138e8a869c7c5e907541aec32b707f57cf9a5e124445", size = 10305039 }, 560 | { url = "https://files.pythonhosted.org/packages/60/e0/475f0c2f26280f46f2d6d1df1ba96b3399e0234cf368cc4c88e6ad10dcd9/ruff-0.11.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:96bc89a5c5fd21a04939773f9e0e276308be0935de06845110f43fd5c2e4ead7", size = 9937939 }, 561 | { url = "https://files.pythonhosted.org/packages/e2/d3/3e61b7fd3e9cdd1e5b8c7ac188bec12975c824e51c5cd3d64caf81b0331e/ruff-0.11.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a9352b9d767889ec5df1483f94870564e8102d4d7e99da52ebf564b882cdc2c7", size = 10923259 }, 562 | { url = "https://files.pythonhosted.org/packages/30/32/cd74149ebb40b62ddd14bd2d1842149aeb7f74191fb0f49bd45c76909ff2/ruff-0.11.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:049a191969a10897fe052ef9cc7491b3ef6de79acd7790af7d7897b7a9bfbcb6", size = 11406212 }, 563 | { url = "https://files.pythonhosted.org/packages/00/ef/033022a6b104be32e899b00de704d7c6d1723a54d4c9e09d147368f14b62/ruff-0.11.0-py3-none-win32.whl", hash = "sha256:3191e9116b6b5bbe187447656f0c8526f0d36b6fd89ad78ccaad6bdc2fad7df2", size = 10310905 }, 564 | { url = "https://files.pythonhosted.org/packages/ed/8a/163f2e78c37757d035bd56cd60c8d96312904ca4a6deeab8442d7b3cbf89/ruff-0.11.0-py3-none-win_amd64.whl", hash = "sha256:c58bfa00e740ca0a6c43d41fb004cd22d165302f360aaa56f7126d544db31a21", size = 11411730 }, 565 | { url = "https://files.pythonhosted.org/packages/4e/f7/096f6efabe69b49d7ca61052fc70289c05d8d35735c137ef5ba5ef423662/ruff-0.11.0-py3-none-win_arm64.whl", hash = "sha256:868364fc23f5aa122b00c6f794211e85f7e78f5dffdf7c590ab90b8c4e69b657", size = 10538956 }, 566 | ] 567 | 568 | [[package]] 569 | name = "six" 570 | version = "1.17.0" 571 | source = { registry = "https://pypi.org/simple" } 572 | sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } 573 | wheels = [ 574 | { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, 575 | ] 576 | 577 | [[package]] 578 | name = "snowballstemmer" 579 | version = "2.2.0" 580 | source = { registry = "https://pypi.org/simple" } 581 | sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 } 582 | wheels = [ 583 | { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 }, 584 | ] 585 | 586 | [[package]] 587 | name = "sphinx" 588 | version = "8.2.3" 589 | source = { registry = "https://pypi.org/simple" } 590 | dependencies = [ 591 | { name = "alabaster" }, 592 | { name = "babel" }, 593 | { name = "colorama", marker = "sys_platform == 'win32'" }, 594 | { name = "docutils" }, 595 | { name = "imagesize" }, 596 | { name = "jinja2" }, 597 | { name = "packaging" }, 598 | { name = "pygments" }, 599 | { name = "requests" }, 600 | { name = "roman-numerals-py" }, 601 | { name = "snowballstemmer" }, 602 | { name = "sphinxcontrib-applehelp" }, 603 | { name = "sphinxcontrib-devhelp" }, 604 | { name = "sphinxcontrib-htmlhelp" }, 605 | { name = "sphinxcontrib-jsmath" }, 606 | { name = "sphinxcontrib-qthelp" }, 607 | { name = "sphinxcontrib-serializinghtml" }, 608 | ] 609 | sdist = { url = "https://files.pythonhosted.org/packages/38/ad/4360e50ed56cb483667b8e6dadf2d3fda62359593faabbe749a27c4eaca6/sphinx-8.2.3.tar.gz", hash = "sha256:398ad29dee7f63a75888314e9424d40f52ce5a6a87ae88e7071e80af296ec348", size = 8321876 } 610 | wheels = [ 611 | { url = "https://files.pythonhosted.org/packages/31/53/136e9eca6e0b9dc0e1962e2c908fbea2e5ac000c2a2fbd9a35797958c48b/sphinx-8.2.3-py3-none-any.whl", hash = "sha256:4405915165f13521d875a8c29c8970800a0141c14cc5416a38feca4ea5d9b9c3", size = 3589741 }, 612 | ] 613 | 614 | [[package]] 615 | name = "sphinx-rtd-theme" 616 | version = "3.0.2" 617 | source = { registry = "https://pypi.org/simple" } 618 | dependencies = [ 619 | { name = "docutils" }, 620 | { name = "sphinx" }, 621 | { name = "sphinxcontrib-jquery" }, 622 | ] 623 | sdist = { url = "https://files.pythonhosted.org/packages/91/44/c97faec644d29a5ceddd3020ae2edffa69e7d00054a8c7a6021e82f20335/sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85", size = 7620463 } 624 | wheels = [ 625 | { url = "https://files.pythonhosted.org/packages/85/77/46e3bac77b82b4df5bb5b61f2de98637724f246b4966cfc34bc5895d852a/sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13", size = 7655561 }, 626 | ] 627 | 628 | [[package]] 629 | name = "sphinxcontrib-applehelp" 630 | version = "2.0.0" 631 | source = { registry = "https://pypi.org/simple" } 632 | sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 } 633 | wheels = [ 634 | { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 }, 635 | ] 636 | 637 | [[package]] 638 | name = "sphinxcontrib-devhelp" 639 | version = "2.0.0" 640 | source = { registry = "https://pypi.org/simple" } 641 | sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 } 642 | wheels = [ 643 | { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 }, 644 | ] 645 | 646 | [[package]] 647 | name = "sphinxcontrib-htmlhelp" 648 | version = "2.1.0" 649 | source = { registry = "https://pypi.org/simple" } 650 | sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 } 651 | wheels = [ 652 | { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 }, 653 | ] 654 | 655 | [[package]] 656 | name = "sphinxcontrib-jquery" 657 | version = "4.1" 658 | source = { registry = "https://pypi.org/simple" } 659 | dependencies = [ 660 | { name = "sphinx" }, 661 | ] 662 | sdist = { url = "https://files.pythonhosted.org/packages/de/f3/aa67467e051df70a6330fe7770894b3e4f09436dea6881ae0b4f3d87cad8/sphinxcontrib-jquery-4.1.tar.gz", hash = "sha256:1620739f04e36a2c779f1a131a2dfd49b2fd07351bf1968ced074365933abc7a", size = 122331 } 663 | wheels = [ 664 | { url = "https://files.pythonhosted.org/packages/76/85/749bd22d1a68db7291c89e2ebca53f4306c3f205853cf31e9de279034c3c/sphinxcontrib_jquery-4.1-py2.py3-none-any.whl", hash = "sha256:f936030d7d0147dd026a4f2b5a57343d233f1fc7b363f68b3d4f1cb0993878ae", size = 121104 }, 665 | ] 666 | 667 | [[package]] 668 | name = "sphinxcontrib-jsmath" 669 | version = "1.0.1" 670 | source = { registry = "https://pypi.org/simple" } 671 | sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 } 672 | wheels = [ 673 | { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 }, 674 | ] 675 | 676 | [[package]] 677 | name = "sphinxcontrib-qthelp" 678 | version = "2.0.0" 679 | source = { registry = "https://pypi.org/simple" } 680 | sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 } 681 | wheels = [ 682 | { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 }, 683 | ] 684 | 685 | [[package]] 686 | name = "sphinxcontrib-serializinghtml" 687 | version = "2.0.0" 688 | source = { registry = "https://pypi.org/simple" } 689 | sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 } 690 | wheels = [ 691 | { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 }, 692 | ] 693 | 694 | [[package]] 695 | name = "tapy" 696 | version = "1.10.0" 697 | source = { editable = "." } 698 | dependencies = [ 699 | { name = "pandas" }, 700 | ] 701 | 702 | [package.dev-dependencies] 703 | dev = [ 704 | { name = "pytest" }, 705 | { name = "pytest-cov" }, 706 | { name = "tox" }, 707 | ] 708 | dev-docs = [ 709 | { name = "readme-renderer" }, 710 | { name = "sphinx" }, 711 | { name = "sphinx-rtd-theme" }, 712 | ] 713 | dev-linters = [ 714 | { name = "isort" }, 715 | { name = "ruff" }, 716 | ] 717 | 718 | [package.metadata] 719 | requires-dist = [{ name = "pandas", specifier = ">=2.2" }] 720 | 721 | [package.metadata.requires-dev] 722 | dev = [ 723 | { name = "pytest", specifier = ">=8.2.2" }, 724 | { name = "pytest-cov", specifier = ">=5.0.0" }, 725 | { name = "tox", specifier = ">=4.16.0" }, 726 | ] 727 | dev-docs = [ 728 | { name = "readme-renderer", specifier = ">=43.0" }, 729 | { name = "sphinx", specifier = ">=7.3.7" }, 730 | { name = "sphinx-rtd-theme", specifier = ">=2.0.0" }, 731 | ] 732 | dev-linters = [ 733 | { name = "isort", specifier = ">=5.13" }, 734 | { name = "ruff", specifier = ">=0.4.9" }, 735 | ] 736 | 737 | [[package]] 738 | name = "tomli" 739 | version = "2.2.1" 740 | source = { registry = "https://pypi.org/simple" } 741 | sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } 742 | wheels = [ 743 | { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, 744 | { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, 745 | { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, 746 | { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, 747 | { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, 748 | { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, 749 | { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, 750 | { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, 751 | { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, 752 | { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, 753 | { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, 754 | { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, 755 | { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, 756 | { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, 757 | { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, 758 | { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, 759 | { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, 760 | { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, 761 | { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, 762 | { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, 763 | { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, 764 | { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, 765 | { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, 766 | { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, 767 | { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, 768 | { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, 769 | { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, 770 | { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, 771 | { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, 772 | { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, 773 | { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, 774 | ] 775 | 776 | [[package]] 777 | name = "tox" 778 | version = "4.24.2" 779 | source = { registry = "https://pypi.org/simple" } 780 | dependencies = [ 781 | { name = "cachetools" }, 782 | { name = "chardet" }, 783 | { name = "colorama" }, 784 | { name = "filelock" }, 785 | { name = "packaging" }, 786 | { name = "platformdirs" }, 787 | { name = "pluggy" }, 788 | { name = "pyproject-api" }, 789 | { name = "virtualenv" }, 790 | ] 791 | sdist = { url = "https://files.pythonhosted.org/packages/51/93/30e4d662748d8451acde46feca03886b85bd74a453691d56abc44ef4bd37/tox-4.24.2.tar.gz", hash = "sha256:d5948b350f76fae436d6545a5e87c2b676ab7a0d7d88c1308651245eadbe8aea", size = 195354 } 792 | wheels = [ 793 | { url = "https://files.pythonhosted.org/packages/7b/eb/f7e6e77a664a96163cc1e7f9829f2e01b5b99aeb1edf0cdf1cd95859f310/tox-4.24.2-py3-none-any.whl", hash = "sha256:92e8290e76ad4e15748860a205865696409a2d014eedeb796a34a0f3b5e7336e", size = 172155 }, 794 | ] 795 | 796 | [[package]] 797 | name = "tzdata" 798 | version = "2025.1" 799 | source = { registry = "https://pypi.org/simple" } 800 | sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 } 801 | wheels = [ 802 | { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 }, 803 | ] 804 | 805 | [[package]] 806 | name = "urllib3" 807 | version = "2.3.0" 808 | source = { registry = "https://pypi.org/simple" } 809 | sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } 810 | wheels = [ 811 | { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, 812 | ] 813 | 814 | [[package]] 815 | name = "virtualenv" 816 | version = "20.29.3" 817 | source = { registry = "https://pypi.org/simple" } 818 | dependencies = [ 819 | { name = "distlib" }, 820 | { name = "filelock" }, 821 | { name = "platformdirs" }, 822 | ] 823 | sdist = { url = "https://files.pythonhosted.org/packages/c7/9c/57d19fa093bcf5ac61a48087dd44d00655f85421d1aa9722f8befbf3f40a/virtualenv-20.29.3.tar.gz", hash = "sha256:95e39403fcf3940ac45bc717597dba16110b74506131845d9b687d5e73d947ac", size = 4320280 } 824 | wheels = [ 825 | { url = "https://files.pythonhosted.org/packages/c2/eb/c6db6e3001d58c6a9e67c74bb7b4206767caa3ccc28c6b9eaf4c23fb4e34/virtualenv-20.29.3-py3-none-any.whl", hash = "sha256:3e3d00f5807e83b234dfb6122bf37cfadf4be216c53a49ac059d02414f819170", size = 4301458 }, 826 | ] 827 | --------------------------------------------------------------------------------