From 3662e699e6db1371f7c79171d41c909fed276c93 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 5 Sep 2023 13:57:44 +0200 Subject: [PATCH 01/59] changed to poetry --- .github/workflows/ci-on-pullreq.yaml | 11 +- .github/workflows/ci-on-push.yaml | 10 +- MANIFEST.in | 6 - poetry.lock | 1309 +++++++++++++++ poetry.toml | 2 + pyproject.toml | 39 + requirements-dev.txt | 4 - requirements-test.txt | 6 - requirements.txt | 8 - setup.py | 20 - versioneer.py | 2189 -------------------------- 11 files changed, 1362 insertions(+), 2242 deletions(-) delete mode 100644 MANIFEST.in create mode 100644 poetry.lock create mode 100644 poetry.toml create mode 100644 pyproject.toml delete mode 100644 requirements-dev.txt delete mode 100644 requirements-test.txt delete mode 100644 requirements.txt delete mode 100644 setup.py delete mode 100644 versioneer.py diff --git a/.github/workflows/ci-on-pullreq.yaml b/.github/workflows/ci-on-pullreq.yaml index c29eb91..e6fa5d6 100644 --- a/.github/workflows/ci-on-pullreq.yaml +++ b/.github/workflows/ci-on-pullreq.yaml @@ -23,12 +23,13 @@ jobs: - name: Install run: | - pip install -e . - pip install -r requirements-dev.txt - pip install -r requirements-test.txt - + pip install poetry + poetry install --with dev --with test + - name: Run tests - run: pytest + run: | + pytest + poetry shell - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v1 diff --git a/.github/workflows/ci-on-push.yaml b/.github/workflows/ci-on-push.yaml index 86616e3..cabb927 100644 --- a/.github/workflows/ci-on-push.yaml +++ b/.github/workflows/ci-on-push.yaml @@ -23,12 +23,14 @@ jobs: - name: Install run: | - pip install -e . - pip install -r requirements-dev.txt - pip install -r requirements-test.txt + pip install poetry + poetry install --with dev test - name: Run tests - run: python -B -m pytest -m "not only_on_pr" + run: | + poetry shell + python -B -m pytest -m "not only_on_pr" + - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 1289af6..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include README.rst -include LICENSE -include requirements.txt -include versioneer.py -include portfolyo/_version.py -include portfolyo/tools/unitdefinitions.txt \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..169da18 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,1309 @@ +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. + +[[package]] +name = "black" +version = "23.7.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.8" +files = [ + {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, + {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, + {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, + {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, + {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, + {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, + {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, + {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, + {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, + {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, + {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, + {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, + {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, + {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, + {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "certifi" +version = "2023.7.22" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, +] + +[[package]] +name = "cfgv" +version = "3.4.0" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, + {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.2.0" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, + {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "codecov" +version = "2.1.13" +description = "Hosted coverage reports for GitHub, Bitbucket and Gitlab" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "codecov-2.1.13-py2.py3-none-any.whl", hash = "sha256:c2ca5e51bba9ebb43644c43d0690148a55086f7f5e6fd36170858fa4206744d5"}, + {file = "codecov-2.1.13.tar.gz", hash = "sha256:2362b685633caeaf45b9951a9b76ce359cd3581dd515b430c6c3f5dfb4d92a8c"}, +] + +[package.dependencies] +coverage = "*" +requests = ">=2.7.9" + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "contourpy" +version = "1.1.0" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, + {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, + {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, + {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, + {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, + {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, + {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, + {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, + {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, + {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, + {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, + {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, + {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, + {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, + {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, + {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, +] + +[package.dependencies] +numpy = ">=1.16" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + +[[package]] +name = "coverage" +version = "7.3.0" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, + {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, + {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, + {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, + {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, + {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, + {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, + {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, + {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, + {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, + {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, + {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, + {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, + {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, + {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, + {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, + {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, + {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, + {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, + {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, + {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, + {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, + {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, + {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, + {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, + {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, + {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, + {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cycler" +version = "0.11.0" +description = "Composable style cycles" +optional = false +python-versions = ">=3.6" +files = [ + {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, + {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, +] + +[[package]] +name = "distlib" +version = "0.3.7" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, + {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, +] + +[[package]] +name = "et-xmlfile" +version = "1.1.0" +description = "An implementation of lxml.xmlfile for the standard library" +optional = false +python-versions = ">=3.6" +files = [ + {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, + {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.12.3" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.8" +files = [ + {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"}, + {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flake8" +version = "6.1.0" +description = "the modular source code checker: pep8 pyflakes and co" +optional = false +python-versions = ">=3.8.1" +files = [ + {file = "flake8-6.1.0-py2.py3-none-any.whl", hash = "sha256:ffdfce58ea94c6580c77888a86506937f9a1a227dfcd15f245d694ae20a6b6e5"}, + {file = "flake8-6.1.0.tar.gz", hash = "sha256:d5b3857f07c030bdb5bf41c7f53799571d75c4491748a3adcd47de929e34cd23"}, +] + +[package.dependencies] +mccabe = ">=0.7.0,<0.8.0" +pycodestyle = ">=2.11.0,<2.12.0" +pyflakes = ">=3.1.0,<3.2.0" + +[[package]] +name = "fonttools" +version = "4.42.1" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"}, + {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"}, + {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"}, + {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"}, + {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"}, + {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"}, + {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"}, + {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"}, + {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"}, + {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"}, + {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"}, + {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"}, + {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"}, + {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"}, + {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"}, + {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"}, + {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"}, + {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"}, + {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"}, + {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"}, + {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"}, + {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"}, + {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"}, + {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"}, + {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"}, + {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"}, + {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"}, + {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"}, + {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"}, + {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"}, + {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"}, + {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"}, + {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"}, + {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "scipy"] +lxml = ["lxml (>=4.0,<5)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.0.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + +[[package]] +name = "holidays" +version = "0.32" +description = "Generate and work with holidays in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "holidays-0.32-py3-none-any.whl", hash = "sha256:4a28233488f0f3bf6c95fc01f92acddb103177b6c7a73b128b1c6878f622e268"}, + {file = "holidays-0.32.tar.gz", hash = "sha256:7ff9b90dbf35085f31589050d6173ca44e98ab27551b29f7696ccfa5b13ef0e6"}, +] + +[package.dependencies] +python-dateutil = "*" + +[[package]] +name = "identify" +version = "2.5.27" +description = "File identification library for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"}, + {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "importlib-resources" +version = "6.0.1" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_resources-6.0.1-py3-none-any.whl", hash = "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf"}, + {file = "importlib_resources-6.0.1.tar.gz", hash = "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "kiwisolver" +version = "1.4.5" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + +[[package]] +name = "matplotlib" +version = "3.7.2" +description = "Python plotting package" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, + {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, + {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, + {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, + {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, + {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, + {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, + {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, + {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, + {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, + {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, + {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, + {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, + {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, + {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, + {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, + {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, + {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, + {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, + {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} +kiwisolver = ">=1.0.1" +numpy = ">=1.20" +packaging = ">=20.0" +pillow = ">=6.2.0" +pyparsing = ">=2.3.1,<3.1" +python-dateutil = ">=2.7" + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "numpy" +version = "1.25.2" +description = "Fundamental package for array computing in Python" +optional = false +python-versions = ">=3.9" +files = [ + {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, + {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, + {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, + {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, + {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, + {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, + {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, + {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, + {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, + {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, + {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, + {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, + {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, + {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, + {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, + {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, + {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, + {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, +] + +[[package]] +name = "openpyxl" +version = "3.1.2" +description = "A Python library to read/write Excel 2010 xlsx/xlsm files" +optional = false +python-versions = ">=3.6" +files = [ + {file = "openpyxl-3.1.2-py2.py3-none-any.whl", hash = "sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5"}, + {file = "openpyxl-3.1.2.tar.gz", hash = "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184"}, +] + +[package.dependencies] +et-xmlfile = "*" + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pandas" +version = "2.1.0" +description = "Powerful data structures for data analysis, time series, and statistics" +optional = false +python-versions = ">=3.9" +files = [ + {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, + {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, + {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, + {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, + {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, + {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, + {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, + {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, + {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, + {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, + {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, + {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, + {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, + {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, + {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, + {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, + {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, + {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, + {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, +] +python-dateutil = ">=2.8.2" +pytz = ">=2020.1" +tzdata = ">=2022.1" + +[package.extras] +all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] +aws = ["s3fs (>=2022.05.0)"] +clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] +compression = ["zstandard (>=0.17.0)"] +computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] +consortium-standard = ["dataframe-api-compat (>=0.1.7)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] +feather = ["pyarrow (>=7.0.0)"] +fss = ["fsspec (>=2022.05.0)"] +gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] +hdf5 = ["tables (>=3.7.0)"] +html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] +mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] +parquet = ["pyarrow (>=7.0.0)"] +performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] +plot = ["matplotlib (>=3.6.1)"] +postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] +spss = ["pyreadstat (>=1.1.5)"] +sql-other = ["SQLAlchemy (>=1.4.36)"] +test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.8.0)"] + +[[package]] +name = "pathspec" +version = "0.11.2" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, +] + +[[package]] +name = "pillow" +version = "10.0.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, + {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, + {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, + {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, + {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, + {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, + {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, + {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, + {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, + {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, + {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, + {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, + {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, + {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, + {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, + {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, + {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, + {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, + {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, + {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, + {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, + {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, + {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, + {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, + {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, + {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "pint" +version = "0.22" +description = "Physical quantities module" +optional = false +python-versions = ">=3.9" +files = [ + {file = "Pint-0.22-py3-none-any.whl", hash = "sha256:6e2b3c5c2b4d9b516608bc860a417a39d66eb99c958f36540cf931d2c2e9f80f"}, + {file = "Pint-0.22.tar.gz", hash = "sha256:2d139f6abbcf3016cad7d3cec05707fe908ac4f99cf59aedfd6ee667b7a64433"}, +] + +[package.dependencies] +typing-extensions = "*" + +[package.extras] +babel = ["babel (<=2.8)"] +dask = ["dask"] +mip = ["mip (>=1.13)"] +numpy = ["numpy (>=1.19.5)"] +pandas = ["pint-pandas (>=0.3)"] +test = ["pytest", "pytest-cov", "pytest-mpl", "pytest-subtests"] +uncertainties = ["uncertainties (>=3.1.6)"] +xarray = ["xarray"] + +[[package]] +name = "pint-pandas" +version = "0.4" +description = "Extend Pandas Dataframe with Physical quantities module" +optional = false +python-versions = ">=3.9" +files = [ + {file = "Pint-Pandas-0.4.tar.gz", hash = "sha256:58eb37dabcfb62e9b2fe21df1a59f1371e6d007f3ee5f1403f00489d8b11548d"}, + {file = "Pint_Pandas-0.4-py3-none-any.whl", hash = "sha256:1e2e8766eaec24360c8d4c14486423ac26f4547205f87d88c926132491d8d596"}, +] + +[package.extras] +test = ["codecov", "coveralls", "nbval", "pyarrow", "pytest", "pytest-cov", "pytest-mpl", "pytest-subtests"] + +[[package]] +name = "platformdirs" +version = "3.10.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, + {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, +] + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "3.4.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"}, + {file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "pycodestyle" +version = "2.11.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"}, + {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, +] + +[[package]] +name = "pyflakes" +version = "3.1.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pyflakes-3.1.0-py2.py3-none-any.whl", hash = "sha256:4132f6d49cb4dae6819e5379898f2b8cce3c5f23994194c24b77d5da2e36f774"}, + {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, +] + +[[package]] +name = "pyparsing" +version = "3.0.9" +description = "pyparsing module - Classes and methods to define and execute parsing grammars" +optional = false +python-versions = ">=3.6.8" +files = [ + {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, + {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, +] + +[package.extras] +diagrams = ["jinja2", "railroad-diagrams"] + +[[package]] +name = "pytest" +version = "7.4.1" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.1-py3-none-any.whl", hash = "sha256:460c9a59b14e27c602eb5ece2e47bec99dc5fc5f6513cf924a7d03a578991b1f"}, + {file = "pytest-7.4.1.tar.gz", hash = "sha256:2f2301e797521b23e4d2585a0a3d7b5e50fdddaaf7e7d6773ea26ddb17c213ab"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.1.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-cov-4.1.0.tar.gz", hash = "sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6"}, + {file = "pytest_cov-4.1.0-py3-none-any.whl", hash = "sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2023.3.post1" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "setuptools" +version = "68.1.2" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, + {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "tzdata" +version = "2023.3" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, + {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, +] + +[[package]] +name = "urllib3" +version = "2.0.4" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, + {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "virtualenv" +version = "20.24.4" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.24.4-py3-none-any.whl", hash = "sha256:29c70bb9b88510f6414ac3e55c8b413a1f96239b6b789ca123437d5e892190cb"}, + {file = "virtualenv-20.24.4.tar.gz", hash = "sha256:772b05bfda7ed3b8ecd16021ca9716273ad9f4467c801f27e83ac73430246dca"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<4" + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] + +[[package]] +name = "zipp" +version = "3.16.2" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, + {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9" +content-hash = "8171f85b1d99e76140725c73800280e599f18bb05cb64d2c90fe76996efa0412" diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 0000000..ab1033b --- /dev/null +++ b/poetry.toml @@ -0,0 +1,2 @@ +[virtualenvs] +in-project = true diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..44db816 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,39 @@ +[tool.poetry] +name = "portfolyo" +version = "0.5.4" +description = "Analyse and manipulate timeseries related to power and gas offtake portfolios" +authors = [ + "Ruud Wijtvliet ", + "Sakshi Singh ", +] +license = "BSD-3" +readme = "README.rst" + +[tool.poetry.dependencies] +python = "^3.9" +pandas = "^2" +numpy = "^1.25.2" +matplotlib = "^3.7.2" +pint = "^0.22" +pint-pandas = "^0.4" +colorama = "^0.4.6" +holidays = "^0.32" + + +[tool.poetry.group.test.dependencies] +codecov = "^2.1.13" +coverage = "^7.3.0" +pytest = "^7.4.1" +pytest-cov = "^4.1.0" +pyyaml = "^6.0.1" +openpyxl = "^3.1.2" + + +[tool.poetry.group.dev.dependencies] +flake8 = "^6.1.0" +black = "^23.7.0" +pre-commit = "^3.4.0" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements-dev.txt b/requirements-dev.txt deleted file mode 100644 index e65c944..0000000 --- a/requirements-dev.txt +++ /dev/null @@ -1,4 +0,0 @@ -flake8 -black -pre-commit -openpyxl \ No newline at end of file diff --git a/requirements-test.txt b/requirements-test.txt deleted file mode 100644 index 464028b..0000000 --- a/requirements-test.txt +++ /dev/null @@ -1,6 +0,0 @@ -codecov==2.1.13 -coverage -pytest-cov -pytest -pyyaml -openpyxl \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bd42d5b..0000000 --- a/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -# List required packages in this file, one per line. -numpy -pandas>=2 -matplotlib -pint<=0.19.2 -pint-pandas -colorama -holidays diff --git a/setup.py b/setup.py deleted file mode 100644 index 3ea0dac..0000000 --- a/setup.py +++ /dev/null @@ -1,20 +0,0 @@ -from setuptools import find_packages, setup - -import versioneer - -setup( - name="portfolyo", - version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), - author="Ruud Wijtvliet", - zip_safe=False, - packages=find_packages(exclude=["tests"]), - description="Analysing and manipulating timeseries related to power and gas offtake portfolios.", - long_description=open("README.rst").read(), - long_description_content_type="text/x-rst", - python_requires=">=3.8", - install_requires=[line.strip() for line in open("requirements.txt", "r")], - # package_data is data that is deployed within the python package on the - # user's system. setuptools will get whatever is listed in MANIFEST.in - include_package_data=True, -) diff --git a/versioneer.py b/versioneer.py deleted file mode 100644 index 189d097..0000000 --- a/versioneer.py +++ /dev/null @@ -1,2189 +0,0 @@ -# Version: 0.22 - -"""The Versioneer - like a rocketeer, but for versions. - -The Versioneer -============== - -* like a rocketeer, but for versions! -* https://github.com/python-versioneer/python-versioneer -* Brian Warner -* License: Public Domain -* Compatible with: Python 3.6, 3.7, 3.8, 3.9, 3.10 and pypy3 -* [![Latest Version][pypi-image]][pypi-url] -* [![Build Status][travis-image]][travis-url] - -This is a tool for managing a recorded version number in distutils/setuptools-based -python projects. The goal is to remove the tedious and error-prone "update -the embedded version string" step from your release process. Making a new -release should be as easy as recording a new tag in your version-control -system, and maybe making new tarballs. - - -## Quick Install - -* `pip install versioneer` to somewhere in your $PATH -* add a `[versioneer]` section to your setup.cfg (see [Install](INSTALL.md)) -* run `versioneer install` in your source tree, commit the results -* Verify version information with `python setup.py version` - -## Version Identifiers - -Source trees come from a variety of places: - -* a version-control system checkout (mostly used by developers) -* a nightly tarball, produced by build automation -* a snapshot tarball, produced by a web-based VCS browser, like github's - "tarball from tag" feature -* a release tarball, produced by "setup.py sdist", distributed through PyPI - -Within each source tree, the version identifier (either a string or a number, -this tool is format-agnostic) can come from a variety of places: - -* ask the VCS tool itself, e.g. "git describe" (for checkouts), which knows - about recent "tags" and an absolute revision-id -* the name of the directory into which the tarball was unpacked -* an expanded VCS keyword ($Id$, etc) -* a `_version.py` created by some earlier build step - -For released software, the version identifier is closely related to a VCS -tag. Some projects use tag names that include more than just the version -string (e.g. "myproject-1.2" instead of just "1.2"), in which case the tool -needs to strip the tag prefix to extract the version identifier. For -unreleased software (between tags), the version identifier should provide -enough information to help developers recreate the same tree, while also -giving them an idea of roughly how old the tree is (after version 1.2, before -version 1.3). Many VCS systems can report a description that captures this, -for example `git describe --tags --dirty --always` reports things like -"0.7-1-g574ab98-dirty" to indicate that the checkout is one revision past the -0.7 tag, has a unique revision id of "574ab98", and is "dirty" (it has -uncommitted changes). - -The version identifier is used for multiple purposes: - -* to allow the module to self-identify its version: `myproject.__version__` -* to choose a name and prefix for a 'setup.py sdist' tarball - -## Theory of Operation - -Versioneer works by adding a special `_version.py` file into your source -tree, where your `__init__.py` can import it. This `_version.py` knows how to -dynamically ask the VCS tool for version information at import time. - -`_version.py` also contains `$Revision$` markers, and the installation -process marks `_version.py` to have this marker rewritten with a tag name -during the `git archive` command. As a result, generated tarballs will -contain enough information to get the proper version. - -To allow `setup.py` to compute a version too, a `versioneer.py` is added to -the top level of your source tree, next to `setup.py` and the `setup.cfg` -that configures it. This overrides several distutils/setuptools commands to -compute the version when invoked, and changes `setup.py build` and `setup.py -sdist` to replace `_version.py` with a small static file that contains just -the generated version data. - -## Installation - -See [INSTALL.md](./INSTALL.md) for detailed installation instructions. - -## Version-String Flavors - -Code which uses Versioneer can learn about its version string at runtime by -importing `_version` from your main `__init__.py` file and running the -`get_versions()` function. From the "outside" (e.g. in `setup.py`), you can -import the top-level `versioneer.py` and run `get_versions()`. - -Both functions return a dictionary with different flavors of version -information: - -* `['version']`: A condensed version string, rendered using the selected - style. This is the most commonly used value for the project's version - string. The default "pep440" style yields strings like `0.11`, - `0.11+2.g1076c97`, or `0.11+2.g1076c97.dirty`. See the "Styles" section - below for alternative styles. - -* `['full-revisionid']`: detailed revision identifier. For Git, this is the - full SHA1 commit id, e.g. "1076c978a8d3cfc70f408fe5974aa6c092c949ac". - -* `['date']`: Date and time of the latest `HEAD` commit. For Git, it is the - commit date in ISO 8601 format. This will be None if the date is not - available. - -* `['dirty']`: a boolean, True if the tree has uncommitted changes. Note that - this is only accurate if run in a VCS checkout, otherwise it is likely to - be False or None - -* `['error']`: if the version string could not be computed, this will be set - to a string describing the problem, otherwise it will be None. It may be - useful to throw an exception in setup.py if this is set, to avoid e.g. - creating tarballs with a version string of "unknown". - -Some variants are more useful than others. Including `full-revisionid` in a -bug report should allow developers to reconstruct the exact code being tested -(or indicate the presence of local changes that should be shared with the -developers). `version` is suitable for display in an "about" box or a CLI -`--version` output: it can be easily compared against release notes and lists -of bugs fixed in various releases. - -The installer adds the following text to your `__init__.py` to place a basic -version in `YOURPROJECT.__version__`: - - from ._version import get_versions - __version__ = get_versions()['version'] - del get_versions - -## Styles - -The setup.cfg `style=` configuration controls how the VCS information is -rendered into a version string. - -The default style, "pep440", produces a PEP440-compliant string, equal to the -un-prefixed tag name for actual releases, and containing an additional "local -version" section with more detail for in-between builds. For Git, this is -TAG[+DISTANCE.gHEX[.dirty]] , using information from `git describe --tags ---dirty --always`. For example "0.11+2.g1076c97.dirty" indicates that the -tree is like the "1076c97" commit but has uncommitted changes (".dirty"), and -that this commit is two revisions ("+2") beyond the "0.11" tag. For released -software (exactly equal to a known tag), the identifier will only contain the -stripped tag, e.g. "0.11". - -Other styles are available. See [details.md](details.md) in the Versioneer -source tree for descriptions. - -## Debugging - -Versioneer tries to avoid fatal errors: if something goes wrong, it will tend -to return a version of "0+unknown". To investigate the problem, run `setup.py -version`, which will run the version-lookup code in a verbose mode, and will -display the full contents of `get_versions()` (including the `error` string, -which may help identify what went wrong). - -## Known Limitations - -Some situations are known to cause problems for Versioneer. This details the -most significant ones. More can be found on Github -[issues page](https://github.com/python-versioneer/python-versioneer/issues). - -### Subprojects - -Versioneer has limited support for source trees in which `setup.py` is not in -the root directory (e.g. `setup.py` and `.git/` are *not* siblings). The are -two common reasons why `setup.py` might not be in the root: - -* Source trees which contain multiple subprojects, such as - [Buildbot](https://github.com/buildbot/buildbot), which contains both - "master" and "slave" subprojects, each with their own `setup.py`, - `setup.cfg`, and `tox.ini`. Projects like these produce multiple PyPI - distributions (and upload multiple independently-installable tarballs). -* Source trees whose main purpose is to contain a C library, but which also - provide bindings to Python (and perhaps other languages) in subdirectories. - -Versioneer will look for `.git` in parent directories, and most operations -should get the right version string. However `pip` and `setuptools` have bugs -and implementation details which frequently cause `pip install .` from a -subproject directory to fail to find a correct version string (so it usually -defaults to `0+unknown`). - -`pip install --editable .` should work correctly. `setup.py install` might -work too. - -Pip-8.1.1 is known to have this problem, but hopefully it will get fixed in -some later version. - -[Bug #38](https://github.com/python-versioneer/python-versioneer/issues/38) is tracking -this issue. The discussion in -[PR #61](https://github.com/python-versioneer/python-versioneer/pull/61) describes the -issue from the Versioneer side in more detail. -[pip PR#3176](https://github.com/pypa/pip/pull/3176) and -[pip PR#3615](https://github.com/pypa/pip/pull/3615) contain work to improve -pip to let Versioneer work correctly. - -Versioneer-0.16 and earlier only looked for a `.git` directory next to the -`setup.cfg`, so subprojects were completely unsupported with those releases. - -### Editable installs with setuptools <= 18.5 - -`setup.py develop` and `pip install --editable .` allow you to install a -project into a virtualenv once, then continue editing the source code (and -test) without re-installing after every change. - -"Entry-point scripts" (`setup(entry_points={"console_scripts": ..})`) are a -convenient way to specify executable scripts that should be installed along -with the python package. - -These both work as expected when using modern setuptools. When using -setuptools-18.5 or earlier, however, certain operations will cause -`pkg_resources.DistributionNotFound` errors when running the entrypoint -script, which must be resolved by re-installing the package. This happens -when the install happens with one version, then the egg_info data is -regenerated while a different version is checked out. Many setup.py commands -cause egg_info to be rebuilt (including `sdist`, `wheel`, and installing into -a different virtualenv), so this can be surprising. - -[Bug #83](https://github.com/python-versioneer/python-versioneer/issues/83) describes -this one, but upgrading to a newer version of setuptools should probably -resolve it. - - -## Updating Versioneer - -To upgrade your project to a new release of Versioneer, do the following: - -* install the new Versioneer (`pip install -U versioneer` or equivalent) -* edit `setup.cfg`, if necessary, to include any new configuration settings - indicated by the release notes. See [UPGRADING](./UPGRADING.md) for details. -* re-run `versioneer install` in your source tree, to replace - `SRC/_version.py` -* commit any changed files - -## Future Directions - -This tool is designed to make it easily extended to other version-control -systems: all VCS-specific components are in separate directories like -src/git/ . The top-level `versioneer.py` script is assembled from these -components by running make-versioneer.py . In the future, make-versioneer.py -will take a VCS name as an argument, and will construct a version of -`versioneer.py` that is specific to the given VCS. It might also take the -configuration arguments that are currently provided manually during -installation by editing setup.py . Alternatively, it might go the other -direction and include code from all supported VCS systems, reducing the -number of intermediate scripts. - -## Similar projects - -* [setuptools_scm](https://github.com/pypa/setuptools_scm/) - a non-vendored build-time - dependency -* [minver](https://github.com/jbweston/miniver) - a lightweight reimplementation of - versioneer -* [versioningit](https://github.com/jwodder/versioningit) - a PEP 518-based setuptools - plugin - -## License - -To make Versioneer easier to embed, all its code is dedicated to the public -domain. The `_version.py` that it creates is also in the public domain. -Specifically, both are released under the Creative Commons "Public Domain -Dedication" license (CC0-1.0), as described in -https://creativecommons.org/publicdomain/zero/1.0/ . - -[pypi-image]: https://img.shields.io/pypi/v/versioneer.svg -[pypi-url]: https://pypi.python.org/pypi/versioneer/ -[travis-image]: -https://img.shields.io/travis/com/python-versioneer/python-versioneer.svg -[travis-url]: https://travis-ci.com/github/python-versioneer/python-versioneer - -""" -# pylint:disable=invalid-name,import-outside-toplevel,missing-function-docstring -# pylint:disable=missing-class-docstring,too-many-branches,too-many-statements -# pylint:disable=raise-missing-from,too-many-lines,too-many-locals,import-error -# pylint:disable=too-few-public-methods,redefined-outer-name,consider-using-with -# pylint:disable=attribute-defined-outside-init,too-many-arguments - -import configparser -import errno -import functools -import json -import os -import re -import subprocess -import sys -from typing import Callable, Dict - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_root(): - """Get the project root directory. - - We require that all commands are run from the project root, i.e. the - directory that contains setup.py, setup.cfg, and versioneer.py . - """ - root = os.path.realpath(os.path.abspath(os.getcwd())) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - # allow 'python path/to/setup.py COMMAND' - root = os.path.dirname(os.path.realpath(os.path.abspath(sys.argv[0]))) - setup_py = os.path.join(root, "setup.py") - versioneer_py = os.path.join(root, "versioneer.py") - if not (os.path.exists(setup_py) or os.path.exists(versioneer_py)): - err = ( - "Versioneer was unable to run the project root directory. " - "Versioneer requires setup.py to be executed from " - "its immediate directory (like 'python setup.py COMMAND'), " - "or in a way that lets it use sys.argv[0] to find the root " - "(like 'python path/to/setup.py COMMAND')." - ) - raise VersioneerBadRootError(err) - try: - # Certain runtime workflows (setup.py install/develop in a setuptools - # tree) execute all dependencies in a single python process, so - # "versioneer" may be imported multiple times, and python's shared - # module-import table will cache the first one. So we can't use - # os.path.dirname(__file__), as that will find whichever - # versioneer.py was first imported, even in later projects. - my_path = os.path.realpath(os.path.abspath(__file__)) - me_dir = os.path.normcase(os.path.splitext(my_path)[0]) - vsr_dir = os.path.normcase(os.path.splitext(versioneer_py)[0]) - if me_dir != vsr_dir: - print( - "Warning: build in %s is using versioneer.py from %s" - % (os.path.dirname(my_path), versioneer_py) - ) - except NameError: - pass - return root - - -def get_config_from_root(root): - """Read the project setup.cfg file to determine Versioneer config.""" - # This might raise OSError (if setup.cfg is missing), or - # configparser.NoSectionError (if it lacks a [versioneer] section), or - # configparser.NoOptionError (if it lacks "VCS="). See the docstring at - # the top of versioneer.py for instructions on writing your setup.cfg . - setup_cfg = os.path.join(root, "setup.cfg") - parser = configparser.ConfigParser() - with open(setup_cfg, "r") as cfg_file: - parser.read_file(cfg_file) - VCS = parser.get("versioneer", "VCS") # mandatory - - # Dict-like interface for non-mandatory entries - section = parser["versioneer"] - - cfg = VersioneerConfig() - cfg.VCS = VCS - cfg.style = section.get("style", "") - cfg.versionfile_source = section.get("versionfile_source") - cfg.versionfile_build = section.get("versionfile_build") - cfg.tag_prefix = section.get("tag_prefix") - if cfg.tag_prefix in ("''", '""'): - cfg.tag_prefix = "" - cfg.parentdir_prefix = section.get("parentdir_prefix") - cfg.verbose = section.get("verbose") - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -# these dictionaries contain VCS-specific tools -LONG_VERSION_PY: Dict[str, str] = {} -HANDLERS: Dict[str, Dict[str, Callable]] = {} - - -def register_vcs_handler(vcs, method): # decorator - """Create decorator to mark a method as the handler of a VCS.""" - - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - HANDLERS.setdefault(vcs, {})[method] = f - return f - - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - process = None - - popen_kwargs = {} - if sys.platform == "win32": - # This hides the console window if pythonw.exe is used - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - popen_kwargs["startupinfo"] = startupinfo - - for command in commands: - try: - dispcmd = str([command] + args) - # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen( - [command] + args, - cwd=cwd, - env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr else None), - **popen_kwargs, - ) - break - except OSError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %s" % dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %s" % (commands,)) - return None, None - stdout = process.communicate()[0].strip().decode() - if process.returncode != 0: - if verbose: - print("unable to run %s (error)" % dispcmd) - print("stdout was %s" % stdout) - return None, process.returncode - return stdout, process.returncode - - -LONG_VERSION_PY[ - "git" -] = r''' -# This file helps to compute a version number in source trees obtained from -# git-archive tarball (such as those provided by githubs download-from-tag -# feature). Distribution tarballs (built by setup.py sdist) and build -# directories (produced by setup.py build) will contain a much shorter file -# that just contains the computed version number. - -# This file is released into the public domain. Generated by -# versioneer-0.22 (https://github.com/python-versioneer/python-versioneer) - -"""Git implementation of _version.py.""" - -import errno -import os -import re -import subprocess -import sys -from typing import Callable, Dict -import functools - - -def get_keywords(): - """Get the keywords needed to look up the version information.""" - # these strings will be replaced by git during git-archive. - # setup.py/versioneer.py will grep for the variable names, so they must - # each be defined on a line of their own. _version.py will just call - # get_keywords(). - git_refnames = "%(DOLLAR)sFormat:%%d%(DOLLAR)s" - git_full = "%(DOLLAR)sFormat:%%H%(DOLLAR)s" - git_date = "%(DOLLAR)sFormat:%%ci%(DOLLAR)s" - keywords = {"refnames": git_refnames, "full": git_full, "date": git_date} - return keywords - - -class VersioneerConfig: - """Container for Versioneer configuration parameters.""" - - -def get_config(): - """Create, populate and return the VersioneerConfig() object.""" - # these strings are filled in when 'setup.py versioneer' creates - # _version.py - cfg = VersioneerConfig() - cfg.VCS = "git" - cfg.style = "%(STYLE)s" - cfg.tag_prefix = "%(TAG_PREFIX)s" - cfg.parentdir_prefix = "%(PARENTDIR_PREFIX)s" - cfg.versionfile_source = "%(VERSIONFILE_SOURCE)s" - cfg.verbose = False - return cfg - - -class NotThisMethod(Exception): - """Exception raised if a method is not valid for the current scenario.""" - - -LONG_VERSION_PY: Dict[str, str] = {} -HANDLERS: Dict[str, Dict[str, Callable]] = {} - - -def register_vcs_handler(vcs, method): # decorator - """Create decorator to mark a method as the handler of a VCS.""" - def decorate(f): - """Store f in HANDLERS[vcs][method].""" - if vcs not in HANDLERS: - HANDLERS[vcs] = {} - HANDLERS[vcs][method] = f - return f - return decorate - - -def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False, - env=None): - """Call the given command(s).""" - assert isinstance(commands, list) - process = None - - popen_kwargs = {} - if sys.platform == "win32": - # This hides the console window if pythonw.exe is used - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - popen_kwargs["startupinfo"] = startupinfo - - for command in commands: - try: - dispcmd = str([command] + args) - # remember shell=False, so use git.cmd on windows, not just git - process = subprocess.Popen([command] + args, cwd=cwd, env=env, - stdout=subprocess.PIPE, - stderr=(subprocess.PIPE if hide_stderr - else None), **popen_kwargs) - break - except OSError: - e = sys.exc_info()[1] - if e.errno == errno.ENOENT: - continue - if verbose: - print("unable to run %%s" %% dispcmd) - print(e) - return None, None - else: - if verbose: - print("unable to find command, tried %%s" %% (commands,)) - return None, None - stdout = process.communicate()[0].strip().decode() - if process.returncode != 0: - if verbose: - print("unable to run %%s (error)" %% dispcmd) - print("stdout was %%s" %% stdout) - return None, process.returncode - return stdout, process.returncode - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for _ in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return {"version": dirname[len(parentdir_prefix):], - "full-revisionid": None, - "dirty": False, "error": None, "date": None} - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print("Tried directories %%s but none started with prefix %%s" %% - (str(rootdirs), parentdir_prefix)) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - with open(versionfile_abs, "r") as fobj: - for line in fobj: - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - except OSError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if "refnames" not in keywords: - raise NotThisMethod("Short version file found") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = {r.strip() for r in refnames.strip("()").split(",")} - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = {r[len(TAG):] for r in refs if r.startswith(TAG)} - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %%d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = {r for r in refs if re.search(r'\d', r)} - if verbose: - print("discarding '%%s', no digits" %% ",".join(refs - tags)) - if verbose: - print("likely tags: %%s" %% ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix):] - # Filter out refs that exactly match prefix or that don't start - # with a number once the prefix is stripped (mostly a concern - # when prefix is '') - if not re.match(r'\d', r): - continue - if verbose: - print("picking %%s" %% r) - return {"version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": None, - "date": date} - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return {"version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, "error": "no suitable tags", "date": None} - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - # GIT_DIR can interfere with correct operation of Versioneer. - # It may be intended to be passed to the Versioneer-versioned project, - # but that should not change where we get our version from. - env = os.environ.copy() - env.pop("GIT_DIR", None) - runner = functools.partial(runner, env=env) - - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, - hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %%s not under git control" %% root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - MATCH_ARGS = ["--match", "%%s*" %% tag_prefix] if tag_prefix else [] - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner(GITS, ["describe", "--tags", "--dirty", - "--always", "--long", *MATCH_ARGS], - cwd=root) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], - cwd=root) - # --abbrev-ref was added in git-1.6.3 - if rc != 0 or branch_name is None: - raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") - branch_name = branch_name.strip() - - if branch_name == "HEAD": - # If we aren't exactly on a branch, pick a branch which represents - # the current commit. If all else fails, we are on a branchless - # commit. - branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) - # --contains was added in git-1.5.4 - if rc != 0 or branches is None: - raise NotThisMethod("'git branch --contains' returned error") - branches = branches.split("\n") - - # Remove the first line if we're running detached - if "(" in branches[0]: - branches.pop(0) - - # Strip off the leading "* " from the list of branches. - branches = [branch[2:] for branch in branches] - if "master" in branches: - branch_name = "master" - elif not branches: - branch_name = None - else: - # Pick the first branch that is returned. Good or bad. - branch_name = branches[0] - - pieces["branch"] = branch_name - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[:git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe) - if not mo: - # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = ("unable to parse git-describe output: '%%s'" - %% describe_out) - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%%s' doesn't start with prefix '%%s'" - print(fmt %% (full_tag, tag_prefix)) - pieces["error"] = ("tag '%%s' doesn't start with prefix '%%s'" - %% (full_tag, tag_prefix)) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix):] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = runner(GITS, ["rev-list", "HEAD", "--count"], cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = runner(GITS, ["show", "-s", "--format=%%ci", "HEAD"], cwd=root)[0].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_branch(pieces): - """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . - - The ".dev0" means not master branch. Note that .dev0 sorts backwards - (a feature branch will appear "older" than the master branch). - - Exceptions: - 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "%%d.g%%s" %% (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+untagged.%%d.g%%s" %% (pieces["distance"], - pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def pep440_split_post(ver): - """Split pep440 version string at the post-release segment. - - Returns the release segments before the post-release and the - post-release version number (or -1 if no post-release segment is present). - """ - vc = str.split(ver, ".post") - return vc[0], int(vc[1] or 0) if len(vc) == 2 else None - - -def render_pep440_pre(pieces): - """TAG[.postN.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - if pieces["distance"]: - # update the post release segment - tag_version, post_version = pep440_split_post(pieces["closest-tag"]) - rendered = tag_version - if post_version is not None: - rendered += ".post%%d.dev%%d" %% (post_version+1, pieces["distance"]) - else: - rendered += ".post0.dev%%d" %% (pieces["distance"]) - else: - # no commits, use the tag as the version - rendered = pieces["closest-tag"] - else: - # exception #1 - rendered = "0.post0.dev%%d" %% pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - return rendered - - -def render_pep440_post_branch(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . - - The ".dev0" means not master branch. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%%s" %% pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+g%%s" %% pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%%d" %% pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%%d-g%%s" %% (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return {"version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None} - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-branch": - rendered = render_pep440_branch(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-post-branch": - rendered = render_pep440_post_branch(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%%s'" %% style) - - return {"version": rendered, "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], "error": None, - "date": pieces.get("date")} - - -def get_versions(): - """Get version information or return default if unable to do so.""" - # I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have - # __file__, we can work backwards from there to the root. Some - # py2exe/bbfreeze/non-CPython implementations don't do __file__, in which - # case we can only use expanded keywords. - - cfg = get_config() - verbose = cfg.verbose - - try: - return git_versions_from_keywords(get_keywords(), cfg.tag_prefix, - verbose) - except NotThisMethod: - pass - - try: - root = os.path.realpath(__file__) - # versionfile_source is the relative path from the top of the source - # tree (where the .git directory might live) to this file. Invert - # this to find the root from __file__. - for _ in cfg.versionfile_source.split('/'): - root = os.path.dirname(root) - except NameError: - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to find root of source tree", - "date": None} - - try: - pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose) - return render(pieces, cfg.style) - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - return versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - except NotThisMethod: - pass - - return {"version": "0+unknown", "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", "date": None} -''' - - -@register_vcs_handler("git", "get_keywords") -def git_get_keywords(versionfile_abs): - """Extract version information from the given file.""" - # the code embedded in _version.py can just fetch the value of these - # keywords. When used from setup.py, we don't want to import _version.py, - # so we do it with a regexp instead. This function is not used from - # _version.py. - keywords = {} - try: - with open(versionfile_abs, "r") as fobj: - for line in fobj: - if line.strip().startswith("git_refnames ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["refnames"] = mo.group(1) - if line.strip().startswith("git_full ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["full"] = mo.group(1) - if line.strip().startswith("git_date ="): - mo = re.search(r'=\s*"(.*)"', line) - if mo: - keywords["date"] = mo.group(1) - except OSError: - pass - return keywords - - -@register_vcs_handler("git", "keywords") -def git_versions_from_keywords(keywords, tag_prefix, verbose): - """Get version information from git keywords.""" - if "refnames" not in keywords: - raise NotThisMethod("Short version file found") - date = keywords.get("date") - if date is not None: - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - - # git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant - # datestamp. However we prefer "%ci" (which expands to an "ISO-8601 - # -like" string, which we must then edit to make compliant), because - # it's been around since git-1.5.3, and it's too difficult to - # discover which version we're using, or to work around using an - # older one. - date = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - refnames = keywords["refnames"].strip() - if refnames.startswith("$Format"): - if verbose: - print("keywords are unexpanded, not using") - raise NotThisMethod("unexpanded keywords, not a git-archive tarball") - refs = {r.strip() for r in refnames.strip("()").split(",")} - # starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of - # just "foo-1.0". If we see a "tag: " prefix, prefer those. - TAG = "tag: " - tags = {r[len(TAG) :] for r in refs if r.startswith(TAG)} - if not tags: - # Either we're using git < 1.8.3, or there really are no tags. We use - # a heuristic: assume all version tags have a digit. The old git %d - # expansion behaves like git log --decorate=short and strips out the - # refs/heads/ and refs/tags/ prefixes that would let us distinguish - # between branches and tags. By ignoring refnames without digits, we - # filter out many common branch names like "release" and - # "stabilization", as well as "HEAD" and "master". - tags = {r for r in refs if re.search(r"\d", r)} - if verbose: - print("discarding '%s', no digits" % ",".join(refs - tags)) - if verbose: - print("likely tags: %s" % ",".join(sorted(tags))) - for ref in sorted(tags): - # sorting will prefer e.g. "2.0" over "2.0rc1" - if ref.startswith(tag_prefix): - r = ref[len(tag_prefix) :] - # Filter out refs that exactly match prefix or that don't start - # with a number once the prefix is stripped (mostly a concern - # when prefix is '') - if not re.match(r"\d", r): - continue - if verbose: - print("picking %s" % r) - return { - "version": r, - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": None, - "date": date, - } - # no suitable tags, so version is "0+unknown", but full hex is still there - if verbose: - print("no suitable tags, using unknown + full revision id") - return { - "version": "0+unknown", - "full-revisionid": keywords["full"].strip(), - "dirty": False, - "error": "no suitable tags", - "date": None, - } - - -@register_vcs_handler("git", "pieces_from_vcs") -def git_pieces_from_vcs(tag_prefix, root, verbose, runner=run_command): - """Get version from 'git describe' in the root of the source tree. - - This only gets called if the git-archive 'subst' keywords were *not* - expanded, and _version.py hasn't already been rewritten with a short - version string, meaning we're inside a checked out source tree. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - - # GIT_DIR can interfere with correct operation of Versioneer. - # It may be intended to be passed to the Versioneer-versioned project, - # but that should not change where we get our version from. - env = os.environ.copy() - env.pop("GIT_DIR", None) - runner = functools.partial(runner, env=env) - - _, rc = runner(GITS, ["rev-parse", "--git-dir"], cwd=root, hide_stderr=True) - if rc != 0: - if verbose: - print("Directory %s not under git control" % root) - raise NotThisMethod("'git rev-parse --git-dir' returned error") - - MATCH_ARGS = ["--match", "%s*" % tag_prefix] if tag_prefix else [] - - # if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty] - # if there isn't one, this yields HEX[-dirty] (no NUM) - describe_out, rc = runner( - GITS, - ["describe", "--tags", "--dirty", "--always", "--long", *MATCH_ARGS], - cwd=root, - ) - # --long was added in git-1.5.5 - if describe_out is None: - raise NotThisMethod("'git describe' failed") - describe_out = describe_out.strip() - full_out, rc = runner(GITS, ["rev-parse", "HEAD"], cwd=root) - if full_out is None: - raise NotThisMethod("'git rev-parse' failed") - full_out = full_out.strip() - - pieces = {} - pieces["long"] = full_out - pieces["short"] = full_out[:7] # maybe improved later - pieces["error"] = None - - branch_name, rc = runner(GITS, ["rev-parse", "--abbrev-ref", "HEAD"], cwd=root) - # --abbrev-ref was added in git-1.6.3 - if rc != 0 or branch_name is None: - raise NotThisMethod("'git rev-parse --abbrev-ref' returned error") - branch_name = branch_name.strip() - - if branch_name == "HEAD": - # If we aren't exactly on a branch, pick a branch which represents - # the current commit. If all else fails, we are on a branchless - # commit. - branches, rc = runner(GITS, ["branch", "--contains"], cwd=root) - # --contains was added in git-1.5.4 - if rc != 0 or branches is None: - raise NotThisMethod("'git branch --contains' returned error") - branches = branches.split("\n") - - # Remove the first line if we're running detached - if "(" in branches[0]: - branches.pop(0) - - # Strip off the leading "* " from the list of branches. - branches = [branch[2:] for branch in branches] - if "master" in branches: - branch_name = "master" - elif not branches: - branch_name = None - else: - # Pick the first branch that is returned. Good or bad. - branch_name = branches[0] - - pieces["branch"] = branch_name - - # parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty] - # TAG might have hyphens. - git_describe = describe_out - - # look for -dirty suffix - dirty = git_describe.endswith("-dirty") - pieces["dirty"] = dirty - if dirty: - git_describe = git_describe[: git_describe.rindex("-dirty")] - - # now we have TAG-NUM-gHEX or HEX - - if "-" in git_describe: - # TAG-NUM-gHEX - mo = re.search(r"^(.+)-(\d+)-g([0-9a-f]+)$", git_describe) - if not mo: - # unparsable. Maybe git-describe is misbehaving? - pieces["error"] = "unable to parse git-describe output: '%s'" % describe_out - return pieces - - # tag - full_tag = mo.group(1) - if not full_tag.startswith(tag_prefix): - if verbose: - fmt = "tag '%s' doesn't start with prefix '%s'" - print(fmt % (full_tag, tag_prefix)) - pieces["error"] = "tag '%s' doesn't start with prefix '%s'" % ( - full_tag, - tag_prefix, - ) - return pieces - pieces["closest-tag"] = full_tag[len(tag_prefix) :] - - # distance: number of commits since tag - pieces["distance"] = int(mo.group(2)) - - # commit: short hex revision ID - pieces["short"] = mo.group(3) - - else: - # HEX: no tags - pieces["closest-tag"] = None - count_out, rc = runner(GITS, ["rev-list", "HEAD", "--count"], cwd=root) - pieces["distance"] = int(count_out) # total number of commits - - # commit date: see ISO-8601 comment in git_versions_from_keywords() - date = runner(GITS, ["show", "-s", "--format=%ci", "HEAD"], cwd=root)[0].strip() - # Use only the last line. Previous lines may contain GPG signature - # information. - date = date.splitlines()[-1] - pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1) - - return pieces - - -def do_vcs_install(manifest_in, versionfile_source, ipy): - """Git-specific installation logic for Versioneer. - - For Git, this means creating/changing .gitattributes to mark _version.py - for export-subst keyword substitution. - """ - GITS = ["git"] - if sys.platform == "win32": - GITS = ["git.cmd", "git.exe"] - files = [manifest_in, versionfile_source] - if ipy: - files.append(ipy) - try: - my_path = __file__ - if my_path.endswith(".pyc") or my_path.endswith(".pyo"): - my_path = os.path.splitext(my_path)[0] + ".py" - versioneer_file = os.path.relpath(my_path) - except NameError: - versioneer_file = "versioneer.py" - files.append(versioneer_file) - present = False - try: - with open(".gitattributes", "r") as fobj: - for line in fobj: - if line.strip().startswith(versionfile_source): - if "export-subst" in line.strip().split()[1:]: - present = True - break - except OSError: - pass - if not present: - with open(".gitattributes", "a+") as fobj: - fobj.write(f"{versionfile_source} export-subst\n") - files.append(".gitattributes") - run_command(GITS, ["add", "--"] + files) - - -def versions_from_parentdir(parentdir_prefix, root, verbose): - """Try to determine the version from the parent directory name. - - Source tarballs conventionally unpack into a directory that includes both - the project name and a version string. We will also support searching up - two directory levels for an appropriately named parent directory - """ - rootdirs = [] - - for _ in range(3): - dirname = os.path.basename(root) - if dirname.startswith(parentdir_prefix): - return { - "version": dirname[len(parentdir_prefix) :], - "full-revisionid": None, - "dirty": False, - "error": None, - "date": None, - } - rootdirs.append(root) - root = os.path.dirname(root) # up a level - - if verbose: - print( - "Tried directories %s but none started with prefix %s" - % (str(rootdirs), parentdir_prefix) - ) - raise NotThisMethod("rootdir doesn't start with parentdir_prefix") - - -SHORT_VERSION_PY = """ -# This file was generated by 'versioneer.py' (0.22) from -# revision-control system data, or from the parent directory name of an -# unpacked source archive. Distribution tarballs contain a pre-generated copy -# of this file. - -import json - -version_json = ''' -%s -''' # END VERSION_JSON - - -def get_versions(): - return json.loads(version_json) -""" - - -def versions_from_file(filename): - """Try to determine the version from _version.py if present.""" - try: - with open(filename) as f: - contents = f.read() - except OSError: - raise NotThisMethod("unable to read _version.py") - mo = re.search( - r"version_json = '''\n(.*)''' # END VERSION_JSON", contents, re.M | re.S - ) - if not mo: - mo = re.search( - r"version_json = '''\r\n(.*)''' # END VERSION_JSON", contents, re.M | re.S - ) - if not mo: - raise NotThisMethod("no version_json in _version.py") - return json.loads(mo.group(1)) - - -def write_to_version_file(filename, versions): - """Write the given version number to the given _version.py file.""" - os.unlink(filename) - contents = json.dumps(versions, sort_keys=True, indent=1, separators=(",", ": ")) - with open(filename, "w") as f: - f.write(SHORT_VERSION_PY % contents) - - print("set %s to '%s'" % (filename, versions["version"])) - - -def plus_or_dot(pieces): - """Return a + if we don't already have one, else return a .""" - if "+" in pieces.get("closest-tag", ""): - return "." - return "+" - - -def render_pep440(pieces): - """Build up version string, with post-release "local version identifier". - - Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you - get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty - - Exceptions: - 1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_branch(pieces): - """TAG[[.dev0]+DISTANCE.gHEX[.dirty]] . - - The ".dev0" means not master branch. Note that .dev0 sorts backwards - (a feature branch will appear "older" than the master branch). - - Exceptions: - 1: no tags. 0[.dev0]+untagged.DISTANCE.gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0" - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+untagged.%d.g%s" % (pieces["distance"], pieces["short"]) - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def pep440_split_post(ver): - """Split pep440 version string at the post-release segment. - - Returns the release segments before the post-release and the - post-release version number (or -1 if no post-release segment is present). - """ - vc = str.split(ver, ".post") - return vc[0], int(vc[1] or 0) if len(vc) == 2 else None - - -def render_pep440_pre(pieces): - """TAG[.postN.devDISTANCE] -- No -dirty. - - Exceptions: - 1: no tags. 0.post0.devDISTANCE - """ - if pieces["closest-tag"]: - if pieces["distance"]: - # update the post release segment - tag_version, post_version = pep440_split_post(pieces["closest-tag"]) - rendered = tag_version - if post_version is not None: - rendered += ".post%d.dev%d" % (post_version + 1, pieces["distance"]) - else: - rendered += ".post0.dev%d" % (pieces["distance"]) - else: - # no commits, use the tag as the version - rendered = pieces["closest-tag"] - else: - # exception #1 - rendered = "0.post0.dev%d" % pieces["distance"] - return rendered - - -def render_pep440_post(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX] . - - The ".dev0" means dirty. Note that .dev0 sorts backwards - (a dirty tree will appear "older" than the corresponding clean one), - but you shouldn't be releasing software with -dirty anyways. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - return rendered - - -def render_pep440_post_branch(pieces): - """TAG[.postDISTANCE[.dev0]+gHEX[.dirty]] . - - The ".dev0" means not master branch. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0]+gHEX[.dirty] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += plus_or_dot(pieces) - rendered += "g%s" % pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["branch"] != "master": - rendered += ".dev0" - rendered += "+g%s" % pieces["short"] - if pieces["dirty"]: - rendered += ".dirty" - return rendered - - -def render_pep440_old(pieces): - """TAG[.postDISTANCE[.dev0]] . - - The ".dev0" means dirty. - - Exceptions: - 1: no tags. 0.postDISTANCE[.dev0] - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"] or pieces["dirty"]: - rendered += ".post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - else: - # exception #1 - rendered = "0.post%d" % pieces["distance"] - if pieces["dirty"]: - rendered += ".dev0" - return rendered - - -def render_git_describe(pieces): - """TAG[-DISTANCE-gHEX][-dirty]. - - Like 'git describe --tags --dirty --always'. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - if pieces["distance"]: - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render_git_describe_long(pieces): - """TAG-DISTANCE-gHEX[-dirty]. - - Like 'git describe --tags --dirty --always -long'. - The distance/hash is unconditional. - - Exceptions: - 1: no tags. HEX[-dirty] (note: no 'g' prefix) - """ - if pieces["closest-tag"]: - rendered = pieces["closest-tag"] - rendered += "-%d-g%s" % (pieces["distance"], pieces["short"]) - else: - # exception #1 - rendered = pieces["short"] - if pieces["dirty"]: - rendered += "-dirty" - return rendered - - -def render(pieces, style): - """Render the given version pieces into the requested style.""" - if pieces["error"]: - return { - "version": "unknown", - "full-revisionid": pieces.get("long"), - "dirty": None, - "error": pieces["error"], - "date": None, - } - - if not style or style == "default": - style = "pep440" # the default - - if style == "pep440": - rendered = render_pep440(pieces) - elif style == "pep440-branch": - rendered = render_pep440_branch(pieces) - elif style == "pep440-pre": - rendered = render_pep440_pre(pieces) - elif style == "pep440-post": - rendered = render_pep440_post(pieces) - elif style == "pep440-post-branch": - rendered = render_pep440_post_branch(pieces) - elif style == "pep440-old": - rendered = render_pep440_old(pieces) - elif style == "git-describe": - rendered = render_git_describe(pieces) - elif style == "git-describe-long": - rendered = render_git_describe_long(pieces) - else: - raise ValueError("unknown style '%s'" % style) - - return { - "version": rendered, - "full-revisionid": pieces["long"], - "dirty": pieces["dirty"], - "error": None, - "date": pieces.get("date"), - } - - -class VersioneerBadRootError(Exception): - """The project root directory is unknown or missing key files.""" - - -def get_versions(verbose=False): - """Get the project version from whatever source is available. - - Returns dict with two keys: 'version' and 'full'. - """ - if "versioneer" in sys.modules: - # see the discussion in cmdclass.py:get_cmdclass() - del sys.modules["versioneer"] - - root = get_root() - cfg = get_config_from_root(root) - - assert cfg.VCS is not None, "please set [versioneer]VCS= in setup.cfg" - handlers = HANDLERS.get(cfg.VCS) - assert handlers, "unrecognized VCS '%s'" % cfg.VCS - verbose = verbose or cfg.verbose - assert ( - cfg.versionfile_source is not None - ), "please set versioneer.versionfile_source" - assert cfg.tag_prefix is not None, "please set versioneer.tag_prefix" - - versionfile_abs = os.path.join(root, cfg.versionfile_source) - - # extract version from first of: _version.py, VCS command (e.g. 'git - # describe'), parentdir. This is meant to work for developers using a - # source checkout, for users of a tarball created by 'setup.py sdist', - # and for users of a tarball/zipball created by 'git archive' or github's - # download-from-tag feature or the equivalent in other VCSes. - - get_keywords_f = handlers.get("get_keywords") - from_keywords_f = handlers.get("keywords") - if get_keywords_f and from_keywords_f: - try: - keywords = get_keywords_f(versionfile_abs) - ver = from_keywords_f(keywords, cfg.tag_prefix, verbose) - if verbose: - print("got version from expanded keyword %s" % ver) - return ver - except NotThisMethod: - pass - - try: - ver = versions_from_file(versionfile_abs) - if verbose: - print("got version from file %s %s" % (versionfile_abs, ver)) - return ver - except NotThisMethod: - pass - - from_vcs_f = handlers.get("pieces_from_vcs") - if from_vcs_f: - try: - pieces = from_vcs_f(cfg.tag_prefix, root, verbose) - ver = render(pieces, cfg.style) - if verbose: - print("got version from VCS %s" % ver) - return ver - except NotThisMethod: - pass - - try: - if cfg.parentdir_prefix: - ver = versions_from_parentdir(cfg.parentdir_prefix, root, verbose) - if verbose: - print("got version from parentdir %s" % ver) - return ver - except NotThisMethod: - pass - - if verbose: - print("unable to compute version") - - return { - "version": "0+unknown", - "full-revisionid": None, - "dirty": None, - "error": "unable to compute version", - "date": None, - } - - -def get_version(): - """Get the short version string for this project.""" - return get_versions()["version"] - - -def get_cmdclass(cmdclass=None): - """Get the custom setuptools/distutils subclasses used by Versioneer. - - If the package uses a different cmdclass (e.g. one from numpy), it - should be provide as an argument. - """ - if "versioneer" in sys.modules: - del sys.modules["versioneer"] - # this fixes the "python setup.py develop" case (also 'install' and - # 'easy_install .'), in which subdependencies of the main project are - # built (using setup.py bdist_egg) in the same python process. Assume - # a main project A and a dependency B, which use different versions - # of Versioneer. A's setup.py imports A's Versioneer, leaving it in - # sys.modules by the time B's setup.py is executed, causing B to run - # with the wrong versioneer. Setuptools wraps the sub-dep builds in a - # sandbox that restores sys.modules to it's pre-build state, so the - # parent is protected against the child's "import versioneer". By - # removing ourselves from sys.modules here, before the child build - # happens, we protect the child from the parent's versioneer too. - # Also see https://github.com/python-versioneer/python-versioneer/issues/52 - - cmds = {} if cmdclass is None else cmdclass.copy() - - # we add "version" to both distutils and setuptools - try: - from setuptools import Command - except ImportError: - from distutils.core import Command - - class cmd_version(Command): - description = "report generated version string" - user_options = [] - boolean_options = [] - - def initialize_options(self): - pass - - def finalize_options(self): - pass - - def run(self): - vers = get_versions(verbose=True) - print("Version: %s" % vers["version"]) - print(" full-revisionid: %s" % vers.get("full-revisionid")) - print(" dirty: %s" % vers.get("dirty")) - print(" date: %s" % vers.get("date")) - if vers["error"]: - print(" error: %s" % vers["error"]) - - cmds["version"] = cmd_version - - # we override "build_py" in both distutils and setuptools - # - # most invocation pathways end up running build_py: - # distutils/build -> build_py - # distutils/install -> distutils/build ->.. - # setuptools/bdist_wheel -> distutils/install ->.. - # setuptools/bdist_egg -> distutils/install_lib -> build_py - # setuptools/install -> bdist_egg ->.. - # setuptools/develop -> ? - # pip install: - # copies source tree to a tempdir before running egg_info/etc - # if .git isn't copied too, 'git describe' will fail - # then does setup.py bdist_wheel, or sometimes setup.py install - # setup.py egg_info -> ? - - # we override different "build_py" commands for both environments - if "build_py" in cmds: - _build_py = cmds["build_py"] - elif "setuptools" in sys.modules: - from setuptools.command.build_py import build_py as _build_py - else: - from distutils.command.build_py import build_py as _build_py - - class cmd_build_py(_build_py): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_py.run(self) - # now locate _version.py in the new build/ directory and replace - # it with an updated value - if cfg.versionfile_build: - target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - cmds["build_py"] = cmd_build_py - - if "build_ext" in cmds: - _build_ext = cmds["build_ext"] - elif "setuptools" in sys.modules: - from setuptools.command.build_ext import build_ext as _build_ext - else: - from distutils.command.build_ext import build_ext as _build_ext - - class cmd_build_ext(_build_ext): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - _build_ext.run(self) - if self.inplace: - # build_ext --inplace will only build extensions in - # build/lib<..> dir with no _version.py to write to. - # As in place builds will already have a _version.py - # in the module dir, we do not need to write one. - return - # now locate _version.py in the new build/ directory and replace - # it with an updated value - target_versionfile = os.path.join(self.build_lib, cfg.versionfile_build) - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - cmds["build_ext"] = cmd_build_ext - - if "cx_Freeze" in sys.modules: # cx_freeze enabled? - from cx_Freeze.dist import build_exe as _build_exe - - # nczeczulin reports that py2exe won't like the pep440-style string - # as FILEVERSION, but it can be used for PRODUCTVERSION, e.g. - # setup(console=[{ - # "version": versioneer.get_version().split("+", 1)[0], # FILEVERSION - # "product_version": versioneer.get_version(), - # ... - - class cmd_build_exe(_build_exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _build_exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - cmds["build_exe"] = cmd_build_exe - del cmds["build_py"] - - if "py2exe" in sys.modules: # py2exe enabled? - from py2exe.distutils_buildexe import py2exe as _py2exe - - class cmd_py2exe(_py2exe): - def run(self): - root = get_root() - cfg = get_config_from_root(root) - versions = get_versions() - target_versionfile = cfg.versionfile_source - print("UPDATING %s" % target_versionfile) - write_to_version_file(target_versionfile, versions) - - _py2exe.run(self) - os.unlink(target_versionfile) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - cmds["py2exe"] = cmd_py2exe - - # we override different "sdist" commands for both environments - if "sdist" in cmds: - _sdist = cmds["sdist"] - elif "setuptools" in sys.modules: - from setuptools.command.sdist import sdist as _sdist - else: - from distutils.command.sdist import sdist as _sdist - - class cmd_sdist(_sdist): - def run(self): - versions = get_versions() - self._versioneer_generated_versions = versions - # unless we update this, the command will keep using the old - # version - self.distribution.metadata.version = versions["version"] - return _sdist.run(self) - - def make_release_tree(self, base_dir, files): - root = get_root() - cfg = get_config_from_root(root) - _sdist.make_release_tree(self, base_dir, files) - # now locate _version.py in the new base_dir directory - # (remembering that it may be a hardlink) and replace it with an - # updated value - target_versionfile = os.path.join(base_dir, cfg.versionfile_source) - print("UPDATING %s" % target_versionfile) - write_to_version_file( - target_versionfile, self._versioneer_generated_versions - ) - - cmds["sdist"] = cmd_sdist - - return cmds - - -CONFIG_ERROR = """ -setup.cfg is missing the necessary Versioneer configuration. You need -a section like: - - [versioneer] - VCS = git - style = pep440 - versionfile_source = src/myproject/_version.py - versionfile_build = myproject/_version.py - tag_prefix = - parentdir_prefix = myproject- - -You will also need to edit your setup.py to use the results: - - import versioneer - setup(version=versioneer.get_version(), - cmdclass=versioneer.get_cmdclass(), ...) - -Please read the docstring in ./versioneer.py for configuration instructions, -edit setup.cfg, and re-run the installer or 'python versioneer.py setup'. -""" - -SAMPLE_CONFIG = """ -# See the docstring in versioneer.py for instructions. Note that you must -# re-run 'versioneer.py setup' after changing this section, and commit the -# resulting files. - -[versioneer] -#VCS = git -#style = pep440 -#versionfile_source = -#versionfile_build = -#tag_prefix = -#parentdir_prefix = - -""" - -OLD_SNIPPET = """ -from ._version import get_versions -__version__ = get_versions()['version'] -del get_versions -""" - -INIT_PY_SNIPPET = """ -from . import {0} -__version__ = {0}.get_versions()['version'] -""" - - -def do_setup(): - """Do main VCS-independent setup function for installing Versioneer.""" - root = get_root() - try: - cfg = get_config_from_root(root) - except (OSError, configparser.NoSectionError, configparser.NoOptionError) as e: - if isinstance(e, (OSError, configparser.NoSectionError)): - print("Adding sample versioneer config to setup.cfg", file=sys.stderr) - with open(os.path.join(root, "setup.cfg"), "a") as f: - f.write(SAMPLE_CONFIG) - print(CONFIG_ERROR, file=sys.stderr) - return 1 - - print(" creating %s" % cfg.versionfile_source) - with open(cfg.versionfile_source, "w") as f: - LONG = LONG_VERSION_PY[cfg.VCS] - f.write( - LONG - % { - "DOLLAR": "$", - "STYLE": cfg.style, - "TAG_PREFIX": cfg.tag_prefix, - "PARENTDIR_PREFIX": cfg.parentdir_prefix, - "VERSIONFILE_SOURCE": cfg.versionfile_source, - } - ) - - ipy = os.path.join(os.path.dirname(cfg.versionfile_source), "__init__.py") - if os.path.exists(ipy): - try: - with open(ipy, "r") as f: - old = f.read() - except OSError: - old = "" - module = os.path.splitext(os.path.basename(cfg.versionfile_source))[0] - snippet = INIT_PY_SNIPPET.format(module) - if OLD_SNIPPET in old: - print(" replacing boilerplate in %s" % ipy) - with open(ipy, "w") as f: - f.write(old.replace(OLD_SNIPPET, snippet)) - elif snippet not in old: - print(" appending to %s" % ipy) - with open(ipy, "a") as f: - f.write(snippet) - else: - print(" %s unmodified" % ipy) - else: - print(" %s doesn't exist, ok" % ipy) - ipy = None - - # Make sure both the top-level "versioneer.py" and versionfile_source - # (PKG/_version.py, used by runtime code) are in MANIFEST.in, so - # they'll be copied into source distributions. Pip won't be able to - # install the package without this. - manifest_in = os.path.join(root, "MANIFEST.in") - simple_includes = set() - try: - with open(manifest_in, "r") as f: - for line in f: - if line.startswith("include "): - for include in line.split()[1:]: - simple_includes.add(include) - except OSError: - pass - # That doesn't cover everything MANIFEST.in can do - # (http://docs.python.org/2/distutils/sourcedist.html#commands), so - # it might give some false negatives. Appending redundant 'include' - # lines is safe, though. - if "versioneer.py" not in simple_includes: - print(" appending 'versioneer.py' to MANIFEST.in") - with open(manifest_in, "a") as f: - f.write("include versioneer.py\n") - else: - print(" 'versioneer.py' already in MANIFEST.in") - if cfg.versionfile_source not in simple_includes: - print( - " appending versionfile_source ('%s') to MANIFEST.in" - % cfg.versionfile_source - ) - with open(manifest_in, "a") as f: - f.write("include %s\n" % cfg.versionfile_source) - else: - print(" versionfile_source already in MANIFEST.in") - - # Make VCS-specific changes. For git, this means creating/changing - # .gitattributes to mark _version.py for export-subst keyword - # substitution. - do_vcs_install(manifest_in, cfg.versionfile_source, ipy) - return 0 - - -def scan_setup_py(): - """Validate the contents of setup.py against Versioneer's expectations.""" - found = set() - setters = False - errors = 0 - with open("setup.py", "r") as f: - for line in f.readlines(): - if "import versioneer" in line: - found.add("import") - if "versioneer.get_cmdclass()" in line: - found.add("cmdclass") - if "versioneer.get_version()" in line: - found.add("get_version") - if "versioneer.VCS" in line: - setters = True - if "versioneer.versionfile_source" in line: - setters = True - if len(found) != 3: - print("") - print("Your setup.py appears to be missing some important items") - print("(but I might be wrong). Please make sure it has something") - print("roughly like the following:") - print("") - print(" import versioneer") - print(" setup( version=versioneer.get_version(),") - print(" cmdclass=versioneer.get_cmdclass(), ...)") - print("") - errors += 1 - if setters: - print("You should remove lines like 'versioneer.VCS = ' and") - print("'versioneer.versionfile_source = ' . This configuration") - print("now lives in setup.cfg, and should be removed from setup.py") - print("") - errors += 1 - return errors - - -if __name__ == "__main__": - cmd = sys.argv[1] - if cmd == "setup": - errors = do_setup() - errors += scan_setup_py() - if errors: - sys.exit(1) From 7a235a1b940e9a705e582d626e6d43a2d96ebc88 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 5 Sep 2023 14:34:34 +0200 Subject: [PATCH 02/59] fixed pint problem (groups in unitdef.txt) and pint-pandas dependency problem by fixing pandas to 2.0 --- poetry.lock | 778 ++++++++++++++++++++++++++-- portfolyo/tools/unitdefinitions.txt | 6 - pyproject.toml | 3 +- tests/utils.py | 1 + 4 files changed, 739 insertions(+), 49 deletions(-) diff --git a/poetry.lock b/poetry.lock index 169da18..d4d8675 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,44 @@ # This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +[[package]] +name = "appnope" +version = "0.1.3" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = "*" +files = [ + {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"}, + {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"}, +] + +[[package]] +name = "asttokens" +version = "2.4.0" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, + {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +test = ["astroid", "pytest"] + +[[package]] +name = "backcall" +version = "0.2.0" +description = "Specifications for callback functions passed in to an API" +optional = false +python-versions = "*" +files = [ + {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, + {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, +] + [[package]] name = "black" version = "23.7.0" @@ -57,6 +96,82 @@ files = [ {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "cfgv" version = "3.4.0" @@ -192,6 +307,25 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "comm" +version = "0.1.4" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.6" +files = [ + {file = "comm-0.1.4-py3-none-any.whl", hash = "sha256:6d52794cba11b36ed9860999cd10fd02d6b2eac177068fdd585e1e2f8a96e67a"}, + {file = "comm-0.1.4.tar.gz", hash = "sha256:354e40a59c9dd6db50c5cc6b4acc887d82e9603787f83b68c01a80a923984d15"}, +] + +[package.dependencies] +traitlets = ">=4" + +[package.extras] +lint = ["black (>=22.6.0)", "mdformat (>0.7)", "mdformat-gfm (>=0.3.5)", "ruff (>=0.0.156)"] +test = ["pytest"] +typing = ["mypy (>=0.990)"] + [[package]] name = "contourpy" version = "1.1.0" @@ -328,6 +462,44 @@ files = [ {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, ] +[[package]] +name = "debugpy" +version = "1.6.7.post1" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "debugpy-1.6.7.post1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:903bd61d5eb433b6c25b48eae5e23821d4c1a19e25c9610205f5aeaccae64e32"}, + {file = "debugpy-1.6.7.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d16882030860081e7dd5aa619f30dec3c2f9a421e69861125f83cc372c94e57d"}, + {file = "debugpy-1.6.7.post1-cp310-cp310-win32.whl", hash = "sha256:eea8d8cfb9965ac41b99a61f8e755a8f50e9a20330938ad8271530210f54e09c"}, + {file = "debugpy-1.6.7.post1-cp310-cp310-win_amd64.whl", hash = "sha256:85969d864c45f70c3996067cfa76a319bae749b04171f2cdeceebe4add316155"}, + {file = "debugpy-1.6.7.post1-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:890f7ab9a683886a0f185786ffbda3b46495c4b929dab083b8c79d6825832a52"}, + {file = "debugpy-1.6.7.post1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4ac7a4dba28801d184b7fc0e024da2635ca87d8b0a825c6087bb5168e3c0d28"}, + {file = "debugpy-1.6.7.post1-cp37-cp37m-win32.whl", hash = "sha256:3370ef1b9951d15799ef7af41f8174194f3482ee689988379763ef61a5456426"}, + {file = "debugpy-1.6.7.post1-cp37-cp37m-win_amd64.whl", hash = "sha256:65b28435a17cba4c09e739621173ff90c515f7b9e8ea469b92e3c28ef8e5cdfb"}, + {file = "debugpy-1.6.7.post1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:92b6dae8bfbd497c90596bbb69089acf7954164aea3228a99d7e43e5267f5b36"}, + {file = "debugpy-1.6.7.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72f5d2ecead8125cf669e62784ef1e6300f4067b0f14d9f95ee00ae06fc7c4f7"}, + {file = "debugpy-1.6.7.post1-cp38-cp38-win32.whl", hash = "sha256:f0851403030f3975d6e2eaa4abf73232ab90b98f041e3c09ba33be2beda43fcf"}, + {file = "debugpy-1.6.7.post1-cp38-cp38-win_amd64.whl", hash = "sha256:3de5d0f97c425dc49bce4293df6a04494309eedadd2b52c22e58d95107e178d9"}, + {file = "debugpy-1.6.7.post1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:38651c3639a4e8bbf0ca7e52d799f6abd07d622a193c406be375da4d510d968d"}, + {file = "debugpy-1.6.7.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:038c51268367c9c935905a90b1c2d2dbfe304037c27ba9d19fe7409f8cdc710c"}, + {file = "debugpy-1.6.7.post1-cp39-cp39-win32.whl", hash = "sha256:4b9eba71c290852f959d2cf8a03af28afd3ca639ad374d393d53d367f7f685b2"}, + {file = "debugpy-1.6.7.post1-cp39-cp39-win_amd64.whl", hash = "sha256:973a97ed3b434eab0f792719a484566c35328196540676685c975651266fccf9"}, + {file = "debugpy-1.6.7.post1-py2.py3-none-any.whl", hash = "sha256:1093a5c541af079c13ac8c70ab8b24d1d35c8cacb676306cf11e57f699c02926"}, + {file = "debugpy-1.6.7.post1.zip", hash = "sha256:fe87ec0182ef624855d05e6ed7e0b7cb1359d2ffa2a925f8ec2d22e98b75d0ca"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + [[package]] name = "distlib" version = "0.3.7" @@ -364,6 +536,20 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "executing" +version = "1.2.0" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = "*" +files = [ + {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, + {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, +] + +[package.extras] +tests = ["asttokens", "littleutils", "pytest", "rich"] + [[package]] name = "filelock" version = "3.12.3" @@ -494,6 +680,25 @@ files = [ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] +[[package]] +name = "importlib-metadata" +version = "6.8.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, + {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, +] + +[package.dependencies] +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + [[package]] name = "importlib-resources" version = "6.0.1" @@ -523,6 +728,141 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "ipykernel" +version = "6.25.2" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.25.2-py3-none-any.whl", hash = "sha256:2e2ee359baba19f10251b99415bb39de1e97d04e1fab385646f24f0596510b77"}, + {file = "ipykernel-6.25.2.tar.gz", hash = "sha256:f468ddd1f17acb48c8ce67fcfa49ba6d46d4f9ac0438c1f441be7c3d1372230b"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=20" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.15.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.9" +files = [ + {file = "ipython-8.15.0-py3-none-any.whl", hash = "sha256:45a2c3a529296870a97b7de34eda4a31bee16bc7bf954e07d39abe49caf8f887"}, + {file = "ipython-8.15.0.tar.gz", hash = "sha256:2baeb5be6949eeebf532150f81746f8333e2ccce02de1c7eedde3f23ed5e9f1e"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "sys_platform == \"darwin\""} +backcall = "*" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} +pickleshare = "*" +prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5" +typing-extensions = {version = "*", markers = "python_version < \"3.10\""} + +[package.extras] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +kernel = ["ipykernel"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] + +[[package]] +name = "jedi" +version = "0.19.0" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"}, + {file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jupyter-client" +version = "8.3.1" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_client-8.3.1-py3-none-any.whl", hash = "sha256:5eb9f55eb0650e81de6b7e34308d8b92d04fe4ec41cd8193a913979e33d8e1a5"}, + {file = "jupyter_client-8.3.1.tar.gz", hash = "sha256:60294b2d5b869356c893f57b1a877ea6510d60d45cf4b38057f1672d85699ac9"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.10\""} +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = ">=5.3" + +[package.extras] +docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] + +[[package]] +name = "jupyter-core" +version = "5.3.1" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.3.1-py3-none-any.whl", hash = "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce"}, + {file = "jupyter_core-5.3.1.tar.gz", hash = "sha256:5ba5c7938a7f97a6b0481463f7ff0dbac7c15ba48cf46fa4035ca6e838aa1aba"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] + [[package]] name = "kiwisolver" version = "1.4.5" @@ -698,6 +1038,20 @@ pillow = ">=6.2.0" pyparsing = ">=2.3.1,<3.1" python-dateutil = ">=2.7" +[[package]] +name = "matplotlib-inline" +version = "0.1.6" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.5" +files = [ + {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"}, + {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"}, +] + +[package.dependencies] +traitlets = "*" + [[package]] name = "mccabe" version = "0.7.0" @@ -720,6 +1074,17 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] +[[package]] +name = "nest-asyncio" +version = "1.5.7" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.5.7-py3-none-any.whl", hash = "sha256:5301c82941b550b3123a1ea772ba9a1c80bad3a182be8c1a5ae6ad3be57a9657"}, + {file = "nest_asyncio-1.5.7.tar.gz", hash = "sha256:6a80f7b98f24d9083ed24608977c09dd608d83f91cccc24c9d2cba6d10e01c10"}, +] + [[package]] name = "nodeenv" version = "1.8.0" @@ -795,35 +1160,42 @@ files = [ [[package]] name = "pandas" -version = "2.1.0" +version = "2.0.3" description = "Powerful data structures for data analysis, time series, and statistics" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "pandas-2.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:40dd20439ff94f1b2ed55b393ecee9cb6f3b08104c2c40b0cb7186a2f0046242"}, - {file = "pandas-2.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d4f38e4fedeba580285eaac7ede4f686c6701a9e618d8a857b138a126d067f2f"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e6a0fe052cf27ceb29be9429428b4918f3740e37ff185658f40d8702f0b3e09"}, - {file = "pandas-2.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d81e1813191070440d4c7a413cb673052b3b4a984ffd86b8dd468c45742d3cc"}, - {file = "pandas-2.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eb20252720b1cc1b7d0b2879ffc7e0542dd568f24d7c4b2347cb035206936421"}, - {file = "pandas-2.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:38f74ef7ebc0ffb43b3d633e23d74882bce7e27bfa09607f3c5d3e03ffd9a4a5"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cda72cc8c4761c8f1d97b169661f23a86b16fdb240bdc341173aee17e4d6cedd"}, - {file = "pandas-2.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d97daeac0db8c993420b10da4f5f5b39b01fc9ca689a17844e07c0a35ac96b4b"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8c58b1113892e0c8078f006a167cc210a92bdae23322bb4614f2f0b7a4b510f"}, - {file = "pandas-2.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:629124923bcf798965b054a540f9ccdfd60f71361255c81fa1ecd94a904b9dd3"}, - {file = "pandas-2.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:70cf866af3ab346a10debba8ea78077cf3a8cd14bd5e4bed3d41555a3280041c"}, - {file = "pandas-2.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:d53c8c1001f6a192ff1de1efe03b31a423d0eee2e9e855e69d004308e046e694"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:86f100b3876b8c6d1a2c66207288ead435dc71041ee4aea789e55ef0e06408cb"}, - {file = "pandas-2.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f330845ad21c11db51e02d8d69acc9035edfd1116926ff7245c7215db57957"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9a6ccf0963db88f9b12df6720e55f337447aea217f426a22d71f4213a3099a6"}, - {file = "pandas-2.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99e678180bc59b0c9443314297bddce4ad35727a1a2656dbe585fd78710b3b9"}, - {file = "pandas-2.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b31da36d376d50a1a492efb18097b9101bdbd8b3fbb3f49006e02d4495d4c644"}, - {file = "pandas-2.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0164b85937707ec7f70b34a6c3a578dbf0f50787f910f21ca3b26a7fd3363437"}, - {file = "pandas-2.1.0.tar.gz", hash = "sha256:62c24c7fc59e42b775ce0679cfa7b14a5f9bfb7643cfbe708c960699e05fb918"}, + {file = "pandas-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8"}, + {file = "pandas-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f"}, + {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183"}, + {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0"}, + {file = "pandas-2.0.3-cp310-cp310-win32.whl", hash = "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210"}, + {file = "pandas-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e"}, + {file = "pandas-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8"}, + {file = "pandas-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26"}, + {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d"}, + {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df"}, + {file = "pandas-2.0.3-cp311-cp311-win32.whl", hash = "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd"}, + {file = "pandas-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b"}, + {file = "pandas-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061"}, + {file = "pandas-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5"}, + {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089"}, + {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0"}, + {file = "pandas-2.0.3-cp38-cp38-win32.whl", hash = "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02"}, + {file = "pandas-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78"}, + {file = "pandas-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b"}, + {file = "pandas-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e"}, + {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b"}, + {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641"}, + {file = "pandas-2.0.3-cp39-cp39-win32.whl", hash = "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682"}, + {file = "pandas-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc"}, + {file = "pandas-2.0.3.tar.gz", hash = "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c"}, ] [package.dependencies] numpy = [ - {version = ">=1.22.4", markers = "python_version < \"3.11\""}, + {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, ] python-dateutil = ">=2.8.2" @@ -831,28 +1203,42 @@ pytz = ">=2020.1" tzdata = ">=2022.1" [package.extras] -all = ["PyQt5 (>=5.15.6)", "SQLAlchemy (>=1.4.36)", "beautifulsoup4 (>=4.11.1)", "bottleneck (>=1.3.4)", "dataframe-api-compat (>=0.1.7)", "fastparquet (>=0.8.1)", "fsspec (>=2022.05.0)", "gcsfs (>=2022.05.0)", "html5lib (>=1.1)", "hypothesis (>=6.46.1)", "jinja2 (>=3.1.2)", "lxml (>=4.8.0)", "matplotlib (>=3.6.1)", "numba (>=0.55.2)", "numexpr (>=2.8.0)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pandas-gbq (>=0.17.5)", "psycopg2 (>=2.9.3)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.5)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "pyxlsb (>=1.0.9)", "qtpy (>=2.2.0)", "s3fs (>=2022.05.0)", "scipy (>=1.8.1)", "tables (>=3.7.0)", "tabulate (>=0.8.10)", "xarray (>=2022.03.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)", "zstandard (>=0.17.0)"] -aws = ["s3fs (>=2022.05.0)"] -clipboard = ["PyQt5 (>=5.15.6)", "qtpy (>=2.2.0)"] -compression = ["zstandard (>=0.17.0)"] -computation = ["scipy (>=1.8.1)", "xarray (>=2022.03.0)"] -consortium-standard = ["dataframe-api-compat (>=0.1.7)"] -excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.10)", "pyxlsb (>=1.0.9)", "xlrd (>=2.0.1)", "xlsxwriter (>=3.0.3)"] +all = ["PyQt5 (>=5.15.1)", "SQLAlchemy (>=1.4.16)", "beautifulsoup4 (>=4.9.3)", "bottleneck (>=1.3.2)", "brotlipy (>=0.7.0)", "fastparquet (>=0.6.3)", "fsspec (>=2021.07.0)", "gcsfs (>=2021.07.0)", "html5lib (>=1.1)", "hypothesis (>=6.34.2)", "jinja2 (>=3.0.0)", "lxml (>=4.6.3)", "matplotlib (>=3.6.1)", "numba (>=0.53.1)", "numexpr (>=2.7.3)", "odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pandas-gbq (>=0.15.0)", "psycopg2 (>=2.8.6)", "pyarrow (>=7.0.0)", "pymysql (>=1.0.2)", "pyreadstat (>=1.1.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)", "python-snappy (>=0.6.0)", "pyxlsb (>=1.0.8)", "qtpy (>=2.2.0)", "s3fs (>=2021.08.0)", "scipy (>=1.7.1)", "tables (>=3.6.1)", "tabulate (>=0.8.9)", "xarray (>=0.21.0)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)", "zstandard (>=0.15.2)"] +aws = ["s3fs (>=2021.08.0)"] +clipboard = ["PyQt5 (>=5.15.1)", "qtpy (>=2.2.0)"] +compression = ["brotlipy (>=0.7.0)", "python-snappy (>=0.6.0)", "zstandard (>=0.15.2)"] +computation = ["scipy (>=1.7.1)", "xarray (>=0.21.0)"] +excel = ["odfpy (>=1.4.1)", "openpyxl (>=3.0.7)", "pyxlsb (>=1.0.8)", "xlrd (>=2.0.1)", "xlsxwriter (>=1.4.3)"] feather = ["pyarrow (>=7.0.0)"] -fss = ["fsspec (>=2022.05.0)"] -gcp = ["gcsfs (>=2022.05.0)", "pandas-gbq (>=0.17.5)"] -hdf5 = ["tables (>=3.7.0)"] -html = ["beautifulsoup4 (>=4.11.1)", "html5lib (>=1.1)", "lxml (>=4.8.0)"] -mysql = ["SQLAlchemy (>=1.4.36)", "pymysql (>=1.0.2)"] -output-formatting = ["jinja2 (>=3.1.2)", "tabulate (>=0.8.10)"] +fss = ["fsspec (>=2021.07.0)"] +gcp = ["gcsfs (>=2021.07.0)", "pandas-gbq (>=0.15.0)"] +hdf5 = ["tables (>=3.6.1)"] +html = ["beautifulsoup4 (>=4.9.3)", "html5lib (>=1.1)", "lxml (>=4.6.3)"] +mysql = ["SQLAlchemy (>=1.4.16)", "pymysql (>=1.0.2)"] +output-formatting = ["jinja2 (>=3.0.0)", "tabulate (>=0.8.9)"] parquet = ["pyarrow (>=7.0.0)"] -performance = ["bottleneck (>=1.3.4)", "numba (>=0.55.2)", "numexpr (>=2.8.0)"] +performance = ["bottleneck (>=1.3.2)", "numba (>=0.53.1)", "numexpr (>=2.7.1)"] plot = ["matplotlib (>=3.6.1)"] -postgresql = ["SQLAlchemy (>=1.4.36)", "psycopg2 (>=2.9.3)"] -spss = ["pyreadstat (>=1.1.5)"] -sql-other = ["SQLAlchemy (>=1.4.36)"] -test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] -xml = ["lxml (>=4.8.0)"] +postgresql = ["SQLAlchemy (>=1.4.16)", "psycopg2 (>=2.8.6)"] +spss = ["pyreadstat (>=1.1.2)"] +sql-other = ["SQLAlchemy (>=1.4.16)"] +test = ["hypothesis (>=6.34.2)", "pytest (>=7.3.2)", "pytest-asyncio (>=0.17.0)", "pytest-xdist (>=2.2.0)"] +xml = ["lxml (>=4.6.3)"] + +[[package]] +name = "parso" +version = "0.8.3" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"}, + {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"}, +] + +[package.extras] +qa = ["flake8 (==3.8.3)", "mypy (==0.782)"] +testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pathspec" @@ -865,6 +1251,31 @@ files = [ {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] +[[package]] +name = "pexpect" +version = "4.8.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"}, + {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pickleshare" +version = "0.7.5" +description = "Tiny 'shelve'-like database with concurrency support" +optional = false +python-versions = "*" +files = [ + {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, + {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, +] + [[package]] name = "pillow" version = "10.0.0" @@ -1020,6 +1431,71 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "prompt-toolkit" +version = "3.0.39" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.5" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, + {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, + {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, + {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, + {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, + {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, + {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, + {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, + {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, + {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, + {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + [[package]] name = "pycodestyle" version = "2.11.0" @@ -1031,6 +1507,17 @@ files = [ {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, ] +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + [[package]] name = "pyflakes" version = "3.1.0" @@ -1042,6 +1529,20 @@ files = [ {file = "pyflakes-3.1.0.tar.gz", hash = "sha256:a0aae034c444db0071aa077972ba4768d40c830d9539fd45bf4cd3f8f6992efc"}, ] +[[package]] +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + [[package]] name = "pyparsing" version = "3.0.9" @@ -1121,6 +1622,29 @@ files = [ {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, ] +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -1170,6 +1694,111 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "pyzmq" +version = "25.1.1" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyzmq-25.1.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:381469297409c5adf9a0e884c5eb5186ed33137badcbbb0560b86e910a2f1e76"}, + {file = "pyzmq-25.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:955215ed0604dac5b01907424dfa28b40f2b2292d6493445dd34d0dfa72586a8"}, + {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:985bbb1316192b98f32e25e7b9958088431d853ac63aca1d2c236f40afb17c83"}, + {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:afea96f64efa98df4da6958bae37f1cbea7932c35878b185e5982821bc883369"}, + {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76705c9325d72a81155bb6ab48d4312e0032bf045fb0754889133200f7a0d849"}, + {file = "pyzmq-25.1.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:77a41c26205d2353a4c94d02be51d6cbdf63c06fbc1295ea57dad7e2d3381b71"}, + {file = "pyzmq-25.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:12720a53e61c3b99d87262294e2b375c915fea93c31fc2336898c26d7aed34cd"}, + {file = "pyzmq-25.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:57459b68e5cd85b0be8184382cefd91959cafe79ae019e6b1ae6e2ba8a12cda7"}, + {file = "pyzmq-25.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:292fe3fc5ad4a75bc8df0dfaee7d0babe8b1f4ceb596437213821f761b4589f9"}, + {file = "pyzmq-25.1.1-cp310-cp310-win32.whl", hash = "sha256:35b5ab8c28978fbbb86ea54958cd89f5176ce747c1fb3d87356cf698048a7790"}, + {file = "pyzmq-25.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:11baebdd5fc5b475d484195e49bae2dc64b94a5208f7c89954e9e354fc609d8f"}, + {file = "pyzmq-25.1.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:d20a0ddb3e989e8807d83225a27e5c2eb2260eaa851532086e9e0fa0d5287d83"}, + {file = "pyzmq-25.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e1c1be77bc5fb77d923850f82e55a928f8638f64a61f00ff18a67c7404faf008"}, + {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d89528b4943d27029a2818f847c10c2cecc79fa9590f3cb1860459a5be7933eb"}, + {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90f26dc6d5f241ba358bef79be9ce06de58d477ca8485e3291675436d3827cf8"}, + {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2b92812bd214018e50b6380ea3ac0c8bb01ac07fcc14c5f86a5bb25e74026e9"}, + {file = "pyzmq-25.1.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:2f957ce63d13c28730f7fd6b72333814221c84ca2421298f66e5143f81c9f91f"}, + {file = "pyzmq-25.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:047a640f5c9c6ade7b1cc6680a0e28c9dd5a0825135acbd3569cc96ea00b2505"}, + {file = "pyzmq-25.1.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7f7e58effd14b641c5e4dec8c7dab02fb67a13df90329e61c869b9cc607ef752"}, + {file = "pyzmq-25.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c2910967e6ab16bf6fbeb1f771c89a7050947221ae12a5b0b60f3bca2ee19bca"}, + {file = "pyzmq-25.1.1-cp311-cp311-win32.whl", hash = "sha256:76c1c8efb3ca3a1818b837aea423ff8a07bbf7aafe9f2f6582b61a0458b1a329"}, + {file = "pyzmq-25.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:44e58a0554b21fc662f2712814a746635ed668d0fbc98b7cb9d74cb798d202e6"}, + {file = "pyzmq-25.1.1-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:e1ffa1c924e8c72778b9ccd386a7067cddf626884fd8277f503c48bb5f51c762"}, + {file = "pyzmq-25.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1af379b33ef33757224da93e9da62e6471cf4a66d10078cf32bae8127d3d0d4a"}, + {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cff084c6933680d1f8b2f3b4ff5bbb88538a4aac00d199ac13f49d0698727ecb"}, + {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2400a94f7dd9cb20cd012951a0cbf8249e3d554c63a9c0cdfd5cbb6c01d2dec"}, + {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d81f1ddae3858b8299d1da72dd7d19dd36aab654c19671aa8a7e7fb02f6638a"}, + {file = "pyzmq-25.1.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:255ca2b219f9e5a3a9ef3081512e1358bd4760ce77828e1028b818ff5610b87b"}, + {file = "pyzmq-25.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a882ac0a351288dd18ecae3326b8a49d10c61a68b01419f3a0b9a306190baf69"}, + {file = "pyzmq-25.1.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:724c292bb26365659fc434e9567b3f1adbdb5e8d640c936ed901f49e03e5d32e"}, + {file = "pyzmq-25.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ca1ed0bb2d850aa8471387882247c68f1e62a4af0ce9c8a1dbe0d2bf69e41fb"}, + {file = "pyzmq-25.1.1-cp312-cp312-win32.whl", hash = "sha256:b3451108ab861040754fa5208bca4a5496c65875710f76789a9ad27c801a0075"}, + {file = "pyzmq-25.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:eadbefd5e92ef8a345f0525b5cfd01cf4e4cc651a2cffb8f23c0dd184975d787"}, + {file = "pyzmq-25.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:db0b2af416ba735c6304c47f75d348f498b92952f5e3e8bff449336d2728795d"}, + {file = "pyzmq-25.1.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c133e93b405eb0d36fa430c94185bdd13c36204a8635470cccc200723c13bb"}, + {file = "pyzmq-25.1.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:273bc3959bcbff3f48606b28229b4721716598d76b5aaea2b4a9d0ab454ec062"}, + {file = "pyzmq-25.1.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cbc8df5c6a88ba5ae385d8930da02201165408dde8d8322072e3e5ddd4f68e22"}, + {file = "pyzmq-25.1.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:18d43df3f2302d836f2a56f17e5663e398416e9dd74b205b179065e61f1a6edf"}, + {file = "pyzmq-25.1.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:73461eed88a88c866656e08f89299720a38cb4e9d34ae6bf5df6f71102570f2e"}, + {file = "pyzmq-25.1.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:34c850ce7976d19ebe7b9d4b9bb8c9dfc7aac336c0958e2651b88cbd46682123"}, + {file = "pyzmq-25.1.1-cp36-cp36m-win32.whl", hash = "sha256:d2045d6d9439a0078f2a34b57c7b18c4a6aef0bee37f22e4ec9f32456c852c71"}, + {file = "pyzmq-25.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:458dea649f2f02a0b244ae6aef8dc29325a2810aa26b07af8374dc2a9faf57e3"}, + {file = "pyzmq-25.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:7cff25c5b315e63b07a36f0c2bab32c58eafbe57d0dce61b614ef4c76058c115"}, + {file = "pyzmq-25.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1579413ae492b05de5a6174574f8c44c2b9b122a42015c5292afa4be2507f28"}, + {file = "pyzmq-25.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3d0a409d3b28607cc427aa5c30a6f1e4452cc44e311f843e05edb28ab5e36da0"}, + {file = "pyzmq-25.1.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:21eb4e609a154a57c520e3d5bfa0d97e49b6872ea057b7c85257b11e78068222"}, + {file = "pyzmq-25.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:034239843541ef7a1aee0c7b2cb7f6aafffb005ede965ae9cbd49d5ff4ff73cf"}, + {file = "pyzmq-25.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f8115e303280ba09f3898194791a153862cbf9eef722ad8f7f741987ee2a97c7"}, + {file = "pyzmq-25.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1a5d26fe8f32f137e784f768143728438877d69a586ddeaad898558dc971a5ae"}, + {file = "pyzmq-25.1.1-cp37-cp37m-win32.whl", hash = "sha256:f32260e556a983bc5c7ed588d04c942c9a8f9c2e99213fec11a031e316874c7e"}, + {file = "pyzmq-25.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:abf34e43c531bbb510ae7e8f5b2b1f2a8ab93219510e2b287a944432fad135f3"}, + {file = "pyzmq-25.1.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:87e34f31ca8f168c56d6fbf99692cc8d3b445abb5bfd08c229ae992d7547a92a"}, + {file = "pyzmq-25.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c9c6c9b2c2f80747a98f34ef491c4d7b1a8d4853937bb1492774992a120f475d"}, + {file = "pyzmq-25.1.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5619f3f5a4db5dbb572b095ea3cb5cc035335159d9da950830c9c4db2fbb6995"}, + {file = "pyzmq-25.1.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5a34d2395073ef862b4032343cf0c32a712f3ab49d7ec4f42c9661e0294d106f"}, + {file = "pyzmq-25.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25f0e6b78220aba09815cd1f3a32b9c7cb3e02cb846d1cfc526b6595f6046618"}, + {file = "pyzmq-25.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3669cf8ee3520c2f13b2e0351c41fea919852b220988d2049249db10046a7afb"}, + {file = "pyzmq-25.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2d163a18819277e49911f7461567bda923461c50b19d169a062536fffe7cd9d2"}, + {file = "pyzmq-25.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:df27ffddff4190667d40de7beba4a950b5ce78fe28a7dcc41d6f8a700a80a3c0"}, + {file = "pyzmq-25.1.1-cp38-cp38-win32.whl", hash = "sha256:a382372898a07479bd34bda781008e4a954ed8750f17891e794521c3e21c2e1c"}, + {file = "pyzmq-25.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:52533489f28d62eb1258a965f2aba28a82aa747202c8fa5a1c7a43b5db0e85c1"}, + {file = "pyzmq-25.1.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:03b3f49b57264909aacd0741892f2aecf2f51fb053e7d8ac6767f6c700832f45"}, + {file = "pyzmq-25.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:330f9e188d0d89080cde66dc7470f57d1926ff2fb5576227f14d5be7ab30b9fa"}, + {file = "pyzmq-25.1.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2ca57a5be0389f2a65e6d3bb2962a971688cbdd30b4c0bd188c99e39c234f414"}, + {file = "pyzmq-25.1.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:d457aed310f2670f59cc5b57dcfced452aeeed77f9da2b9763616bd57e4dbaae"}, + {file = "pyzmq-25.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c56d748ea50215abef7030c72b60dd723ed5b5c7e65e7bc2504e77843631c1a6"}, + {file = "pyzmq-25.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8f03d3f0d01cb5a018debeb412441996a517b11c5c17ab2001aa0597c6d6882c"}, + {file = "pyzmq-25.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:820c4a08195a681252f46926de10e29b6bbf3e17b30037bd4250d72dd3ddaab8"}, + {file = "pyzmq-25.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:17ef5f01d25b67ca8f98120d5fa1d21efe9611604e8eb03a5147360f517dd1e2"}, + {file = "pyzmq-25.1.1-cp39-cp39-win32.whl", hash = "sha256:04ccbed567171579ec2cebb9c8a3e30801723c575601f9a990ab25bcac6b51e2"}, + {file = "pyzmq-25.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:e61f091c3ba0c3578411ef505992d356a812fb200643eab27f4f70eed34a29ef"}, + {file = "pyzmq-25.1.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ade6d25bb29c4555d718ac6d1443a7386595528c33d6b133b258f65f963bb0f6"}, + {file = "pyzmq-25.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0c95ddd4f6e9fca4e9e3afaa4f9df8552f0ba5d1004e89ef0a68e1f1f9807c7"}, + {file = "pyzmq-25.1.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48e466162a24daf86f6b5ca72444d2bf39a5e58da5f96370078be67c67adc978"}, + {file = "pyzmq-25.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abc719161780932c4e11aaebb203be3d6acc6b38d2f26c0f523b5b59d2fc1996"}, + {file = "pyzmq-25.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1ccf825981640b8c34ae54231b7ed00271822ea1c6d8ba1090ebd4943759abf5"}, + {file = "pyzmq-25.1.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c2f20ce161ebdb0091a10c9ca0372e023ce24980d0e1f810f519da6f79c60800"}, + {file = "pyzmq-25.1.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:deee9ca4727f53464daf089536e68b13e6104e84a37820a88b0a057b97bba2d2"}, + {file = "pyzmq-25.1.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:aa8d6cdc8b8aa19ceb319aaa2b660cdaccc533ec477eeb1309e2a291eaacc43a"}, + {file = "pyzmq-25.1.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:019e59ef5c5256a2c7378f2fb8560fc2a9ff1d315755204295b2eab96b254d0a"}, + {file = "pyzmq-25.1.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b9af3757495c1ee3b5c4e945c1df7be95562277c6e5bccc20a39aec50f826cd0"}, + {file = "pyzmq-25.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:548d6482dc8aadbe7e79d1b5806585c8120bafa1ef841167bc9090522b610fa6"}, + {file = "pyzmq-25.1.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:057e824b2aae50accc0f9a0570998adc021b372478a921506fddd6c02e60308e"}, + {file = "pyzmq-25.1.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2243700cc5548cff20963f0ca92d3e5e436394375ab8a354bbea2b12911b20b0"}, + {file = "pyzmq-25.1.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79986f3b4af059777111409ee517da24a529bdbd46da578b33f25580adcff728"}, + {file = "pyzmq-25.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:11d58723d44d6ed4dd677c5615b2ffb19d5c426636345567d6af82be4dff8a55"}, + {file = "pyzmq-25.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:49d238cf4b69652257db66d0c623cd3e09b5d2e9576b56bc067a396133a00d4a"}, + {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fedbdc753827cf014c01dbbee9c3be17e5a208dcd1bf8641ce2cd29580d1f0d4"}, + {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc16ac425cc927d0a57d242589f87ee093884ea4804c05a13834d07c20db203c"}, + {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11c1d2aed9079c6b0c9550a7257a836b4a637feb334904610f06d70eb44c56d2"}, + {file = "pyzmq-25.1.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e8a701123029cc240cea61dd2d16ad57cab4691804143ce80ecd9286b464d180"}, + {file = "pyzmq-25.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:61706a6b6c24bdece85ff177fec393545a3191eeda35b07aaa1458a027ad1304"}, + {file = "pyzmq-25.1.1.tar.gz", hash = "sha256:259c22485b71abacdfa8bf79720cd7bcf4b9d128b30ea554f01ae71fdbfdaa23"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + [[package]] name = "requests" version = "2.31.0" @@ -1218,6 +1847,25 @@ files = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] +[[package]] +name = "stack-data" +version = "0.6.2" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, + {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + [[package]] name = "tomli" version = "2.0.1" @@ -1229,6 +1877,41 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "tornado" +version = "6.3.3" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">= 3.8" +files = [ + {file = "tornado-6.3.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:502fba735c84450974fec147340016ad928d29f1e91f49be168c0a4c18181e1d"}, + {file = "tornado-6.3.3-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:805d507b1f588320c26f7f097108eb4023bbaa984d63176d1652e184ba24270a"}, + {file = "tornado-6.3.3-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd19ca6c16882e4d37368e0152f99c099bad93e0950ce55e71daed74045908f"}, + {file = "tornado-6.3.3-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ac51f42808cca9b3613f51ffe2a965c8525cb1b00b7b2d56828b8045354f76a"}, + {file = "tornado-6.3.3-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71a8db65160a3c55d61839b7302a9a400074c9c753040455494e2af74e2501f2"}, + {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ceb917a50cd35882b57600709dd5421a418c29ddc852da8bcdab1f0db33406b0"}, + {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:7d01abc57ea0dbb51ddfed477dfe22719d376119844e33c661d873bf9c0e4a16"}, + {file = "tornado-6.3.3-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9dc4444c0defcd3929d5c1eb5706cbe1b116e762ff3e0deca8b715d14bf6ec17"}, + {file = "tornado-6.3.3-cp38-abi3-win32.whl", hash = "sha256:65ceca9500383fbdf33a98c0087cb975b2ef3bfb874cb35b8de8740cf7f41bd3"}, + {file = "tornado-6.3.3-cp38-abi3-win_amd64.whl", hash = "sha256:22d3c2fa10b5793da13c807e6fc38ff49a4f6e1e3868b0a6f4164768bb8e20f5"}, + {file = "tornado-6.3.3.tar.gz", hash = "sha256:e7d8db41c0181c80d76c982aacc442c0783a2c54d6400fe028954201a2e032fe"}, +] + +[[package]] +name = "traitlets" +version = "5.9.0" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.7" +files = [ + {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"}, + {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] + [[package]] name = "typing-extensions" version = "4.7.1" @@ -1288,6 +1971,17 @@ platformdirs = ">=3.9.1,<4" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "wcwidth" +version = "0.2.6" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, + {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, +] + [[package]] name = "zipp" version = "3.16.2" @@ -1306,4 +2000,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "8171f85b1d99e76140725c73800280e599f18bb05cb64d2c90fe76996efa0412" +content-hash = "a8264c7cf58ac4ed7d8ab385ad2d2e6e92d1d27254ad4cd21522bfedf9ef50a9" diff --git a/portfolyo/tools/unitdefinitions.txt b/portfolyo/tools/unitdefinitions.txt index dbec2e7..054acb7 100644 --- a/portfolyo/tools/unitdefinitions.txt +++ b/portfolyo/tools/unitdefinitions.txt @@ -1,9 +1,3 @@ - -@defaults - system = energysector1 -@end - - # prefixes centi- = 1e-2 = c- kilo- = 1e3 = k- = K- diff --git a/pyproject.toml b/pyproject.toml index 44db816..7488944 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ readme = "README.rst" [tool.poetry.dependencies] python = "^3.9" -pandas = "^2" +pandas = "~2.0.0" numpy = "^1.25.2" matplotlib = "^3.7.2" pint = "^0.22" @@ -33,6 +33,7 @@ openpyxl = "^3.1.2" flake8 = "^6.1.0" black = "^23.7.0" pre-commit = "^3.4.0" +ipykernel = "^6.25.2" [build-system] requires = ["poetry-core"] diff --git a/tests/utils.py b/tests/utils.py index a639c50..63803a1 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,5 +1,6 @@ """Create uniform ids for testcases.""" from typing import Any, Dict + import pandas as pd import portfolyo as pf From 6d1117d7043e7b8c734fc7f98fb9275df422aa56 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 5 Sep 2023 15:17:23 +0200 Subject: [PATCH 03/59] ci pipeline --- .github/workflows/ci-on-push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-on-push.yaml b/.github/workflows/ci-on-push.yaml index cabb927..4d495ff 100644 --- a/.github/workflows/ci-on-push.yaml +++ b/.github/workflows/ci-on-push.yaml @@ -24,7 +24,7 @@ jobs: - name: Install run: | pip install poetry - poetry install --with dev test + poetry install --with dev,test - name: Run tests run: | From 5bce0c350fdde0cd4d1532838ad80de28caf143e Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 5 Sep 2023 15:17:34 +0200 Subject: [PATCH 04/59] ci pipeline --- .github/workflows/ci-on-pullreq.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-on-pullreq.yaml b/.github/workflows/ci-on-pullreq.yaml index e6fa5d6..e014fa5 100644 --- a/.github/workflows/ci-on-pullreq.yaml +++ b/.github/workflows/ci-on-pullreq.yaml @@ -24,7 +24,7 @@ jobs: - name: Install run: | pip install poetry - poetry install --with dev --with test + poetry install --with dev,test - name: Run tests run: | From af97c212e0335898c2add4f5288c292bcf58f952 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 5 Sep 2023 15:40:59 +0200 Subject: [PATCH 05/59] ci with poetry --- .github/workflows/ci-on-pullreq.yaml | 3 +-- .github/workflows/ci-on-push.yaml | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-on-pullreq.yaml b/.github/workflows/ci-on-pullreq.yaml index e014fa5..f2a0dce 100644 --- a/.github/workflows/ci-on-pullreq.yaml +++ b/.github/workflows/ci-on-pullreq.yaml @@ -28,8 +28,7 @@ jobs: - name: Run tests run: | - pytest - poetry shell + poetry run pytest - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v1 diff --git a/.github/workflows/ci-on-push.yaml b/.github/workflows/ci-on-push.yaml index 4d495ff..779fef7 100644 --- a/.github/workflows/ci-on-push.yaml +++ b/.github/workflows/ci-on-push.yaml @@ -28,8 +28,7 @@ jobs: - name: Run tests run: | - poetry shell - python -B -m pytest -m "not only_on_pr" + poetry run python -B -m pytest -m "not only_on_pr" - name: Upload coverage to Codecov From 81df6f46c00dbc047ea70ff008012aba108a68c9 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Fri, 8 Sep 2023 16:06:27 +0200 Subject: [PATCH 06/59] solve dependency problems between pandas and pint-pandas --- poetry.lock | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index d4d8675..98af956 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2000,4 +2000,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a8264c7cf58ac4ed7d8ab385ad2d2e6e92d1d27254ad4cd21522bfedf9ef50a9" +content-hash = "333615d60823472696a89ef26aec79ac78f3550ec81f1255d7fb819b2abda157" diff --git a/pyproject.toml b/pyproject.toml index 7488944..fd8bdce 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,11 +11,11 @@ readme = "README.rst" [tool.poetry.dependencies] python = "^3.9" -pandas = "~2.0.0" +pandas = "~2.0" # pandas 2.1.0 doesn't play nice with pint-pandas. Update when new pint-pandas version is released (>0.5) numpy = "^1.25.2" matplotlib = "^3.7.2" pint = "^0.22" -pint-pandas = "^0.4" +pint-pandas = "^0.5" colorama = "^0.4.6" holidays = "^0.32" From 0a941bb8bb8c7adbacb1cf9668022947f356ea07 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Fri, 8 Sep 2023 17:46:19 +0200 Subject: [PATCH 07/59] workaround pint-pandas bug --- portfolyo/tools/changefreq.py | 16 +++++++++++++--- tests/dev/test_develop.py | 22 +++++++++++++++------- tests/utils.py | 2 ++ 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/portfolyo/tools/changefreq.py b/portfolyo/tools/changefreq.py index 47209c3..635bf1a 100644 --- a/portfolyo/tools/changefreq.py +++ b/portfolyo/tools/changefreq.py @@ -1,7 +1,7 @@ """Functions to change frequency of a pandas dataframe.""" import datetime as dt -from typing import Union +from typing import Any, Union import pandas as pd @@ -10,6 +10,14 @@ from . import trim as tools_trim +def _astype(s: pd.Series, dtype: Any) -> pd.Series: + # HACK: s.astype(float) results in incorrect datatype (see https://github.com/hgrecco/pint-pandas/issues/203). + # therefore: workaround taking the magnitude if wanted dtype is float (in this case, s.dtype should be 'pint[dimensionless]') + if dtype == float and s.dtype == "pint[dimensionless]": + return s.pint.magnitude + return s.astype(dtype) + + def _emptyseries(s_ref: pd.Series, freq) -> pd.Series: i = pd.DatetimeIndex([], freq=freq, tz=s_ref.index.tz) return pd.Series([], i, dtype=s_ref.dtype, name=s_ref.name) @@ -21,7 +29,8 @@ def _downsample_avgable(s: pd.Series, freq: str) -> pd.Series: summable = s.mul(s.index.duration, axis=0) # now has a pint dtype summable2 = _downsample_summable(summable, freq) s2 = summable2.div(summable2.index.duration, axis=0) - return s2.astype(s.dtype).rename(s.name) + s2 = _astype(s2, s.dtype) + return s2.rename(s.name) def _downsample_summable(s: pd.Series, freq: str) -> pd.Series: @@ -62,7 +71,8 @@ def _upsample_summable(s: pd.Series, freq: str) -> pd.Series: avgable = s.div(s.index.duration, axis=0) # now has a pint dtype avgable2 = _upsample_avgable(avgable, freq) s2 = avgable2.mul(avgable2.index.duration, axis=0) - return s2.astype(s.dtype).rename(s.name) + s2 = _astype(s2, s.dtype) + return s2.rename(s.name) def _upsample_avgable(s: pd.Series, freq: str) -> pd.Series: diff --git a/tests/dev/test_develop.py b/tests/dev/test_develop.py index 540b73a..2221b4e 100644 --- a/tests/dev/test_develop.py +++ b/tests/dev/test_develop.py @@ -61,8 +61,16 @@ def test_series(freq, tz, start, name, name_has_unit, request_unit): @pytest.mark.parametrize("request_unit", [True, False]) @pytest.mark.parametrize( - ("cols", "name_has_unit"), - [("q", True), ("wq", True), ("rp", True), ("prwq", True), ("qx", False)], + ("cols", "first_col_has_unit"), + [ + ("q", True), + ("wq", True), + ("rp", True), + ("prwq", True), + ("qx", True), + ("xq", False), + ("xy", False), + ], ) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize( @@ -76,15 +84,15 @@ def test_series(freq, tz, start, name, name_has_unit, request_unit): ("AS", "2020"), ], ) -def test_dataframe(freq, tz, start, cols, name_has_unit, request_unit): +def test_dataframe(freq, tz, start, cols, first_col_has_unit, request_unit): """Test dataframe creation.""" i = None if freq is None else dev.get_index(freq, tz, start) df = dev.get_dataframe(i, cols, request_unit) - if request_unit and name_has_unit: - _ = df.pint.dequantify() + unit = df.pint.dequantify().columns.get_level_values("unit")[0] + if request_unit and first_col_has_unit: + assert unit != "No Unit" else: - with pytest.raises((ValueError, AttributeError)): - _ = df.pint.dequantify() + assert unit == "No Unit" @pytest.mark.parametrize("kind", [Kind.COMPLETE, Kind.VOLUME, Kind.PRICE]) diff --git a/tests/utils.py b/tests/utils.py index c3cc891..3c9fecf 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -21,6 +21,8 @@ def id_fn(data: Any): return f"Df({''.join(str(c) for c in data.columns)})" elif isinstance(data, classes.PfLine): return f"{data.__class__.__name__}" + elif isinstance(data, pf.PfState): + return f"{data.__class__.__name__}" elif isinstance(data, pf.Q_): return f"Q({data.units})" elif isinstance(data, type): From 67ad1b41579ee949af8b4768d0ce7a462435decd Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Fri, 15 Sep 2023 20:01:59 +0200 Subject: [PATCH 08/59] typo --- portfolyo/testing/testing.py | 1 + portfolyo/tools/changefreq.py | 1 + tests/core/pfline/test_interop.py | 2 ++ ...est_pfline_arithmatic_numeric_and_error.py | 1 - .../core/pfline/test_pfline_excelclipboard.py | 19 +++++++++++++++++++ tests/core/pfstate/test_pfstate_arithmatic.py | 2 +- .../pfstate/test_pfstate_excelclipboard.py | 16 ++++++++++++++++ 7 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tests/core/pfline/test_pfline_excelclipboard.py create mode 100644 tests/core/pfstate/test_pfstate_excelclipboard.py diff --git a/portfolyo/testing/testing.py b/portfolyo/testing/testing.py index e58caaa..7d06df0 100644 --- a/portfolyo/testing/testing.py +++ b/portfolyo/testing/testing.py @@ -16,6 +16,7 @@ def assert_frame_equal(left: pd.DataFrame, right: pd.DataFrame, *args, **kwargs) right = tools.unit.drop_units(right).sort_index(axis=1) left = left.replace([np.inf, -np.inf], np.nan) right = right.replace([np.inf, -np.inf], np.nan) + # TODO: Test if units are the same pd.testing.assert_frame_equal(left, right, *args, **kwargs) diff --git a/portfolyo/tools/changefreq.py b/portfolyo/tools/changefreq.py index 635bf1a..7a86da1 100644 --- a/portfolyo/tools/changefreq.py +++ b/portfolyo/tools/changefreq.py @@ -11,6 +11,7 @@ def _astype(s: pd.Series, dtype: Any) -> pd.Series: + """Convert dtype of series ``s`` to ``dtype``.""" # HACK: s.astype(float) results in incorrect datatype (see https://github.com/hgrecco/pint-pandas/issues/203). # therefore: workaround taking the magnitude if wanted dtype is float (in this case, s.dtype should be 'pint[dimensionless]') if dtype == float and s.dtype == "pint[dimensionless]": diff --git a/tests/core/pfline/test_interop.py b/tests/core/pfline/test_interop.py index aa20336..1c544c6 100644 --- a/tests/core/pfline/test_interop.py +++ b/tests/core/pfline/test_interop.py @@ -7,6 +7,8 @@ from portfolyo.core.pfline import interop as io from portfolyo.tools.unit import Q_ +np.random.seed(3) # ensure same data all the time + idx1 = pd.date_range("2020", freq="MS", periods=12) val1 = 100 + 20 * np.random.random(len(idx1)) s1 = pd.Series(val1, idx1) diff --git a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py index cba97a9..e31de56 100644 --- a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py +++ b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py @@ -458,7 +458,6 @@ def test_negation(testcase: Case): do_test(testcase) -@pytest.mark.parametrize("testcase", additiontestcases(), ids=id_fn) @pytest.mark.parametrize("order", ["normal", "reversed"]) def test_addition(testcase: Case, order: str): do_test(testcase, order) diff --git a/tests/core/pfline/test_pfline_excelclipboard.py b/tests/core/pfline/test_pfline_excelclipboard.py new file mode 100644 index 0000000..8110001 --- /dev/null +++ b/tests/core/pfline/test_pfline_excelclipboard.py @@ -0,0 +1,19 @@ +"""Test if portfolio line can be exported.""" + +import pytest + +import portfolyo as pf + + +@pytest.mark.parametrize("levels", [1, 2, 3]) +def test_pfline_toexcel(levels: int): + """Test if data can be exported to excel.""" + pfl = pf.dev.get_randompfline(max_nlevels=levels) + pfl.to_excel("test.xlsx") + + +@pytest.mark.parametrize("levels", [1, 2, 3]) +def test_pfline_toclipboard(levels: int): + """Test if data can be copied to clipboard.""" + pfl = pf.dev.get_randompfline(max_nlevels=levels) + pfl.to_clipboard() diff --git a/tests/core/pfstate/test_pfstate_arithmatic.py b/tests/core/pfstate/test_pfstate_arithmatic.py index 6481e91..2ea1e84 100644 --- a/tests/core/pfstate/test_pfstate_arithmatic.py +++ b/tests/core/pfstate/test_pfstate_arithmatic.py @@ -100,7 +100,7 @@ ("offtake", "volume"): [3.0, 4], ("sourced", "volume"): [12 / 5, 5 / 4], ("sourced", "price"): [1.0, 2], - ("unsourced", "volume"): [np.nan, 15], + ("unsourced", "volume"): [np.nan, 15.0], ("unsourced", "price"): [400 / 150, 0.5], ("pnl_cost", "price"): [1.6, 62.5 / 60], }, diff --git a/tests/core/pfstate/test_pfstate_excelclipboard.py b/tests/core/pfstate/test_pfstate_excelclipboard.py new file mode 100644 index 0000000..5fdf494 --- /dev/null +++ b/tests/core/pfstate/test_pfstate_excelclipboard.py @@ -0,0 +1,16 @@ +"""Test if portfolio line can be exported.""" + + +import portfolyo as pf + + +def test_pfstate_toexcel(): + """Test if data can be exported to excel.""" + pfs = pf.dev.get_pfstate() + pfs.to_excel("test.xlsx") + + +def test_pfstate_toclipboard(): + """Test if data can be copied to clipboard.""" + pfs = pf.dev.get_pfstate() + pfs.to_clipboard() From 01b66663cfd7d770d93c92d8ef8fabfdbe696413 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Fri, 3 Nov 2023 17:10:43 +0100 Subject: [PATCH 09/59] seaborn pinned version to 0.8 --- .gitignore | 3 +- poetry.lock | 1120 ++++++++++++++++++----------------- portfolyo/visualize/plot.py | 2 +- 3 files changed, 594 insertions(+), 531 deletions(-) diff --git a/.gitignore b/.gitignore index be263b0..f6ea1bf 100644 --- a/.gitignore +++ b/.gitignore @@ -155,4 +155,5 @@ cython_debug/ # OWN -.issues/ \ No newline at end of file +.issues/ +.DS_Store \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index 98af956..df8e6c7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "appnope" @@ -13,61 +13,47 @@ files = [ [[package]] name = "asttokens" -version = "2.4.0" +version = "2.4.1" description = "Annotate AST trees with source code positions" optional = false python-versions = "*" files = [ - {file = "asttokens-2.4.0-py2.py3-none-any.whl", hash = "sha256:cf8fc9e61a86461aa9fb161a14a0841a03c405fa829ac6b202670b3495d2ce69"}, - {file = "asttokens-2.4.0.tar.gz", hash = "sha256:2e0171b991b2c959acc6c49318049236844a5da1d65ba2672c4880c1c894834e"}, + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, ] [package.dependencies] six = ">=1.12.0" [package.extras] -test = ["astroid", "pytest"] - -[[package]] -name = "backcall" -version = "0.2.0" -description = "Specifications for callback functions passed in to an API" -optional = false -python-versions = "*" -files = [ - {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"}, - {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"}, -] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "black" -version = "23.7.0" +version = "23.10.1" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"}, - {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"}, - {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"}, - {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"}, - {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"}, - {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"}, - {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"}, - {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"}, - {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"}, - {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"}, - {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"}, - {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"}, - {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"}, - {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"}, - {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"}, + {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, + {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, + {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, + {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, + {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, + {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, + {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, + {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, + {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, + {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, + {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, + {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, + {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, + {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, + {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, + {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, + {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, + {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, ] [package.dependencies] @@ -77,7 +63,7 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -98,75 +84,63 @@ files = [ [[package]] name = "cffi" -version = "1.15.1" +version = "1.16.0" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = "*" +python-versions = ">=3.8" files = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] [package.dependencies] @@ -185,86 +159,101 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, - {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, - {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, - {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, - {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, - {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, - {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] [[package]] @@ -340,6 +329,7 @@ files = [ {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, + {file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"}, {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, @@ -348,6 +338,7 @@ files = [ {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, + {file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"}, {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, @@ -356,6 +347,7 @@ files = [ {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, + {file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"}, {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, @@ -364,6 +356,7 @@ files = [ {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, + {file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"}, {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, @@ -384,65 +377,136 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pill test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "wurlitzer"] +[[package]] +name = "contourpy" +version = "1.1.1" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.8" +files = [ + {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, + {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, + {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, + {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, + {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, + {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, + {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, + {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, + {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, + {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, + {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, + {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, + {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, + {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, + {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, + {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, + {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, + {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, + {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, + {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, + {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, + {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, + {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, + {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, + {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, + {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, + {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, + {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, + {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, +] + +[package.dependencies] +numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""} + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "wurlitzer"] + [[package]] name = "coverage" -version = "7.3.0" +version = "7.3.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db76a1bcb51f02b2007adacbed4c88b6dee75342c37b05d1822815eed19edee5"}, - {file = "coverage-7.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c02cfa6c36144ab334d556989406837336c1d05215a9bdf44c0bc1d1ac1cb637"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477c9430ad5d1b80b07f3c12f7120eef40bfbf849e9e7859e53b9c93b922d2af"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce2ee86ca75f9f96072295c5ebb4ef2a43cecf2870b0ca5e7a1cbdd929cf67e1"}, - {file = "coverage-7.3.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68d8a0426b49c053013e631c0cdc09b952d857efa8f68121746b339912d27a12"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3eb0c93e2ea6445b2173da48cb548364f8f65bf68f3d090404080d338e3a689"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:90b6e2f0f66750c5a1178ffa9370dec6c508a8ca5265c42fbad3ccac210a7977"}, - {file = "coverage-7.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:96d7d761aea65b291a98c84e1250cd57b5b51726821a6f2f8df65db89363be51"}, - {file = "coverage-7.3.0-cp310-cp310-win32.whl", hash = "sha256:63c5b8ecbc3b3d5eb3a9d873dec60afc0cd5ff9d9f1c75981d8c31cfe4df8527"}, - {file = "coverage-7.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:97c44f4ee13bce914272589b6b41165bbb650e48fdb7bd5493a38bde8de730a1"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:74c160285f2dfe0acf0f72d425f3e970b21b6de04157fc65adc9fd07ee44177f"}, - {file = "coverage-7.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b543302a3707245d454fc49b8ecd2c2d5982b50eb63f3535244fd79a4be0c99d"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad0f87826c4ebd3ef484502e79b39614e9c03a5d1510cfb623f4a4a051edc6fd"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13c6cbbd5f31211d8fdb477f0f7b03438591bdd077054076eec362cf2207b4a7"}, - {file = "coverage-7.3.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac440c43e9b479d1241fe9d768645e7ccec3fb65dc3a5f6e90675e75c3f3e3a"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3c9834d5e3df9d2aba0275c9f67989c590e05732439b3318fa37a725dff51e74"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4c8e31cf29b60859876474034a83f59a14381af50cbe8a9dbaadbf70adc4b214"}, - {file = "coverage-7.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7a9baf8e230f9621f8e1d00c580394a0aa328fdac0df2b3f8384387c44083c0f"}, - {file = "coverage-7.3.0-cp311-cp311-win32.whl", hash = "sha256:ccc51713b5581e12f93ccb9c5e39e8b5d4b16776d584c0f5e9e4e63381356482"}, - {file = "coverage-7.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:887665f00ea4e488501ba755a0e3c2cfd6278e846ada3185f42d391ef95e7e70"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d000a739f9feed900381605a12a61f7aaced6beae832719ae0d15058a1e81c1b"}, - {file = "coverage-7.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59777652e245bb1e300e620ce2bef0d341945842e4eb888c23a7f1d9e143c446"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9737bc49a9255d78da085fa04f628a310c2332b187cd49b958b0e494c125071"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5247bab12f84a1d608213b96b8af0cbb30d090d705b6663ad794c2f2a5e5b9fe"}, - {file = "coverage-7.3.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ac9a1de294773b9fa77447ab7e529cf4fe3910f6a0832816e5f3d538cfea9a"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:85b7335c22455ec12444cec0d600533a238d6439d8d709d545158c1208483873"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:36ce5d43a072a036f287029a55b5c6a0e9bd73db58961a273b6dc11a2c6eb9c2"}, - {file = "coverage-7.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:211a4576e984f96d9fce61766ffaed0115d5dab1419e4f63d6992b480c2bd60b"}, - {file = "coverage-7.3.0-cp312-cp312-win32.whl", hash = "sha256:56afbf41fa4a7b27f6635bc4289050ac3ab7951b8a821bca46f5b024500e6321"}, - {file = "coverage-7.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:7f297e0c1ae55300ff688568b04ff26b01c13dfbf4c9d2b7d0cb688ac60df479"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ac0dec90e7de0087d3d95fa0533e1d2d722dcc008bc7b60e1143402a04c117c1"}, - {file = "coverage-7.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:438856d3f8f1e27f8e79b5410ae56650732a0dcfa94e756df88c7e2d24851fcd"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1084393c6bda8875c05e04fce5cfe1301a425f758eb012f010eab586f1f3905e"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49ab200acf891e3dde19e5aa4b0f35d12d8b4bd805dc0be8792270c71bd56c54"}, - {file = "coverage-7.3.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67e6bbe756ed458646e1ef2b0778591ed4d1fcd4b146fc3ba2feb1a7afd4254"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f39c49faf5344af36042b293ce05c0d9004270d811c7080610b3e713251c9b0"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7df91fb24c2edaabec4e0eee512ff3bc6ec20eb8dccac2e77001c1fe516c0c84"}, - {file = "coverage-7.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:34f9f0763d5fa3035a315b69b428fe9c34d4fc2f615262d6be3d3bf3882fb985"}, - {file = "coverage-7.3.0-cp38-cp38-win32.whl", hash = "sha256:bac329371d4c0d456e8d5f38a9b0816b446581b5f278474e416ea0c68c47dcd9"}, - {file = "coverage-7.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b859128a093f135b556b4765658d5d2e758e1fae3e7cc2f8c10f26fe7005e543"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed8d310afe013db1eedd37176d0839dc66c96bcfcce8f6607a73ffea2d6ba"}, - {file = "coverage-7.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61260ec93f99f2c2d93d264b564ba912bec502f679793c56f678ba5251f0393"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97af9554a799bd7c58c0179cc8dbf14aa7ab50e1fd5fa73f90b9b7215874ba28"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3558e5b574d62f9c46b76120a5c7c16c4612dc2644c3d48a9f4064a705eaee95"}, - {file = "coverage-7.3.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37d5576d35fcb765fca05654f66aa71e2808d4237d026e64ac8b397ffa66a56a"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:07ea61bcb179f8f05ffd804d2732b09d23a1238642bf7e51dad62082b5019b34"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:80501d1b2270d7e8daf1b64b895745c3e234289e00d5f0e30923e706f110334e"}, - {file = "coverage-7.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4eddd3153d02204f22aef0825409091a91bf2a20bce06fe0f638f5c19a85de54"}, - {file = "coverage-7.3.0-cp39-cp39-win32.whl", hash = "sha256:2d22172f938455c156e9af2612650f26cceea47dc86ca048fa4e0b2d21646ad3"}, - {file = "coverage-7.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:60f64e2007c9144375dd0f480a54d6070f00bb1a28f65c408370544091c9bc9e"}, - {file = "coverage-7.3.0-pp38.pp39.pp310-none-any.whl", hash = "sha256:5492a6ce3bdb15c6ad66cb68a0244854d9917478877a25671d70378bdc8562d0"}, - {file = "coverage-7.3.0.tar.gz", hash = "sha256:49dbb19cdcafc130f597d9e04a29d0a032ceedf729e41b181f51cd170e6ee865"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d872145f3a3231a5f20fd48500274d7df222e291d90baa2026cc5152b7ce86bf"}, + {file = "coverage-7.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:310b3bb9c91ea66d59c53fa4989f57d2436e08f18fb2f421a1b0b6b8cc7fffda"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f47d39359e2c3779c5331fc740cf4bce6d9d680a7b4b4ead97056a0ae07cb49a"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa72dbaf2c2068404b9870d93436e6d23addd8bbe9295f49cbca83f6e278179c"}, + {file = "coverage-7.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:beaa5c1b4777f03fc63dfd2a6bd820f73f036bfb10e925fce067b00a340d0f3f"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dbc1b46b92186cc8074fee9d9fbb97a9dd06c6cbbef391c2f59d80eabdf0faa6"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:315a989e861031334d7bee1f9113c8770472db2ac484e5b8c3173428360a9148"}, + {file = "coverage-7.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d1bc430677773397f64a5c88cb522ea43175ff16f8bfcc89d467d974cb2274f9"}, + {file = "coverage-7.3.2-cp310-cp310-win32.whl", hash = "sha256:a889ae02f43aa45032afe364c8ae84ad3c54828c2faa44f3bfcafecb5c96b02f"}, + {file = "coverage-7.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c0ba320de3fb8c6ec16e0be17ee1d3d69adcda99406c43c0409cb5c41788a611"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ac8c802fa29843a72d32ec56d0ca792ad15a302b28ca6203389afe21f8fa062c"}, + {file = "coverage-7.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:89a937174104339e3a3ffcf9f446c00e3a806c28b1841c63edb2b369310fd074"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e267e9e2b574a176ddb983399dec325a80dbe161f1a32715c780b5d14b5f583a"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2443cbda35df0d35dcfb9bf8f3c02c57c1d6111169e3c85fc1fcc05e0c9f39a3"}, + {file = "coverage-7.3.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4175e10cc8dda0265653e8714b3174430b07c1dca8957f4966cbd6c2b1b8065a"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0cbf38419fb1a347aaf63481c00f0bdc86889d9fbf3f25109cf96c26b403fda1"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5c913b556a116b8d5f6ef834038ba983834d887d82187c8f73dec21049abd65c"}, + {file = "coverage-7.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1981f785239e4e39e6444c63a98da3a1db8e971cb9ceb50a945ba6296b43f312"}, + {file = "coverage-7.3.2-cp311-cp311-win32.whl", hash = "sha256:43668cabd5ca8258f5954f27a3aaf78757e6acf13c17604d89648ecc0cc66640"}, + {file = "coverage-7.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10c39c0452bf6e694511c901426d6b5ac005acc0f78ff265dbe36bf81f808a2"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4cbae1051ab791debecc4a5dcc4a1ff45fc27b91b9aee165c8a27514dd160836"}, + {file = "coverage-7.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12d15ab5833a997716d76f2ac1e4b4d536814fc213c85ca72756c19e5a6b3d63"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7bba973ebee5e56fe9251300c00f1579652587a9f4a5ed8404b15a0471f216"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe494faa90ce6381770746077243231e0b83ff3f17069d748f645617cefe19d4"}, + {file = "coverage-7.3.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6e9589bd04d0461a417562649522575d8752904d35c12907d8c9dfeba588faf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d51ac2a26f71da1b57f2dc81d0e108b6ab177e7d30e774db90675467c847bbdf"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:99b89d9f76070237975b315b3d5f4d6956ae354a4c92ac2388a5695516e47c84"}, + {file = "coverage-7.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fa28e909776dc69efb6ed975a63691bc8172b64ff357e663a1bb06ff3c9b589a"}, + {file = "coverage-7.3.2-cp312-cp312-win32.whl", hash = "sha256:289fe43bf45a575e3ab10b26d7b6f2ddb9ee2dba447499f5401cfb5ecb8196bb"}, + {file = "coverage-7.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7dbc3ed60e8659bc59b6b304b43ff9c3ed858da2839c78b804973f613d3e92ed"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f94b734214ea6a36fe16e96a70d941af80ff3bfd716c141300d95ebc85339738"}, + {file = "coverage-7.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:af3d828d2c1cbae52d34bdbb22fcd94d1ce715d95f1a012354a75e5913f1bda2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:630b13e3036e13c7adc480ca42fa7afc2a5d938081d28e20903cf7fd687872e2"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9eacf273e885b02a0273bb3a2170f30e2d53a6d53b72dbe02d6701b5296101c"}, + {file = "coverage-7.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f17966e861ff97305e0801134e69db33b143bbfb36436efb9cfff6ec7b2fd9"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b4275802d16882cf9c8b3d057a0839acb07ee9379fa2749eca54efbce1535b82"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:72c0cfa5250f483181e677ebc97133ea1ab3eb68645e494775deb6a7f6f83901"}, + {file = "coverage-7.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cb536f0dcd14149425996821a168f6e269d7dcd2c273a8bff8201e79f5104e76"}, + {file = "coverage-7.3.2-cp38-cp38-win32.whl", hash = "sha256:307adb8bd3abe389a471e649038a71b4eb13bfd6b7dd9a129fa856f5c695cf92"}, + {file = "coverage-7.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:88ed2c30a49ea81ea3b7f172e0269c182a44c236eb394718f976239892c0a27a"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b631c92dfe601adf8f5ebc7fc13ced6bb6e9609b19d9a8cd59fa47c4186ad1ce"}, + {file = "coverage-7.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d3d9df4051c4a7d13036524b66ecf7a7537d14c18a384043f30a303b146164e9"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7363d3b6a1119ef05015959ca24a9afc0ea8a02c687fe7e2d557705375c01f"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f11cc3c967a09d3695d2a6f03fb3e6236622b93be7a4b5dc09166a861be6d25"}, + {file = "coverage-7.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:149de1d2401ae4655c436a3dced6dd153f4c3309f599c3d4bd97ab172eaf02d9"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3a4006916aa6fee7cd38db3bfc95aa9c54ebb4ffbfc47c677c8bba949ceba0a6"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9028a3871280110d6e1aa2df1afd5ef003bab5fb1ef421d6dc748ae1c8ef2ebc"}, + {file = "coverage-7.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9f805d62aec8eb92bab5b61c0f07329275b6f41c97d80e847b03eb894f38d083"}, + {file = "coverage-7.3.2-cp39-cp39-win32.whl", hash = "sha256:d1c88ec1a7ff4ebca0219f5b1ef863451d828cccf889c173e1253aa84b1e07ce"}, + {file = "coverage-7.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b4767da59464bb593c07afceaddea61b154136300881844768037fd5e859353f"}, + {file = "coverage-7.3.2-pp38.pp39.pp310-none-any.whl", hash = "sha256:ae97af89f0fbf373400970c0a21eef5aa941ffeed90aee43650b81f7d7f47637"}, + {file = "coverage-7.3.2.tar.gz", hash = "sha256:be32ad29341b0170e795ca590e1c07e81fc061cb5b10c74ce7203491484404ef"}, ] [package.dependencies] @@ -453,40 +517,44 @@ toml = ["tomli"] [[package]] name = "cycler" -version = "0.11.0" +version = "0.12.1" description = "Composable style cycles" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"}, - {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"}, + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, ] +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "debugpy" -version = "1.6.7.post1" +version = "1.8.0" description = "An implementation of the Debug Adapter Protocol for Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "debugpy-1.6.7.post1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:903bd61d5eb433b6c25b48eae5e23821d4c1a19e25c9610205f5aeaccae64e32"}, - {file = "debugpy-1.6.7.post1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d16882030860081e7dd5aa619f30dec3c2f9a421e69861125f83cc372c94e57d"}, - {file = "debugpy-1.6.7.post1-cp310-cp310-win32.whl", hash = "sha256:eea8d8cfb9965ac41b99a61f8e755a8f50e9a20330938ad8271530210f54e09c"}, - {file = "debugpy-1.6.7.post1-cp310-cp310-win_amd64.whl", hash = "sha256:85969d864c45f70c3996067cfa76a319bae749b04171f2cdeceebe4add316155"}, - {file = "debugpy-1.6.7.post1-cp37-cp37m-macosx_11_0_x86_64.whl", hash = "sha256:890f7ab9a683886a0f185786ffbda3b46495c4b929dab083b8c79d6825832a52"}, - {file = "debugpy-1.6.7.post1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4ac7a4dba28801d184b7fc0e024da2635ca87d8b0a825c6087bb5168e3c0d28"}, - {file = "debugpy-1.6.7.post1-cp37-cp37m-win32.whl", hash = "sha256:3370ef1b9951d15799ef7af41f8174194f3482ee689988379763ef61a5456426"}, - {file = "debugpy-1.6.7.post1-cp37-cp37m-win_amd64.whl", hash = "sha256:65b28435a17cba4c09e739621173ff90c515f7b9e8ea469b92e3c28ef8e5cdfb"}, - {file = "debugpy-1.6.7.post1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:92b6dae8bfbd497c90596bbb69089acf7954164aea3228a99d7e43e5267f5b36"}, - {file = "debugpy-1.6.7.post1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72f5d2ecead8125cf669e62784ef1e6300f4067b0f14d9f95ee00ae06fc7c4f7"}, - {file = "debugpy-1.6.7.post1-cp38-cp38-win32.whl", hash = "sha256:f0851403030f3975d6e2eaa4abf73232ab90b98f041e3c09ba33be2beda43fcf"}, - {file = "debugpy-1.6.7.post1-cp38-cp38-win_amd64.whl", hash = "sha256:3de5d0f97c425dc49bce4293df6a04494309eedadd2b52c22e58d95107e178d9"}, - {file = "debugpy-1.6.7.post1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:38651c3639a4e8bbf0ca7e52d799f6abd07d622a193c406be375da4d510d968d"}, - {file = "debugpy-1.6.7.post1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:038c51268367c9c935905a90b1c2d2dbfe304037c27ba9d19fe7409f8cdc710c"}, - {file = "debugpy-1.6.7.post1-cp39-cp39-win32.whl", hash = "sha256:4b9eba71c290852f959d2cf8a03af28afd3ca639ad374d393d53d367f7f685b2"}, - {file = "debugpy-1.6.7.post1-cp39-cp39-win_amd64.whl", hash = "sha256:973a97ed3b434eab0f792719a484566c35328196540676685c975651266fccf9"}, - {file = "debugpy-1.6.7.post1-py2.py3-none-any.whl", hash = "sha256:1093a5c541af079c13ac8c70ab8b24d1d35c8cacb676306cf11e57f699c02926"}, - {file = "debugpy-1.6.7.post1.zip", hash = "sha256:fe87ec0182ef624855d05e6ed7e0b7cb1359d2ffa2a925f8ec2d22e98b75d0ca"}, + {file = "debugpy-1.8.0-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7fb95ca78f7ac43393cd0e0f2b6deda438ec7c5e47fa5d38553340897d2fbdfb"}, + {file = "debugpy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef9ab7df0b9a42ed9c878afd3eaaff471fce3fa73df96022e1f5c9f8f8c87ada"}, + {file = "debugpy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:a8b7a2fd27cd9f3553ac112f356ad4ca93338feadd8910277aff71ab24d8775f"}, + {file = "debugpy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5d9de202f5d42e62f932507ee8b21e30d49aae7e46d5b1dd5c908db1d7068637"}, + {file = "debugpy-1.8.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:ef54404365fae8d45cf450d0544ee40cefbcb9cb85ea7afe89a963c27028261e"}, + {file = "debugpy-1.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60009b132c91951354f54363f8ebdf7457aeb150e84abba5ae251b8e9f29a8a6"}, + {file = "debugpy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:8cd0197141eb9e8a4566794550cfdcdb8b3db0818bdf8c49a8e8f8053e56e38b"}, + {file = "debugpy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:a64093656c4c64dc6a438e11d59369875d200bd5abb8f9b26c1f5f723622e153"}, + {file = "debugpy-1.8.0-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:b05a6b503ed520ad58c8dc682749113d2fd9f41ffd45daec16e558ca884008cd"}, + {file = "debugpy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c6fb41c98ec51dd010d7ed650accfd07a87fe5e93eca9d5f584d0578f28f35f"}, + {file = "debugpy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:46ab6780159eeabb43c1495d9c84cf85d62975e48b6ec21ee10c95767c0590aa"}, + {file = "debugpy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:bdc5ef99d14b9c0fcb35351b4fbfc06ac0ee576aeab6b2511702e5a648a2e595"}, + {file = "debugpy-1.8.0-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:61eab4a4c8b6125d41a34bad4e5fe3d2cc145caecd63c3fe953be4cc53e65bf8"}, + {file = "debugpy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:125b9a637e013f9faac0a3d6a82bd17c8b5d2c875fb6b7e2772c5aba6d082332"}, + {file = "debugpy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:57161629133113c97b387382045649a2b985a348f0c9366e22217c87b68b73c6"}, + {file = "debugpy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:e3412f9faa9ade82aa64a50b602544efcba848c91384e9f93497a458767e6926"}, + {file = "debugpy-1.8.0-py2.py3-none-any.whl", hash = "sha256:9c9b0ac1ce2a42888199df1a1906e45e6f3c9555497643a85e0bf2406e3ffbc4"}, + {file = "debugpy-1.8.0.zip", hash = "sha256:12af2c55b419521e33d5fb21bd022df0b5eb267c3e178f1d374a63a2a6bdccd0"}, ] [[package]] @@ -538,35 +606,33 @@ test = ["pytest (>=6)"] [[package]] name = "executing" -version = "1.2.0" +version = "2.0.1" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = "*" +python-versions = ">=3.5" files = [ - {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"}, - {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"}, + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, ] [package.extras] -tests = ["asttokens", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] [[package]] name = "filelock" -version = "3.12.3" +version = "3.13.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.12.3-py3-none-any.whl", hash = "sha256:f067e40ccc40f2b48395a80fcbd4728262fab54e232e090a4063ab804179efeb"}, - {file = "filelock-3.12.3.tar.gz", hash = "sha256:0ecc1dd2ec4672a10c8550a8182f1bd0c0a5088470ecd5a125e45f49472fac3d"}, + {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, + {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.11\""} - [package.extras] -docs = ["furo (>=2023.7.26)", "sphinx (>=7.1.2)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3)", "diff-cover (>=7.7)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +typing = ["typing-extensions (>=4.8)"] [[package]] name = "flake8" @@ -586,49 +652,57 @@ pyflakes = ">=3.1.0,<3.2.0" [[package]] name = "fonttools" -version = "4.42.1" +version = "4.44.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ed1a13a27f59d1fc1920394a7f596792e9d546c9ca5a044419dca70c37815d7c"}, - {file = "fonttools-4.42.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c9b1ce7a45978b821a06d375b83763b27a3a5e8a2e4570b3065abad240a18760"}, - {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f720fa82a11c0f9042376fd509b5ed88dab7e3cd602eee63a1af08883b37342b"}, - {file = "fonttools-4.42.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db55cbaea02a20b49fefbd8e9d62bd481aaabe1f2301dabc575acc6b358874fa"}, - {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a35981d90feebeaef05e46e33e6b9e5b5e618504672ca9cd0ff96b171e4bfff"}, - {file = "fonttools-4.42.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:68a02bbe020dc22ee0540e040117535f06df9358106d3775e8817d826047f3fd"}, - {file = "fonttools-4.42.1-cp310-cp310-win32.whl", hash = "sha256:12a7c247d1b946829bfa2f331107a629ea77dc5391dfd34fdcd78efa61f354ca"}, - {file = "fonttools-4.42.1-cp310-cp310-win_amd64.whl", hash = "sha256:a398bdadb055f8de69f62b0fc70625f7cbdab436bbb31eef5816e28cab083ee8"}, - {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:689508b918332fb40ce117131633647731d098b1b10d092234aa959b4251add5"}, - {file = "fonttools-4.42.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e36344e48af3e3bde867a1ca54f97c308735dd8697005c2d24a86054a114a71"}, - {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19b7db825c8adee96fac0692e6e1ecd858cae9affb3b4812cdb9d934a898b29e"}, - {file = "fonttools-4.42.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:113337c2d29665839b7d90b39f99b3cac731f72a0eda9306165a305c7c31d341"}, - {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:37983b6bdab42c501202500a2be3a572f50d4efe3237e0686ee9d5f794d76b35"}, - {file = "fonttools-4.42.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6ed2662a3d9c832afa36405f8748c250be94ae5dfc5283d668308391f2102861"}, - {file = "fonttools-4.42.1-cp311-cp311-win32.whl", hash = "sha256:179737095eb98332a2744e8f12037b2977f22948cf23ff96656928923ddf560a"}, - {file = "fonttools-4.42.1-cp311-cp311-win_amd64.whl", hash = "sha256:f2b82f46917d8722e6b5eafeefb4fb585d23babd15d8246c664cd88a5bddd19c"}, - {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:62f481ac772fd68901573956231aea3e4b1ad87b9b1089a61613a91e2b50bb9b"}, - {file = "fonttools-4.42.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f2f806990160d1ce42d287aa419df3ffc42dfefe60d473695fb048355fe0c6a0"}, - {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db372213d39fa33af667c2aa586a0c1235e88e9c850f5dd5c8e1f17515861868"}, - {file = "fonttools-4.42.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d18fc642fd0ac29236ff88ecfccff229ec0386090a839dd3f1162e9a7944a40"}, - {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8708b98c278012ad267ee8a7433baeb809948855e81922878118464b274c909d"}, - {file = "fonttools-4.42.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c95b0724a6deea2c8c5d3222191783ced0a2f09bd6d33f93e563f6f1a4b3b3a4"}, - {file = "fonttools-4.42.1-cp38-cp38-win32.whl", hash = "sha256:4aa79366e442dbca6e2c8595645a3a605d9eeabdb7a094d745ed6106816bef5d"}, - {file = "fonttools-4.42.1-cp38-cp38-win_amd64.whl", hash = "sha256:acb47f6f8680de24c1ab65ebde39dd035768e2a9b571a07c7b8da95f6c8815fd"}, - {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5fb289b7a815638a7613d46bcf324c9106804725b2bb8ad913c12b6958ffc4ec"}, - {file = "fonttools-4.42.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53eb5091ddc8b1199330bb7b4a8a2e7995ad5d43376cadce84523d8223ef3136"}, - {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:46a0ec8adbc6ff13494eb0c9c2e643b6f009ce7320cf640de106fb614e4d4360"}, - {file = "fonttools-4.42.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7cc7d685b8eeca7ae69dc6416833fbfea61660684b7089bca666067cb2937dcf"}, - {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:be24fcb80493b2c94eae21df70017351851652a37de514de553435b256b2f249"}, - {file = "fonttools-4.42.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:515607ec756d7865f23070682622c49d922901943697871fc292277cf1e71967"}, - {file = "fonttools-4.42.1-cp39-cp39-win32.whl", hash = "sha256:0eb79a2da5eb6457a6f8ab904838454accc7d4cccdaff1fd2bd3a0679ea33d64"}, - {file = "fonttools-4.42.1-cp39-cp39-win_amd64.whl", hash = "sha256:7286aed4ea271df9eab8d7a9b29e507094b51397812f7ce051ecd77915a6e26b"}, - {file = "fonttools-4.42.1-py3-none-any.whl", hash = "sha256:9398f244e28e0596e2ee6024f808b06060109e33ed38dcc9bded452fd9bbb853"}, - {file = "fonttools-4.42.1.tar.gz", hash = "sha256:c391cd5af88aacaf41dd7cfb96eeedfad297b5899a39e12f4c2c3706d0a3329d"}, + {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1cd1c6bb097e774d68402499ff66185190baaa2629ae2f18515a2c50b93db0c"}, + {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9eab7f9837fdaa2a10a524fbcc2ec24bf60637c044b6e4a59c3f835b90f0fae"}, + {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f412954275e594f7a51c16f3b3edd850acb0d842fefc33856b63a17e18499a5"}, + {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50d25893885e80a5955186791eed5579f1e75921751539cc1dc3ffd1160b48cf"}, + {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:22ea8aa7b3712450b42b044702bd3a64fd118006bad09a6f94bd1b227088492e"}, + {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df40daa6c03b98652ffe8110ae014fe695437f6e1cb5a07e16ea37f40e73ac86"}, + {file = "fonttools-4.44.0-cp310-cp310-win32.whl", hash = "sha256:bca49da868e8bde569ef36f0cc1b6de21d56bf9c3be185c503b629c19a185287"}, + {file = "fonttools-4.44.0-cp310-cp310-win_amd64.whl", hash = "sha256:dbac86d83d96099890e731cc2af97976ff2c98f4ba432fccde657c5653a32f1c"}, + {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e8ff7d19a6804bfd561cfcec9b4200dd1788e28f7de4be70189801530c47c1b3"}, + {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8a1fa9a718de0bc026979c93e1e9b55c5efde60d76f91561fd713387573817d"}, + {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05064f95aacdfc06f21e55096c964b2228d942b8675fa26995a2551f6329d2d"}, + {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31b38528f25bc662401e6ffae14b3eb7f1e820892fd80369a37155e3b636a2f4"}, + {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:05d7c4d2c95b9490e669f3cb83918799bf1c838619ac6d3bad9ea017cfc63f2e"}, + {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6999e80a125b0cd8e068d0210b63323f17338038c2ecd2e11b9209ec430fe7f2"}, + {file = "fonttools-4.44.0-cp311-cp311-win32.whl", hash = "sha256:a7aec7f5d14dfcd71fb3ebc299b3f000c21fdc4043079101777ed2042ba5b7c5"}, + {file = "fonttools-4.44.0-cp311-cp311-win_amd64.whl", hash = "sha256:518a945dbfe337744bfff31423c1430303b8813c5275dffb0f2577f0734a1189"}, + {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:59b6ad83cce067d10f4790c037a5904424f45bebb5e7be2eb2db90402f288267"}, + {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c2de1fb18198acd400c45ffe2aef5420c8d55fde903e91cba705596099550f3b"}, + {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f308b7a8d28208d54315d11d35f9888d6d607673dd4d42d60b463682ee0400"}, + {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66bc6efd829382f7a7e6cf33c2fb32b13edc8a239eb15f32acbf197dce7a0165"}, + {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a8b99713d3a0d0e876b6aecfaada5e7dc9fe979fcd90ef9fa0ba1d9b9aed03f2"}, + {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b63da598d9cbc52e2381f922da0e94d60c0429f92207bd3fb04d112fc82ea7cb"}, + {file = "fonttools-4.44.0-cp312-cp312-win32.whl", hash = "sha256:f611c97678604e302b725f71626edea113a5745a7fb557c958b39edb6add87d5"}, + {file = "fonttools-4.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:58af428746fa73a2edcbf26aff33ac4ef3c11c8d75bb200eaea2f7e888d2de4e"}, + {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9ee8692e23028564c13d924004495f284df8ac016a19f17a87251210e1f1f928"}, + {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dab3d00d27b1a79ae4d4a240e8ceea8af0ff049fd45f05adb4f860d93744110d"}, + {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f53526668beccdb3409c6055a4ffe50987a7f05af6436fa55d61f5e7bd450219"}, + {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3da036b016c975c2d8c69005bdc4d5d16266f948a7fab950244e0f58301996a"}, + {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b99fe8ef4093f672d00841569d2d05691e50334d79f4d9c15c1265d76d5580d2"}, + {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d16d9634ff1e5cea2cf4a8cbda9026f766e4b5f30b48f8180f0e99133d3abfc"}, + {file = "fonttools-4.44.0-cp38-cp38-win32.whl", hash = "sha256:3d29509f6e05e8d725db59c2d8c076223d793e4e35773040be6632a0349f2f97"}, + {file = "fonttools-4.44.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4fa4f4bc8fd86579b8cdbe5e948f35d82c0eda0091c399d009b2a5a6b61c040"}, + {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c794de4086f06ae609b71ac944ec7deb09f34ecf73316fddc041087dd24bba39"}, + {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2db63941fee3122e31a21dd0f5b2138ce9906b661a85b63622421d3654a74ae2"}, + {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb01c49c8aa035d5346f46630209923d4927ed15c2493db38d31da9f811eb70d"}, + {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c79af80a835410874683b5779b6c1ec1d5a285e11c45b5193e79dd691eb111"}, + {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6e6aa2d066f8dafd06d8d0799b4944b5d5a1f015dd52ac01bdf2895ebe169a0"}, + {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63a3112f753baef8c6ac2f5f574bb9ac8001b86c8c0c0380039db47a7f512d20"}, + {file = "fonttools-4.44.0-cp39-cp39-win32.whl", hash = "sha256:54efed22b2799a85475e6840e907c402ba49892c614565dc770aa97a53621b2b"}, + {file = "fonttools-4.44.0-cp39-cp39-win_amd64.whl", hash = "sha256:2e91e19b583961979e2e5a701269d3cfc07418963bee717f8160b0a24332826b"}, + {file = "fonttools-4.44.0-py3-none-any.whl", hash = "sha256:b9beb0fa6ff3ea808ad4a6962d68ac0f140ddab080957b20d9e268e4d67fb335"}, + {file = "fonttools-4.44.0.tar.gz", hash = "sha256:4e90dd81b6e0d97ebfe52c0d12a17a9ef7f305d6bfbb93081265057d6092f252"}, ] [package.extras] -all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.0.0)", "xattr", "zopfli (>=0.1.4)"] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] graphite = ["lz4 (>=1.7.4.2)"] interpolatable = ["munkres", "scipy"] lxml = ["lxml (>=4.0,<5)"] @@ -638,7 +712,7 @@ repacker = ["uharfbuzz (>=0.23.0)"] symfont = ["sympy"] type1 = ["xattr"] ufo = ["fs (>=2.2.0,<3)"] -unicode = ["unicodedata2 (>=15.0.0)"] +unicode = ["unicodedata2 (>=15.1.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] @@ -657,13 +731,13 @@ python-dateutil = "*" [[package]] name = "identify" -version = "2.5.27" +version = "2.5.31" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.27-py2.py3-none-any.whl", hash = "sha256:fdb527b2dfe24602809b2201e033c2a113d7bdf716db3ca8e3243f735dcecaba"}, - {file = "identify-2.5.27.tar.gz", hash = "sha256:287b75b04a0e22d727bc9a41f0d4f3c1bcada97490fa6eabb5b28f0e9097e733"}, + {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"}, + {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"}, ] [package.extras] @@ -701,21 +775,21 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs [[package]] name = "importlib-resources" -version = "6.0.1" +version = "6.1.0" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.0.1-py3-none-any.whl", hash = "sha256:134832a506243891221b88b4ae1213327eea96ceb4e407a00d790bb0626f45cf"}, - {file = "importlib_resources-6.0.1.tar.gz", hash = "sha256:4359457e42708462b9626a04657c6208ad799ceb41e5c58c57ffa0e6a098a5d4"}, + {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, + {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, ] [package.dependencies] zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-ruff", "zipp (>=3.17)"] [[package]] name = "iniconfig" @@ -730,13 +804,13 @@ files = [ [[package]] name = "ipykernel" -version = "6.25.2" +version = "6.26.0" description = "IPython Kernel for Jupyter" optional = false python-versions = ">=3.8" files = [ - {file = "ipykernel-6.25.2-py3-none-any.whl", hash = "sha256:2e2ee359baba19f10251b99415bb39de1e97d04e1fab385646f24f0596510b77"}, - {file = "ipykernel-6.25.2.tar.gz", hash = "sha256:f468ddd1f17acb48c8ce67fcfa49ba6d46d4f9ac0438c1f441be7c3d1372230b"}, + {file = "ipykernel-6.26.0-py3-none-any.whl", hash = "sha256:3ba3dc97424b87b31bb46586b5167b3161b32d7820b9201a9e698c71e271602c"}, + {file = "ipykernel-6.26.0.tar.gz", hash = "sha256:553856658eb8430bbe9653ea041a41bff63e9606fc4628873fc92a6cf3abd404"}, ] [package.dependencies] @@ -763,25 +837,23 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio" [[package]] name = "ipython" -version = "8.15.0" +version = "8.17.2" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" files = [ - {file = "ipython-8.15.0-py3-none-any.whl", hash = "sha256:45a2c3a529296870a97b7de34eda4a31bee16bc7bf954e07d39abe49caf8f887"}, - {file = "ipython-8.15.0.tar.gz", hash = "sha256:2baeb5be6949eeebf532150f81746f8333e2ccce02de1c7eedde3f23ed5e9f1e"}, + {file = "ipython-8.17.2-py3-none-any.whl", hash = "sha256:1e4d1d666a023e3c93585ba0d8e962867f7a111af322efff6b9c58062b3e5444"}, + {file = "ipython-8.17.2.tar.gz", hash = "sha256:126bb57e1895594bb0d91ea3090bbd39384f6fe87c3d57fd558d0670f50339bb"}, ] [package.dependencies] appnope = {version = "*", markers = "sys_platform == \"darwin\""} -backcall = "*" colorama = {version = "*", markers = "sys_platform == \"win32\""} decorator = "*" exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} jedi = ">=0.16" matplotlib-inline = "*" pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""} -pickleshare = "*" prompt-toolkit = ">=3.0.30,<3.0.37 || >3.0.37,<3.1.0" pygments = ">=2.4.0" stack-data = "*" @@ -789,27 +861,27 @@ traitlets = ">=5" typing-extensions = {version = "*", markers = "python_version < \"3.10\""} [package.extras] -all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.21)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] +all = ["black", "curio", "docrepr", "exceptiongroup", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"] black = ["black"] -doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] +doc = ["docrepr", "exceptiongroup", "ipykernel", "matplotlib", "pickleshare", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio (<0.22)", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pytest (<7.1)", "pytest-asyncio", "testpath"] -test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.21)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"] +test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] [[package]] name = "jedi" -version = "0.19.0" +version = "0.19.1" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" files = [ - {file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"}, - {file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"}, + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, ] [package.dependencies] @@ -818,17 +890,17 @@ parso = ">=0.8.3,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jupyter-client" -version = "8.3.1" +version = "8.5.0" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.3.1-py3-none-any.whl", hash = "sha256:5eb9f55eb0650e81de6b7e34308d8b92d04fe4ec41cd8193a913979e33d8e1a5"}, - {file = "jupyter_client-8.3.1.tar.gz", hash = "sha256:60294b2d5b869356c893f57b1a877ea6510d60d45cf4b38057f1672d85699ac9"}, + {file = "jupyter_client-8.5.0-py3-none-any.whl", hash = "sha256:c3877aac7257ec68d79b5c622ce986bd2a992ca42f6ddc9b4dd1da50e89f7028"}, + {file = "jupyter_client-8.5.0.tar.gz", hash = "sha256:e8754066510ce456358df363f97eae64b50860f30dc1fe8c6771440db3be9a63"}, ] [package.dependencies] @@ -845,13 +917,13 @@ test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pyt [[package]] name = "jupyter-core" -version = "5.3.1" +version = "5.5.0" description = "Jupyter core package. A base package on which Jupyter projects rely." optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_core-5.3.1-py3-none-any.whl", hash = "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce"}, - {file = "jupyter_core-5.3.1.tar.gz", hash = "sha256:5ba5c7938a7f97a6b0481463f7ff0dbac7c15ba48cf46fa4035ca6e838aa1aba"}, + {file = "jupyter_core-5.5.0-py3-none-any.whl", hash = "sha256:e11e02cd8ae0a9de5c6c44abf5727df9f2581055afe00b22183f621ba3585805"}, + {file = "jupyter_core-5.5.0.tar.gz", hash = "sha256:880b86053bf298a8724994f95e99b99130659022a4f7f45f563084b6223861d3"}, ] [package.dependencies] @@ -860,7 +932,7 @@ pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_ traitlets = ">=5.3" [package.extras] -docs = ["myst-parser", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"] [[package]] @@ -978,52 +1050,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.7.2" +version = "3.8.1" description = "Python plotting package" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:2699f7e73a76d4c110f4f25be9d2496d6ab4f17345307738557d345f099e07de"}, - {file = "matplotlib-3.7.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a8035ba590658bae7562786c9cc6ea1a84aa49d3afab157e414c9e2ea74f496d"}, - {file = "matplotlib-3.7.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2f8e4a49493add46ad4a8c92f63e19d548b2b6ebbed75c6b4c7f46f57d36cdd1"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71667eb2ccca4c3537d9414b1bc00554cb7f91527c17ee4ec38027201f8f1603"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:152ee0b569a37630d8628534c628456b28686e085d51394da6b71ef84c4da201"}, - {file = "matplotlib-3.7.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:070f8dddd1f5939e60aacb8fa08f19551f4b0140fab16a3669d5cd6e9cb28fc8"}, - {file = "matplotlib-3.7.2-cp310-cp310-win32.whl", hash = "sha256:fdbb46fad4fb47443b5b8ac76904b2e7a66556844f33370861b4788db0f8816a"}, - {file = "matplotlib-3.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:23fb1750934e5f0128f9423db27c474aa32534cec21f7b2153262b066a581fd1"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:30e1409b857aa8a747c5d4f85f63a79e479835f8dffc52992ac1f3f25837b544"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:50e0a55ec74bf2d7a0ebf50ac580a209582c2dd0f7ab51bc270f1b4a0027454e"}, - {file = "matplotlib-3.7.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ac60daa1dc83e8821eed155796b0f7888b6b916cf61d620a4ddd8200ac70cd64"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305e3da477dc8607336ba10bac96986d6308d614706cae2efe7d3ffa60465b24"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c308b255efb9b06b23874236ec0f10f026673ad6515f602027cc8ac7805352d"}, - {file = "matplotlib-3.7.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60c521e21031632aa0d87ca5ba0c1c05f3daacadb34c093585a0be6780f698e4"}, - {file = "matplotlib-3.7.2-cp311-cp311-win32.whl", hash = "sha256:26bede320d77e469fdf1bde212de0ec889169b04f7f1179b8930d66f82b30cbc"}, - {file = "matplotlib-3.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:af4860132c8c05261a5f5f8467f1b269bf1c7c23902d75f2be57c4a7f2394b3e"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a1733b8e84e7e40a9853e505fe68cc54339f97273bdfe6f3ed980095f769ddc7"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d9881356dc48e58910c53af82b57183879129fa30492be69058c5b0d9fddf391"}, - {file = "matplotlib-3.7.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f081c03f413f59390a80b3e351cc2b2ea0205839714dbc364519bcf51f4b56ca"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1cd120fca3407a225168238b790bd5c528f0fafde6172b140a2f3ab7a4ea63e9"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c1590b90aa7bd741b54c62b78de05d4186271e34e2377e0289d943b3522273"}, - {file = "matplotlib-3.7.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d2ff3c984b8a569bc1383cd468fc06b70d7b59d5c2854ca39f1436ae8394117"}, - {file = "matplotlib-3.7.2-cp38-cp38-win32.whl", hash = "sha256:5dea00b62d28654b71ca92463656d80646675628d0828e08a5f3b57e12869e13"}, - {file = "matplotlib-3.7.2-cp38-cp38-win_amd64.whl", hash = "sha256:0f506a1776ee94f9e131af1ac6efa6e5bc7cb606a3e389b0ccb6e657f60bb676"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:6515e878f91894c2e4340d81f0911857998ccaf04dbc1bba781e3d89cbf70608"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:71f7a8c6b124e904db550f5b9fe483d28b896d4135e45c4ea381ad3b8a0e3256"}, - {file = "matplotlib-3.7.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:12f01b92ecd518e0697da4d97d163b2b3aa55eb3eb4e2c98235b3396d7dad55f"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a7e28d6396563955f7af437894a36bf2b279462239a41028323e04b85179058b"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbcf59334ff645e6a67cd5f78b4b2cdb76384cdf587fa0d2dc85f634a72e1a3e"}, - {file = "matplotlib-3.7.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:318c89edde72ff95d8df67d82aca03861240512994a597a435a1011ba18dbc7f"}, - {file = "matplotlib-3.7.2-cp39-cp39-win32.whl", hash = "sha256:ce55289d5659b5b12b3db4dc9b7075b70cef5631e56530f14b2945e8836f2d20"}, - {file = "matplotlib-3.7.2-cp39-cp39-win_amd64.whl", hash = "sha256:2ecb5be2b2815431c81dc115667e33da0f5a1bcf6143980d180d09a717c4a12e"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:fdcd28360dbb6203fb5219b1a5658df226ac9bebc2542a9e8f457de959d713d0"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3cca3e842b11b55b52c6fb8bd6a4088693829acbfcdb3e815fa9b7d5c92c1b"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebf577c7a6744e9e1bd3fee45fc74a02710b214f94e2bde344912d85e0c9af7c"}, - {file = "matplotlib-3.7.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:936bba394682049919dda062d33435b3be211dc3dcaa011e09634f060ec878b2"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bc221ffbc2150458b1cd71cdd9ddd5bb37962b036e41b8be258280b5b01da1dd"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35d74ebdb3f71f112b36c2629cf32323adfbf42679e2751252acd468f5001c07"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:717157e61b3a71d3d26ad4e1770dc85156c9af435659a25ee6407dc866cb258d"}, - {file = "matplotlib-3.7.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:20f844d6be031948148ba49605c8b96dfe7d3711d1b63592830d650622458c11"}, - {file = "matplotlib-3.7.2.tar.gz", hash = "sha256:a8cdb91dddb04436bd2f098b8fdf4b81352e68cf4d2c6756fcc414791076569b"}, + {file = "matplotlib-3.8.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e11ab864323fa73ac1b7849688d9671c47a2665242e899785b4db1a375b547e1"}, + {file = "matplotlib-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43a9d40feb63c9e31a0b8b069dcbd74a912f59bdc0095d187126694cd26977e4"}, + {file = "matplotlib-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608ea2951838d391e45dec2e644888db6899c752d3c29e157af9dcefb3d7d8d5"}, + {file = "matplotlib-3.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82ec95b02e894561c21e066bd0c716e4b410df141ce9441aa5af6cd937e4ade2"}, + {file = "matplotlib-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e3ad1759ad4a5245172c6d32b8ada603a6020d03211524c39d78d25c9a7dc0d2"}, + {file = "matplotlib-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:20a0fdfd3ee836179047f3782be060057b878ad37f5abe29edf006a1ff3ecd73"}, + {file = "matplotlib-3.8.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7658b7073c1d6a2922ecc0ed41602410fae88586cb8a54f7a2063d537b6beaf7"}, + {file = "matplotlib-3.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf6889643d4560fcc56f9f0941f078e4df0d72a6c3e4ca548841fc13c5642664"}, + {file = "matplotlib-3.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff842e27bc6a80de08c40e0bfdce460bd08080e8a94af131162b6a1b8948f2cc"}, + {file = "matplotlib-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f99d07c0e753717775be7be39ab383453b4d8b629c9fa174596b970c6555890"}, + {file = "matplotlib-3.8.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f34b46dbb1db1f09bfa937cd5853e5f2af232caeeff509c3ab6e43fd33780eae"}, + {file = "matplotlib-3.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1fcb49b6baf0375281979cbf26695ec10bd1cada1e311893e89533b3b70143e7"}, + {file = "matplotlib-3.8.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e17674ee127f78f26fea237e7f4d5cf910a8be82beb6260fedf358b88075b823"}, + {file = "matplotlib-3.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d921c0270647ab11c3ef283efaaa3d46fd005ba233bfb3aea75231cdf3656de8"}, + {file = "matplotlib-3.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2afe7d2f8c9e35e94fbcfcfd9b28f29cb32f0a9068cba469cf907428379c8db9"}, + {file = "matplotlib-3.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a504ff40f81d6233603475a45497a6dca37a873393fa20ae6f7dd6596ef72b"}, + {file = "matplotlib-3.8.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cd54bbf089953140905768ed4626d7223e1ad1d7e2a138410a9c4d3b865ccd80"}, + {file = "matplotlib-3.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:27502d2452208ae784c19504644f09f83742809143bbeae147617640930aa344"}, + {file = "matplotlib-3.8.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f55fb5ff02d999a100be28bf6ffe826e1867a54c7b465409685332c9dd48ffa5"}, + {file = "matplotlib-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:afb72822ae410d62aa1a2920c6563cb5680de9078358f0e9474396c6c3e06be2"}, + {file = "matplotlib-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43cf368a4a1d8cbc426944806e5e183cead746647a64d2cdb786441546235967"}, + {file = "matplotlib-3.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c54c55457c7f5ea4dfdba0020004fc7667f5c10c8d9b8010d735345acc06c9b8"}, + {file = "matplotlib-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e3bb809b743653b5aab5d72ee45c8c937c28e147b0846b0826a54bece898608c"}, + {file = "matplotlib-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:c1b0ecaa0d1f4fe1e30f625a2347f0034a89a7d17c39efbb502e554d92ee2f61"}, + {file = "matplotlib-3.8.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ca84deaa38cb64b7dd160ca2046b45f7b5dbff2b0179642e1339fadc337446c9"}, + {file = "matplotlib-3.8.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed3b29f54f6bbf3eaca4cbd23bc260155153ace63b7f597c474fa6fc6f386530"}, + {file = "matplotlib-3.8.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d24c47a1bb47e392fbcd26fe322e4ff3431653ac1e8718e4e147d450ae97a44"}, + {file = "matplotlib-3.8.1.tar.gz", hash = "sha256:044df81c1f6f3a8e52d70c4cfcb44e77ea9632a10929932870dfaa90de94365d"}, ] [package.dependencies] @@ -1031,11 +1090,11 @@ contourpy = ">=1.0.1" cycler = ">=0.10" fonttools = ">=4.22.0" importlib-resources = {version = ">=3.2.0", markers = "python_version < \"3.10\""} -kiwisolver = ">=1.0.1" -numpy = ">=1.20" +kiwisolver = ">=1.3.1" +numpy = ">=1.21,<2" packaging = ">=20.0" -pillow = ">=6.2.0" -pyparsing = ">=2.3.1,<3.1" +pillow = ">=8" +pyparsing = ">=2.3.1" python-dateutil = ">=2.7" [[package]] @@ -1076,13 +1135,13 @@ files = [ [[package]] name = "nest-asyncio" -version = "1.5.7" +version = "1.5.8" description = "Patch asyncio to allow nested event loops" optional = false python-versions = ">=3.5" files = [ - {file = "nest_asyncio-1.5.7-py3-none-any.whl", hash = "sha256:5301c82941b550b3123a1ea772ba9a1c80bad3a182be8c1a5ae6ad3be57a9657"}, - {file = "nest_asyncio-1.5.7.tar.gz", hash = "sha256:6a80f7b98f24d9083ed24608977c09dd608d83f91cccc24c9d2cba6d10e01c10"}, + {file = "nest_asyncio-1.5.8-py3-none-any.whl", hash = "sha256:accda7a339a70599cb08f9dd09a67e0c2ef8d8d6f4c07f96ab203f2ae254e48d"}, + {file = "nest_asyncio-1.5.8.tar.gz", hash = "sha256:25aa2ca0d2a5b5531956b9e273b45cf664cae2b145101d73b86b199978d48fdb"}, ] [[package]] @@ -1149,13 +1208,13 @@ et-xmlfile = "*" [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] @@ -1195,8 +1254,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -1265,80 +1324,67 @@ files = [ [package.dependencies] ptyprocess = ">=0.5" -[[package]] -name = "pickleshare" -version = "0.7.5" -description = "Tiny 'shelve'-like database with concurrency support" -optional = false -python-versions = "*" -files = [ - {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"}, - {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"}, -] - [[package]] name = "pillow" -version = "10.0.0" +version = "10.1.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "Pillow-10.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f62406a884ae75fb2f818694469519fb685cc7eaff05d3451a9ebe55c646891"}, - {file = "Pillow-10.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d5db32e2a6ccbb3d34d87c87b432959e0db29755727afb37290e10f6e8e62614"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edf4392b77bdc81f36e92d3a07a5cd072f90253197f4a52a55a8cec48a12483b"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:520f2a520dc040512699f20fa1c363eed506e94248d71f85412b625026f6142c"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:8c11160913e3dd06c8ffdb5f233a4f254cb449f4dfc0f8f4549eda9e542c93d1"}, - {file = "Pillow-10.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a74ba0c356aaa3bb8e3eb79606a87669e7ec6444be352870623025d75a14a2bf"}, - {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d0dae4cfd56969d23d94dc8e89fb6a217be461c69090768227beb8ed28c0a3"}, - {file = "Pillow-10.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:22c10cc517668d44b211717fd9775799ccec4124b9a7f7b3635fc5386e584992"}, - {file = "Pillow-10.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:dffe31a7f47b603318c609f378ebcd57f1554a3a6a8effbc59c3c69f804296de"}, - {file = "Pillow-10.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:9fb218c8a12e51d7ead2a7c9e101a04982237d4855716af2e9499306728fb485"}, - {file = "Pillow-10.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d35e3c8d9b1268cbf5d3670285feb3528f6680420eafe35cccc686b73c1e330f"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ed64f9ca2f0a95411e88a4efbd7a29e5ce2cea36072c53dd9d26d9c76f753b3"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b6eb5502f45a60a3f411c63187db83a3d3107887ad0d036c13ce836f8a36f1d"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c1fbe7621c167ecaa38ad29643d77a9ce7311583761abf7836e1510c580bf3dd"}, - {file = "Pillow-10.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cd25d2a9d2b36fcb318882481367956d2cf91329f6892fe5d385c346c0649629"}, - {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3b08d4cc24f471b2c8ca24ec060abf4bebc6b144cb89cba638c720546b1cf538"}, - {file = "Pillow-10.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d737a602fbd82afd892ca746392401b634e278cb65d55c4b7a8f48e9ef8d008d"}, - {file = "Pillow-10.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3a82c40d706d9aa9734289740ce26460a11aeec2d9c79b7af87bb35f0073c12f"}, - {file = "Pillow-10.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:bc2ec7c7b5d66b8ec9ce9f720dbb5fa4bace0f545acd34870eff4a369b44bf37"}, - {file = "Pillow-10.0.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:d80cf684b541685fccdd84c485b31ce73fc5c9b5d7523bf1394ce134a60c6883"}, - {file = "Pillow-10.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76de421f9c326da8f43d690110f0e79fe3ad1e54be811545d7d91898b4c8493e"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81ff539a12457809666fef6624684c008e00ff6bf455b4b89fd00a140eecd640"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce543ed15570eedbb85df19b0a1a7314a9c8141a36ce089c0a894adbfccb4568"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:685ac03cc4ed5ebc15ad5c23bc555d68a87777586d970c2c3e216619a5476223"}, - {file = "Pillow-10.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d72e2ecc68a942e8cf9739619b7f408cc7b272b279b56b2c83c6123fcfa5cdff"}, - {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d50b6aec14bc737742ca96e85d6d0a5f9bfbded018264b3b70ff9d8c33485551"}, - {file = "Pillow-10.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:00e65f5e822decd501e374b0650146063fbb30a7264b4d2744bdd7b913e0cab5"}, - {file = "Pillow-10.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f31f9fdbfecb042d046f9d91270a0ba28368a723302786c0009ee9b9f1f60199"}, - {file = "Pillow-10.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:1ce91b6ec08d866b14413d3f0bbdea7e24dfdc8e59f562bb77bc3fe60b6144ca"}, - {file = "Pillow-10.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:349930d6e9c685c089284b013478d6f76e3a534e36ddfa912cde493f235372f3"}, - {file = "Pillow-10.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3a684105f7c32488f7153905a4e3015a3b6c7182e106fe3c37fbb5ef3e6994c3"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4f69b3700201b80bb82c3a97d5e9254084f6dd5fb5b16fc1a7b974260f89f43"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f07ea8d2f827d7d2a49ecf1639ec02d75ffd1b88dcc5b3a61bbb37a8759ad8d"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:040586f7d37b34547153fa383f7f9aed68b738992380ac911447bb78f2abe530"}, - {file = "Pillow-10.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f88a0b92277de8e3ca715a0d79d68dc82807457dae3ab8699c758f07c20b3c51"}, - {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c7cf14a27b0d6adfaebb3ae4153f1e516df54e47e42dcc073d7b3d76111a8d86"}, - {file = "Pillow-10.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3400aae60685b06bb96f99a21e1ada7bc7a413d5f49bce739828ecd9391bb8f7"}, - {file = "Pillow-10.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbc02381779d412145331789b40cc7b11fdf449e5d94f6bc0b080db0a56ea3f0"}, - {file = "Pillow-10.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9211e7ad69d7c9401cfc0e23d49b69ca65ddd898976d660a2fa5904e3d7a9baa"}, - {file = "Pillow-10.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:faaf07ea35355b01a35cb442dd950d8f1bb5b040a7787791a535de13db15ed90"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9f72a021fbb792ce98306ffb0c348b3c9cb967dce0f12a49aa4c3d3fdefa967"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f7c16705f44e0504a3a2a14197c1f0b32a95731d251777dcb060aa83022cb2d"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:76edb0a1fa2b4745fb0c99fb9fb98f8b180a1bbceb8be49b087e0b21867e77d3"}, - {file = "Pillow-10.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:368ab3dfb5f49e312231b6f27b8820c823652b7cd29cfbd34090565a015e99ba"}, - {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:608bfdee0d57cf297d32bcbb3c728dc1da0907519d1784962c5f0c68bb93e5a3"}, - {file = "Pillow-10.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5c6e3df6bdd396749bafd45314871b3d0af81ff935b2d188385e970052091017"}, - {file = "Pillow-10.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:7be600823e4c8631b74e4a0d38384c73f680e6105a7d3c6824fcf226c178c7e6"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:92be919bbc9f7d09f7ae343c38f5bb21c973d2576c1d45600fce4b74bafa7ac0"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8182b523b2289f7c415f589118228d30ac8c355baa2f3194ced084dac2dbba"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:38250a349b6b390ee6047a62c086d3817ac69022c127f8a5dc058c31ccef17f3"}, - {file = "Pillow-10.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88af2003543cc40c80f6fca01411892ec52b11021b3dc22ec3bc9d5afd1c5334"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c189af0545965fa8d3b9613cfdb0cd37f9d71349e0f7750e1fd704648d475ed2"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7b031a6fc11365970e6a5686d7ba8c63e4c1cf1ea143811acbb524295eabed"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db24668940f82321e746773a4bc617bfac06ec831e5c88b643f91f122a785684"}, - {file = "Pillow-10.0.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:efe8c0681042536e0d06c11f48cebe759707c9e9abf880ee213541c5b46c5bf3"}, - {file = "Pillow-10.0.0.tar.gz", hash = "sha256:9c82b5b3e043c7af0d95792d0d20ccf68f61a1fec6b3530e718b688422727396"}, + {file = "Pillow-10.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1ab05f3db77e98f93964697c8efc49c7954b08dd61cff526b7f2531a22410106"}, + {file = "Pillow-10.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6932a7652464746fcb484f7fc3618e6503d2066d853f68a4bd97193a3996e273"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f63b5a68daedc54c7c3464508d8c12075e56dcfbd42f8c1bf40169061ae666"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0949b55eb607898e28eaccb525ab104b2d86542a85c74baf3a6dc24002edec2"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ae88931f93214777c7a3aa0a8f92a683f83ecde27f65a45f95f22d289a69e593"}, + {file = "Pillow-10.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b0eb01ca85b2361b09480784a7931fc648ed8b7836f01fb9241141b968feb1db"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d27b5997bdd2eb9fb199982bb7eb6164db0426904020dc38c10203187ae2ff2f"}, + {file = "Pillow-10.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7df5608bc38bd37ef585ae9c38c9cd46d7c81498f086915b0f97255ea60c2818"}, + {file = "Pillow-10.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:41f67248d92a5e0a2076d3517d8d4b1e41a97e2df10eb8f93106c89107f38b57"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1fb29c07478e6c06a46b867e43b0bcdb241b44cc52be9bc25ce5944eed4648e7"}, + {file = "Pillow-10.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2cdc65a46e74514ce742c2013cd4a2d12e8553e3a2563c64879f7c7e4d28bce7"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50d08cd0a2ecd2a8657bd3d82c71efd5a58edb04d9308185d66c3a5a5bed9610"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:062a1610e3bc258bff2328ec43f34244fcec972ee0717200cb1425214fe5b839"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:61f1a9d247317fa08a308daaa8ee7b3f760ab1809ca2da14ecc88ae4257d6172"}, + {file = "Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a646e48de237d860c36e0db37ecaecaa3619e6f3e9d5319e527ccbc8151df061"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:47e5bf85b80abc03be7455c95b6d6e4896a62f6541c1f2ce77a7d2bb832af262"}, + {file = "Pillow-10.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a92386125e9ee90381c3369f57a2a50fa9e6aa8b1cf1d9c4b200d41a7dd8e992"}, + {file = "Pillow-10.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f7c276c05a9767e877a0b4c5050c8bee6a6d960d7f0c11ebda6b99746068c2a"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:a89b8312d51715b510a4fe9fc13686283f376cfd5abca8cd1c65e4c76e21081b"}, + {file = "Pillow-10.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:00f438bb841382b15d7deb9a05cc946ee0f2c352653c7aa659e75e592f6fa17d"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3d929a19f5469b3f4df33a3df2983db070ebb2088a1e145e18facbc28cae5b27"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a92109192b360634a4489c0c756364c0c3a2992906752165ecb50544c251312"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:0248f86b3ea061e67817c47ecbe82c23f9dd5d5226200eb9090b3873d3ca32de"}, + {file = "Pillow-10.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9882a7451c680c12f232a422730f986a1fcd808da0fd428f08b671237237d651"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1c3ac5423c8c1da5928aa12c6e258921956757d976405e9467c5f39d1d577a4b"}, + {file = "Pillow-10.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:806abdd8249ba3953c33742506fe414880bad78ac25cc9a9b1c6ae97bedd573f"}, + {file = "Pillow-10.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:eaed6977fa73408b7b8a24e8b14e59e1668cfc0f4c40193ea7ced8e210adf996"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:fe1e26e1ffc38be097f0ba1d0d07fcade2bcfd1d023cda5b29935ae8052bd793"}, + {file = "Pillow-10.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7a7e3daa202beb61821c06d2517428e8e7c1aab08943e92ec9e5755c2fc9ba5e"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:24fadc71218ad2b8ffe437b54876c9382b4a29e030a05a9879f615091f42ffc2"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1d323703cfdac2036af05191b969b910d8f115cf53093125e4058f62012c9a"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:912e3812a1dbbc834da2b32299b124b5ddcb664ed354916fd1ed6f193f0e2d01"}, + {file = "Pillow-10.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:7dbaa3c7de82ef37e7708521be41db5565004258ca76945ad74a8e998c30af8d"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9d7bc666bd8c5a4225e7ac71f2f9d12466ec555e89092728ea0f5c0c2422ea80"}, + {file = "Pillow-10.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:baada14941c83079bf84c037e2d8b7506ce201e92e3d2fa0d1303507a8538212"}, + {file = "Pillow-10.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:2ef6721c97894a7aa77723740a09547197533146fba8355e86d6d9a4a1056b14"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0a026c188be3b443916179f5d04548092e253beb0c3e2ee0a4e2cdad72f66099"}, + {file = "Pillow-10.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:04f6f6149f266a100374ca3cc368b67fb27c4af9f1cc8cb6306d849dcdf12616"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb40c011447712d2e19cc261c82655f75f32cb724788df315ed992a4d65696bb"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a8413794b4ad9719346cd9306118450b7b00d9a15846451549314a58ac42219"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c9aeea7b63edb7884b031a35305629a7593272b54f429a9869a4f63a1bf04c34"}, + {file = "Pillow-10.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b4005fee46ed9be0b8fb42be0c20e79411533d1fd58edabebc0dd24626882cfd"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4d0152565c6aa6ebbfb1e5d8624140a440f2b99bf7afaafbdbf6430426497f28"}, + {file = "Pillow-10.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d921bc90b1defa55c9917ca6b6b71430e4286fc9e44c55ead78ca1a9f9eba5f2"}, + {file = "Pillow-10.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:cfe96560c6ce2f4c07d6647af2d0f3c54cc33289894ebd88cfbb3bcd5391e256"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:937bdc5a7f5343d1c97dc98149a0be7eb9704e937fe3dc7140e229ae4fc572a7"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c25762197144e211efb5f4e8ad656f36c8d214d390585d1d21281f46d556ba"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:afc8eef765d948543a4775f00b7b8c079b3321d6b675dde0d02afa2ee23000b4"}, + {file = "Pillow-10.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:883f216eac8712b83a63f41b76ddfb7b2afab1b74abbb413c5df6680f071a6b9"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b920e4d028f6442bea9a75b7491c063f0b9a3972520731ed26c83e254302eb1e"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c41d960babf951e01a49c9746f92c5a7e0d939d1652d7ba30f6b3090f27e412"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1fafabe50a6977ac70dfe829b2d5735fd54e190ab55259ec8aea4aaea412fa0b"}, + {file = "Pillow-10.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3b834f4b16173e5b92ab6566f0473bfb09f939ba14b23b8da1f54fa63e4b623f"}, + {file = "Pillow-10.1.0.tar.gz", hash = "sha256:e6bf8de6c36ed96c86ea3b6e1d5273c53f46ef518a062464cd7ef5dd2cf92e38"}, ] [package.extras] @@ -1371,27 +1417,31 @@ xarray = ["xarray"] [[package]] name = "pint-pandas" -version = "0.4" +version = "0.5" description = "Extend Pandas Dataframe with Physical quantities module" optional = false python-versions = ">=3.9" files = [ - {file = "Pint-Pandas-0.4.tar.gz", hash = "sha256:58eb37dabcfb62e9b2fe21df1a59f1371e6d007f3ee5f1403f00489d8b11548d"}, - {file = "Pint_Pandas-0.4-py3-none-any.whl", hash = "sha256:1e2e8766eaec24360c8d4c14486423ac26f4547205f87d88c926132491d8d596"}, + {file = "Pint-Pandas-0.5.tar.gz", hash = "sha256:48ec96d457f802a347763dee1d3e1a273f11f90e4e595df17fd44613dd14a61c"}, + {file = "Pint_Pandas-0.5-py3-none-any.whl", hash = "sha256:a33e8b43052a867b7b00a8c2c1fa3a7cc9af0eb0c0c17734a62a66eae5bbb1dd"}, ] +[package.dependencies] +pandas = ">=1.5" +pint = ">=0.21" + [package.extras] test = ["codecov", "coveralls", "nbval", "pyarrow", "pytest", "pytest-cov", "pytest-mpl", "pytest-subtests"] [[package]] name = "platformdirs" -version = "3.10.0" +version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, ] [package.extras] @@ -1415,13 +1465,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.4.0" +version = "3.5.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.8" files = [ - {file = "pre_commit-3.4.0-py2.py3-none-any.whl", hash = "sha256:96d529a951f8b677f730a7212442027e8ba53f9b04d217c4c67dc56c393ad945"}, - {file = "pre_commit-3.4.0.tar.gz", hash = "sha256:6bbd5129a64cad4c0dfaeeb12cd8f7ea7e15b77028d985341478c8af3c759522"}, + {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, + {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, ] [package.dependencies] @@ -1447,25 +1497,27 @@ wcwidth = "*" [[package]] name = "psutil" -version = "5.9.5" +version = "5.9.6" description = "Cross-platform lib for process and system monitoring in Python." optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" -files = [ - {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"}, - {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"}, - {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"}, - {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"}, - {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"}, - {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"}, - {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"}, - {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"}, - {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"}, - {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"}, - {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"}, +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fb8a697f11b0f5994550555fcfe3e69799e5b060c8ecf9e2f75c69302cc35c0d"}, + {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:91ecd2d9c00db9817a4b4192107cf6954addb5d9d67a969a4f436dbc9200f88c"}, + {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:10e8c17b4f898d64b121149afb136c53ea8b68c7531155147867b7b1ac9e7e28"}, + {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:18cd22c5db486f33998f37e2bb054cc62fd06646995285e02a51b1e08da97017"}, + {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:ca2780f5e038379e520281e4c032dddd086906ddff9ef0d1b9dcf00710e5071c"}, + {file = "psutil-5.9.6-cp27-none-win32.whl", hash = "sha256:70cb3beb98bc3fd5ac9ac617a327af7e7f826373ee64c80efd4eb2856e5051e9"}, + {file = "psutil-5.9.6-cp27-none-win_amd64.whl", hash = "sha256:51dc3d54607c73148f63732c727856f5febec1c7c336f8f41fcbd6315cce76ac"}, + {file = "psutil-5.9.6-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c69596f9fc2f8acd574a12d5f8b7b1ba3765a641ea5d60fb4736bf3c08a8214a"}, + {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92e0cc43c524834af53e9d3369245e6cc3b130e78e26100d1f63cdb0abeb3d3c"}, + {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:748c9dd2583ed86347ed65d0035f45fa8c851e8d90354c122ab72319b5f366f4"}, + {file = "psutil-5.9.6-cp36-cp36m-win32.whl", hash = "sha256:3ebf2158c16cc69db777e3c7decb3c0f43a7af94a60d72e87b2823aebac3d602"}, + {file = "psutil-5.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:ff18b8d1a784b810df0b0fff3bcb50ab941c3b8e2c8de5726f9c71c601c611aa"}, + {file = "psutil-5.9.6-cp37-abi3-win32.whl", hash = "sha256:a6f01f03bf1843280f4ad16f4bde26b817847b4c1a0db59bf6419807bc5ce05c"}, + {file = "psutil-5.9.6-cp37-abi3-win_amd64.whl", hash = "sha256:6e5fb8dc711a514da83098bc5234264e551ad980cec5f85dabf4d38ed6f15e9a"}, + {file = "psutil-5.9.6-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:daecbcbd29b289aac14ece28eca6a3e60aa361754cf6da3dfb20d4d32b6c7f57"}, + {file = "psutil-5.9.6.tar.gz", hash = "sha256:e4b92ddcd7dd4cdd3f900180ea1e104932c7bce234fb88976e2a3b296441225a"}, ] [package.extras] @@ -1498,13 +1550,13 @@ tests = ["pytest"] [[package]] name = "pycodestyle" -version = "2.11.0" +version = "2.11.1" description = "Python style guide checker" optional = false python-versions = ">=3.8" files = [ - {file = "pycodestyle-2.11.0-py2.py3-none-any.whl", hash = "sha256:5d1013ba8dc7895b548be5afb05740ca82454fd899971563d2ef625d090326f8"}, - {file = "pycodestyle-2.11.0.tar.gz", hash = "sha256:259bcc17857d8a8b3b4a2327324b79e5f020a13c16074670f9c8c8f872ea76d0"}, + {file = "pycodestyle-2.11.1-py2.py3-none-any.whl", hash = "sha256:44fe31000b2d866f2e41841b18528a505fbd7fef9017b04eff4e2648a0fadc67"}, + {file = "pycodestyle-2.11.1.tar.gz", hash = "sha256:41ba0e7afc9752dfb53ced5489e89f8186be00e599e712660695b7a75ff2663f"}, ] [[package]] @@ -1545,13 +1597,13 @@ plugins = ["importlib-metadata"] [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, ] [package.extras] @@ -1559,13 +1611,13 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.4.1" +version = "7.4.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.1-py3-none-any.whl", hash = "sha256:460c9a59b14e27c602eb5ece2e47bec99dc5fc5f6513cf924a7d03a578991b1f"}, - {file = "pytest-7.4.1.tar.gz", hash = "sha256:2f2301e797521b23e4d2585a0a3d7b5e50fdddaaf7e7d6773ea26ddb17c213ab"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] @@ -1657,6 +1709,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1664,8 +1717,15 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1682,6 +1742,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1689,6 +1750,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1822,19 +1884,19 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "setuptools" -version = "68.1.2" +version = "68.2.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.1.2-py3-none-any.whl", hash = "sha256:3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b"}, - {file = "setuptools-68.1.2.tar.gz", hash = "sha256:3d4dfa6d95f1b101d695a6160a7626e15583af71a5f52176efa5d39a054d475d"}, + {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, + {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5,<=7.1.2)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" @@ -1849,13 +1911,13 @@ files = [ [[package]] name = "stack-data" -version = "0.6.2" +version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" files = [ - {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"}, - {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"}, + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, ] [package.dependencies] @@ -1899,28 +1961,28 @@ files = [ [[package]] name = "traitlets" -version = "5.9.0" +version = "5.13.0" description = "Traitlets Python configuration system" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"}, - {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"}, + {file = "traitlets-5.13.0-py3-none-any.whl", hash = "sha256:baf991e61542da48fe8aef8b779a9ea0aa38d8a54166ee250d5af5ecf4486619"}, + {file = "traitlets-5.13.0.tar.gz", hash = "sha256:9b232b9430c8f57288c1024b34a8f0251ddcc47268927367a0dd3eeaca40deb5"}, ] [package.extras] docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] -test = ["argcomplete (>=2.0)", "pre-commit", "pytest", "pytest-mock"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.6.0)", "pre-commit", "pytest (>=7.0,<7.5)", "pytest-mock", "pytest-mypy-testing"] [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.8.0" +description = "Backported and Experimental Type Hints for Python 3.8+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, + {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, ] [[package]] @@ -1936,13 +1998,13 @@ files = [ [[package]] name = "urllib3" -version = "2.0.4" +version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.7" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] [package.extras] @@ -1953,13 +2015,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.4" +version = "20.24.6" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.4-py3-none-any.whl", hash = "sha256:29c70bb9b88510f6414ac3e55c8b413a1f96239b6b789ca123437d5e892190cb"}, - {file = "virtualenv-20.24.4.tar.gz", hash = "sha256:772b05bfda7ed3b8ecd16021ca9716273ad9f4467c801f27e83ac73430246dca"}, + {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, + {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, ] [package.dependencies] @@ -1973,31 +2035,31 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wcwidth" -version = "0.2.6" +version = "0.2.9" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, - {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, + {file = "wcwidth-0.2.9-py2.py3-none-any.whl", hash = "sha256:9a929bd8380f6cd9571a968a9c8f4353ca58d7cd812a4822bba831f8d685b223"}, + {file = "wcwidth-0.2.9.tar.gz", hash = "sha256:a675d1a4a2d24ef67096a04b85b02deeecd8e226f57b5e3a72dbb9ed99d27da8"}, ] [[package]] name = "zipp" -version = "3.16.2" +version = "3.17.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.17.0-py3-none-any.whl", hash = "sha256:0e923e726174922dce09c53c59ad483ff7bbb8e572e00c7f7c46b88556409f31"}, + {file = "zipp-3.17.0.tar.gz", hash = "sha256:84e64a1c28cf7e91ed2078bb8cc8c259cb19b76942096c8d7b84947690cabaf0"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "333615d60823472696a89ef26aec79ac78f3550ec81f1255d7fb819b2abda157" +content-hash = "6ff1dc0338c619998ef943b8ceaeec6b8ee2bc669986065d0081d3cc9e84cdec" diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 1398eca..bfdba2f 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -10,7 +10,7 @@ from .. import tools from .categories import Categories, Category # noqa -mpl.style.use("seaborn") +mpl.style.use("seaborn-v0_8") # Plotting philosophy for timeseries: # Not all plot types (bar, line, step, etc.) are suitable for all quantities. From 41f1ec4d29892929c4693370db21a08a9a9fd405 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 10 Nov 2023 14:35:23 +0100 Subject: [PATCH 10/59] fixed to_excel function, updated version of pint --- poetry.lock | 29 ++++++++--------------------- portfolyo/core/pfstate/pfstate.py | 2 +- pyproject.toml | 4 ++-- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/poetry.lock b/poetry.lock index df8e6c7..9dc4985 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. [[package]] name = "appnope" @@ -1393,43 +1393,30 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "pint" -version = "0.22" +version = "0.19.2" description = "Physical quantities module" optional = false -python-versions = ">=3.9" +python-versions = ">=3.8" files = [ - {file = "Pint-0.22-py3-none-any.whl", hash = "sha256:6e2b3c5c2b4d9b516608bc860a417a39d66eb99c958f36540cf931d2c2e9f80f"}, - {file = "Pint-0.22.tar.gz", hash = "sha256:2d139f6abbcf3016cad7d3cec05707fe908ac4f99cf59aedfd6ee667b7a64433"}, + {file = "Pint-0.19.2.tar.gz", hash = "sha256:e1d4989ff510b378dad64f91711e7bdabe5ca78d75b06a18569ac454678c4baf"}, ] -[package.dependencies] -typing-extensions = "*" - [package.extras] -babel = ["babel (<=2.8)"] -dask = ["dask"] -mip = ["mip (>=1.13)"] numpy = ["numpy (>=1.19.5)"] -pandas = ["pint-pandas (>=0.3)"] test = ["pytest", "pytest-cov", "pytest-mpl", "pytest-subtests"] uncertainties = ["uncertainties (>=3.1.6)"] -xarray = ["xarray"] [[package]] name = "pint-pandas" -version = "0.5" +version = "0.4" description = "Extend Pandas Dataframe with Physical quantities module" optional = false python-versions = ">=3.9" files = [ - {file = "Pint-Pandas-0.5.tar.gz", hash = "sha256:48ec96d457f802a347763dee1d3e1a273f11f90e4e595df17fd44613dd14a61c"}, - {file = "Pint_Pandas-0.5-py3-none-any.whl", hash = "sha256:a33e8b43052a867b7b00a8c2c1fa3a7cc9af0eb0c0c17734a62a66eae5bbb1dd"}, + {file = "Pint-Pandas-0.4.tar.gz", hash = "sha256:58eb37dabcfb62e9b2fe21df1a59f1371e6d007f3ee5f1403f00489d8b11548d"}, + {file = "Pint_Pandas-0.4-py3-none-any.whl", hash = "sha256:1e2e8766eaec24360c8d4c14486423ac26f4547205f87d88c926132491d8d596"}, ] -[package.dependencies] -pandas = ">=1.5" -pint = ">=0.21" - [package.extras] test = ["codecov", "coveralls", "nbval", "pyarrow", "pytest", "pytest-cov", "pytest-mpl", "pytest-subtests"] @@ -2062,4 +2049,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "6ff1dc0338c619998ef943b8ceaeec6b8ee2bc669986065d0081d3cc9e84cdec" +content-hash = "9e5351161e7ff51bbee970abcfe960646e947754be1ef9911feab5d160de2f6e" diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index 4010902..d8dcf09 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -173,7 +173,7 @@ def dataframe( dfs = [] for part in ("offtakevolume", "pnl_cost", "sourced", "unsourced"): childlevels = 0 if part == "pnl_cost" else -1 # always flatten pnl_cost - dfin = self[part].dataframe(cols, childlevels, has_units=has_units) + dfin = self[part].dataframe(cols, has_units= has_units, childlevels= childlevels) dfs.append(tools.frame.add_header(dfin, part)) return tools.frame.concat(dfs, axis=1) diff --git a/pyproject.toml b/pyproject.toml index fd8bdce..cdef709 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,8 +14,8 @@ python = "^3.9" pandas = "~2.0" # pandas 2.1.0 doesn't play nice with pint-pandas. Update when new pint-pandas version is released (>0.5) numpy = "^1.25.2" matplotlib = "^3.7.2" -pint = "^0.22" -pint-pandas = "^0.5" +pint = "0.19.2" +pint-pandas = "0.4" colorama = "^0.4.6" holidays = "^0.32" From 8ee06588562e3dec7eb376cc13d40ccc9fc32bbc Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Mon, 13 Nov 2023 12:29:39 +0100 Subject: [PATCH 11/59] fixed arithmatic on pflines without overlap --- portfolyo/core/pfline/arithmatic.py | 2 ++ tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py | 2 +- tests/utils.py | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/portfolyo/core/pfline/arithmatic.py b/portfolyo/core/pfline/arithmatic.py index 4220429..26f95db 100644 --- a/portfolyo/core/pfline/arithmatic.py +++ b/portfolyo/core/pfline/arithmatic.py @@ -224,6 +224,8 @@ def two_flatpflines(pfl1: FlatPfLine, pfl2: FlatPfLine) -> FlatPfLine: # newdf["p"] = newdf["r"] / newdf["q"] newdfs = tools.intersect.frames(pfl1.df, pfl2.df) # keep only common rows newdf = sum(newdfs) + if len(newdf.index) == 0: + raise NotImplementedError("Cannot perform operation on 2 portfolio lines without any overlapping timestamps.") if pfl1.kind is Kind.COMPLETE: # Calculate price from wavg instead of r/q, to handle edge case p1==p2, q==0. values = pd.DataFrame({"1": newdfs[0].p, "2": newdfs[1].p}) diff --git a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py index e31de56..ce15f04 100644 --- a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py +++ b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py @@ -245,7 +245,7 @@ class Case: expected: Any def __repr__(self): - return f"Case({id_fn(self.value1)},{self.operation},{id_fn(self.value2)})" + return f"Case({id_fn(self.value1)},{self.operation},{id_fn(self.value2)},{id_fn(self.expected)})" def dimlessseries(s: pd.Series) -> pd.Series: diff --git a/tests/utils.py b/tests/utils.py index 3c9fecf..bd14c9e 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -7,7 +7,7 @@ from portfolyo.core.pfline import Kind, Structure, classes -def id_fn(data: Any): +def id_fn(data: Any) -> str: """Readable id of test case""" if isinstance(data, Dict): return str({key: id_fn(val) for key, val in data.items()}) @@ -33,6 +33,8 @@ def id_fn(data: Any): return str(data) elif isinstance(data, str): return data + elif isinstance(data, type) and issubclass(data, Exception): + return data.__name__ elif data is None: return "None" return str(data) From 150f3c14d5cc5e7337c61d8bde2e04e55ab7af2a Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 13 Nov 2023 12:36:11 +0100 Subject: [PATCH 12/59] small changes small changes --- .../pfline/test_pfline_arithmatic_numeric_and_error.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py index e31de56..2e72333 100644 --- a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py +++ b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py @@ -318,6 +318,7 @@ def subtractiontestcases(): c: series_ref[c].loc[i_ab] - series_b[c].loc[i_ab] for c in kind.summable } yield Case(pfl, "-", flatset_b[kind], pf.PfLine(series)) + #This one is the issue yield Case(flatset_ref[Kind.VOLUME], "-", flatset_c[Kind.VOLUME], Exception) yield Case(flatset_ref[Kind.VOLUME], "-", flatset_d[Kind.VOLUME], Exception) yield Case(flatset_ref[Kind.VOLUME], "-", flatset_e[Kind.VOLUME], Exception) @@ -457,13 +458,15 @@ def uniontestcases(): def test_negation(testcase: Case): do_test(testcase) - +#added function additiontestcases since the test for multiolication also had corresponding function +#but it didn't help ( +@pytest.mark.parametrize("testcase", additiontestcases(), ids=id_fn) @pytest.mark.parametrize("order", ["normal", "reversed"]) def test_addition(testcase: Case, order: str): do_test(testcase, order) -@pytest.mark.parametrize("testcase", subtractiontestcases(), ids=id_fn) +@pytest.mark.parametrize("testcase", list(subtractiontestcases()), ids=id_fn) def test_subtraction(testcase: Case): do_test(testcase) From 90bf90f8fa5cff9813fbaf7eec3d32543fbad3a1 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Mon, 13 Nov 2023 15:18:05 +0100 Subject: [PATCH 13/59] more consistent functions to get random pfline --- .gitignore | 3 +- portfolyo/core/pfline/arithmatic.py | 4 +- portfolyo/core/pfline/dataframeexport.py | 2 +- portfolyo/core/pfstate/pfstate.py | 4 +- portfolyo/dev/develop.py | 49 +++++++++++++------ .../test_pfline_arithmatic_kind_and_error.py | 4 +- ...est_pfline_arithmatic_numeric_and_error.py | 7 +-- .../core/pfline/test_pfline_excelclipboard.py | 4 +- 8 files changed, 51 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index f6ea1bf..6590164 100644 --- a/.gitignore +++ b/.gitignore @@ -156,4 +156,5 @@ cython_debug/ # OWN .issues/ -.DS_Store \ No newline at end of file +.DS_Store +test.xlsx diff --git a/portfolyo/core/pfline/arithmatic.py b/portfolyo/core/pfline/arithmatic.py index 26f95db..bf0d41f 100644 --- a/portfolyo/core/pfline/arithmatic.py +++ b/portfolyo/core/pfline/arithmatic.py @@ -225,7 +225,9 @@ def two_flatpflines(pfl1: FlatPfLine, pfl2: FlatPfLine) -> FlatPfLine: newdfs = tools.intersect.frames(pfl1.df, pfl2.df) # keep only common rows newdf = sum(newdfs) if len(newdf.index) == 0: - raise NotImplementedError("Cannot perform operation on 2 portfolio lines without any overlapping timestamps.") + raise NotImplementedError( + "Cannot perform operation on 2 portfolio lines without any overlapping timestamps." + ) if pfl1.kind is Kind.COMPLETE: # Calculate price from wavg instead of r/q, to handle edge case p1==p2, q==0. values = pd.DataFrame({"1": newdfs[0].p, "2": newdfs[1].p}) diff --git a/portfolyo/core/pfline/dataframeexport.py b/portfolyo/core/pfline/dataframeexport.py index ae5deac..bd6ee9a 100644 --- a/portfolyo/core/pfline/dataframeexport.py +++ b/portfolyo/core/pfline/dataframeexport.py @@ -76,6 +76,6 @@ def dataframe( # One big dataframe. dfs = [flatdf] for name, child in self.items(): - childdf = child.dataframe(cols, has_units, childlevels - 1) + childdf = child.dataframe(cols, has_units, childlevels=childlevels - 1) dfs.append(tools.frame.add_header(childdf, name)) return tools.frame.concat(dfs, 1) diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index d8dcf09..b90b79c 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -173,7 +173,9 @@ def dataframe( dfs = [] for part in ("offtakevolume", "pnl_cost", "sourced", "unsourced"): childlevels = 0 if part == "pnl_cost" else -1 # always flatten pnl_cost - dfin = self[part].dataframe(cols, has_units= has_units, childlevels= childlevels) + dfin = self[part].dataframe( + cols, has_units=has_units, childlevels=childlevels + ) dfs.append(tools.frame.add_header(dfin, part)) return tools.frame.concat(dfs, axis=1) diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index ed83849..76baeea 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -131,15 +131,15 @@ def get_dataframe( def get_pfline( i: pd.DatetimeIndex = None, kind: Kind = Kind.COMPLETE, - structure: Structure = Structure.FLAT, + nlevels: int = 1, *, _seed: int = None, ) -> FlatPfLine: """Get a portfolio line.""" - if structure is Structure.FLAT: + if nlevels == 1: return get_flatpfline(i, kind, _seed=_seed) else: - return get_nestedpfline(i, kind, _seed=_seed) + return get_nestedpfline(i, kind, nlevels, _seed=_seed) def get_flatpfline( @@ -156,24 +156,37 @@ def get_flatpfline( def get_nestedpfline( - i: pd.DatetimeIndex = None, kind: Kind = Kind.COMPLETE, *, _seed: int = None + i: pd.DatetimeIndex = None, + kind: Kind = Kind.COMPLETE, + nlevels: int = 2, + *, + _seed: int = None, ) -> NestedPfLine: - """Get nested portfolio line. With 2 (flat) children of the same ``kind``.""" + """Get nested portfolio line. With 2 children of the same ``kind``. If ``nlevels``==2, the children are both flat; if not, + the portfolio line is multiply nested.""" if i is None: i = get_index(_seed=_seed) - return create.nestedpfline( - { - "A": get_flatpfline(i, kind, _seed=_seed), - "B": get_flatpfline(i, kind, _seed=_seed), - } - ) + if nlevels == 2: + return create.nestedpfline( + { + "A": get_flatpfline(i, kind, _seed=_seed), + "B": get_flatpfline(i, kind, _seed=_seed), + } + ) + else: + return create.nestedpfline( + { + "A": get_nestedpfline(i, kind, nlevels - 1, _seed=_seed), + "B": get_nestedpfline(i, kind, nlevels - 1, _seed=_seed), + } + ) def get_randompfline( i: pd.DatetimeIndex = None, kind: Kind = Kind.COMPLETE, max_nlevels: int = 3, - childcount: int = 2, + max_childcount: int = 2, prefix: str = "", *, _seed: int = None, @@ -185,16 +198,22 @@ def get_randompfline( i = get_index(_seed=_seed) if _seed: np.random.seed(_seed) - nlevels = np.random.randint(0, max_nlevels) + nlevels = np.random.randint(1, max_nlevels + 1) # Create flat PfLine. - if nlevels == 0: + if nlevels == 1: return get_flatpfline(i, kind, _seed=_seed) # Create nested PfLine. children = {} + childcount = np.random.randint(1, max_childcount + 1) for c in range(childcount): name = f"part {prefix}{c}." children[name] = get_randompfline( - i, kind, max_nlevels - 1, prefix=f"{prefix}{c}.", _seed=_seed + i, + kind, + max_nlevels - 1, + max_childcount, + prefix=f"{prefix}{c}.", + _seed=_seed, ) return create.nestedpfline(children) diff --git a/tests/core/pfline/test_pfline_arithmatic_kind_and_error.py b/tests/core/pfline/test_pfline_arithmatic_kind_and_error.py index 4e64655..d716236 100644 --- a/tests/core/pfline/test_pfline_arithmatic_kind_and_error.py +++ b/tests/core/pfline/test_pfline_arithmatic_kind_and_error.py @@ -81,9 +81,9 @@ class CaseConfig: # TestcaseConfig class Pfls: # Testpfls def __init__(self, i: pd.DatetimeIndex): self._pfls = [ - pf.dev.get_pfline(i, kind, structure, _seed=1) + pf.dev.get_pfline(i, kind, nlevels, _seed=1) for kind in Kind - for structure in Structure + for nlevels in (1, 2, 3) ] def fetch(self, kind: Kind = None, structure: Structure = None) -> Iterable[PfLine]: diff --git a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py index 22deea5..ae082d7 100644 --- a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py +++ b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py @@ -318,7 +318,7 @@ def subtractiontestcases(): c: series_ref[c].loc[i_ab] - series_b[c].loc[i_ab] for c in kind.summable } yield Case(pfl, "-", flatset_b[kind], pf.PfLine(series)) - #This one is the issue + # This one is the issue yield Case(flatset_ref[Kind.VOLUME], "-", flatset_c[Kind.VOLUME], Exception) yield Case(flatset_ref[Kind.VOLUME], "-", flatset_d[Kind.VOLUME], Exception) yield Case(flatset_ref[Kind.VOLUME], "-", flatset_e[Kind.VOLUME], Exception) @@ -458,8 +458,9 @@ def uniontestcases(): def test_negation(testcase: Case): do_test(testcase) -#added function additiontestcases since the test for multiolication also had corresponding function -#but it didn't help ( + +# added function additiontestcases since the test for multiolication also had corresponding function +# but it didn't help ( @pytest.mark.parametrize("testcase", additiontestcases(), ids=id_fn) @pytest.mark.parametrize("order", ["normal", "reversed"]) def test_addition(testcase: Case, order: str): diff --git a/tests/core/pfline/test_pfline_excelclipboard.py b/tests/core/pfline/test_pfline_excelclipboard.py index 8110001..78fe159 100644 --- a/tests/core/pfline/test_pfline_excelclipboard.py +++ b/tests/core/pfline/test_pfline_excelclipboard.py @@ -8,12 +8,12 @@ @pytest.mark.parametrize("levels", [1, 2, 3]) def test_pfline_toexcel(levels: int): """Test if data can be exported to excel.""" - pfl = pf.dev.get_randompfline(max_nlevels=levels) + pfl = pf.dev.get_pfline(nlevels=levels) pfl.to_excel("test.xlsx") @pytest.mark.parametrize("levels", [1, 2, 3]) def test_pfline_toclipboard(levels: int): """Test if data can be copied to clipboard.""" - pfl = pf.dev.get_randompfline(max_nlevels=levels) + pfl = pf.dev.get_pfline(nlevels=levels) pfl.to_clipboard() From 65dd175dc8708c7d36a5b82fde90cc3c439d152c Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 13 Nov 2023 15:23:51 +0100 Subject: [PATCH 14/59] deleted comment --- tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py index 22deea5..609182a 100644 --- a/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py +++ b/tests/core/pfline/test_pfline_arithmatic_numeric_and_error.py @@ -458,8 +458,8 @@ def uniontestcases(): def test_negation(testcase: Case): do_test(testcase) -#added function additiontestcases since the test for multiolication also had corresponding function -#but it didn't help ( + + @pytest.mark.parametrize("testcase", additiontestcases(), ids=id_fn) @pytest.mark.parametrize("order", ["normal", "reversed"]) def test_addition(testcase: Case, order: str): From d120b034579e326e1f4fc4a04f23912c6b886d24 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 15 Nov 2023 11:20:10 +0100 Subject: [PATCH 15/59] change the python version for push request to 3.11 --- .github/workflows/ci-on-push.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-on-push.yaml b/.github/workflows/ci-on-push.yaml index 779fef7..a2fd85e 100644 --- a/.github/workflows/ci-on-push.yaml +++ b/.github/workflows/ci-on-push.yaml @@ -9,7 +9,7 @@ jobs: fail-fast: true matrix: os: ["ubuntu-latest"] - python-version: ["3.8"] + python-version: ["3.11"] steps: - name: Checkout source From 657b6bfc6efb00b5038c841712f00513d3da27ca Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 15 Nov 2023 11:28:36 +0100 Subject: [PATCH 16/59] test --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 67e19b1..d4dec64 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,4 +18,4 @@ markers = pythonpath = ./tests [bdist_wheel] -universal = 1 \ No newline at end of file +universal = 1 From 6871b2c2a827f871465119cdb885aa8a9f7dbed3 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 15 Nov 2023 12:12:03 +0100 Subject: [PATCH 17/59] Removed unused dependency --- portfolyo/dev/develop.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index 76baeea..10e95f9 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -9,7 +9,7 @@ import pandas as pd from .. import tools -from ..core.pfline import FlatPfLine, Kind, Structure, NestedPfLine, PfLine, create +from ..core.pfline import FlatPfLine, Kind, NestedPfLine, PfLine, create from ..core.pfstate import PfState from . import mockup From 85ec27c7523cb9f38eed06b8207bc1ca83e901b7 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 15 Nov 2023 15:05:34 +0100 Subject: [PATCH 18/59] updated toml --- poetry.lock | 378 ++++++++++++++++++++++++------------------------- pyproject.toml | 1 + 2 files changed, 189 insertions(+), 190 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9dc4985..c962fc7 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. [[package]] name = "appnope" @@ -31,29 +31,29 @@ test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] [[package]] name = "black" -version = "23.10.1" +version = "23.11.0" description = "The uncompromising code formatter." optional = false python-versions = ">=3.8" files = [ - {file = "black-23.10.1-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:ec3f8e6234c4e46ff9e16d9ae96f4ef69fa328bb4ad08198c8cee45bb1f08c69"}, - {file = "black-23.10.1-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:1b917a2aa020ca600483a7b340c165970b26e9029067f019e3755b56e8dd5916"}, - {file = "black-23.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c74de4c77b849e6359c6f01987e94873c707098322b91490d24296f66d067dc"}, - {file = "black-23.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4d10b0f016616a0d93d24a448100adf1699712fb7a4efd0e2c32bbb219b173"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b15b75fc53a2fbcac8a87d3e20f69874d161beef13954747e053bca7a1ce53a0"}, - {file = "black-23.10.1-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:e293e4c2f4a992b980032bbd62df07c1bcff82d6964d6c9496f2cd726e246ace"}, - {file = "black-23.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d56124b7a61d092cb52cce34182a5280e160e6aff3137172a68c2c2c4b76bcb"}, - {file = "black-23.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:3f157a8945a7b2d424da3335f7ace89c14a3b0625e6593d21139c2d8214d55ce"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:cfcce6f0a384d0da692119f2d72d79ed07c7159879d0bb1bb32d2e443382bf3a"}, - {file = "black-23.10.1-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:33d40f5b06be80c1bbce17b173cda17994fbad096ce60eb22054da021bf933d1"}, - {file = "black-23.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:840015166dbdfbc47992871325799fd2dc0dcf9395e401ada6d88fe11498abad"}, - {file = "black-23.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:037e9b4664cafda5f025a1728c50a9e9aedb99a759c89f760bd83730e76ba884"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:7cb5936e686e782fddb1c73f8aa6f459e1ad38a6a7b0e54b403f1f05a1507ee9"}, - {file = "black-23.10.1-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:7670242e90dc129c539e9ca17665e39a146a761e681805c54fbd86015c7c84f7"}, - {file = "black-23.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ed45ac9a613fb52dad3b61c8dea2ec9510bf3108d4db88422bacc7d1ba1243d"}, - {file = "black-23.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:6d23d7822140e3fef190734216cefb262521789367fbdc0b3f22af6744058982"}, - {file = "black-23.10.1-py3-none-any.whl", hash = "sha256:d431e6739f727bb2e0495df64a6c7a5310758e87505f5f8cde9ff6c0f2d7e4fe"}, - {file = "black-23.10.1.tar.gz", hash = "sha256:1f8ce316753428ff68749c65a5f7844631aa18c8679dfd3ca9dc1a289979c258"}, + {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, + {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, + {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, + {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, + {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, + {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, + {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, + {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, + {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, + {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, + {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, + {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, + {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, + {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, + {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, + {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, + {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, + {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, ] [package.dependencies] @@ -298,155 +298,83 @@ files = [ [[package]] name = "comm" -version = "0.1.4" +version = "0.2.0" description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "comm-0.1.4-py3-none-any.whl", hash = "sha256:6d52794cba11b36ed9860999cd10fd02d6b2eac177068fdd585e1e2f8a96e67a"}, - {file = "comm-0.1.4.tar.gz", hash = "sha256:354e40a59c9dd6db50c5cc6b4acc887d82e9603787f83b68c01a80a923984d15"}, + {file = "comm-0.2.0-py3-none-any.whl", hash = "sha256:2da8d9ebb8dd7bfc247adaff99f24dce705638a8042b85cb995066793e391001"}, + {file = "comm-0.2.0.tar.gz", hash = "sha256:a517ea2ca28931c7007a7a99c562a0fa5883cfb48963140cf642c41c948498be"}, ] [package.dependencies] traitlets = ">=4" [package.extras] -lint = ["black (>=22.6.0)", "mdformat (>0.7)", "mdformat-gfm (>=0.3.5)", "ruff (>=0.0.156)"] test = ["pytest"] -typing = ["mypy (>=0.990)"] [[package]] name = "contourpy" -version = "1.1.0" +version = "1.2.0" description = "Python library for calculating contours of 2D quadrilateral grids" optional = false -python-versions = ">=3.8" -files = [ - {file = "contourpy-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:89f06eff3ce2f4b3eb24c1055a26981bffe4e7264acd86f15b97e40530b794bc"}, - {file = "contourpy-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dffcc2ddec1782dd2f2ce1ef16f070861af4fb78c69862ce0aab801495dda6a3"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ae46595e22f93592d39a7eac3d638cda552c3e1160255258b695f7b58e5655"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17cfaf5ec9862bc93af1ec1f302457371c34e688fbd381f4035a06cd47324f48"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18a64814ae7bce73925131381603fff0116e2df25230dfc80d6d690aa6e20b37"}, - {file = "contourpy-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c81f22b4f572f8a2110b0b741bb64e5a6427e0a198b2cdc1fbaf85f352a3aa"}, - {file = "contourpy-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:53cc3a40635abedbec7f1bde60f8c189c49e84ac180c665f2cd7c162cc454baa"}, - {file = "contourpy-1.1.0-cp310-cp310-win32.whl", hash = "sha256:9b2dd2ca3ac561aceef4c7c13ba654aaa404cf885b187427760d7f7d4c57cff8"}, - {file = "contourpy-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:1f795597073b09d631782e7245016a4323cf1cf0b4e06eef7ea6627e06a37ff2"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0b7b04ed0961647691cfe5d82115dd072af7ce8846d31a5fac6c142dcce8b882"}, - {file = "contourpy-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27bc79200c742f9746d7dd51a734ee326a292d77e7d94c8af6e08d1e6c15d545"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052cc634bf903c604ef1a00a5aa093c54f81a2612faedaa43295809ffdde885e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9382a1c0bc46230fb881c36229bfa23d8c303b889b788b939365578d762b5c18"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5cec36c5090e75a9ac9dbd0ff4a8cf7cecd60f1b6dc23a374c7d980a1cd710e"}, - {file = "contourpy-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0cbd657e9bde94cd0e33aa7df94fb73c1ab7799378d3b3f902eb8eb2e04a3a"}, - {file = "contourpy-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:181cbace49874f4358e2929aaf7ba84006acb76694102e88dd15af861996c16e"}, - {file = "contourpy-1.1.0-cp311-cp311-win32.whl", hash = "sha256:edb989d31065b1acef3828a3688f88b2abb799a7db891c9e282df5ec7e46221b"}, - {file = "contourpy-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb3b7d9e6243bfa1efb93ccfe64ec610d85cfe5aec2c25f97fbbd2e58b531256"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb41692aa09aeb19c7c213411854402f29f6613845ad2453d30bf421fe68fed"}, - {file = "contourpy-1.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5d123a5bc63cd34c27ff9c7ac1cd978909e9c71da12e05be0231c608048bb2ae"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62013a2cf68abc80dadfd2307299bfa8f5aa0dcaec5b2954caeb5fa094171103"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b6616375d7de55797d7a66ee7d087efe27f03d336c27cf1f32c02b8c1a5ac70"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:317267d915490d1e84577924bd61ba71bf8681a30e0d6c545f577363157e5e94"}, - {file = "contourpy-1.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d551f3a442655f3dcc1285723f9acd646ca5858834efeab4598d706206b09c9f"}, - {file = "contourpy-1.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e7a117ce7df5a938fe035cad481b0189049e8d92433b4b33aa7fc609344aafa1"}, - {file = "contourpy-1.1.0-cp38-cp38-win32.whl", hash = "sha256:108dfb5b3e731046a96c60bdc46a1a0ebee0760418951abecbe0fc07b5b93b27"}, - {file = "contourpy-1.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4f26b25b4f86087e7d75e63212756c38546e70f2a92d2be44f80114826e1cd4"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bc00bb4225d57bff7ebb634646c0ee2a1298402ec10a5fe7af79df9a51c1bfd9"}, - {file = "contourpy-1.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:189ceb1525eb0655ab8487a9a9c41f42a73ba52d6789754788d1883fb06b2d8a"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f2931ed4741f98f74b410b16e5213f71dcccee67518970c42f64153ea9313b9"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:30f511c05fab7f12e0b1b7730ebdc2ec8deedcfb505bc27eb570ff47c51a8f15"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:143dde50520a9f90e4a2703f367cf8ec96a73042b72e68fcd184e1279962eb6f"}, - {file = "contourpy-1.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e94bef2580e25b5fdb183bf98a2faa2adc5b638736b2c0a4da98691da641316a"}, - {file = "contourpy-1.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ed614aea8462735e7d70141374bd7650afd1c3f3cb0c2dbbcbe44e14331bf002"}, - {file = "contourpy-1.1.0-cp39-cp39-win32.whl", hash = "sha256:71551f9520f008b2950bef5f16b0e3587506ef4f23c734b71ffb7b89f8721999"}, - {file = "contourpy-1.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:438ba416d02f82b692e371858143970ed2eb6337d9cdbbede0d8ad9f3d7dd17d"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a698c6a7a432789e587168573a864a7ea374c6be8d4f31f9d87c001d5a843493"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:397b0ac8a12880412da3551a8cb5a187d3298a72802b45a3bd1805e204ad8439"}, - {file = "contourpy-1.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a67259c2b493b00e5a4d0f7bfae51fb4b3371395e47d079a4446e9b0f4d70e76"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b836d22bd2c7bb2700348e4521b25e077255ebb6ab68e351ab5aa91ca27e027"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084eaa568400cfaf7179b847ac871582199b1b44d5699198e9602ecbbb5f6104"}, - {file = "contourpy-1.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:911ff4fd53e26b019f898f32db0d4956c9d227d51338fb3b03ec72ff0084ee5f"}, - {file = "contourpy-1.1.0.tar.gz", hash = "sha256:e53046c3863828d21d531cc3b53786e6580eb1ba02477e8681009b6aa0870b21"}, -] - -[package.dependencies] -numpy = ">=1.16" - -[package.extras] -bokeh = ["bokeh", "selenium"] -docs = ["furo", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.2.0)", "types-Pillow"] -test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] - -[[package]] -name = "contourpy" -version = "1.1.1" -description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "contourpy-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:46e24f5412c948d81736509377e255f6040e94216bf1a9b5ea1eaa9d29f6ec1b"}, - {file = "contourpy-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e48694d6a9c5a26ee85b10130c77a011a4fedf50a7279fa0bdaf44bafb4299d"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a66045af6cf00e19d02191ab578a50cb93b2028c3eefed999793698e9ea768ae"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ebf42695f75ee1a952f98ce9775c873e4971732a87334b099dde90b6af6a916"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6aec19457617ef468ff091669cca01fa7ea557b12b59a7908b9474bb9674cf0"}, - {file = "contourpy-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:462c59914dc6d81e0b11f37e560b8a7c2dbab6aca4f38be31519d442d6cde1a1"}, - {file = "contourpy-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6d0a8efc258659edc5299f9ef32d8d81de8b53b45d67bf4bfa3067f31366764d"}, - {file = "contourpy-1.1.1-cp310-cp310-win32.whl", hash = "sha256:d6ab42f223e58b7dac1bb0af32194a7b9311065583cc75ff59dcf301afd8a431"}, - {file = "contourpy-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:549174b0713d49871c6dee90a4b499d3f12f5e5f69641cd23c50a4542e2ca1eb"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:407d864db716a067cc696d61fa1ef6637fedf03606e8417fe2aeed20a061e6b2"}, - {file = "contourpy-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dfe80c017973e6a4c367e037cb31601044dd55e6bfacd57370674867d15a899b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e30aaf2b8a2bac57eb7e1650df1b3a4130e8d0c66fc2f861039d507a11760e1b"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3de23ca4f381c3770dee6d10ead6fff524d540c0f662e763ad1530bde5112532"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:566f0e41df06dfef2431defcfaa155f0acfa1ca4acbf8fd80895b1e7e2ada40e"}, - {file = "contourpy-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04c2f0adaf255bf756cf08ebef1be132d3c7a06fe6f9877d55640c5e60c72c5"}, - {file = "contourpy-1.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d0c188ae66b772d9d61d43c6030500344c13e3f73a00d1dc241da896f379bb62"}, - {file = "contourpy-1.1.1-cp311-cp311-win32.whl", hash = "sha256:0683e1ae20dc038075d92e0e0148f09ffcefab120e57f6b4c9c0f477ec171f33"}, - {file = "contourpy-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:8636cd2fc5da0fb102a2504fa2c4bea3cbc149533b345d72cdf0e7a924decc45"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:560f1d68a33e89c62da5da4077ba98137a5e4d3a271b29f2f195d0fba2adcb6a"}, - {file = "contourpy-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:24216552104ae8f3b34120ef84825400b16eb6133af2e27a190fdc13529f023e"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56de98a2fb23025882a18b60c7f0ea2d2d70bbbcfcf878f9067234b1c4818442"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:07d6f11dfaf80a84c97f1a5ba50d129d9303c5b4206f776e94037332e298dda8"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1eaac5257a8f8a047248d60e8f9315c6cff58f7803971170d952555ef6344a7"}, - {file = "contourpy-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19557fa407e70f20bfaba7d55b4d97b14f9480856c4fb65812e8a05fe1c6f9bf"}, - {file = "contourpy-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:081f3c0880712e40effc5f4c3b08feca6d064cb8cfbb372ca548105b86fd6c3d"}, - {file = "contourpy-1.1.1-cp312-cp312-win32.whl", hash = "sha256:059c3d2a94b930f4dafe8105bcdc1b21de99b30b51b5bce74c753686de858cb6"}, - {file = "contourpy-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f44d78b61740e4e8c71db1cf1fd56d9050a4747681c59ec1094750a658ceb970"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:70e5a10f8093d228bb2b552beeb318b8928b8a94763ef03b858ef3612b29395d"}, - {file = "contourpy-1.1.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8394e652925a18ef0091115e3cc191fef350ab6dc3cc417f06da66bf98071ae9"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5bd5680f844c3ff0008523a71949a3ff5e4953eb7701b28760805bc9bcff217"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66544f853bfa85c0d07a68f6c648b2ec81dafd30f272565c37ab47a33b220684"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0c02b75acfea5cab07585d25069207e478d12309557f90a61b5a3b4f77f46ce"}, - {file = "contourpy-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41339b24471c58dc1499e56783fedc1afa4bb018bcd035cfb0ee2ad2a7501ef8"}, - {file = "contourpy-1.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f29fb0b3f1217dfe9362ec55440d0743fe868497359f2cf93293f4b2701b8251"}, - {file = "contourpy-1.1.1-cp38-cp38-win32.whl", hash = "sha256:f9dc7f933975367251c1b34da882c4f0e0b2e24bb35dc906d2f598a40b72bfc7"}, - {file = "contourpy-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:498e53573e8b94b1caeb9e62d7c2d053c263ebb6aa259c81050766beb50ff8d9"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba42e3810999a0ddd0439e6e5dbf6d034055cdc72b7c5c839f37a7c274cb4eba"}, - {file = "contourpy-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6c06e4c6e234fcc65435223c7b2a90f286b7f1b2733058bdf1345d218cc59e34"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca6fab080484e419528e98624fb5c4282148b847e3602dc8dbe0cb0669469887"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:93df44ab351119d14cd1e6b52a5063d3336f0754b72736cc63db59307dabb718"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eafbef886566dc1047d7b3d4b14db0d5b7deb99638d8e1be4e23a7c7ac59ff0f"}, - {file = "contourpy-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efe0fab26d598e1ec07d72cf03eaeeba8e42b4ecf6b9ccb5a356fde60ff08b85"}, - {file = "contourpy-1.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f08e469821a5e4751c97fcd34bcb586bc243c39c2e39321822060ba902eac49e"}, - {file = "contourpy-1.1.1-cp39-cp39-win32.whl", hash = "sha256:bfc8a5e9238232a45ebc5cb3bfee71f1167064c8d382cadd6076f0d51cff1da0"}, - {file = "contourpy-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:c84fdf3da00c2827d634de4fcf17e3e067490c4aea82833625c4c8e6cdea0887"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:229a25f68046c5cf8067d6d6351c8b99e40da11b04d8416bf8d2b1d75922521e"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a10dab5ea1bd4401c9483450b5b0ba5416be799bbd50fc7a6cc5e2a15e03e8a3"}, - {file = "contourpy-1.1.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4f9147051cb8fdb29a51dc2482d792b3b23e50f8f57e3720ca2e3d438b7adf23"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a75cc163a5f4531a256f2c523bd80db509a49fc23721b36dd1ef2f60ff41c3cb"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b53d5769aa1f2d4ea407c65f2d1d08002952fac1d9e9d307aa2e1023554a163"}, - {file = "contourpy-1.1.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11b836b7dbfb74e049c302bbf74b4b8f6cb9d0b6ca1bf86cfa8ba144aedadd9c"}, - {file = "contourpy-1.1.1.tar.gz", hash = "sha256:96ba37c2e24b7212a77da85004c38e7c4d155d3e72a45eeaf22c1f03f607e8ab"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0274c1cb63625972c0c007ab14dd9ba9e199c36ae1a231ce45d725cbcbfd10a8"}, + {file = "contourpy-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab459a1cbbf18e8698399c595a01f6dcc5c138220ca3ea9e7e6126232d102bb4"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fdd887f17c2f4572ce548461e4f96396681212d858cae7bd52ba3310bc6f00f"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d16edfc3fc09968e09ddffada434b3bf989bf4911535e04eada58469873e28e"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c203f617abc0dde5792beb586f827021069fb6d403d7f4d5c2b543d87edceb9"}, + {file = "contourpy-1.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b69303ceb2e4d4f146bf82fda78891ef7bcd80c41bf16bfca3d0d7eb545448aa"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:884c3f9d42d7218304bc74a8a7693d172685c84bd7ab2bab1ee567b769696df9"}, + {file = "contourpy-1.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4a1b1208102be6e851f20066bf0e7a96b7d48a07c9b0cfe6d0d4545c2f6cadab"}, + {file = "contourpy-1.2.0-cp310-cp310-win32.whl", hash = "sha256:34b9071c040d6fe45d9826cbbe3727d20d83f1b6110d219b83eb0e2a01d79488"}, + {file = "contourpy-1.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:bd2f1ae63998da104f16a8b788f685e55d65760cd1929518fd94cd682bf03e41"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dd10c26b4eadae44783c45ad6655220426f971c61d9b239e6f7b16d5cdaaa727"}, + {file = "contourpy-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5c6b28956b7b232ae801406e529ad7b350d3f09a4fde958dfdf3c0520cdde0dd"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebeac59e9e1eb4b84940d076d9f9a6cec0064e241818bcb6e32124cc5c3e377a"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:139d8d2e1c1dd52d78682f505e980f592ba53c9f73bd6be102233e358b401063"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e9dc350fb4c58adc64df3e0703ab076f60aac06e67d48b3848c23647ae4310e"}, + {file = "contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18fc2b4ed8e4a8fe849d18dce4bd3c7ea637758c6343a1f2bae1e9bd4c9f4686"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:16a7380e943a6d52472096cb7ad5264ecee36ed60888e2a3d3814991a0107286"}, + {file = "contourpy-1.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8d8faf05be5ec8e02a4d86f616fc2a0322ff4a4ce26c0f09d9f7fb5330a35c95"}, + {file = "contourpy-1.2.0-cp311-cp311-win32.whl", hash = "sha256:67b7f17679fa62ec82b7e3e611c43a016b887bd64fb933b3ae8638583006c6d6"}, + {file = "contourpy-1.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:99ad97258985328b4f207a5e777c1b44a83bfe7cf1f87b99f9c11d4ee477c4de"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:575bcaf957a25d1194903a10bc9f316c136c19f24e0985a2b9b5608bdf5dbfe0"}, + {file = "contourpy-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9e6c93b5b2dbcedad20a2f18ec22cae47da0d705d454308063421a3b290d9ea4"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464b423bc2a009088f19bdf1f232299e8b6917963e2b7e1d277da5041f33a779"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68ce4788b7d93e47f84edd3f1f95acdcd142ae60bc0e5493bfd120683d2d4316"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d7d1f8871998cdff5d2ff6a087e5e1780139abe2838e85b0b46b7ae6cc25399"}, + {file = "contourpy-1.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e739530c662a8d6d42c37c2ed52a6f0932c2d4a3e8c1f90692ad0ce1274abe0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:247b9d16535acaa766d03037d8e8fb20866d054d3c7fbf6fd1f993f11fc60ca0"}, + {file = "contourpy-1.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:461e3ae84cd90b30f8d533f07d87c00379644205b1d33a5ea03381edc4b69431"}, + {file = "contourpy-1.2.0-cp312-cp312-win32.whl", hash = "sha256:1c2559d6cffc94890b0529ea7eeecc20d6fadc1539273aa27faf503eb4656d8f"}, + {file = "contourpy-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:491b1917afdd8638a05b611a56d46587d5a632cabead889a5440f7c638bc6ed9"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5fd1810973a375ca0e097dee059c407913ba35723b111df75671a1976efa04bc"}, + {file = "contourpy-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:999c71939aad2780f003979b25ac5b8f2df651dac7b38fb8ce6c46ba5abe6ae9"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7caf9b241464c404613512d5594a6e2ff0cc9cb5615c9475cc1d9b514218ae8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:266270c6f6608340f6c9836a0fb9b367be61dde0c9a9a18d5ece97774105ff3e"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbd50d0a0539ae2e96e537553aff6d02c10ed165ef40c65b0e27e744a0f10af8"}, + {file = "contourpy-1.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11f8d2554e52f459918f7b8e6aa20ec2a3bce35ce95c1f0ef4ba36fbda306df5"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ce96dd400486e80ac7d195b2d800b03e3e6a787e2a522bfb83755938465a819e"}, + {file = "contourpy-1.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6d3364b999c62f539cd403f8123ae426da946e142312a514162adb2addd8d808"}, + {file = "contourpy-1.2.0-cp39-cp39-win32.whl", hash = "sha256:1c88dfb9e0c77612febebb6ac69d44a8d81e3dc60f993215425b62c1161353f4"}, + {file = "contourpy-1.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:78e6ad33cf2e2e80c5dfaaa0beec3d61face0fb650557100ee36db808bfa6843"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be16975d94c320432657ad2402f6760990cb640c161ae6da1363051805fa8108"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b95a225d4948b26a28c08307a60ac00fb8671b14f2047fc5476613252a129776"}, + {file = "contourpy-1.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d7e03c0f9a4f90dc18d4e77e9ef4ec7b7bbb437f7f675be8e530d65ae6ef956"}, + {file = "contourpy-1.2.0.tar.gz", hash = "sha256:171f311cb758de7da13fc53af221ae47a5877be5a0843a9fe150818c51ed276a"}, ] [package.dependencies] -numpy = {version = ">=1.16,<2.0", markers = "python_version <= \"3.11\""} +numpy = ">=1.20,<2.0" [package.extras] bokeh = ["bokeh", "selenium"] docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] -mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.4.1)", "types-Pillow"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pillow"] test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] -test-no-images = ["pytest", "pytest-cov", "wurlitzer"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] [[package]] name = "coverage" @@ -775,13 +703,13 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs [[package]] name = "importlib-resources" -version = "6.1.0" +version = "6.1.1" description = "Read resources from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_resources-6.1.0-py3-none-any.whl", hash = "sha256:aa50258bbfa56d4e33fbd8aa3ef48ded10d1735f11532b8df95388cc6bdb7e83"}, - {file = "importlib_resources-6.1.0.tar.gz", hash = "sha256:9d48dcccc213325e810fd723e7fbb45ccb39f6cf5c31f00cf2b965f5f10f3cb9"}, + {file = "importlib_resources-6.1.1-py3-none-any.whl", hash = "sha256:e8bf90d8213b486f428c9c39714b920041cb02c184686a3dee24905aaa8105d6"}, + {file = "importlib_resources-6.1.1.tar.gz", hash = "sha256:3893a00122eafde6894c59914446a512f728a0c1a45f9bb9b63721b6bacf0b4a"}, ] [package.dependencies] @@ -894,13 +822,13 @@ testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] [[package]] name = "jupyter-client" -version = "8.5.0" +version = "8.6.0" description = "Jupyter protocol implementation and client libraries" optional = false python-versions = ">=3.8" files = [ - {file = "jupyter_client-8.5.0-py3-none-any.whl", hash = "sha256:c3877aac7257ec68d79b5c622ce986bd2a992ca42f6ddc9b4dd1da50e89f7028"}, - {file = "jupyter_client-8.5.0.tar.gz", hash = "sha256:e8754066510ce456358df363f97eae64b50860f30dc1fe8c6771440db3be9a63"}, + {file = "jupyter_client-8.6.0-py3-none-any.whl", hash = "sha256:909c474dbe62582ae62b758bca86d6518c85234bdee2d908c778db6d72f39d99"}, + {file = "jupyter_client-8.6.0.tar.gz", hash = "sha256:0642244bb83b4764ae60d07e010e15f0e2d275ec4e918a8f7b80fbbef3ca60c7"}, ] [package.dependencies] @@ -1160,36 +1088,47 @@ setuptools = "*" [[package]] name = "numpy" -version = "1.25.2" +version = "1.26.2" description = "Fundamental package for array computing in Python" optional = false python-versions = ">=3.9" files = [ - {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"}, - {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"}, - {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"}, - {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"}, - {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"}, - {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"}, - {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"}, - {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"}, - {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"}, - {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"}, - {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"}, - {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"}, - {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"}, - {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"}, - {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"}, - {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"}, - {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"}, - {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"}, + {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, + {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, + {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, + {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, + {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, + {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, + {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, + {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, + {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, + {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, + {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, + {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, + {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, + {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, + {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, + {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, + {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, + {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, + {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, + {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, + {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, + {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, + {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, + {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, + {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, + {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, + {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, + {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, + {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, + {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, + {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, + {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, + {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, ] [[package]] @@ -1254,8 +1193,8 @@ files = [ [package.dependencies] numpy = [ {version = ">=1.20.3", markers = "python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, {version = ">=1.23.2", markers = "python_version >= \"3.11\""}, - {version = ">=1.21.0", markers = "python_version >= \"3.10\" and python_version < \"3.11\""}, ] python-dateutil = ">=2.8.2" pytz = ">=2020.1" @@ -1470,13 +1409,13 @@ virtualenv = ">=20.10.0" [[package]] name = "prompt-toolkit" -version = "3.0.39" +version = "3.0.41" description = "Library for building powerful interactive command lines in Python" optional = false python-versions = ">=3.7.0" files = [ - {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, - {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, + {file = "prompt_toolkit-3.0.41-py3-none-any.whl", hash = "sha256:f36fe301fafb7470e86aaf90f036eef600a3210be4decf461a5b1ca8403d3cb2"}, + {file = "prompt_toolkit-3.0.41.tar.gz", hash = "sha256:941367d97fc815548822aa26c2a269fdc4eb21e9ec05fc5d447cf09bad5d75f0"}, ] [package.dependencies] @@ -1596,6 +1535,66 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pyqt5" +version = "5.15.10" +description = "Python bindings for the Qt cross platform application toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyQt5-5.15.10-cp37-abi3-macosx_10_13_x86_64.whl", hash = "sha256:93288d62ebd47b1933d80c27f5d43c7c435307b84d480af689cef2474e87e4c8"}, + {file = "PyQt5-5.15.10-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:862cea3be95b4b0a2b9678003b3a18edf7bd5eafd673860f58820f246d4bf616"}, + {file = "PyQt5-5.15.10-cp37-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:b89478d16d4118664ff58ed609e0a804d002703c9420118de7e4e70fa1cb5486"}, + {file = "PyQt5-5.15.10-cp37-abi3-win32.whl", hash = "sha256:ff99b4f91aa8eb60510d5889faad07116d3340041916e46c07d519f7cad344e1"}, + {file = "PyQt5-5.15.10-cp37-abi3-win_amd64.whl", hash = "sha256:501355f327e9a2c38db0428e1a236d25ebcb99304cd6e668c05d1188d514adec"}, + {file = "PyQt5-5.15.10.tar.gz", hash = "sha256:d46b7804b1b10a4ff91753f8113e5b5580d2b4462f3226288e2d84497334898a"}, +] + +[package.dependencies] +PyQt5-Qt5 = ">=5.15.2" +PyQt5-sip = ">=12.13,<13" + +[[package]] +name = "pyqt5-qt5" +version = "5.15.11" +description = "The subset of a Qt installation needed by PyQt5." +optional = false +python-versions = "*" +files = [ + {file = "PyQt5_Qt5-5.15.11-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:109c418d221538751e4d7755a81c978ee31abbd65facb3f1f361dca74a1b758a"}, + {file = "PyQt5_Qt5-5.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3cccb21942eb49d21fb0193f28e3e8ae3d35395f158e8a9d4d58e23efa3a2ea7"}, +] + +[[package]] +name = "pyqt5-sip" +version = "12.13.0" +description = "The sip module support for PyQt5" +optional = false +python-versions = ">=3.7" +files = [ + {file = "PyQt5_sip-12.13.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a7e3623b2c743753625c4650ec7696362a37fb36433b61824cf257f6d3d43cca"}, + {file = "PyQt5_sip-12.13.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6e4ac714252370ca037c7d609da92388057165edd4f94e63354f6d65c3ed9d53"}, + {file = "PyQt5_sip-12.13.0-cp310-cp310-win32.whl", hash = "sha256:d5032da3fff62da055104926ffe76fd6044c1221f8ad35bb60804bcb422fe866"}, + {file = "PyQt5_sip-12.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a8cdd6cb66adcbe5c941723ed1544eba05cf19b6c961851b58ccdae1c894afb"}, + {file = "PyQt5_sip-12.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f85fb633a522f04e48008de49dce1ff1d947011b48885b8428838973fbca412"}, + {file = "PyQt5_sip-12.13.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec60162e034c42fb99859206d62b83b74f987d58937b3a82bdc07b5c3d190dec"}, + {file = "PyQt5_sip-12.13.0-cp311-cp311-win32.whl", hash = "sha256:205cd449d08a2b024a468fb6100cd7ed03e946b4f49706f508944006f955ae1a"}, + {file = "PyQt5_sip-12.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:1c8371682f77852256f1f2d38c41e2e684029f43330f0635870895ab01c02f6c"}, + {file = "PyQt5_sip-12.13.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7fe3375b508c5bc657d73b9896bba8a768791f1f426c68053311b046bcebdddf"}, + {file = "PyQt5_sip-12.13.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:773731b1b5ab1a7cf5621249f2379c95e3d2905e9bd96ff3611b119586daa876"}, + {file = "PyQt5_sip-12.13.0-cp312-cp312-win32.whl", hash = "sha256:fb4a5271fa3f6bc2feb303269a837a95a6d8dd16be553aa40e530de7fb81bfdf"}, + {file = "PyQt5_sip-12.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:3a4498f3b1b15f43f5d12963accdce0fd652b0bcaae6baf8008663365827444c"}, + {file = "PyQt5_sip-12.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b984c2620a7a7eaf049221b09ae50a345317add2624c706c7d2e9e6632a9587"}, + {file = "PyQt5_sip-12.13.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3188a06956aef86f604fb0d14421a110fad70d2a9e943dbacbfc3303f651dade"}, + {file = "PyQt5_sip-12.13.0-cp38-cp38-win32.whl", hash = "sha256:108a15f603e1886988c4b0d9d41cb74c9f9815bf05cefc843d559e8c298a10ce"}, + {file = "PyQt5_sip-12.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:db228cd737f5cbfc66a3c3e50042140cb80b30b52edc5756dbbaa2346ec73137"}, + {file = "PyQt5_sip-12.13.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5338773bbaedaa4f16a73c142fb23cc18c327be6c338813af70260b756c7bc92"}, + {file = "PyQt5_sip-12.13.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:29fa9cc964517c9fc3f94f072b9a2aeef4e7a2eda1879cb835d9e06971161cdf"}, + {file = "PyQt5_sip-12.13.0-cp39-cp39-win32.whl", hash = "sha256:96414c93f3d33963887cf562d50d88b955121fbfd73f937c8eca46643e77bf61"}, + {file = "PyQt5_sip-12.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:bbc7cd498bf19e0862097be1ad2243e824dea56726f00c11cff1b547c2d31d01"}, + {file = "PyQt5_sip-12.13.0.tar.gz", hash = "sha256:7f321daf84b9c9dbca61b80e1ef37bdaffc0e93312edae2cd7da25b953971d91"}, +] + [[package]] name = "pytest" version = "7.4.3" @@ -1985,18 +1984,17 @@ files = [ [[package]] name = "urllib3" -version = "2.0.7" +version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -2022,13 +2020,13 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "wcwidth" -version = "0.2.9" +version = "0.2.10" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" files = [ - {file = "wcwidth-0.2.9-py2.py3-none-any.whl", hash = "sha256:9a929bd8380f6cd9571a968a9c8f4353ca58d7cd812a4822bba831f8d685b223"}, - {file = "wcwidth-0.2.9.tar.gz", hash = "sha256:a675d1a4a2d24ef67096a04b85b02deeecd8e226f57b5e3a72dbb9ed99d27da8"}, + {file = "wcwidth-0.2.10-py2.py3-none-any.whl", hash = "sha256:aec5179002dd0f0d40c456026e74a729661c9d468e1ed64405e3a6c2176ca36f"}, + {file = "wcwidth-0.2.10.tar.gz", hash = "sha256:390c7454101092a6a5e43baad8f83de615463af459201709556b6e4b1c861f97"}, ] [[package]] @@ -2049,4 +2047,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "9e5351161e7ff51bbee970abcfe960646e947754be1ef9911feab5d160de2f6e" +content-hash = "f0d7ec7e681c4ce33f0a3b48a3b217c32e0b48c19b4dd7119126b5750f7fcee4" diff --git a/pyproject.toml b/pyproject.toml index cdef709..c078769 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ pytest = "^7.4.1" pytest-cov = "^4.1.0" pyyaml = "^6.0.1" openpyxl = "^3.1.2" +PyQt5 = "^5.15" [tool.poetry.group.dev.dependencies] From a7322b6a3f0569e92814da5c963aa0d08d4781af Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 15 Nov 2023 15:16:01 +0100 Subject: [PATCH 19/59] added exception if no clipboard available --- tests/core/pfstate/test_pfstate_excelclipboard.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/core/pfstate/test_pfstate_excelclipboard.py b/tests/core/pfstate/test_pfstate_excelclipboard.py index 5fdf494..d2a2a47 100644 --- a/tests/core/pfstate/test_pfstate_excelclipboard.py +++ b/tests/core/pfstate/test_pfstate_excelclipboard.py @@ -1,7 +1,8 @@ """Test if portfolio line can be exported.""" - +import pytest import portfolyo as pf +import pandas as pd def test_pfstate_toexcel(): @@ -13,4 +14,7 @@ def test_pfstate_toexcel(): def test_pfstate_toclipboard(): """Test if data can be copied to clipboard.""" pfs = pf.dev.get_pfstate() - pfs.to_clipboard() + try: + pfs.to_clipboard() + except pd.errors.PyperclipException: + pytest.skip("Clipboard not available on all systems.") From 1cac21ec6f985d8f793fce23d7b1038df40dfd57 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 15 Nov 2023 15:22:24 +0100 Subject: [PATCH 20/59] updated toml --- poetry.lock | 62 +------------------------------------------------- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 62 deletions(-) diff --git a/poetry.lock b/poetry.lock index c962fc7..21a3f5b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1535,66 +1535,6 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] -[[package]] -name = "pyqt5" -version = "5.15.10" -description = "Python bindings for the Qt cross platform application toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "PyQt5-5.15.10-cp37-abi3-macosx_10_13_x86_64.whl", hash = "sha256:93288d62ebd47b1933d80c27f5d43c7c435307b84d480af689cef2474e87e4c8"}, - {file = "PyQt5-5.15.10-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:862cea3be95b4b0a2b9678003b3a18edf7bd5eafd673860f58820f246d4bf616"}, - {file = "PyQt5-5.15.10-cp37-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:b89478d16d4118664ff58ed609e0a804d002703c9420118de7e4e70fa1cb5486"}, - {file = "PyQt5-5.15.10-cp37-abi3-win32.whl", hash = "sha256:ff99b4f91aa8eb60510d5889faad07116d3340041916e46c07d519f7cad344e1"}, - {file = "PyQt5-5.15.10-cp37-abi3-win_amd64.whl", hash = "sha256:501355f327e9a2c38db0428e1a236d25ebcb99304cd6e668c05d1188d514adec"}, - {file = "PyQt5-5.15.10.tar.gz", hash = "sha256:d46b7804b1b10a4ff91753f8113e5b5580d2b4462f3226288e2d84497334898a"}, -] - -[package.dependencies] -PyQt5-Qt5 = ">=5.15.2" -PyQt5-sip = ">=12.13,<13" - -[[package]] -name = "pyqt5-qt5" -version = "5.15.11" -description = "The subset of a Qt installation needed by PyQt5." -optional = false -python-versions = "*" -files = [ - {file = "PyQt5_Qt5-5.15.11-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:109c418d221538751e4d7755a81c978ee31abbd65facb3f1f361dca74a1b758a"}, - {file = "PyQt5_Qt5-5.15.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3cccb21942eb49d21fb0193f28e3e8ae3d35395f158e8a9d4d58e23efa3a2ea7"}, -] - -[[package]] -name = "pyqt5-sip" -version = "12.13.0" -description = "The sip module support for PyQt5" -optional = false -python-versions = ">=3.7" -files = [ - {file = "PyQt5_sip-12.13.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a7e3623b2c743753625c4650ec7696362a37fb36433b61824cf257f6d3d43cca"}, - {file = "PyQt5_sip-12.13.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6e4ac714252370ca037c7d609da92388057165edd4f94e63354f6d65c3ed9d53"}, - {file = "PyQt5_sip-12.13.0-cp310-cp310-win32.whl", hash = "sha256:d5032da3fff62da055104926ffe76fd6044c1221f8ad35bb60804bcb422fe866"}, - {file = "PyQt5_sip-12.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:9a8cdd6cb66adcbe5c941723ed1544eba05cf19b6c961851b58ccdae1c894afb"}, - {file = "PyQt5_sip-12.13.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0f85fb633a522f04e48008de49dce1ff1d947011b48885b8428838973fbca412"}, - {file = "PyQt5_sip-12.13.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:ec60162e034c42fb99859206d62b83b74f987d58937b3a82bdc07b5c3d190dec"}, - {file = "PyQt5_sip-12.13.0-cp311-cp311-win32.whl", hash = "sha256:205cd449d08a2b024a468fb6100cd7ed03e946b4f49706f508944006f955ae1a"}, - {file = "PyQt5_sip-12.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:1c8371682f77852256f1f2d38c41e2e684029f43330f0635870895ab01c02f6c"}, - {file = "PyQt5_sip-12.13.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7fe3375b508c5bc657d73b9896bba8a768791f1f426c68053311b046bcebdddf"}, - {file = "PyQt5_sip-12.13.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:773731b1b5ab1a7cf5621249f2379c95e3d2905e9bd96ff3611b119586daa876"}, - {file = "PyQt5_sip-12.13.0-cp312-cp312-win32.whl", hash = "sha256:fb4a5271fa3f6bc2feb303269a837a95a6d8dd16be553aa40e530de7fb81bfdf"}, - {file = "PyQt5_sip-12.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:3a4498f3b1b15f43f5d12963accdce0fd652b0bcaae6baf8008663365827444c"}, - {file = "PyQt5_sip-12.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b984c2620a7a7eaf049221b09ae50a345317add2624c706c7d2e9e6632a9587"}, - {file = "PyQt5_sip-12.13.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3188a06956aef86f604fb0d14421a110fad70d2a9e943dbacbfc3303f651dade"}, - {file = "PyQt5_sip-12.13.0-cp38-cp38-win32.whl", hash = "sha256:108a15f603e1886988c4b0d9d41cb74c9f9815bf05cefc843d559e8c298a10ce"}, - {file = "PyQt5_sip-12.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:db228cd737f5cbfc66a3c3e50042140cb80b30b52edc5756dbbaa2346ec73137"}, - {file = "PyQt5_sip-12.13.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5338773bbaedaa4f16a73c142fb23cc18c327be6c338813af70260b756c7bc92"}, - {file = "PyQt5_sip-12.13.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:29fa9cc964517c9fc3f94f072b9a2aeef4e7a2eda1879cb835d9e06971161cdf"}, - {file = "PyQt5_sip-12.13.0-cp39-cp39-win32.whl", hash = "sha256:96414c93f3d33963887cf562d50d88b955121fbfd73f937c8eca46643e77bf61"}, - {file = "PyQt5_sip-12.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:bbc7cd498bf19e0862097be1ad2243e824dea56726f00c11cff1b547c2d31d01"}, - {file = "PyQt5_sip-12.13.0.tar.gz", hash = "sha256:7f321daf84b9c9dbca61b80e1ef37bdaffc0e93312edae2cd7da25b953971d91"}, -] - [[package]] name = "pytest" version = "7.4.3" @@ -2047,4 +1987,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "f0d7ec7e681c4ce33f0a3b48a3b217c32e0b48c19b4dd7119126b5750f7fcee4" +content-hash = "9e5351161e7ff51bbee970abcfe960646e947754be1ef9911feab5d160de2f6e" diff --git a/pyproject.toml b/pyproject.toml index c078769..6141abc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,7 +27,7 @@ pytest = "^7.4.1" pytest-cov = "^4.1.0" pyyaml = "^6.0.1" openpyxl = "^3.1.2" -PyQt5 = "^5.15" + [tool.poetry.group.dev.dependencies] From 047807b1538a35ea958487143d5c306eb6250af2 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 10:04:06 +0100 Subject: [PATCH 21/59] fixed pfline_excelclipboad.py --- tests/core/pfline/test_pfline_excelclipboard.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/core/pfline/test_pfline_excelclipboard.py b/tests/core/pfline/test_pfline_excelclipboard.py index 78fe159..08c0829 100644 --- a/tests/core/pfline/test_pfline_excelclipboard.py +++ b/tests/core/pfline/test_pfline_excelclipboard.py @@ -3,6 +3,7 @@ import pytest import portfolyo as pf +import pandas as pd @pytest.mark.parametrize("levels", [1, 2, 3]) @@ -16,4 +17,7 @@ def test_pfline_toexcel(levels: int): def test_pfline_toclipboard(levels: int): """Test if data can be copied to clipboard.""" pfl = pf.dev.get_pfline(nlevels=levels) - pfl.to_clipboard() + try: + pfl.to_clipboard() + except pd.errors.PyperclipException: + pytest.skip("Clipboard not available on all systems.") From 8b46ec6f19cd2355b02fd099ad434133fc1bf22c Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 10:33:16 +0100 Subject: [PATCH 22/59] changed lock file for pre-commit --- poetry.lock | 100 ++++++++++++++++++++++++------------------------- pyproject.toml | 1 + 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/poetry.lock b/poetry.lock index 21a3f5b..f938494 100644 --- a/poetry.lock +++ b/poetry.lock @@ -580,53 +580,53 @@ pyflakes = ">=3.1.0,<3.2.0" [[package]] name = "fonttools" -version = "4.44.0" +version = "4.44.3" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1cd1c6bb097e774d68402499ff66185190baaa2629ae2f18515a2c50b93db0c"}, - {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9eab7f9837fdaa2a10a524fbcc2ec24bf60637c044b6e4a59c3f835b90f0fae"}, - {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f412954275e594f7a51c16f3b3edd850acb0d842fefc33856b63a17e18499a5"}, - {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50d25893885e80a5955186791eed5579f1e75921751539cc1dc3ffd1160b48cf"}, - {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:22ea8aa7b3712450b42b044702bd3a64fd118006bad09a6f94bd1b227088492e"}, - {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df40daa6c03b98652ffe8110ae014fe695437f6e1cb5a07e16ea37f40e73ac86"}, - {file = "fonttools-4.44.0-cp310-cp310-win32.whl", hash = "sha256:bca49da868e8bde569ef36f0cc1b6de21d56bf9c3be185c503b629c19a185287"}, - {file = "fonttools-4.44.0-cp310-cp310-win_amd64.whl", hash = "sha256:dbac86d83d96099890e731cc2af97976ff2c98f4ba432fccde657c5653a32f1c"}, - {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e8ff7d19a6804bfd561cfcec9b4200dd1788e28f7de4be70189801530c47c1b3"}, - {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8a1fa9a718de0bc026979c93e1e9b55c5efde60d76f91561fd713387573817d"}, - {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05064f95aacdfc06f21e55096c964b2228d942b8675fa26995a2551f6329d2d"}, - {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31b38528f25bc662401e6ffae14b3eb7f1e820892fd80369a37155e3b636a2f4"}, - {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:05d7c4d2c95b9490e669f3cb83918799bf1c838619ac6d3bad9ea017cfc63f2e"}, - {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6999e80a125b0cd8e068d0210b63323f17338038c2ecd2e11b9209ec430fe7f2"}, - {file = "fonttools-4.44.0-cp311-cp311-win32.whl", hash = "sha256:a7aec7f5d14dfcd71fb3ebc299b3f000c21fdc4043079101777ed2042ba5b7c5"}, - {file = "fonttools-4.44.0-cp311-cp311-win_amd64.whl", hash = "sha256:518a945dbfe337744bfff31423c1430303b8813c5275dffb0f2577f0734a1189"}, - {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:59b6ad83cce067d10f4790c037a5904424f45bebb5e7be2eb2db90402f288267"}, - {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c2de1fb18198acd400c45ffe2aef5420c8d55fde903e91cba705596099550f3b"}, - {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f308b7a8d28208d54315d11d35f9888d6d607673dd4d42d60b463682ee0400"}, - {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66bc6efd829382f7a7e6cf33c2fb32b13edc8a239eb15f32acbf197dce7a0165"}, - {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a8b99713d3a0d0e876b6aecfaada5e7dc9fe979fcd90ef9fa0ba1d9b9aed03f2"}, - {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b63da598d9cbc52e2381f922da0e94d60c0429f92207bd3fb04d112fc82ea7cb"}, - {file = "fonttools-4.44.0-cp312-cp312-win32.whl", hash = "sha256:f611c97678604e302b725f71626edea113a5745a7fb557c958b39edb6add87d5"}, - {file = "fonttools-4.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:58af428746fa73a2edcbf26aff33ac4ef3c11c8d75bb200eaea2f7e888d2de4e"}, - {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9ee8692e23028564c13d924004495f284df8ac016a19f17a87251210e1f1f928"}, - {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dab3d00d27b1a79ae4d4a240e8ceea8af0ff049fd45f05adb4f860d93744110d"}, - {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f53526668beccdb3409c6055a4ffe50987a7f05af6436fa55d61f5e7bd450219"}, - {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3da036b016c975c2d8c69005bdc4d5d16266f948a7fab950244e0f58301996a"}, - {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b99fe8ef4093f672d00841569d2d05691e50334d79f4d9c15c1265d76d5580d2"}, - {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d16d9634ff1e5cea2cf4a8cbda9026f766e4b5f30b48f8180f0e99133d3abfc"}, - {file = "fonttools-4.44.0-cp38-cp38-win32.whl", hash = "sha256:3d29509f6e05e8d725db59c2d8c076223d793e4e35773040be6632a0349f2f97"}, - {file = "fonttools-4.44.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4fa4f4bc8fd86579b8cdbe5e948f35d82c0eda0091c399d009b2a5a6b61c040"}, - {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c794de4086f06ae609b71ac944ec7deb09f34ecf73316fddc041087dd24bba39"}, - {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2db63941fee3122e31a21dd0f5b2138ce9906b661a85b63622421d3654a74ae2"}, - {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb01c49c8aa035d5346f46630209923d4927ed15c2493db38d31da9f811eb70d"}, - {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c79af80a835410874683b5779b6c1ec1d5a285e11c45b5193e79dd691eb111"}, - {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6e6aa2d066f8dafd06d8d0799b4944b5d5a1f015dd52ac01bdf2895ebe169a0"}, - {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63a3112f753baef8c6ac2f5f574bb9ac8001b86c8c0c0380039db47a7f512d20"}, - {file = "fonttools-4.44.0-cp39-cp39-win32.whl", hash = "sha256:54efed22b2799a85475e6840e907c402ba49892c614565dc770aa97a53621b2b"}, - {file = "fonttools-4.44.0-cp39-cp39-win_amd64.whl", hash = "sha256:2e91e19b583961979e2e5a701269d3cfc07418963bee717f8160b0a24332826b"}, - {file = "fonttools-4.44.0-py3-none-any.whl", hash = "sha256:b9beb0fa6ff3ea808ad4a6962d68ac0f140ddab080957b20d9e268e4d67fb335"}, - {file = "fonttools-4.44.0.tar.gz", hash = "sha256:4e90dd81b6e0d97ebfe52c0d12a17a9ef7f305d6bfbb93081265057d6092f252"}, + {file = "fonttools-4.44.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:192ebdb3bb1882b7ed3ad4b949a106ddd8b428d046ddce64df2d459f7a2db31b"}, + {file = "fonttools-4.44.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20898476cf9c61795107b91409f4b1cf86de6e92b41095bbe900c05b5b117c96"}, + {file = "fonttools-4.44.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:437204780611f9f80f74cd4402fa451e920d1c4b6cb474a0818a734b4affc477"}, + {file = "fonttools-4.44.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50152205ed3e16c5878a006ee53ecc402acac9af68357343be1e5c36f66ccb24"}, + {file = "fonttools-4.44.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ba9c407d8bd63b21910b98399aeec87e24ca9c3e62ea60c246e505c4a4df6c27"}, + {file = "fonttools-4.44.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:79a6babb87d7f70f8aed88f157bbdc5d2f01ad8b01e9535ff07e43e96ad25548"}, + {file = "fonttools-4.44.3-cp310-cp310-win32.whl", hash = "sha256:32e8a5cebfe8f797461b02084104053b2690ebf0cc38eda5beb9ba24ce43c349"}, + {file = "fonttools-4.44.3-cp310-cp310-win_amd64.whl", hash = "sha256:c26649a6ce6f1ce4dd6748f64b18f70e39c618c6188286ab9534a949da28164c"}, + {file = "fonttools-4.44.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5cd114cb20b491f6812aa397040b06a469563c1a01ec94c8c5d96b76d84916db"}, + {file = "fonttools-4.44.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e84084cc325f888c3495df7ec25f6133be0f606efb80a9c9e072ea6064ede9ac"}, + {file = "fonttools-4.44.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:877e36afce69cfdbd0453a4f44b16e865ac29f06df29f10f0b822a68ab858e86"}, + {file = "fonttools-4.44.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1c2cb1e2a7cfeaeb40b8823f238d7e02929b3a0b53e133e757dec5e99c327c9"}, + {file = "fonttools-4.44.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dd752b778b37863cf5146d0112aafcd5693235831f09303809ab9c1e564c236b"}, + {file = "fonttools-4.44.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8f4e22c5128cb604d3b0b869eb8d3092a1c10cbe6def402ff46bb920f7169374"}, + {file = "fonttools-4.44.3-cp311-cp311-win32.whl", hash = "sha256:4831d948bc3cea9cd8bf0c92a087f4392068bcac3b584a61a4c837c48a012337"}, + {file = "fonttools-4.44.3-cp311-cp311-win_amd64.whl", hash = "sha256:948b35e54b0c1b6acf9d63c70515051b7d400d69b61c91377cf0e8742d71c44d"}, + {file = "fonttools-4.44.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fad1c74aa10b77764d3cdf3481bd181d4949e0b46f2da6f9e57543d4adbda177"}, + {file = "fonttools-4.44.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b6a77e3b994649f72fb46b0b8cfe64481b5640e5aecc2d77961300a34fe1dc4f"}, + {file = "fonttools-4.44.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2bff4f9d5edc10b29d2a2daeefd78a47289ba2f751c9bf247925b9d43c6efd79"}, + {file = "fonttools-4.44.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3302998e02a854a41c930f9f1366eb8092dbc5fe7ff636d86aeb28d232f4610a"}, + {file = "fonttools-4.44.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8c7985017e7fb2c2613fa5c440457cd45a6ea808f8d08ed70c27e02e6862cbbe"}, + {file = "fonttools-4.44.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:35d88af2b63060ed2b50aa00d38f60edf4c0b9275a77ae1a98e8d2c03540c617"}, + {file = "fonttools-4.44.3-cp312-cp312-win32.whl", hash = "sha256:5478a77a15d01a21c569fc4ab6f2faba852a21d0932eef02ac4c4a4b50af8070"}, + {file = "fonttools-4.44.3-cp312-cp312-win_amd64.whl", hash = "sha256:979fc845703e0d9b35bc65379fcf34d050e04c3e0b3381a0f66b0be33183da1c"}, + {file = "fonttools-4.44.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7a8b9f22d3c147ecdc7be46f9f1e1df0523541df0535fac5bdd653726218d068"}, + {file = "fonttools-4.44.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bcb0fde94374ba00c118d632b0b5f1f4447401313166bcb14d737322928e358f"}, + {file = "fonttools-4.44.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eb365cd8ae4765973fa036aed0077ac26f37b2f8240a72c4a29cd9d8a31027f"}, + {file = "fonttools-4.44.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c329e21502c894fe4c800e32bc3ce37c6b5ca95778d32dff17d7ebf5cac94efa"}, + {file = "fonttools-4.44.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:345a30db8adfbb868221234fb434dd2fc5bfe27baafbaf418528f6c5a5a95584"}, + {file = "fonttools-4.44.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2fe4eed749de2e6bf3aa05d18df04231a712a16c08974af5e67bb9f75a25d10f"}, + {file = "fonttools-4.44.3-cp38-cp38-win32.whl", hash = "sha256:3b179a284b73802edd6d910e6384f28098cb03bd263fd87db6abb31679f68863"}, + {file = "fonttools-4.44.3-cp38-cp38-win_amd64.whl", hash = "sha256:4c805a0b0545fd9becf6dfe8d57e45a7c1af7fdbfd0a7d776c5e999e4edec9f5"}, + {file = "fonttools-4.44.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f647d270ee90f70acbf5b31a53d486ba0897624236f9056d624c4e436386a14e"}, + {file = "fonttools-4.44.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ba82ee938bd7ea16762124a650bf2529f67dfe9999f64e0ebe1ef0a04baceafd"}, + {file = "fonttools-4.44.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3bbca4f873d96c20757c24c70a903251a8998e1931bd888b49956f21d94b441"}, + {file = "fonttools-4.44.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50b43fd55089ae850a050f0c382f13fc9586279a540b646b28b9e93fbc05b8a3"}, + {file = "fonttools-4.44.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:cde83f83919ae7569a0316e093e04022dbb8ae5217f41cf591f125dd35d4dc0d"}, + {file = "fonttools-4.44.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72ec91b85391dd4b06991c0919215ecf910554df2842df32e928155ea5b74aef"}, + {file = "fonttools-4.44.3-cp39-cp39-win32.whl", hash = "sha256:367aa3e81a096e9a95dfc0d5afcbd0a299d857bac6d0fe5f1614c6f3e53f447f"}, + {file = "fonttools-4.44.3-cp39-cp39-win_amd64.whl", hash = "sha256:718599de63b337518bfa5ce67e4ae462da3dd582a74fbe805f56b3704eb334a1"}, + {file = "fonttools-4.44.3-py3-none-any.whl", hash = "sha256:42eefbb1babf81de40ab4a6ace6018c8c5a0d79ece0f986f73a9904b26ee511b"}, + {file = "fonttools-4.44.3.tar.gz", hash = "sha256:f77b6c0add23a3f1ec8eda40015bcb8e92796f7d06a074de102a31c7d007c05b"}, ] [package.extras] @@ -684,22 +684,22 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "4.13.0" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, + {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "importlib-resources" @@ -1987,4 +1987,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "9e5351161e7ff51bbee970abcfe960646e947754be1ef9911feab5d160de2f6e" +content-hash = "17ac55ac10630fc89a83c323428c70b11f4ea6cb845b81a70437193e03f09b2e" diff --git a/pyproject.toml b/pyproject.toml index 6141abc..b5fbafd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,6 +35,7 @@ flake8 = "^6.1.0" black = "^23.7.0" pre-commit = "^3.4.0" ipykernel = "^6.25.2" +importlib-metadata = "^4.8" [build-system] requires = ["poetry-core"] From af1924683f561715b9701430fcd1373167350e19 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 11:21:55 +0100 Subject: [PATCH 23/59] install poetry libraries in pre-commit step --- .github/workflows/pre-commit.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index 544d9d0..11648b6 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -7,4 +7,8 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 + - name: Install + run: | + pip install poetry + poetry install --with dev,test - uses: pre-commit/action@v2.0.0 \ No newline at end of file From 7c106c855789cabd27a9bdd07e8cc1a12374b50d Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 11:43:01 +0100 Subject: [PATCH 24/59] use black on all files in pre-commit --- .github/workflows/pre-commit.yaml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index 11648b6..323bc63 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -7,8 +7,6 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 - - name: Install - run: | - pip install poetry - poetry install --with dev,test - - uses: pre-commit/action@v2.0.0 \ No newline at end of file + - uses: pre-commit/action@v2.0.0 + with: + extra_args: black --all-files \ No newline at end of file From f325b758ed25d8fa19010d0bb8fe5a9d00b094e5 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 11:55:38 +0100 Subject: [PATCH 25/59] updated flake8 version in pre-commit.yaml --- .github/workflows/pre-commit.yaml | 2 -- .pre-commit-config.yaml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/pre-commit.yaml b/.github/workflows/pre-commit.yaml index 323bc63..e5f7926 100644 --- a/.github/workflows/pre-commit.yaml +++ b/.github/workflows/pre-commit.yaml @@ -8,5 +8,3 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 - uses: pre-commit/action@v2.0.0 - with: - extra_args: black --all-files \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index fea53af..47c09fc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - id: black language_version: python3 - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 6.1.0 hooks: - id: flake8 language_version: python3 \ No newline at end of file From 4cb6bc8bb74e19a25a1ef5ebab0672bb6cef87c8 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 13:43:50 +0100 Subject: [PATCH 26/59] exclude .venv folder from flake8 --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index d4dec64..ec14d73 100644 --- a/setup.cfg +++ b/setup.cfg @@ -7,7 +7,7 @@ tag_prefix = parentdir_prefix = [flake8] -exclude = __init__.py,versioneer.py,_version.py +exclude = __init__.py,versioneer.py,_version.py,.venv/ max-line-length = 120 ignore = E501, W503 From cbef5e769d185bb76ae365c4228eafaca34216ca Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 17 Nov 2023 14:17:57 +0100 Subject: [PATCH 27/59] changed setup.cfg to ignore flake8 error messages --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index ec14d73..4e57090 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,7 +9,7 @@ parentdir_prefix = [flake8] exclude = __init__.py,versioneer.py,_version.py,.venv/ max-line-length = 120 -ignore = E501, W503 +ignore = E501, W503, E202, E226 [tool:pytest] addopts = --cov=. From 5ce68396e08755bc9f9972bd8a0957cc8118196f Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Tue, 21 Nov 2023 10:52:33 +0100 Subject: [PATCH 28/59] initial commit --- portfolyo/core/mixins/plot.py | 22 +++++++++++++++++++++- portfolyo/visualize/plot.py | 2 +- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index b0a1c0f..25e1754 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -68,9 +68,13 @@ def plot_to_ax( raise ValueError( f"For this PfLine, parameter ``col`` must be one of {', '.join(self.kind.available)}; got {col}." ) + # if len(self.items()) == 0: + # print("This PFline doesn't have any children") + # for (name, child) in self.items(): + # vis.plot_timeseries(ax, getattr(self, name), how, labelfmt, **kwargs) vis.plot_timeseries(ax, getattr(self, col), how, labelfmt, **kwargs) - def plot(self: PfLine, cols: str = None) -> plt.Figure: + def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: """Plot one or more timeseries of the PfLine. Parameters @@ -79,6 +83,8 @@ def plot(self: PfLine, cols: str = None) -> plt.Figure: The columns to plot. Default: plot volume (in [MW] for daily values and shorter, [MWh] for monthly values and longer) and price `p` [Eur/MWh] (if available). + children : bool, optional (default: False) + If True, plot also the direct children of the PfLine. Returns ------- @@ -110,6 +116,20 @@ def plot(self: PfLine, cols: str = None) -> plt.Figure: kwargs = defaultkwargs(col, is_category) s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) + for name, child in self.items(): + # kwargs = defaultkwargs(col, is_category) + s = getattr(child, col) + # the first time: set the type of axes to the type of the s series type + # the second type: tries to convert the unit that were set to base units + # but it fails + # setattr(ax, "_unit", None) + vis.plot_timeseries(ax, s, **kwargs) + + # for (name, child) in self.items(): + # for col, ax in zipped: + # kwargs = defaultkwargs(col, is_category) + # s = getattr(child, col) + # vis.plot_timeseries(ax, s, **kwargs) return fig diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index bfdba2f..2e7ebeb 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -283,7 +283,7 @@ def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: raise ValueError( f"Cannot plot series with units {s.pint.units} on axes with units {axunit}." ) - return s.astype(axunit) + return s.astype(f"pint[{axunit}]") # Axes does not have unit. if unit is not None: From 545879bdeddbec6d74efc6eca597e0588f70d9e5 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 21 Nov 2023 14:53:01 +0100 Subject: [PATCH 29/59] first try at plotting children --- dev_scripts/plot_test.py | 9 +++++++++ portfolyo/core/mixins/plot.py | 19 +++++-------------- 2 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 dev_scripts/plot_test.py diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py new file mode 100644 index 0000000..78a1e44 --- /dev/null +++ b/dev_scripts/plot_test.py @@ -0,0 +1,9 @@ +"""Create several plots to see if plotting still works.""" + +import pandas as pd + + +def plots(): + """Create 16 plots: (w, q, p, r) x (hourly, monthly) x (children, no children).""" + i = pd.date_range("2020", "2021", freq="H") + print(i) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 25e1754..4bf8ab5 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -116,20 +116,11 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: kwargs = defaultkwargs(col, is_category) s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) - for name, child in self.items(): - # kwargs = defaultkwargs(col, is_category) - s = getattr(child, col) - # the first time: set the type of axes to the type of the s series type - # the second type: tries to convert the unit that were set to base units - # but it fails - # setattr(ax, "_unit", None) - vis.plot_timeseries(ax, s, **kwargs) - - # for (name, child) in self.items(): - # for col, ax in zipped: - # kwargs = defaultkwargs(col, is_category) - # s = getattr(child, col) - # vis.plot_timeseries(ax, s, **kwargs) + if children: + for name, child in self.items(): + kwargs["align"] = "edge" # TODO + kwargs["labelfmt"] = "" + vis.plot_timeseries(ax, getattr(child, col), **kwargs) return fig From 420b530808fe6d165e45ed948d4d27e0d9534b3f Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 1 Dec 2023 14:11:23 +0100 Subject: [PATCH 30/59] bar plot with children --- dev_scripts/plot_test.py | 26 +- docs/tutorial/part3.ipynb | 1910 +++++++++++++++++---------------- docs/tutorial/part4.ipynb | 556 +++++----- portfolyo/core/mixins/plot.py | 22 +- portfolyo/visualize/plot.py | 17 +- 5 files changed, 1300 insertions(+), 1231 deletions(-) diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index 78a1e44..d33f47e 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -1,9 +1,29 @@ """Create several plots to see if plotting still works.""" import pandas as pd +import matplotlib.pyplot as plt +import portfolyo as pf -def plots(): +def plots(children: int = 1): """Create 16 plots: (w, q, p, r) x (hourly, monthly) x (children, no children).""" - i = pd.date_range("2020", "2021", freq="H") - print(i) + index = pd.date_range("2024", freq="AS", periods=3) + pfl1 = pf.PfLine(pd.Series([0.2, 0.22, 0.3], index, dtype="pint[GW]")) + dict_of_children = {} + for i in range(children): + key = str(i) + dict_of_children[key] = pfl1 + + pfl = pf.PfLine(dict_of_children) + + pfl.print() + pfl.plot(children=True) + plt.show() + + # pf_nested_pr.print() + # pf_nested_pr.plot(children=True) + # plt.show() + print("The number of children is:", children) + + +plots(int(input())) diff --git a/docs/tutorial/part3.ipynb b/docs/tutorial/part3.ipynb index e71e8bf..1abbd36 100644 --- a/docs/tutorial/part3.ipynb +++ b/docs/tutorial/part3.ipynb @@ -1,948 +1,968 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Tutorial part 3\n", - "\n", - "In [part 1](part1.ipynb) and [part 2](part2.ipynb) we have learnt about portfolio lines. These are timeseries, or collections of timeseries, describing the volumes and/or prices during various delivery periods.\n", - "\n", - "In this part, we'll combine portfolio lines into a \"portfolio state\" (``PfState``) object. As we'll see, some of the methods and properties we know from the ``PfLine`` class also apply here.\n", - "\n", - "\n", - "## Example data\n", - "\n", - "Let's again use the mock functions to get some portfolio lines. (The parameter details here are not important, we just want some more-or-less realistic data). To change things up a bit from the previous tutorial parts, we'll look at about 80 days in the autumn of 2024, in quarterhourly (``\"15T\"``) resolution. And let's localize the data to a specific timezone:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "import portfolyo as pf\n", - "import pandas as pd\n", - "\n", - "index = pd.date_range('2024-09-20', '2024-12-10', freq='15T', inclusive='left', tz='Europe/Berlin')\n", - "# Creating offtake portfolio line.\n", - "ts_offtake = -1 * pf.dev.w_offtake(index, avg=50)\n", - "offtake = pf.PfLine({'w': ts_offtake})\n", - "# Creating portfolio line with market prices (here: price-forward curve).\n", - "ts_prices = pf.dev.p_marketprices(index, avg=200)\n", - "prices = pf.PfLine({'p': ts_prices})\n", - "\n", - "# Creating portfolio line with sourced volume.\n", - "ts_sourced_power1, ts_sourced_price1 = pf.dev.wp_sourced(ts_offtake, 'QS', 0.3, p_avg=120)\n", - "sourced_quarters = pf.PfLine({'w': ts_sourced_power1, 'p': ts_sourced_price1})\n", - "ts_sourced_power2, ts_sourced_price2 = pf.dev.wp_sourced(ts_offtake, 'MS', 0.2, p_avg=150)\n", - "sourced_months = pf.PfLine({'w': ts_sourced_power2, 'p': ts_sourced_price2})\n", - "sourced = pf.PfLine({'quarter_products': sourced_quarters, 'month_products': sourced_months})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can now use these portfolio lines to create a portfolio state.\n", - "\n", - "## Portfolio State\n", - "\n", - "The ``PfState`` class is used to hold information about offtake, market prices, and sourcing. Let's create one from the portfolio lines we just created:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PfState object.\n", - ". Start: 2024-09-20 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-12-10 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : <15 * Minutes> (7780 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "──────── offtake\n", - " 2024-09-20 00:00:00 +0200 -45.8 -11 \n", - " 2024-09-20 00:15:00 +0200 -44.4 -11 \n", - " .. .. .. .. ..\n", - " 2024-12-09 23:30:00 +0100 -60.5 -15 \n", - " 2024-12-09 23:45:00 +0100 -58.3 -15 \n", - "─●────── pnl_cost\n", - " │ 2024-09-20 00:00:00 +0200 45.8 11 136.54 1 564\n", - " │ 2024-09-20 00:15:00 +0200 44.4 11 135.21 1 500\n", - " │ .. .. .. .. ..\n", - " │ 2024-12-09 23:30:00 +0100 60.5 15 167.89 2 540\n", - " │ 2024-12-09 23:45:00 +0100 58.3 15 167.21 2 436\n", - " ├●───── sourced\n", - " ││ 2024-09-20 00:00:00 +0200 31.3 8 135.03 1 058\n", - " ││ 2024-09-20 00:15:00 +0200 31.3 8 135.03 1 058\n", - " ││ .. .. .. .. ..\n", - " ││ 2024-12-09 23:30:00 +0100 35.7 9 126.09 1 124\n", - " ││ 2024-12-09 23:45:00 +0100 35.7 9 126.09 1 124\n", - " │├───── quarter_products\n", - " ││ 2024-09-20 00:00:00 +0200 16.4 4 102.48 421\n", - " ││ 2024-09-20 00:15:00 +0200 16.4 4 102.48 421\n", - " ││ .. .. .. .. ..\n", - " ││ 2024-12-09 23:30:00 +0100 13.4 3 111.14 372\n", - " ││ 2024-12-09 23:45:00 +0100 13.4 3 111.14 372\n", - " │└───── month_products\n", - " │ 2024-09-20 00:00:00 +0200 14.9 4 170.85 637\n", - " │ 2024-09-20 00:15:00 +0200 14.9 4 170.85 637\n", - " │ .. .. .. .. ..\n", - " │ 2024-12-09 23:30:00 +0100 22.3 6 135.07 752\n", - " │ 2024-12-09 23:45:00 +0100 22.3 6 135.07 752\n", - " └────── unsourced\n", - " 2024-09-20 00:00:00 +0200 14.5 4 139.81 506\n", - " 2024-09-20 00:15:00 +0200 13.0 3 135.64 442\n", - " .. .. .. .. ..\n", - " 2024-12-09 23:30:00 +0100 24.8 6 227.88 1 416\n", - " 2024-12-09 23:45:00 +0100 22.6 6 232.05 1 312" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pfs = pf.PfState(offtake, prices, sourced)\n", - "\n", - "pfs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note from how these portfolio lines were created, that ``offtake`` has negative values. The sign conventions are discussed [here](../core/pfstate.rst#sign-conventions).\n", - "\n", - "This portfolio state contains values for every quarterhour in the specified time period. Let's see what features this class has, starting with two methods we already met when discussing the ``PfLine`` class.\n", - "\n", - "### Plotting\n", - "\n", - "Just as when working with portfolio lines, we can get a quick overview of the portfolio state with the ``.plot()`` method..." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "pfs.plot();" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "...and we can copy its data to the clipboard, or save it as an Excel workbook:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "pfs.to_clipboard()\n", - "pfs.to_excel('portfolio_state.xlsx')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Looking at the offtake, we can see the daily and weekly cycles, as well as a slow increase over the entire time period.\n", - "\n", - "This graph is a bit too detailed for most purposes, so let's look at the second method we know from ``PfLine``: resampling.\n", - "\n", - "### Resampling\n", - "\n", - "We might prefer to see hourly, daily, or monthly values instead of the quarterhourly values that are in ``pfs``. For this, we can resample the object with the ``.asfreq()`` method. In this code example, we also use the ``.print()`` method, which adds some helpful coloring to the output:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PfState object.\n", - ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\u001b[1m\u001b[37m──────── offtake\n", - " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -54.7 -40 744 \n", - " \u001b[1m\u001b[37m \u001b[0m2024-11-01 00:00:00 +0100 -59.4 -42 732 \n", - "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 54.7 40 744 160.48 6 538 471\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-11-01 00:00:00 +0100 59.4 42 732 182.94 7 817 452\n", - " \u001b[1m\u001b[33m├\u001b[1m\u001b[36m●\u001b[1m\u001b[33m───── sourced\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 31.2 23 221 132.58 3 078 642\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-11-01 00:00:00 +0100 25.9 18 652 133.27 2 485 849\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m├───── quarter_products\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 13.8 10 256 106.54 1 092 646\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-11-01 00:00:00 +0100 13.7 9 897 106.78 1 056 810\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m└───── month_products\n", - " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 17.4 12 964 153.19 1 985 996\n", - " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-11-01 00:00:00 +0100 12.2 8 755 163.22 1 429 039\n", - " \u001b[1m\u001b[33m└────── unsourced\n", - " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 23.5 17 523 197.44 3 459 829\n", - " \u001b[1m\u001b[33m \u001b[0m2024-11-01 00:00:00 +0100 33.4 24 080 221.41 5 331 603\n" - ] - } - ], - "source": [ - "pfs_monthly = pfs.asfreq('MS')\n", - "pfs_monthly.print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note how the resampled output only contains those months, that are *entirely* included in the original data. ``pfl`` has data in September and December, but as these are not present in their entirety, they are dropped from ``pfl_monthly``.\n", - "\n", - "### On frequencies and unsourced prices\n", - "\n", - "There is one other important consequence of resampling: the unsourced prices are now *specific for this portfolio*. We can demonstrate this by creating a second portfolio state, using the *same price-forward curve* (but different offtake and sourced volume):" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "pfs2 = pf.PfState(offtake*1.5, prices, sourced*2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "At this shortest frequency, the unsourced prices are identical (namely, the price-forward curve). Let's create a dataframe with the prices to verify this:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pfspfs2hpfc
2024-09-20 00:00:00+02:00139.80568207211454139.80568207211454139.80568207211454
2024-09-20 00:15:00+02:00135.63901540544785135.63901540544785135.63901540544785
2024-09-20 00:30:00+02:00131.47234873878116131.47234873878116131.47234873878116
2024-09-20 00:45:00+02:00128.13901540544785128.13901540544785128.13901540544785
2024-09-20 01:00:00+02:00124.80568207211451124.80568207211451124.80568207211451
............
2024-12-09 22:45:00+01:00217.88078474854294217.88078474854294217.88078474854294
2024-12-09 23:00:00+01:00221.2141180818763221.2141180818763221.2141180818763
2024-12-09 23:15:00+01:00224.54745141520962224.54745141520962224.54745141520962
2024-12-09 23:30:00+01:00227.88078474854294227.88078474854294227.88078474854294
2024-12-09 23:45:00+01:00232.0474514152096232.0474514152096232.0474514152096
\n", - "

7780 rows × 3 columns

\n", - "
" - ], - "text/plain": [ - " pfs pfs2 \\\n", - "2024-09-20 00:00:00+02:00 139.80568207211454 139.80568207211454 \n", - "2024-09-20 00:15:00+02:00 135.63901540544785 135.63901540544785 \n", - "2024-09-20 00:30:00+02:00 131.47234873878116 131.47234873878116 \n", - "2024-09-20 00:45:00+02:00 128.13901540544785 128.13901540544785 \n", - "2024-09-20 01:00:00+02:00 124.80568207211451 124.80568207211451 \n", - "... ... ... \n", - "2024-12-09 22:45:00+01:00 217.88078474854294 217.88078474854294 \n", - "2024-12-09 23:00:00+01:00 221.2141180818763 221.2141180818763 \n", - "2024-12-09 23:15:00+01:00 224.54745141520962 224.54745141520962 \n", - "2024-12-09 23:30:00+01:00 227.88078474854294 227.88078474854294 \n", - "2024-12-09 23:45:00+01:00 232.0474514152096 232.0474514152096 \n", - "\n", - " hpfc \n", - "2024-09-20 00:00:00+02:00 139.80568207211454 \n", - "2024-09-20 00:15:00+02:00 135.63901540544785 \n", - "2024-09-20 00:30:00+02:00 131.47234873878116 \n", - "2024-09-20 00:45:00+02:00 128.13901540544785 \n", - "2024-09-20 01:00:00+02:00 124.80568207211451 \n", - "... ... \n", - "2024-12-09 22:45:00+01:00 217.88078474854294 \n", - "2024-12-09 23:00:00+01:00 221.2141180818763 \n", - "2024-12-09 23:15:00+01:00 224.54745141520962 \n", - "2024-12-09 23:30:00+01:00 227.88078474854294 \n", - "2024-12-09 23:45:00+01:00 232.0474514152096 \n", - "\n", - "[7780 rows x 3 columns]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame({'pfs': pfs.unsourcedprice.p, 'pfs2': pfs2.unsourcedprice.p, 'hpfc': prices.p})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "However, at every other frequency, they are not equal. When changing the frequency, a *volume-weighted* average is calculated for the unsourced prices - just like with every other price-and-volume timeseries. This makes that the unsourced prices apply only to the unsourced volume profile *of that portfolio*:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
pfspfs2hpfc
2024-10-01 00:00:00+02:00197.4437803760265192.11463549822653194.78888729464586
2024-11-01 00:00:00+01:00221.40989836363784217.79829542112196220.07479863376392
\n", - "
" - ], - "text/plain": [ - " pfs pfs2 \\\n", - "2024-10-01 00:00:00+02:00 197.4437803760265 192.11463549822653 \n", - "2024-11-01 00:00:00+01:00 221.40989836363784 217.79829542112196 \n", - "\n", - " hpfc \n", - "2024-10-01 00:00:00+02:00 194.78888729464586 \n", - "2024-11-01 00:00:00+01:00 220.07479863376392 " - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame({'pfs': pfs.asfreq('MS').unsourcedprice.p, 'pfs2': pfs2.asfreq('MS').unsourcedprice.p, 'hpfc': prices.asfreq('MS').p})" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This has important consequences. \n", - "\n", - "For example, when doing a scenario analysis in which the unsourced volume is changed (e.g. \"what happens if the offtake increases by 50%?\"), we cannot expect the results to be correct *unless we are working at the original frequency*. In situations where it is clear that this error looms, a ``UserWarning`` is shown to alert the user (e.g. in the examples further below). For more information on unsourced volume, [see this section](../core/pfstate.rst#Unsourced-price) in the documentation on the `PfState` class.\n", - "\n", - "For this reason, we commonly work with our porfolio states at the frequency of the price-forward curve. Downsampling is only done to see the aggregated values for verification or reporting." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Components\n", - "\n", - "Now, let's look at the portfolio state ``pfs_monthly`` in a bit more detail, to learn more about the ``PfState`` class.\n", - "\n", - "The portfolio state is presented to us as a tree structure, with several branches. Each branch is a portfolio line. E.g, ``offtake`` and ``sourced`` are the portfolio lines we specified when creating the object. Also, the branch ``pnl_cost`` is the sum of ``sourced`` and ``unsourced``, with ``sourced`` being the sum of ``quarter_products`` and ``month_products``. \n", - "\n", - "The unsourced volume is found by comparing the offtake to what is already sourced. This volume is valued at the market prices in the forward curve.\n", - "\n", - "These portfolio lines can be obtained from the portfolio state by accessing them as attributes. E.g. ``.offtakevolume``, ``.sourced``, ``.unsourced``, or ``.pnl_cost``. The latter is the best estimate for what it will cost to procure the offtake:" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PfLine object with price and volume information.\n", - ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - ". Children: 'sourced' (price and volume), 'unsourced' (price and volume)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\n", - "2024-10-01 00:00:00 +0200 54.7 40 744 160.48 6 538 471\n", - "2024-11-01 00:00:00 +0100 59.4 42 732 182.94 7 817 452" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pfs_monthly.pnl_cost" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice that this portfolio line has children, and as a reminder, we can \"drill into\" the object to get these nested portfolio line, e.g. with ``pfl_monthly.pnl_cost[\"sourced\"]``.\n", - "\n", - "There are some other components that are not explicitly shown:\n", - "\n", - "* We may be interested in how much of the offtake has already been sourced or unsourced. These fractions are available at the ``.sourcedfraction`` and ``.unsourcedfraction`` properties.\n", - "\n", - "* You may have noticed that ``unsourced`` is the inverse from what traders would call the \"open positions\" or \"portfolio positions\": if our portfolio is short, the unsourced volume is positive. For those that prefer this other perspective, it is available at ``.netposition``.\n", - "\n", - "### Export\n", - "\n", - "Just as with portfolio lines, we can create an excel file that contains all the information in a portfolio state with its ``.to_excel()`` method, and we can copy it to the clipboard with the ``.to_clipboard()`` method.\n", - "\n", - "### MtM\n", - "\n", - "We can evaluate the value of our sourcing contracts against the current forward curve (\"mark-to-market\") with the ``.mtm_of_sourced()`` method." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Analyses with portfolio states\n", - "\n", - "We'll now look at how we can do \"what-if\" analyses with portfolio state. The original portfolio state we will consider as the reference and store it in an appropriately named variable:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "ref = pfs" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The monthly procurement prices of this portfolio are what interest us the most. As a reminder, we can find the procurement volumes and costs with:" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PfLine object with price and volume information.\n", - ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - ". Children: 'sourced' (price and volume), 'unsourced' (price and volume)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\n", - "2024-10-01 00:00:00 +0200 54.7 40 744 160.48 6 538 471\n", - "2024-11-01 00:00:00 +0100 59.4 42 732 182.94 7 817 452" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cost_ref = ref.asfreq('MS').pnl_cost\n", - "cost_ref" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "(Or we could go one step further and focus on only the prices with ``ref.asfreq(\"MS\").pnl_cost.p``.)\n", - "\n", - "### Change in offtake\n", - "\n", - "Now, what would happen if the offtake were to increase by 25%? Qualitatively, this is not hard. An increase in the offtake increases the unsourced volume. And because the market prices are higher than what we pay for the sourced volume, this means that the procurement price will go up. \n", - "\n", - "How much? Let's see. First, we create a new portfolio state, from the reference, by setting the offtake to the new value. We can do this with the ``.set_offtake()`` method. After that, we can again see what the procurement volumes and costs are. (Note the ``UserWarning`` which was mentioned [above](#on-frequencies-and-unsourced-pricesE).)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfstate\\pfstate.py:199: UserWarning: This operation changes the unsourced volume. This causes inaccuracies in its price if the portfolio state has a frequency that is longer than the spot market.\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "text/plain": [ - "PfLine object with price and volume information.\n", - ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - ". Children: 'sourced' (price and volume), 'unsourced' (price and volume)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\n", - "2024-10-01 00:00:00 +0200 68.4 50 930 168.64 8 588 719\n", - "2024-11-01 00:00:00 +0100 74.2 53 416 191.54 10 231 182" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "higherofftake = ref.offtakevolume * 1.25\n", - "pfs_higherofftake = ref.set_offtakevolume(higherofftake)\n", - "cost_higherofftake = pfs_higherofftake.asfreq(\"MS\").pnl_cost\n", - "cost_higherofftake" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Comparing these two ``cost`` portfolio lines, we see that indeed the values for ``w`` and ``q`` have increased to 125% of the original values. Also, the procurement prices have increased. We can quickly calculate by how much:" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2024-10-01 00:00:00+02:00 8.160879013401626\n", - "2024-11-01 00:00:00+01:00 8.599884206454362\n", - "Freq: MS, Name: p, dtype: pint[Eur/MWh]" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "cost_higherofftake.p - cost_ref.p" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We could similarly create a portfolio states for situations with a market price drop of 40%. Or one which combines both effects:" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfstate\\pfstate.py:199: UserWarning: This operation changes the unsourced volume. This causes inaccuracies in its price if the portfolio state has a frequency that is longer than the spot market.\n", - " warnings.warn(\n" - ] - } - ], - "source": [ - "lowerprices = ref.unsourcedprice * 0.6\n", - "pfs_lowerprices = ref.set_unsourcedprice(lowerprices)\n", - "pfs_lowerprices_higherofftake = ref.set_offtakevolume(higherofftake).set_unsourcedprice(lowerprices)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Hedging\n", - "\n", - "Hedging can reduce the sensitivity of our portfolio to changes in the market price. Given the current market price curve, we can calculate how much we'd need to source to obtain a fully hedged portfolio:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "needed = ref.hedge_of_unsourced(\"val\", \"MS\") # value hedge with month products" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's say we procure exactly that volume. We can add it to the sourced volume in our portfolio state:" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfstate\\pfstate.py:209: UserWarning: This operation changes the unsourced volume. This causes inaccuracies in its price if the portfolio state has a frequency that is longer than the spot market.\n", - " warnings.warn(\n" - ] - } - ], - "source": [ - "hedged = ref.add_sourced(pf.PfLine({\"newvolume\": needed}))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "(We could have obtained the same result with the ``ref.source_unsourced()`` method.)\n", - "\n", - "The portfolio is now hedged at the month level. We can verify this by looking at the unsourced volume. In case of a volume hedge, the unsourced volume (``q`` and ``w``) is 0, even if its monetary value (``r``) is not; in case of a value hedge, it is the reverse:" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "PfLine object with price and volume information.\n", - ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\n", - "2024-10-01 00:00:00 +0200 -0.2 -173 0.00 -0\n", - "2024-11-01 00:00:00 +0100 -0.2 -134 0.00 -0" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "hedged.asfreq('MS').unsourced" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Because the market prices have not changed, the best-estimate procurement prices (at month level and longer) are also unchanged from before. (This is verified in the \"before\" columns of the dataframe further below.)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Market price change\n", - "\n", - "A hedged profile is less impacted by market price changes. To see that this is indeed the case, let's look at a scenario with an increase in the forward price curve by 40 Eur/MWh, for both portfolio states:" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "newprices = prices + pf.Q_(40.0, 'Eur/MWh')\n", - "ref_higherprices = ref.set_unsourcedprice(newprices)\n", - "hedged_higherprices = hedged.set_unsourcedprice(newprices)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The reference portfolio has gotten a lot more expensive, whereas the procurement price for the hedged portfolio has not moved significantly:" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
refhedged
beforeafterbeforeafter
unitEur/MWhEur/MWhEur/MWhEur/MWh
2024-10-01 00:00:00+02:00160.478106177.681366160.478106160.307936
2024-11-01 00:00:00+01:00182.939602205.480086182.939602182.814260
\n", - "
" - ], - "text/plain": [ - " ref hedged \n", - " before after before after\n", - "unit Eur/MWh Eur/MWh Eur/MWh Eur/MWh\n", - "2024-10-01 00:00:00+02:00 160.478106 177.681366 160.478106 160.307936\n", - "2024-11-01 00:00:00+01:00 182.939602 205.480086 182.939602 182.814260" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pd.DataFrame({\n", - " ('ref', 'before'): ref.pnl_cost.asfreq('MS').p, \n", - " ('ref', 'after'): ref_higherprices.pnl_cost.asfreq('MS').p, \n", - " ('hedged', 'before'): hedged.pnl_cost.asfreq('MS').p, \n", - " ('hedged', 'after'): hedged_higherprices.pnl_cost.asfreq('MS').p,\n", - "}).pint.dequantify()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For the observant reader: it may seem that the portfolio was not fully hedged after all, as a small change in the procurement price is seen. The reason is that each strategy (i.e., volume or value hedge) fully protects only against a specific price change (i.e., absolute or relative). A volume hedge does not *fully* hedge against an absolute price change such as the one we see here." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This tutorial is continued [in part 4](part4.ipynb)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('pf38')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "642a4be8010ca5d45039b988c1d8379a91572488c4d23a0b88e966c6713c7e45" - } - } + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tutorial part 3\n", + "\n", + "In [part 1](part1.ipynb) and [part 2](part2.ipynb) we have learnt about portfolio lines. These are timeseries, or collections of timeseries, describing the volumes and/or prices during various delivery periods.\n", + "\n", + "In this part, we'll combine portfolio lines into a \"portfolio state\" (``PfState``) object. As we'll see, some of the methods and properties we know from the ``PfLine`` class also apply here.\n", + "\n", + "\n", + "## Example data\n", + "\n", + "Let's again use the mock functions to get some portfolio lines. (The parameter details here are not important, we just want some more-or-less realistic data). To change things up a bit from the previous tutorial parts, we'll look at about 80 days in the autumn of 2024, in quarterhourly (``\"15T\"``) resolution. And let's localize the data to a specific timezone:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import portfolyo as pf\n", + "import pandas as pd\n", + "\n", + "index = pd.date_range(\n", + " \"2024-09-20\", \"2024-12-10\", freq=\"15T\", inclusive=\"left\", tz=\"Europe/Berlin\"\n", + ")\n", + "# Creating offtake portfolio line.\n", + "ts_offtake = -1 * pf.dev.w_offtake(index, avg=50)\n", + "offtake = pf.PfLine({\"w\": ts_offtake})\n", + "# Creating portfolio line with market prices (here: price-forward curve).\n", + "ts_prices = pf.dev.p_marketprices(index, avg=200)\n", + "prices = pf.PfLine({\"p\": ts_prices})\n", + "\n", + "# Creating portfolio line with sourced volume.\n", + "ts_sourced_power1, ts_sourced_price1 = pf.dev.wp_sourced(\n", + " ts_offtake, \"QS\", 0.3, p_avg=120\n", + ")\n", + "sourced_quarters = pf.PfLine({\"w\": ts_sourced_power1, \"p\": ts_sourced_price1})\n", + "ts_sourced_power2, ts_sourced_price2 = pf.dev.wp_sourced(\n", + " ts_offtake, \"MS\", 0.2, p_avg=150\n", + ")\n", + "sourced_months = pf.PfLine({\"w\": ts_sourced_power2, \"p\": ts_sourced_price2})\n", + "sourced = pf.PfLine(\n", + " {\"quarter_products\": sourced_quarters, \"month_products\": sourced_months}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now use these portfolio lines to create a portfolio state.\n", + "\n", + "## Portfolio State\n", + "\n", + "The ``PfState`` class is used to hold information about offtake, market prices, and sourcing. Let's create one from the portfolio lines we just created:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PfState object.\n", + ". Start: 2024-09-20 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-12-10 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : <15 * Minutes> (7780 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "──────── offtake\n", + " 2024-09-20 00:00:00 +0200 -45.8 -11 \n", + " 2024-09-20 00:15:00 +0200 -44.4 -11 \n", + " .. .. .. .. ..\n", + " 2024-12-09 23:30:00 +0100 -60.5 -15 \n", + " 2024-12-09 23:45:00 +0100 -58.3 -15 \n", + "─●────── pnl_cost\n", + " │ 2024-09-20 00:00:00 +0200 45.8 11 136.54 1 564\n", + " │ 2024-09-20 00:15:00 +0200 44.4 11 135.21 1 500\n", + " │ .. .. .. .. ..\n", + " │ 2024-12-09 23:30:00 +0100 60.5 15 167.89 2 540\n", + " │ 2024-12-09 23:45:00 +0100 58.3 15 167.21 2 436\n", + " ├●───── sourced\n", + " ││ 2024-09-20 00:00:00 +0200 31.3 8 135.03 1 058\n", + " ││ 2024-09-20 00:15:00 +0200 31.3 8 135.03 1 058\n", + " ││ .. .. .. .. ..\n", + " ││ 2024-12-09 23:30:00 +0100 35.7 9 126.09 1 124\n", + " ││ 2024-12-09 23:45:00 +0100 35.7 9 126.09 1 124\n", + " │├───── quarter_products\n", + " ││ 2024-09-20 00:00:00 +0200 16.4 4 102.48 421\n", + " ││ 2024-09-20 00:15:00 +0200 16.4 4 102.48 421\n", + " ││ .. .. .. .. ..\n", + " ││ 2024-12-09 23:30:00 +0100 13.4 3 111.14 372\n", + " ││ 2024-12-09 23:45:00 +0100 13.4 3 111.14 372\n", + " │└───── month_products\n", + " │ 2024-09-20 00:00:00 +0200 14.9 4 170.85 637\n", + " │ 2024-09-20 00:15:00 +0200 14.9 4 170.85 637\n", + " │ .. .. .. .. ..\n", + " │ 2024-12-09 23:30:00 +0100 22.3 6 135.07 752\n", + " │ 2024-12-09 23:45:00 +0100 22.3 6 135.07 752\n", + " └────── unsourced\n", + " 2024-09-20 00:00:00 +0200 14.5 4 139.81 506\n", + " 2024-09-20 00:15:00 +0200 13.0 3 135.64 442\n", + " .. .. .. .. ..\n", + " 2024-12-09 23:30:00 +0100 24.8 6 227.88 1 416\n", + " 2024-12-09 23:45:00 +0100 22.6 6 232.05 1 312" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pfs = pf.PfState(offtake, prices, sourced)\n", + "\n", + "pfs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note from how these portfolio lines were created, that ``offtake`` has negative values. The sign conventions are discussed [here](../core/pfstate.rst#sign-conventions).\n", + "\n", + "This portfolio state contains values for every quarterhour in the specified time period. Let's see what features this class has, starting with two methods we already met when discussing the ``PfLine`` class.\n", + "\n", + "### Plotting\n", + "\n", + "Just as when working with portfolio lines, we can get a quick overview of the portfolio state with the ``.plot()`` method..." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "pfs.plot();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "...and we can copy its data to the clipboard, or save it as an Excel workbook:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "pfs.to_clipboard()\n", + "pfs.to_excel(\"portfolio_state.xlsx\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Looking at the offtake, we can see the daily and weekly cycles, as well as a slow increase over the entire time period.\n", + "\n", + "This graph is a bit too detailed for most purposes, so let's look at the second method we know from ``PfLine``: resampling.\n", + "\n", + "### Resampling\n", + "\n", + "We might prefer to see hourly, daily, or monthly values instead of the quarterhourly values that are in ``pfs``. For this, we can resample the object with the ``.asfreq()`` method. In this code example, we also use the ``.print()`` method, which adds some helpful coloring to the output:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PfState object.\n", + ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\u001b[1m\u001b[37m──────── offtake\n", + " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -54.7 -40 744 \n", + " \u001b[1m\u001b[37m \u001b[0m2024-11-01 00:00:00 +0100 -59.4 -42 732 \n", + "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 54.7 40 744 160.48 6 538 471\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-11-01 00:00:00 +0100 59.4 42 732 182.94 7 817 452\n", + " \u001b[1m\u001b[33m├\u001b[1m\u001b[36m●\u001b[1m\u001b[33m───── sourced\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 31.2 23 221 132.58 3 078 642\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-11-01 00:00:00 +0100 25.9 18 652 133.27 2 485 849\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m├───── quarter_products\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 13.8 10 256 106.54 1 092 646\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-11-01 00:00:00 +0100 13.7 9 897 106.78 1 056 810\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m└───── month_products\n", + " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 17.4 12 964 153.19 1 985 996\n", + " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-11-01 00:00:00 +0100 12.2 8 755 163.22 1 429 039\n", + " \u001b[1m\u001b[33m└────── unsourced\n", + " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 23.5 17 523 197.44 3 459 829\n", + " \u001b[1m\u001b[33m \u001b[0m2024-11-01 00:00:00 +0100 33.4 24 080 221.41 5 331 603\n" + ] + } + ], + "source": [ + "pfs_monthly = pfs.asfreq(\"MS\")\n", + "pfs_monthly.print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note how the resampled output only contains those months, that are *entirely* included in the original data. ``pfl`` has data in September and December, but as these are not present in their entirety, they are dropped from ``pfl_monthly``.\n", + "\n", + "### On frequencies and unsourced prices\n", + "\n", + "There is one other important consequence of resampling: the unsourced prices are now *specific for this portfolio*. We can demonstrate this by creating a second portfolio state, using the *same price-forward curve* (but different offtake and sourced volume):" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "pfs2 = pf.PfState(offtake * 1.5, prices, sourced * 2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At this shortest frequency, the unsourced prices are identical (namely, the price-forward curve). Let's create a dataframe with the prices to verify this:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
pfspfs2hpfc
2024-09-20 00:00:00+02:00139.80568207211454139.80568207211454139.80568207211454
2024-09-20 00:15:00+02:00135.63901540544785135.63901540544785135.63901540544785
2024-09-20 00:30:00+02:00131.47234873878116131.47234873878116131.47234873878116
2024-09-20 00:45:00+02:00128.13901540544785128.13901540544785128.13901540544785
2024-09-20 01:00:00+02:00124.80568207211451124.80568207211451124.80568207211451
............
2024-12-09 22:45:00+01:00217.88078474854294217.88078474854294217.88078474854294
2024-12-09 23:00:00+01:00221.2141180818763221.2141180818763221.2141180818763
2024-12-09 23:15:00+01:00224.54745141520962224.54745141520962224.54745141520962
2024-12-09 23:30:00+01:00227.88078474854294227.88078474854294227.88078474854294
2024-12-09 23:45:00+01:00232.0474514152096232.0474514152096232.0474514152096
\n", + "

7780 rows × 3 columns

\n", + "
" + ], + "text/plain": [ + " pfs pfs2 \\\n", + "2024-09-20 00:00:00+02:00 139.80568207211454 139.80568207211454 \n", + "2024-09-20 00:15:00+02:00 135.63901540544785 135.63901540544785 \n", + "2024-09-20 00:30:00+02:00 131.47234873878116 131.47234873878116 \n", + "2024-09-20 00:45:00+02:00 128.13901540544785 128.13901540544785 \n", + "2024-09-20 01:00:00+02:00 124.80568207211451 124.80568207211451 \n", + "... ... ... \n", + "2024-12-09 22:45:00+01:00 217.88078474854294 217.88078474854294 \n", + "2024-12-09 23:00:00+01:00 221.2141180818763 221.2141180818763 \n", + "2024-12-09 23:15:00+01:00 224.54745141520962 224.54745141520962 \n", + "2024-12-09 23:30:00+01:00 227.88078474854294 227.88078474854294 \n", + "2024-12-09 23:45:00+01:00 232.0474514152096 232.0474514152096 \n", + "\n", + " hpfc \n", + "2024-09-20 00:00:00+02:00 139.80568207211454 \n", + "2024-09-20 00:15:00+02:00 135.63901540544785 \n", + "2024-09-20 00:30:00+02:00 131.47234873878116 \n", + "2024-09-20 00:45:00+02:00 128.13901540544785 \n", + "2024-09-20 01:00:00+02:00 124.80568207211451 \n", + "... ... \n", + "2024-12-09 22:45:00+01:00 217.88078474854294 \n", + "2024-12-09 23:00:00+01:00 221.2141180818763 \n", + "2024-12-09 23:15:00+01:00 224.54745141520962 \n", + "2024-12-09 23:30:00+01:00 227.88078474854294 \n", + "2024-12-09 23:45:00+01:00 232.0474514152096 \n", + "\n", + "[7780 rows x 3 columns]" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.DataFrame(\n", + " {\"pfs\": pfs.unsourcedprice.p, \"pfs2\": pfs2.unsourcedprice.p, \"hpfc\": prices.p}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, at every other frequency, they are not equal. When changing the frequency, a *volume-weighted* average is calculated for the unsourced prices - just like with every other price-and-volume timeseries. This makes that the unsourced prices apply only to the unsourced volume profile *of that portfolio*:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
pfspfs2hpfc
2024-10-01 00:00:00+02:00197.4437803760265192.11463549822653194.78888729464586
2024-11-01 00:00:00+01:00221.40989836363784217.79829542112196220.07479863376392
\n", + "
" + ], + "text/plain": [ + " pfs pfs2 \\\n", + "2024-10-01 00:00:00+02:00 197.4437803760265 192.11463549822653 \n", + "2024-11-01 00:00:00+01:00 221.40989836363784 217.79829542112196 \n", + "\n", + " hpfc \n", + "2024-10-01 00:00:00+02:00 194.78888729464586 \n", + "2024-11-01 00:00:00+01:00 220.07479863376392 " + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.DataFrame(\n", + " {\n", + " \"pfs\": pfs.asfreq(\"MS\").unsourcedprice.p,\n", + " \"pfs2\": pfs2.asfreq(\"MS\").unsourcedprice.p,\n", + " \"hpfc\": prices.asfreq(\"MS\").p,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This has important consequences. \n", + "\n", + "For example, when doing a scenario analysis in which the unsourced volume is changed (e.g. \"what happens if the offtake increases by 50%?\"), we cannot expect the results to be correct *unless we are working at the original frequency*. In situations where it is clear that this error looms, a ``UserWarning`` is shown to alert the user (e.g. in the examples further below). For more information on unsourced volume, [see this section](../core/pfstate.rst#Unsourced-price) in the documentation on the `PfState` class.\n", + "\n", + "For this reason, we commonly work with our porfolio states at the frequency of the price-forward curve. Downsampling is only done to see the aggregated values for verification or reporting." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Components\n", + "\n", + "Now, let's look at the portfolio state ``pfs_monthly`` in a bit more detail, to learn more about the ``PfState`` class.\n", + "\n", + "The portfolio state is presented to us as a tree structure, with several branches. Each branch is a portfolio line. E.g, ``offtake`` and ``sourced`` are the portfolio lines we specified when creating the object. Also, the branch ``pnl_cost`` is the sum of ``sourced`` and ``unsourced``, with ``sourced`` being the sum of ``quarter_products`` and ``month_products``. \n", + "\n", + "The unsourced volume is found by comparing the offtake to what is already sourced. This volume is valued at the market prices in the forward curve.\n", + "\n", + "These portfolio lines can be obtained from the portfolio state by accessing them as attributes. E.g. ``.offtakevolume``, ``.sourced``, ``.unsourced``, or ``.pnl_cost``. The latter is the best estimate for what it will cost to procure the offtake:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PfLine object with price and volume information.\n", + ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + ". Children: 'sourced' (price and volume), 'unsourced' (price and volume)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\n", + "2024-10-01 00:00:00 +0200 54.7 40 744 160.48 6 538 471\n", + "2024-11-01 00:00:00 +0100 59.4 42 732 182.94 7 817 452" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pfs_monthly.pnl_cost" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice that this portfolio line has children, and as a reminder, we can \"drill into\" the object to get these nested portfolio line, e.g. with ``pfl_monthly.pnl_cost[\"sourced\"]``.\n", + "\n", + "There are some other components that are not explicitly shown:\n", + "\n", + "* We may be interested in how much of the offtake has already been sourced or unsourced. These fractions are available at the ``.sourcedfraction`` and ``.unsourcedfraction`` properties.\n", + "\n", + "* You may have noticed that ``unsourced`` is the inverse from what traders would call the \"open positions\" or \"portfolio positions\": if our portfolio is short, the unsourced volume is positive. For those that prefer this other perspective, it is available at ``.netposition``.\n", + "\n", + "### Export\n", + "\n", + "Just as with portfolio lines, we can create an excel file that contains all the information in a portfolio state with its ``.to_excel()`` method, and we can copy it to the clipboard with the ``.to_clipboard()`` method.\n", + "\n", + "### MtM\n", + "\n", + "We can evaluate the value of our sourcing contracts against the current forward curve (\"mark-to-market\") with the ``.mtm_of_sourced()`` method." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analyses with portfolio states\n", + "\n", + "We'll now look at how we can do \"what-if\" analyses with portfolio state. The original portfolio state we will consider as the reference and store it in an appropriately named variable:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "ref = pfs" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The monthly procurement prices of this portfolio are what interest us the most. As a reminder, we can find the procurement volumes and costs with:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PfLine object with price and volume information.\n", + ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + ". Children: 'sourced' (price and volume), 'unsourced' (price and volume)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\n", + "2024-10-01 00:00:00 +0200 54.7 40 744 160.48 6 538 471\n", + "2024-11-01 00:00:00 +0100 59.4 42 732 182.94 7 817 452" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cost_ref = ref.asfreq(\"MS\").pnl_cost\n", + "cost_ref" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(Or we could go one step further and focus on only the prices with ``ref.asfreq(\"MS\").pnl_cost.p``.)\n", + "\n", + "### Change in offtake\n", + "\n", + "Now, what would happen if the offtake were to increase by 25%? Qualitatively, this is not hard. An increase in the offtake increases the unsourced volume. And because the market prices are higher than what we pay for the sourced volume, this means that the procurement price will go up. \n", + "\n", + "How much? Let's see. First, we create a new portfolio state, from the reference, by setting the offtake to the new value. We can do this with the ``.set_offtake()`` method. After that, we can again see what the procurement volumes and costs are. (Note the ``UserWarning`` which was mentioned [above](#on-frequencies-and-unsourced-pricesE).)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfstate\\pfstate.py:199: UserWarning: This operation changes the unsourced volume. This causes inaccuracies in its price if the portfolio state has a frequency that is longer than the spot market.\n", + " warnings.warn(\n" + ] }, - "nbformat": 4, - "nbformat_minor": 2 + { + "data": { + "text/plain": [ + "PfLine object with price and volume information.\n", + ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + ". Children: 'sourced' (price and volume), 'unsourced' (price and volume)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\n", + "2024-10-01 00:00:00 +0200 68.4 50 930 168.64 8 588 719\n", + "2024-11-01 00:00:00 +0100 74.2 53 416 191.54 10 231 182" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "higherofftake = ref.offtakevolume * 1.25\n", + "pfs_higherofftake = ref.set_offtakevolume(higherofftake)\n", + "cost_higherofftake = pfs_higherofftake.asfreq(\"MS\").pnl_cost\n", + "cost_higherofftake" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Comparing these two ``cost`` portfolio lines, we see that indeed the values for ``w`` and ``q`` have increased to 125% of the original values. Also, the procurement prices have increased. We can quickly calculate by how much:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "2024-10-01 00:00:00+02:00 8.160879013401626\n", + "2024-11-01 00:00:00+01:00 8.599884206454362\n", + "Freq: MS, Name: p, dtype: pint[Eur/MWh]" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "cost_higherofftake.p - cost_ref.p" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We could similarly create a portfolio states for situations with a market price drop of 40%. Or one which combines both effects:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfstate\\pfstate.py:199: UserWarning: This operation changes the unsourced volume. This causes inaccuracies in its price if the portfolio state has a frequency that is longer than the spot market.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "lowerprices = ref.unsourcedprice * 0.6\n", + "pfs_lowerprices = ref.set_unsourcedprice(lowerprices)\n", + "pfs_lowerprices_higherofftake = ref.set_offtakevolume(higherofftake).set_unsourcedprice(\n", + " lowerprices\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Hedging\n", + "\n", + "Hedging can reduce the sensitivity of our portfolio to changes in the market price. Given the current market price curve, we can calculate how much we'd need to source to obtain a fully hedged portfolio:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "needed = ref.hedge_of_unsourced(\"val\", \"MS\") # value hedge with month products" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's say we procure exactly that volume. We can add it to the sourced volume in our portfolio state:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfstate\\pfstate.py:209: UserWarning: This operation changes the unsourced volume. This causes inaccuracies in its price if the portfolio state has a frequency that is longer than the spot market.\n", + " warnings.warn(\n" + ] + } + ], + "source": [ + "hedged = ref.add_sourced(pf.PfLine({\"newvolume\": needed}))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(We could have obtained the same result with the ``ref.source_unsourced()`` method.)\n", + "\n", + "The portfolio is now hedged at the month level. We can verify this by looking at the unsourced volume. In case of a volume hedge, the unsourced volume (``q`` and ``w``) is 0, even if its monetary value (``r``) is not; in case of a value hedge, it is the reverse:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "PfLine object with price and volume information.\n", + ". Start: 2024-10-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-12-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\n", + "2024-10-01 00:00:00 +0200 -0.2 -173 0.00 -0\n", + "2024-11-01 00:00:00 +0100 -0.2 -134 0.00 -0" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "hedged.asfreq(\"MS\").unsourced" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because the market prices have not changed, the best-estimate procurement prices (at month level and longer) are also unchanged from before. (This is verified in the \"before\" columns of the dataframe further below.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Market price change\n", + "\n", + "A hedged profile is less impacted by market price changes. To see that this is indeed the case, let's look at a scenario with an increase in the forward price curve by 40 Eur/MWh, for both portfolio states:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "newprices = prices + pf.Q_(40.0, \"Eur/MWh\")\n", + "ref_higherprices = ref.set_unsourcedprice(newprices)\n", + "hedged_higherprices = hedged.set_unsourcedprice(newprices)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The reference portfolio has gotten a lot more expensive, whereas the procurement price for the hedged portfolio has not moved significantly:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
refhedged
beforeafterbeforeafter
unitEur/MWhEur/MWhEur/MWhEur/MWh
2024-10-01 00:00:00+02:00160.478106177.681366160.478106160.307936
2024-11-01 00:00:00+01:00182.939602205.480086182.939602182.814260
\n", + "
" + ], + "text/plain": [ + " ref hedged \n", + " before after before after\n", + "unit Eur/MWh Eur/MWh Eur/MWh Eur/MWh\n", + "2024-10-01 00:00:00+02:00 160.478106 177.681366 160.478106 160.307936\n", + "2024-11-01 00:00:00+01:00 182.939602 205.480086 182.939602 182.814260" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pd.DataFrame(\n", + " {\n", + " (\"ref\", \"before\"): ref.pnl_cost.asfreq(\"MS\").p,\n", + " (\"ref\", \"after\"): ref_higherprices.pnl_cost.asfreq(\"MS\").p,\n", + " (\"hedged\", \"before\"): hedged.pnl_cost.asfreq(\"MS\").p,\n", + " (\"hedged\", \"after\"): hedged_higherprices.pnl_cost.asfreq(\"MS\").p,\n", + " }\n", + ").pint.dequantify()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For the observant reader: it may seem that the portfolio was not fully hedged after all, as a small change in the procurement price is seen. The reason is that each strategy (i.e., volume or value hedge) fully protects only against a specific price change (i.e., absolute or relative). A volume hedge does not *fully* hedge against an absolute price change such as the one we see here." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This tutorial is continued [in part 4](part4.ipynb)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.13 ('pf38')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "642a4be8010ca5d45039b988c1d8379a91572488c4d23a0b88e966c6713c7e45" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/docs/tutorial/part4.ipynb b/docs/tutorial/part4.ipynb index eee3669..0a323da 100644 --- a/docs/tutorial/part4.ipynb +++ b/docs/tutorial/part4.ipynb @@ -1,282 +1,282 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Tutorial part 4\n", - "\n", - "In [part 3](part3.ipynb) we have learnt about portfolio states and how to use them in scenario analyses. Here we learn how to export them and how to combine several ones.\n", - "\n", - "## Example data\n", - "\n", - "We start with a similar portfolio state as in the previous part:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PfState object.\n", - ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\u001b[1m\u001b[37m──────── offtake\n", - " \u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 -49.4 -35 593 \n", - " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -54.7 -40 748 \n", - "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 49.4 35 593 147.61 5 253 964\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 54.7 40 748 163.85 6 676 561\n", - " \u001b[1m\u001b[33m├\u001b[1m\u001b[36m●\u001b[1m\u001b[33m───── sourced\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 28.9 20 844 123.03 2 564 413\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 26.0 19 389 132.10 2 561 236\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m├───── quarter_products\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-09-01 00:00:00 +0200 13.8 9 943 103.24 1 026 519\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 11.1 8 261 118.15 976 055\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m└───── month_products\n", - " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-09-01 00:00:00 +0200 15.1 10 901 141.07 1 537 894\n", - " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 14.9 11 128 142.45 1 585 180\n", - " \u001b[1m\u001b[33m└────── unsourced\n", - " \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 20.5 14 749 182.36 2 689 551\n", - " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 28.7 21 358 192.68 4 115 325\n" - ] - } - ], - "source": [ - "import portfolyo as pf\n", - "import pandas as pd\n", - "\n", - "index = pd.date_range(\n", - " \"2024-09-01\", \"2024-11-01\", freq=\"15T\", inclusive=\"left\", tz=\"Europe/Berlin\"\n", - ")\n", - "# Creating portfolio line with market prices (here: price-forward curve).\n", - "ts_prices = pf.dev.p_marketprices(index, avg=200)\n", - "prices = pf.PfLine({\"p\": ts_prices})\n", - "\n", - "\n", - "# Creating offtake portfolio line.\n", - "ts_offtake = -1 * pf.dev.w_offtake(index, avg=50)\n", - "offtake = pf.PfLine({\"w\": ts_offtake})\n", - "\n", - "# Creating portfolio line with sourced volume.\n", - "ts_sourced_power1, ts_sourced_price1 = pf.dev.wp_sourced(\n", - " ts_offtake, \"QS\", 0.3, p_avg=120\n", - ")\n", - "sourced_quarters = pf.PfLine({\"w\": ts_sourced_power1, \"p\": ts_sourced_price1})\n", - "ts_sourced_power2, ts_sourced_price2 = pf.dev.wp_sourced(\n", - " ts_offtake, \"MS\", 0.2, p_avg=150\n", - ")\n", - "sourced_months = pf.PfLine({\"w\": ts_sourced_power2, \"p\": ts_sourced_price2})\n", - "sourced = pf.PfLine(\n", - " {\"quarter_products\": sourced_quarters, \"month_products\": sourced_months}\n", - ")\n", - "\n", - "# Create the portfolio state.\n", - "pfs1 = pf.PfState(offtake, prices, sourced).asfreq('MS')\n", - "\n", - "pfs1.print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Arithmatic\n", - "\n", - "The final part about portfolio lines is the arithmatic that can be done with them.\n", - "\n", - "Let's create a second portfolio state:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PfState object.\n", - ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "\u001b[1m\u001b[37m──────── offtake\n", - " \u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 -98.9 -71 186 \n", - " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -109.4 -81 495 \n", - "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 98.9 71 186 118.77 8 454 414\n", - " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 109.4 81 495 131.98 10 755 857\n", - " \u001b[1m\u001b[33m├────── sourced\n", - " \u001b[1m\u001b[33m│ \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 80.0 57 600 100.00 5 760 000\n", - " \u001b[1m\u001b[33m│ \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 80.0 59 600 100.00 5 960 000\n", - " \u001b[1m\u001b[33m└────── unsourced\n", - " \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 18.9 13 586 198.33 2 694 414\n", - " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 29.4 21 895 219.04 4 795 857\n" - ] - } - ], - "source": [ - "offtake2 = offtake * 2\n", - "sourced2 = pf.PfLine(pd.DataFrame({\"w\": 80, \"p\": 100}, index))\n", - "pfs2 = pf.PfState(offtake2, prices, sourced2).asfreq('MS')\n", - "pfs2.print()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that ``pfs1`` and ``pfs2`` have distinct unsourced prices at this month level, even though they were created using the same market prices on the quarter-hour level.\n", - "\n", - "### Addition and subtraction\n", - "\n", - "We can add these two portfolio states:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfline\\enable_arithmatic.py:82: PfLineFlattenedWarning: When adding a FlatPfLine and NestedPfLine, the NestedPfLine is flattened.\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "text/plain": [ - "PfState object.\n", - ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "──────── offtake\n", - " 2024-09-01 00:00:00 +0200 -148.3 -106 778 \n", - " 2024-10-01 00:00:00 +0200 -164.1 -122 243 \n", - "─●────── pnl_cost\n", - " │ 2024-09-01 00:00:00 +0200 148.3 106 778 128.38 13 708 378\n", - " │ 2024-10-01 00:00:00 +0200 164.1 122 243 142.60 17 432 418\n", - " ├────── sourced\n", - " │ 2024-09-01 00:00:00 +0200 108.9 78 444 106.12 8 324 413\n", - " │ 2024-10-01 00:00:00 +0200 106.0 78 989 107.88 8 521 236\n", - " └────── unsourced\n", - " 2024-09-01 00:00:00 +0200 39.4 28 334 190.02 5 383 965\n", - " 2024-10-01 00:00:00 +0200 58.1 43 254 206.02 8 911 182" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pfs1 + pfs2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note that the individual components are added together. The volumes (offtake, sourced, unsourced) are summed; the prices (sourced and unsourced) are the energy-weighted averaged. (Or, put differently, the *revenues* are also summed, and the prices are calculated from the volume-total and renevue-total.)\n", - "\n", - "Note also that the sourced volume of ``pfs1`` has been flattened, i.e., the values of its children are lost. This is because ``pfs2`` does not have any children. This behaviour is described [here](../core/pfline.rst#Arithmatic).\n", - "\n", - "Likewise we can subtract them with ``pfs1 - pfs2``:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfline\\enable_arithmatic.py:82: PfLineFlattenedWarning: When adding a FlatPfLine and NestedPfLine, the NestedPfLine is flattened.\n", - " warnings.warn(\n" - ] - }, - { - "data": { - "text/plain": [ - "PfState object.\n", - ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", - ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", - ". Freq : (2 datapoints)\n", - " w q p r\n", - " MW MWh Eur/MWh Eur\n", - "──────── offtake\n", - " 2024-09-01 00:00:00 +0200 49.4 35 593 \n", - " 2024-10-01 00:00:00 +0200 54.7 40 748 \n", - "─●────── pnl_cost\n", - " │ 2024-09-01 00:00:00 +0200 -49.4 -35 593 89.92 -3 200 450\n", - " │ 2024-10-01 00:00:00 +0200 -54.7 -40 748 100.11 -4 079 296\n", - " ├────── sourced\n", - " │ 2024-09-01 00:00:00 +0200 -51.1 -36 756 86.94 -3 195 587\n", - " │ 2024-10-01 00:00:00 +0200 -54.0 -40 211 84.52 -3 398 764\n", - " └────── unsourced\n", - " 2024-09-01 00:00:00 +0200 1.6 1 163 -4.18 -4 863\n", - " 2024-10-01 00:00:00 +0200 -0.7 -537 1 267.81 -680 532" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "pfs1 - pfs2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "That was it for this tutorial!" - ] - } + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tutorial part 4\n", + "\n", + "In [part 3](part3.ipynb) we have learnt about portfolio states and how to use them in scenario analyses. Here we learn how to export them and how to combine several ones.\n", + "\n", + "## Example data\n", + "\n", + "We start with a similar portfolio state as in the previous part:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PfState object.\n", + ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\u001b[1m\u001b[37m──────── offtake\n", + " \u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 -49.4 -35 593 \n", + " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -54.7 -40 748 \n", + "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 49.4 35 593 147.61 5 253 964\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 54.7 40 748 163.85 6 676 561\n", + " \u001b[1m\u001b[33m├\u001b[1m\u001b[36m●\u001b[1m\u001b[33m───── sourced\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 28.9 20 844 123.03 2 564 413\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│\u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 26.0 19 389 132.10 2 561 236\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m├───── quarter_products\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-09-01 00:00:00 +0200 13.8 9 943 103.24 1 026 519\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 11.1 8 261 118.15 976 055\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[36m└───── month_products\n", + " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-09-01 00:00:00 +0200 15.1 10 901 141.07 1 537 894\n", + " \u001b[1m\u001b[33m│ \u001b[1m\u001b[36m \u001b[0m2024-10-01 00:00:00 +0200 14.9 11 128 142.45 1 585 180\n", + " \u001b[1m\u001b[33m└────── unsourced\n", + " \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 20.5 14 749 182.36 2 689 551\n", + " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 28.7 21 358 192.68 4 115 325\n" + ] + } ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.8.13 ('pf38')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.13" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "642a4be8010ca5d45039b988c1d8379a91572488c4d23a0b88e966c6713c7e45" - } - } + "source": [ + "import portfolyo as pf\n", + "import pandas as pd\n", + "\n", + "index = pd.date_range(\n", + " \"2024-09-01\", \"2024-11-01\", freq=\"15T\", inclusive=\"left\", tz=\"Europe/Berlin\"\n", + ")\n", + "# Creating portfolio line with market prices (here: price-forward curve).\n", + "ts_prices = pf.dev.p_marketprices(index, avg=200)\n", + "prices = pf.PfLine({\"p\": ts_prices})\n", + "\n", + "\n", + "# Creating offtake portfolio line.\n", + "ts_offtake = -1 * pf.dev.w_offtake(index, avg=50)\n", + "offtake = pf.PfLine({\"w\": ts_offtake})\n", + "\n", + "# Creating portfolio line with sourced volume.\n", + "ts_sourced_power1, ts_sourced_price1 = pf.dev.wp_sourced(\n", + " ts_offtake, \"QS\", 0.3, p_avg=120\n", + ")\n", + "sourced_quarters = pf.PfLine({\"w\": ts_sourced_power1, \"p\": ts_sourced_price1})\n", + "ts_sourced_power2, ts_sourced_price2 = pf.dev.wp_sourced(\n", + " ts_offtake, \"MS\", 0.2, p_avg=150\n", + ")\n", + "sourced_months = pf.PfLine({\"w\": ts_sourced_power2, \"p\": ts_sourced_price2})\n", + "sourced = pf.PfLine(\n", + " {\"quarter_products\": sourced_quarters, \"month_products\": sourced_months}\n", + ")\n", + "\n", + "# Create the portfolio state.\n", + "pfs1 = pf.PfState(offtake, prices, sourced).asfreq(\"MS\")\n", + "\n", + "pfs1.print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Arithmatic\n", + "\n", + "The final part about portfolio lines is the arithmatic that can be done with them.\n", + "\n", + "Let's create a second portfolio state:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PfState object.\n", + ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "\u001b[1m\u001b[37m──────── offtake\n", + " \u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 -98.9 -71 186 \n", + " \u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 -109.4 -81 495 \n", + "\u001b[1m\u001b[37m─\u001b[1m\u001b[33m●\u001b[1m\u001b[37m────── pnl_cost\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-09-01 00:00:00 +0200 98.9 71 186 118.77 8 454 414\n", + " \u001b[1m\u001b[33m│\u001b[1m\u001b[37m \u001b[0m2024-10-01 00:00:00 +0200 109.4 81 495 131.98 10 755 857\n", + " \u001b[1m\u001b[33m├────── sourced\n", + " \u001b[1m\u001b[33m│ \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 80.0 57 600 100.00 5 760 000\n", + " \u001b[1m\u001b[33m│ \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 80.0 59 600 100.00 5 960 000\n", + " \u001b[1m\u001b[33m└────── unsourced\n", + " \u001b[1m\u001b[33m \u001b[0m2024-09-01 00:00:00 +0200 18.9 13 586 198.33 2 694 414\n", + " \u001b[1m\u001b[33m \u001b[0m2024-10-01 00:00:00 +0200 29.4 21 895 219.04 4 795 857\n" + ] + } + ], + "source": [ + "offtake2 = offtake * 2\n", + "sourced2 = pf.PfLine(pd.DataFrame({\"w\": 80, \"p\": 100}, index))\n", + "pfs2 = pf.PfState(offtake2, prices, sourced2).asfreq(\"MS\")\n", + "pfs2.print()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that ``pfs1`` and ``pfs2`` have distinct unsourced prices at this month level, even though they were created using the same market prices on the quarter-hour level.\n", + "\n", + "### Addition and subtraction\n", + "\n", + "We can add these two portfolio states:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfline\\enable_arithmatic.py:82: PfLineFlattenedWarning: When adding a FlatPfLine and NestedPfLine, the NestedPfLine is flattened.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "text/plain": [ + "PfState object.\n", + ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "──────── offtake\n", + " 2024-09-01 00:00:00 +0200 -148.3 -106 778 \n", + " 2024-10-01 00:00:00 +0200 -164.1 -122 243 \n", + "─●────── pnl_cost\n", + " │ 2024-09-01 00:00:00 +0200 148.3 106 778 128.38 13 708 378\n", + " │ 2024-10-01 00:00:00 +0200 164.1 122 243 142.60 17 432 418\n", + " ├────── sourced\n", + " │ 2024-09-01 00:00:00 +0200 108.9 78 444 106.12 8 324 413\n", + " │ 2024-10-01 00:00:00 +0200 106.0 78 989 107.88 8 521 236\n", + " └────── unsourced\n", + " 2024-09-01 00:00:00 +0200 39.4 28 334 190.02 5 383 965\n", + " 2024-10-01 00:00:00 +0200 58.1 43 254 206.02 8 911 182" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pfs1 + pfs2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the individual components are added together. The volumes (offtake, sourced, unsourced) are summed; the prices (sourced and unsourced) are the energy-weighted averaged. (Or, put differently, the *revenues* are also summed, and the prices are calculated from the volume-total and renevue-total.)\n", + "\n", + "Note also that the sourced volume of ``pfs1`` has been flattened, i.e., the values of its children are lost. This is because ``pfs2`` does not have any children. This behaviour is described [here](../core/pfline.rst#Arithmatic).\n", + "\n", + "Likewise we can subtract them with ``pfs1 - pfs2``:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\ruud.wijtvliet\\ruud\\python\\dev\\portfolyo\\portfolyo\\core\\pfline\\enable_arithmatic.py:82: PfLineFlattenedWarning: When adding a FlatPfLine and NestedPfLine, the NestedPfLine is flattened.\n", + " warnings.warn(\n" + ] + }, + { + "data": { + "text/plain": [ + "PfState object.\n", + ". Start: 2024-09-01 00:00:00+02:00 (incl) . Timezone : Europe/Berlin \n", + ". End : 2024-11-01 00:00:00+01:00 (excl) . Start-of-day: 00:00:00 \n", + ". Freq : (2 datapoints)\n", + " w q p r\n", + " MW MWh Eur/MWh Eur\n", + "──────── offtake\n", + " 2024-09-01 00:00:00 +0200 49.4 35 593 \n", + " 2024-10-01 00:00:00 +0200 54.7 40 748 \n", + "─●────── pnl_cost\n", + " │ 2024-09-01 00:00:00 +0200 -49.4 -35 593 89.92 -3 200 450\n", + " │ 2024-10-01 00:00:00 +0200 -54.7 -40 748 100.11 -4 079 296\n", + " ├────── sourced\n", + " │ 2024-09-01 00:00:00 +0200 -51.1 -36 756 86.94 -3 195 587\n", + " │ 2024-10-01 00:00:00 +0200 -54.0 -40 211 84.52 -3 398 764\n", + " └────── unsourced\n", + " 2024-09-01 00:00:00 +0200 1.6 1 163 -4.18 -4 863\n", + " 2024-10-01 00:00:00 +0200 -0.7 -537 1 267.81 -680 532" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pfs1 - pfs2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That was it for this tutorial!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.8.13 ('pf38')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 }, - "nbformat": 4, - "nbformat_minor": 2 + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "642a4be8010ca5d45039b988c1d8379a91572488c4d23a0b88e966c6713c7e45" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 } \ No newline at end of file diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 4b32328..8f2e5e0 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -117,10 +117,28 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) if children: + # TODO: probably we need to check "how" of the parent beforehand also + num_children = len(self) + total_width = 0.8 + + # Calculate the maximum width per child, considering the offset + width_w_padding = total_width / num_children + padding = width_w_padding * (0.1 if num_children > 1 else 0.5) + width_per_child = width_w_padding - padding + offset = -(total_width / 2.0) for name, child in self.items(): - kwargs["align"] = "edge" # TODO + kwargs["align"] = "edge" kwargs["labelfmt"] = "" - vis.plot_timeseries(ax, getattr(child, col), **kwargs) + + # Calculate width and offset dynamically based on the number of children + vis.plot_timeseries( + ax, + getattr(child, col), + width=width_per_child, + offset=offset + padding / 2.0, + **kwargs, + ) + offset = offset + width_w_padding if num_children > 1 else 0 return fig diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 2e7ebeb..9b9b476 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -111,7 +111,13 @@ def plot_timeseries_as_jagged( @append_to_doc(docstringliteral_plotparameters) def plot_timeseries_as_bar( - ax: plt.Axes, s: pd.Series, labelfmt: str = "", cat: bool = None, **kwargs + ax: plt.Axes, + s: pd.Series, + labelfmt: str = "", + cat: bool = None, + width: float = 0.8, + offset: float = 0, + **kwargs, ) -> None: """Plot timeseries ``s`` to axis ``ax``, as bars. Ideally, only used for plots with categorical (i.e, non-time) x-axis.""" @@ -119,10 +125,14 @@ def plot_timeseries_as_bar( if use_categories(ax, s, cat): categories = Categories(s) - ax.bar(categories.x(), categories.y(), 0.8, **kwargs) + ax.bar( + [x + offset for x in categories.x()], categories.y(), width=width, **kwargs + ) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) + ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) + set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) else: # Bad combination: bar graph on time-axis. But allow anyway. @@ -224,6 +234,7 @@ def plot_timeseries( how: str = "jagged", labelfmt: str = None, cat: bool = None, + width: float = 0.8, **kwargs, ) -> None: """Plot timeseries to given axis. @@ -244,7 +255,7 @@ def plot_timeseries( if how == "jagged": plot_timeseries_as_jagged(ax, s, labelfmt, cat, **kwargs) elif how == "bar": - plot_timeseries_as_bar(ax, s, labelfmt, cat, **kwargs) + plot_timeseries_as_bar(ax, s, labelfmt, cat, width=width, **kwargs) elif how == "area": plot_timeseries_as_area(ax, s, labelfmt, cat, **kwargs) elif how == "step": From 4e68c334e4c590b4ab10d8d5ca110ab750a5fa06 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Tue, 12 Dec 2023 10:22:07 +0100 Subject: [PATCH 31/59] created plot_children(),fixed bug with darken --- dev_scripts/plot_test.py | 27 ++++++-------- portfolyo/core/mixins/plot.py | 70 ++++++++++++++++++++++++----------- portfolyo/dev/develop.py | 4 +- portfolyo/visualize/colors.py | 2 +- portfolyo/visualize/plot.py | 8 ++-- 5 files changed, 68 insertions(+), 43 deletions(-) diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index d33f47e..8d5a0af 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -1,23 +1,20 @@ """Create several plots to see if plotting still works.""" -import pandas as pd import matplotlib.pyplot as plt import portfolyo as pf -def plots(children: int = 1): - """Create 16 plots: (w, q, p, r) x (hourly, monthly) x (children, no children).""" - index = pd.date_range("2024", freq="AS", periods=3) - pfl1 = pf.PfLine(pd.Series([0.2, 0.22, 0.3], index, dtype="pint[GW]")) - dict_of_children = {} - for i in range(children): - key = str(i) - dict_of_children[key] = pfl1 - - pfl = pf.PfLine(dict_of_children) - - pfl.print() - pfl.plot(children=True) +def plot_bars(children: int = 1): + """Create bar chart with 4 subplots: (q) x (daily, monthly) x (children, no children).""" + index = pf.dev.get_index(freq="D") + pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=children) + pfl2 = pfl1.asfreq("MS") + pfl1.print() + pfl2.print() + # nd = pfl1.index[5] + # pfl1 = pfl1.loc[:end] + pfl2.plot("q", children=True) + # pfl2.plot("p", children=False) plt.show() # pf_nested_pr.print() @@ -26,4 +23,4 @@ def plots(children: int = 1): print("The number of children is:", children) -plots(int(input())) +plot_bars(4) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 8f2e5e0..05e9daf 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -114,34 +114,60 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: for col, ax in zip(cols, axes.flatten()): kwargs = defaultkwargs(col, is_category) + if children and kwargs["how"] == "bar": + kwargs["how"] = "hline" s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) if children: - # TODO: probably we need to check "how" of the parent beforehand also - num_children = len(self) - total_width = 0.8 - - # Calculate the maximum width per child, considering the offset - width_w_padding = total_width / num_children - padding = width_w_padding * (0.1 if num_children > 1 else 0.5) - width_per_child = width_w_padding - padding - offset = -(total_width / 2.0) - for name, child in self.items(): - kwargs["align"] = "edge" - kwargs["labelfmt"] = "" - - # Calculate width and offset dynamically based on the number of children - vis.plot_timeseries( - ax, - getattr(child, col), - width=width_per_child, - offset=offset + padding / 2.0, - **kwargs, - ) - offset = offset + width_w_padding if num_children > 1 else 0 + kwargs_children = defaultkwargs(col, is_category) + self.plot_children(col, ax, **kwargs_children) return fig + def plot_children(self: PfLine, col: str, ax: plt.Axes, **kwargs): + if kwargs["how"] == "bar": + bottom_offset = [[0.0, 0.0] for i in range(0, self.index.size)] + child_color = getattr(vis.Colors.Wqpr, col, "grey") + for name, child in self.items(): + bar_heights = getattr(child, col) + offsets = [0.0 for i in range(0, self.index.size)] + + for i in range(0, len(bar_heights)): + obj = bar_heights[i] + if obj.magnitude > 0: + offsets[i] = bottom_offset[i][0] + bottom_offset[i][0] += obj.magnitude + else: + offsets[i] = bottom_offset[i][1] + bottom_offset[i][1] += obj.magnitude + + kwargs["labelfmt"] = "" + kwargs["bottom"] = offsets + kwargs["color"] = child_color + + # Calculate width and offset dynamically based on the number of children + vis.plot_timeseries( + ax, + bar_heights, + **kwargs, + ) + + # for i in range(0, len(bar_heights)): + # obj = bar_heights[i] + # bottom_offset[i] += obj.magnitude + child_color = child_color.darken(0.3) + else: + child_color = getattr(vis.Colors.Wqpr, col, "grey") + for name, child in self.items(): + kwargs["labelfmt"] = "" + kwargs["color"] = child_color + vis.plot_timeseries( + ax, + getattr(child, col), + **kwargs, + ) + child_color = child_color.darken(0.5) + class PfStatePlot: # def plot_to_ax( diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index 039bb1c..e71b892 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -198,7 +198,7 @@ def get_pfline( childcount : int, optional (default: 2) Number of children on each level. (Ignored if `nlevels` == 1) positive : bool, optional (default: False) - If True, return only positive values. If False, make 1/3 of pflines negative. + If True, return only positive values. If False, make 1/2 of pflines negative. _ancestornames : Tuple[str], optional (default: ()) Text to start the childrens' names with (concatenated with '-') _seed : int, optional (default: no seed value) @@ -222,7 +222,7 @@ def get_pfline( Kind.COMPLETE: "qr", }[kind] df = get_dataframe(i, columns, _seed=_seed) - if not positive and np.random.rand() < 0.33: + if not positive and np.random.randint(1, 3) == 1: df = -1 * df # HACK: `-df` leads to error in pint. Maybe fixed in future return create.flatpfline(df) # Create nested PfLine. diff --git a/portfolyo/visualize/colors.py b/portfolyo/visualize/colors.py index 28be08e..917c7be 100644 --- a/portfolyo/visualize/colors.py +++ b/portfolyo/visualize/colors.py @@ -18,7 +18,7 @@ def lighten(self, value): def darken(self, value): """Darken the color by fraction ``value`` (between 0 and 1).""" - return self.lighten(self, -value) + return self.lighten(-value) light = property(lambda self: self.lighten(0.3)) xlight = property(lambda self: self.lighten(0.6)) diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 9b9b476..9b2394b 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -103,7 +103,7 @@ def plot_timeseries_as_jagged( ax.plot(categories.x(), categories.y(), **kwargs) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, False) - + ax.autoscale() else: ax.plot(s.index, s.values, **kwargs) set_data_labels(ax, s.index, s.values, labelfmt, False) @@ -133,6 +133,7 @@ def plot_timeseries_as_bar( ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) + ax.autoscale() else: # Bad combination: bar graph on time-axis. But allow anyway. @@ -171,7 +172,7 @@ def plot_timeseries_as_area( ax.fill_between(ctgr_extra.x() - 0.5, 0, ctgr_extra.y(), step="post", **kwargs) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - + ax.autoscale() else: ax.fill_between(splot.index, 0, splot.values, step="post", **kwargs) delta = s.index.right - s.index @@ -198,7 +199,7 @@ def plot_timeseries_as_step( ax.step(ctgr_extra.x() - 0.5, ctgr_extra.y(), where="post", **kwargs) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - + ax.autoscale() else: ax.step(splot.index, splot.values, where="post", **kwargs) delta = s.index.right - s.index @@ -221,6 +222,7 @@ def plot_timeseries_as_hline( ax.hlines(categories.y(), categories.x() - 0.5, categories.x() + 0.5, **kwargs) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) + ax.autoscale() else: delta = s.index.right - s.index From 6416b13b593218859f7fcda2e4b368f370ae7e98 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 20 Dec 2023 10:29:39 +0100 Subject: [PATCH 32/59] area plots for children stacked on top of each other. for daily it plots only parent --- dev_scripts/plot_test.py | 17 +++++----- portfolyo/core/mixins/plot.py | 58 +++++++++++++++++------------------ portfolyo/visualize/colors.py | 3 +- portfolyo/visualize/plot.py | 32 +++++++++++++------ 4 files changed, 63 insertions(+), 47 deletions(-) diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index 8d5a0af..9c6e8b5 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -8,13 +8,16 @@ def plot_bars(children: int = 1): """Create bar chart with 4 subplots: (q) x (daily, monthly) x (children, no children).""" index = pf.dev.get_index(freq="D") pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=children) - pfl2 = pfl1.asfreq("MS") - pfl1.print() - pfl2.print() - # nd = pfl1.index[5] - # pfl1 = pfl1.loc[:end] - pfl2.plot("q", children=True) - # pfl2.plot("p", children=False) + # pfl2 = pfl1.asfreq("MS") + pfl3 = pf.dev.get_nestedpfline(index, nlevels=2, childcount=children) + pfl4 = pfl3.asfreq("MS") + # pfl1.print() + pfl4.print() + end = pfl1.index[5] + pfl1 = pfl1.loc[:end] + + pfl1.plot("r", children=True) + # pfl2.plot("r", children=False) plt.show() # pf_nested_pr.print() diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 05e9daf..752650d 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -8,6 +8,7 @@ import matplotlib import numpy as np +import itertools from matplotlib import pyplot as plt from ... import tools @@ -114,24 +115,33 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: for col, ax in zip(cols, axes.flatten()): kwargs = defaultkwargs(col, is_category) - if children and kwargs["how"] == "bar": - kwargs["how"] = "hline" + if is_category: + if children and kwargs["how"] == "bar": + # kwargs["how"] = "hline" + kwargs["color"] = "none" + kwargs["edgecolor"] = "seagreen" + kwargs["linewidth"] = 2 + if children and kwargs["how"] == "area": + # continue + kwargs["how"] = "step" + if children: + kwargs_children = defaultkwargs(col, is_category) + self.plot_children(col, ax, **kwargs_children) + ax.legend(loc="upper right") + kwargs["alpha"] = 0.5 s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) - if children: - kwargs_children = defaultkwargs(col, is_category) - self.plot_children(col, ax, **kwargs_children) return fig def plot_children(self: PfLine, col: str, ax: plt.Axes, **kwargs): - if kwargs["how"] == "bar": + if kwargs["how"] == "bar" or kwargs["how"] == "area": bottom_offset = [[0.0, 0.0] for i in range(0, self.index.size)] - child_color = getattr(vis.Colors.Wqpr, col, "grey") - for name, child in self.items(): + for (name, child), color_enum in zip( + self.items(), itertools.cycle(vis.Colors.General) + ): bar_heights = getattr(child, col) offsets = [0.0 for i in range(0, self.index.size)] - for i in range(0, len(bar_heights)): obj = bar_heights[i] if obj.magnitude > 0: @@ -143,30 +153,18 @@ def plot_children(self: PfLine, col: str, ax: plt.Axes, **kwargs): kwargs["labelfmt"] = "" kwargs["bottom"] = offsets - kwargs["color"] = child_color - + kwargs["color"] = color_enum.value.lighten(0.5) + kwargs["label"] = name # Calculate width and offset dynamically based on the number of children - vis.plot_timeseries( - ax, - bar_heights, - **kwargs, - ) - - # for i in range(0, len(bar_heights)): - # obj = bar_heights[i] - # bottom_offset[i] += obj.magnitude - child_color = child_color.darken(0.3) + vis.plot_timeseries(ax, bar_heights, **kwargs) else: - child_color = getattr(vis.Colors.Wqpr, col, "grey") - for name, child in self.items(): + for (name, child), color_enum in zip( + self.items(), itertools.cycle(vis.Colors.General) + ): kwargs["labelfmt"] = "" - kwargs["color"] = child_color - vis.plot_timeseries( - ax, - getattr(child, col), - **kwargs, - ) - child_color = child_color.darken(0.5) + kwargs["color"] = color_enum.value.lighten(0.5) + kwargs["label"] = name + vis.plot_timeseries(ax, getattr(child, col), **kwargs) class PfStatePlot: diff --git a/portfolyo/visualize/colors.py b/portfolyo/visualize/colors.py index 917c7be..284e350 100644 --- a/portfolyo/visualize/colors.py +++ b/portfolyo/visualize/colors.py @@ -1,6 +1,7 @@ """Creating colors for use in plotting.""" import colorsys +from enum import Enum from collections import namedtuple import matplotlib as mpl @@ -27,7 +28,7 @@ def darken(self, value): class Colors: - class General: + class General(Enum): PURPLE = Color(0.549, 0.110, 0.706) GREEN = Color(0.188, 0.463, 0.165) BLUE = Color(0.125, 0.247, 0.600) diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 9b2394b..f01028c 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -116,7 +116,6 @@ def plot_timeseries_as_bar( labelfmt: str = "", cat: bool = None, width: float = 0.8, - offset: float = 0, **kwargs, ) -> None: """Plot timeseries ``s`` to axis ``ax``, as bars. Ideally, only used for plots with @@ -125,12 +124,7 @@ def plot_timeseries_as_bar( if use_categories(ax, s, cat): categories = Categories(s) - ax.bar( - [x + offset for x in categories.x()], categories.y(), width=width, **kwargs - ) - ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) - set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - + ax.bar(categories.x(), categories.y(), width=width, **kwargs) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) ax.autoscale() @@ -154,7 +148,11 @@ def plot_timeseries_as_bar( @append_to_doc(docstringliteral_plotparameters) def plot_timeseries_as_area( - ax: plt.Axes, s: pd.Series, labelfmt: str = "", cat: bool = None, **kwargs + ax: plt.Axes, + s: pd.Series, + labelfmt: str = "", + cat: bool = None, + **kwargs, ) -> None: """Plot timeseries ``s`` to axis ``ax``, as stepped area between 0 and value. Ideally, only used for plots with time (i.e., non-categorical) axis.""" @@ -168,8 +166,24 @@ def plot_timeseries_as_area( categories = Categories(s) ctgr_extra = Categories(splot) + y_value = ctgr_extra.y() + height = ctgr_extra.y().quantity.magnitude + if "bottom" in kwargs: + bottom = kwargs["bottom"] + bottom.append(bottom[-1]) + del kwargs["bottom"] + else: + bottom = [0.0 for i in range(0, height.size)] + # make bottom into pintarray + bottom = bottom * y_value.dtype.units # Center around x-tick: - ax.fill_between(ctgr_extra.x() - 0.5, 0, ctgr_extra.y(), step="post", **kwargs) + ax.fill_between( + ctgr_extra.x() - 0.5, + bottom, + [sum(x) for x in zip(bottom, ctgr_extra.y())], + step="post", + **kwargs, + ) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) ax.autoscale() From 8f958c53c9f8f3a333b4d7b5640d413287c9773f Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Tue, 2 Jan 2024 14:40:51 +0100 Subject: [PATCH 33/59] changed the logic of all plot_timeseries_as functions, now based on frequency --- dev_scripts/panda.py | 18 ++++ dev_scripts/plot_state.py | 19 ++++ dev_scripts/plot_test.py | 33 +++--- portfolyo/core/mixins/plot.py | 137 ++++++++++++++++--------- portfolyo/visualize/plot.py | 188 ++++++++++++++++++---------------- 5 files changed, 242 insertions(+), 153 deletions(-) create mode 100644 dev_scripts/panda.py create mode 100644 dev_scripts/plot_state.py diff --git a/dev_scripts/panda.py b/dev_scripts/panda.py new file mode 100644 index 0000000..3e89e20 --- /dev/null +++ b/dev_scripts/panda.py @@ -0,0 +1,18 @@ +import pandas as pd + +# Create a sample DataFrame with a DatetimeIndex +df = pd.DataFrame( + index=pd.date_range(start="2022-04-01", end="2023-03-31", freq="M"), + data={"value": range(12)}, +) + +# Display the original DataFrame +print("Original DataFrame:") +print(df) + +# Change the frequency of the DatetimeIndex +df_resampled = df.asfreq(freq="AS") + +# Display the DataFrame with the new frequency +print("\nDataFrame with new Frequency:") +print(df_resampled) diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py new file mode 100644 index 0000000..e81ba0b --- /dev/null +++ b/dev_scripts/plot_state.py @@ -0,0 +1,19 @@ +import matplotlib.pyplot as plt +import portfolyo as pf + + +"""Plot PfState to test of adding axes for un/sourced prices.""" + +index = pf.dev.get_index(freq="D") +pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=2) +pfs = pf.dev.get_pfstate(index) +pfs2 = pfs.asfreq("MS") +# unsourced = pfs.unsourcedprice +# unsourced.print() + +# sourced = pfs.sourcedprice +# sourced.print() + +pfs2.print() +pfs2.plot() +plt.show() diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index 9c6e8b5..543f8ab 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -8,22 +8,25 @@ def plot_bars(children: int = 1): """Create bar chart with 4 subplots: (q) x (daily, monthly) x (children, no children).""" index = pf.dev.get_index(freq="D") pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=children) - # pfl2 = pfl1.asfreq("MS") - pfl3 = pf.dev.get_nestedpfline(index, nlevels=2, childcount=children) - pfl4 = pfl3.asfreq("MS") - # pfl1.print() - pfl4.print() - end = pfl1.index[5] - pfl1 = pfl1.loc[:end] - - pfl1.plot("r", children=True) - # pfl2.plot("r", children=False) + pfl2 = pfl1.asfreq("MS") + pfl2.print() + pfl2.plot("p", children=True) + # pfl1.plot("p", children=False) plt.show() - - # pf_nested_pr.print() - # pf_nested_pr.plot(children=True) - # plt.show() print("The number of children is:", children) -plot_bars(4) +def plot_bars_to_ax(): + # Create a figure and an array of subplots (2 rows, 2 columns) + index = pf.dev.get_index(freq="D") + pfl1 = pf.dev.get_flatpfline(index) + pfl2 = pfl1.asfreq("MS") + + fig, axs = plt.subplots(1, 2) + pfl2.plot_to_ax(axs[0], "q", "bar", "") + pfl2.plot_to_ax(axs[1], "p", "hline", "") + plt.show() + + +# plot_bars(4) +plot_bars_to_ax() diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 752650d..0690a43 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict +from typing import TYPE_CHECKING, Dict, List, Tuple import matplotlib import numpy as np @@ -115,56 +115,84 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: for col, ax in zip(cols, axes.flatten()): kwargs = defaultkwargs(col, is_category) - if is_category: - if children and kwargs["how"] == "bar": - # kwargs["how"] = "hline" + + if children: + # adjust kwargs for parent if plotting children + if kwargs["how"] == "bar": kwargs["color"] = "none" kwargs["edgecolor"] = "seagreen" kwargs["linewidth"] = 2 - if children and kwargs["how"] == "area": - # continue + if kwargs["how"] == "area": kwargs["how"] = "step" - if children: - kwargs_children = defaultkwargs(col, is_category) - self.plot_children(col, ax, **kwargs_children) - ax.legend(loc="upper right") + + self.plot_children(col, ax, is_category) + ax.legend(loc="upper right") kwargs["alpha"] = 0.5 s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) return fig - def plot_children(self: PfLine, col: str, ax: plt.Axes, **kwargs): - if kwargs["how"] == "bar" or kwargs["how"] == "area": - bottom_offset = [[0.0, 0.0] for i in range(0, self.index.size)] - for (name, child), color_enum in zip( - self.items(), itertools.cycle(vis.Colors.General) - ): - bar_heights = getattr(child, col) - offsets = [0.0 for i in range(0, self.index.size)] - for i in range(0, len(bar_heights)): - obj = bar_heights[i] - if obj.magnitude > 0: - offsets[i] = bottom_offset[i][0] - bottom_offset[i][0] += obj.magnitude - else: - offsets[i] = bottom_offset[i][1] - bottom_offset[i][1] += obj.magnitude - - kwargs["labelfmt"] = "" - kwargs["bottom"] = offsets - kwargs["color"] = color_enum.value.lighten(0.5) - kwargs["label"] = name - # Calculate width and offset dynamically based on the number of children - vis.plot_timeseries(ax, bar_heights, **kwargs) - else: + def get_stacked_offsets(self: PfLine, col: str) -> Dict[str, List[List[float]]]: + # Calculates offset for each child based on the height of the previous child + # It disdinguishes between postive and negative offsets + # Saves values of offsets in 2 dimmensional array: for positive and negative offsets + return_val = {} + + bottom_offset = [[0.0, 0.0] for i in range(0, self.index.size)] + for name, child in self.items(): + bar_heights = getattr(child, col) + offsets = [0.0 for i in range(0, self.index.size)] + for i in range(0, len(bar_heights)): + obj = bar_heights[i] + if obj.magnitude > 0: + offsets[i] = bottom_offset[i][0] + bottom_offset[i][0] += obj.magnitude + else: + offsets[i] = bottom_offset[i][1] + bottom_offset[i][1] += obj.magnitude + + return_val[name] = offsets + + return return_val + + def get_children_with_colors(self: PfLine) -> List[Tuple(str, PfLine, vis.Color)]: + # return a list of child columns with a color for each + return [ + (name, child, color_enum.value.lighten(0.5)) for (name, child), color_enum in zip( self.items(), itertools.cycle(vis.Colors.General) - ): - kwargs["labelfmt"] = "" - kwargs["color"] = color_enum.value.lighten(0.5) - kwargs["label"] = name - vis.plot_timeseries(ax, getattr(child, col), **kwargs) + ) + ] + + def plot_children(self: PfLine, col: str, ax: plt.Axes, is_category: bool) -> None: + """Plot children of the PfLine to the same ax as parent. + + Parameters + ---------- + cols : str, optional + The columns to plot. Default: plot volume (in [MW] for daily values and + shorter, [MWh] for monthly values and longer) and price `p` [Eur/MWh] + (if available). + ax : plt.Axes + The axes object to which to plot the timeseries. + + """ + kwargs = defaultkwargs(col, is_category) + kwargs["labelfmt"] = "" + is_stacked_type = kwargs["how"] == "bar" or kwargs["how"] == "area" + + if is_stacked_type: + offsets = self.get_stacked_offsets(col) + colors = [] + for name, child, color in self.get_children_with_colors(): + kwargs["color"] = color + kwargs["label"] = name + colors.append(color) + if is_stacked_type: + kwargs["bottom"] = offsets[name] + + vis.plot_timeseries(ax, getattr(child, col), **kwargs) class PfStatePlot: @@ -225,12 +253,15 @@ def plot(self: PfState) -> plt.Figure: plt.Figure The figure object to which the series was plotted. """ - gridspec = {"width_ratios": [1, 1], "height_ratios": [4, 1]} + gridspec = {"width_ratios": [1, 1, 1], "height_ratios": [4, 1]} fig, axes = plt.subplots( - 2, 2, sharex=True, gridspec_kw=gridspec, figsize=(10, 6) + 2, 3, sharex=True, gridspec_kw=gridspec, figsize=(10, 6) ) axes = axes.flatten() - axes[0].sharey(axes[1]) + axes[1].sharey(axes[0]) + axes[2].sharey(axes[0]) + axes[4].sharey(axes[3]) + axes[5].sharey(axes[3]) # If freq is MS or longer: use categorical axes. Plot volumes in MWh. # If freq is D or shorter: use time axes. Plot volumes in MW. @@ -238,20 +269,24 @@ def plot(self: PfState) -> plt.Figure: # Volumes. if is_category: - so, ss = -1 * self.offtakevolume.q, self.sourced.q + so, ss, usv = -1 * self.offtakevolume.q, self.sourced.q, self.unsourced.q kwargs = defaultkwargs("q", is_category) else: - so, ss = -1 * self.offtakevolume.w, self.sourced.w + so, ss, usv = -1 * self.offtakevolume.w, self.sourced.w, self.unsourced.w kwargs = defaultkwargs("w", is_category) vis.plot_timeseries(axes[0], so, **kwargs) vis.plot_timeseries(axes[1], ss, **kwargs) + # Unsourced volume. + vis.plot_timeseries(axes[2], usv, **kwargs) # Procurement Price. - vis.plot_timeseries(axes[2], self.pnl_cost.p, **defaultkwargs("p", is_category)) + vis.plot_timeseries(axes[3], self.pnl_cost.p, **defaultkwargs("p", is_category)) + # sourced price + vis.plot_timeseries(axes[4], self.sourced.p, **defaultkwargs("p", is_category)) - # Sourced fraction. + # unsourced price vis.plot_timeseries( - axes[3], self.sourcedfraction, **defaultkwargs("f", is_category) + axes[5], self.unsourced.p, **defaultkwargs("p", is_category) ) # Empty. @@ -259,8 +294,10 @@ def plot(self: PfState) -> plt.Figure: # Set titles. axes[0].set_title("Offtake volume") axes[1].set_title("Sourced volume") - axes[2].set_title("Procurement price") - axes[3].set_title("Sourced fraction") + axes[2].set_title("Unsourced volume") + axes[3].set_title("Procurement price") + axes[4].set_title("Sourced price") + axes[5].set_title("Unsourced price") # Format tick labels. formatter = matplotlib.ticker.FuncFormatter( @@ -268,7 +305,7 @@ def plot(self: PfState) -> plt.Figure: ) axes[0].yaxis.set_major_formatter(formatter) axes[1].yaxis.set_major_formatter(formatter) - axes[3].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)) + # axes[3].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)) # Set ticks. axes[0].xaxis.set_tick_params(labeltop=False, labelbottom=True) diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index f01028c..5d19040 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -59,7 +59,7 @@ def use_categories(ax: plt.Axes, s: pd.Series, cat: bool = None) -> bool: """Determine if plot should be made with category axis (True) or datetime axis (False).""" # We use categorical data if... if (ax.lines or ax.collections or ax.containers) and ax.xaxis.have_units(): - return True # ...ax already has category axis; or + return cat # ...ax already has category axis; or elif cat is None and tools.freq.shortest(s.index.freq, "MS") == "MS": return True # ...it's the default for the given frequency; or elif cat is True: @@ -114,36 +114,22 @@ def plot_timeseries_as_bar( ax: plt.Axes, s: pd.Series, labelfmt: str = "", - cat: bool = None, + cat: bool = None, # don't need width: float = 0.8, **kwargs, ) -> None: """Plot timeseries ``s`` to axis ``ax``, as bars. Ideally, only used for plots with categorical (i.e, non-time) x-axis.""" + if not is_categorical(s): + raise Exception("This plot is not compatible with continous values") + check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) - if use_categories(ax, s, cat): - categories = Categories(s) - ax.bar(categories.x(), categories.y(), width=width, **kwargs) - ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) - set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - ax.autoscale() - else: - # Bad combination: bar graph on time-axis. But allow anyway. - - # This is slow if there are many elements. - # x = s.index + 0.5 * (s.index.right - s.index) - # width = pd.Timedelta(hours=s.index.duration.median().to("h").magnitude * 0.8) - # ax.bar(x.values, s.values, width, **kwargs) - - # This is faster. - delta = s.index.right - s.index - x = np.array(list(zip(s.index + 0.1 * delta, s.index + 0.9 * delta))).flatten() - magnitudes = np.array([[v, 0] for v in s.values.quantity.magnitude]).flatten() - values = tools.unit.PA_(magnitudes, s.values.quantity.units) - ax.fill_between(x, 0, values, step="post", **kwargs) - - set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, True) + categories = Categories(s) + ax.bar(categories.x(), categories.y(), width=width, **kwargs) + ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) + set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) + ax.autoscale() @append_to_doc(docstringliteral_plotparameters) @@ -156,41 +142,34 @@ def plot_timeseries_as_area( ) -> None: """Plot timeseries ``s`` to axis ``ax``, as stepped area between 0 and value. Ideally, only used for plots with time (i.e., non-categorical) axis.""" + if is_categorical(s): + raise Exception("This plot is not compatible with continous values") + check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) splot = s.copy() # modified with additional (repeated) datapoint splot[splot.index.right[-1]] = splot.values[-1] - if use_categories(ax, s, cat): - # Bad combination: area graph on categorical axis. But allow anyway. - - categories = Categories(s) - ctgr_extra = Categories(splot) - y_value = ctgr_extra.y() - height = ctgr_extra.y().quantity.magnitude - if "bottom" in kwargs: - bottom = kwargs["bottom"] - bottom.append(bottom[-1]) - del kwargs["bottom"] - else: - bottom = [0.0 for i in range(0, height.size)] - # make bottom into pintarray - bottom = bottom * y_value.dtype.units - # Center around x-tick: - ax.fill_between( - ctgr_extra.x() - 0.5, - bottom, - [sum(x) for x in zip(bottom, ctgr_extra.y())], - step="post", - **kwargs, - ) - ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) - set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - ax.autoscale() + if "bottom" in kwargs: + bottom = kwargs["bottom"] + bottom.append(bottom[-1]) + del kwargs["bottom"] else: - ax.fill_between(splot.index, 0, splot.values, step="post", **kwargs) - delta = s.index.right - s.index - set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, True) + bottom = [0.0 for i in range(0, splot.size)] + # make bottom into pintarray + bottom = bottom * splot.values[0].units + # bottom = bottom * splot.pint.units + + ax.fill_between( + splot.index, + bottom, + [sum(x) for x in zip(bottom, splot.values)], + step="post", + **kwargs, + ) + delta = s.index.right - s.index + set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, True) + ax.autoscale() @append_to_doc(docstringliteral_plotparameters) @@ -199,25 +178,18 @@ def plot_timeseries_as_step( ) -> None: """Plot timeseries ``s`` to axis ``ax``, as stepped line (horizontal and vertical lines). Ideally, only used for plots with time (i.e., non-categorical) axis.""" + if is_categorical(s): + raise Exception("This plot is not compatible with continous values") + check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) splot = s.copy() # modified with additional (repeated) datapoint splot[splot.index.right[-1]] = splot.values[-1] - if use_categories(ax, s, cat): - # Bad combination: step graph on categorical axis. But allow anyway. - - categories = Categories(s) - ctgr_extra = Categories(splot) - # Center around x-tick: - ax.step(ctgr_extra.x() - 0.5, ctgr_extra.y(), where="post", **kwargs) - ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) - set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - ax.autoscale() - else: - ax.step(splot.index, splot.values, where="post", **kwargs) - delta = s.index.right - s.index - set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, True) + ax.step(splot.index, splot.values, where="post", **kwargs) + delta = s.index.right - s.index + set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, True) + ax.autoscale() @append_to_doc(docstringliteral_plotparameters) @@ -226,22 +198,18 @@ def plot_timeseries_as_hline( ) -> None: """Plot timeseries ``s`` to axis ``ax``, as horizontal lines. Ideally, only used for plots with time (i.e., non-categorical) axis.""" + if not is_categorical(s): + raise Exception("This plot is not compatible with continous values") + check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) - - if use_categories(ax, s, cat): - # Bad combination: hline graph on categorical axis. But allow anyway. - - categories = Categories(s) - # Center around x-tick: - ax.hlines(categories.y(), categories.x() - 0.5, categories.x() + 0.5, **kwargs) - ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) - set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) - ax.autoscale() - - else: - delta = s.index.right - s.index - ax.hlines(s.values, s.index, s.index.right, **kwargs) - set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, False) + categories = Categories(s) + # Center around x-tick: + ax.hlines(categories.y(), categories.x() - 0.5, categories.x() + 0.5, **kwargs) + ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) + set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) + ax.autoscale() + # Adjust the margins around the plot + ax.margins(x=0.2, y=0.2) def plot_timeseries( @@ -250,7 +218,6 @@ def plot_timeseries( how: str = "jagged", labelfmt: str = None, cat: bool = None, - width: float = 0.8, **kwargs, ) -> None: """Plot timeseries to given axis. @@ -271,7 +238,7 @@ def plot_timeseries( if how == "jagged": plot_timeseries_as_jagged(ax, s, labelfmt, cat, **kwargs) elif how == "bar": - plot_timeseries_as_bar(ax, s, labelfmt, cat, width=width, **kwargs) + plot_timeseries_as_bar(ax, s, labelfmt, cat, **kwargs) elif how == "area": plot_timeseries_as_area(ax, s, labelfmt, cat, **kwargs) elif how == "step": @@ -284,6 +251,32 @@ def plot_timeseries( ) +def set_portfolyo_attr(ax, name, val): + """ + Sets attribute ax._portfolyo which is a dictionary: ._portfolyo = {'unit': ..., 'freq': ..., ...} + If dictionary doesn't exist yet, creates an empty dictionary + """ + pattr = getattr(ax, "_portfolyo", {}) + pattr[name] = val + setattr(ax, "_portfolyo", pattr) + + +def get_portfolyo_attr(ax, name, default_val=None): + """ + Gets values from dictionary ax._portfolyo, if it doesn't exist returns None. + """ + pattr = getattr(ax, "_portfolyo", {}) + return pattr[name] if name in pattr else default_val + + +def is_categorical(s: pd.Series) -> bool: + """The function checks whether frequency of panda Series falls into continous or categorical group""" + if s.index.freq in ["AS", "QS", "MS"]: + return True + else: + return False + + def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: """Ensure axes ``ax`` has unit associated with it and checks compatibility with series ``s``. Also sets y label as unit abbreviation. @@ -302,7 +295,7 @@ def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: if s.dtype == float or s.dtype == int: s = s.astype("pint[1]") # Find preexisting unit. - axunit = getattr(ax, "_unit", None) + axunit = get_portfolyo_attr(ax, "unit", None) # Axes already has unit. Convert series to that unit; ignore any supplied custom unit. if axunit is not None: @@ -320,16 +313,35 @@ def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: f"Cannot convert series with units {s.pint.units} to units {unit}." ) s = s.astype(unit) - setattr(ax, "_unit", unit) + set_portfolyo_attr(ax, "unit", unit) else: # No custom unit provided. Convert series to base units. s = s.pint.to_base_units() - setattr(ax, "_unit", s.pint.units) + set_portfolyo_attr(ax, "unit", s.pint.units) - ax.set_ylabel(f"{ax._unit:~P}") + ax.set_ylabel(f"{get_portfolyo_attr(ax,'unit'):~P}") return s +def check_ax_s_compatible(ax: plt.Axes, s: pd.Series): + """Ensure axes ``ax`` has frequency associated with it and checks compatibility with series + ``s``. + If axes `ax`` has frequency, compare to pd.Series frequency. If they are equal, return s, if not equal, return error. + If axes `ax`` doesn't have frequency, assign frequency of s to it. + """ + # Find preexisting frequency. + axfreq = get_portfolyo_attr(ax, "freq", None) + series_freq = s.index.freq + # Axes does not have frequency. + if axfreq is None: + set_portfolyo_attr(ax, "freq", series_freq) + else: + if get_portfolyo_attr(ax, "freq") != series_freq: + raise AttributeError( + "The frequency of PFLine is not compatible with current axes" + ) + + def set_data_labels( ax: plt.Axes, xx, yy, labelfmt, outside: bool = False, maxcount: int = 24 ): From 96ca68a9760140bd17ca60e572e6c4b281b14d2d Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 3 Jan 2024 14:21:32 +0100 Subject: [PATCH 34/59] created a function to test plotting pfline --- dev_scripts/plot_test.py | 67 +++++++++++++++++++++++++-------- portfolyo/core/mixins/plot.py | 30 +++++++++++---- portfolyo/visualize/__init__.py | 1 - portfolyo/visualize/plot.py | 67 ++++++++++++--------------------- 4 files changed, 98 insertions(+), 67 deletions(-) diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index 543f8ab..a9f7cfc 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -2,31 +2,66 @@ import matplotlib.pyplot as plt import portfolyo as pf +from portfolyo.visualize.plot import ( + CategoricalValuesNotSupported, + ContinuousValuesNotSupported, +) -def plot_bars(children: int = 1): - """Create bar chart with 4 subplots: (q) x (daily, monthly) x (children, no children).""" +def plot_pfline_to_ax(value: str, how: str, children: int = 1): + """Plot a timeseries of the PfLine to 4 axes: (daily, monthly) x (children, no children). + Proper values to parameters: + "p", "step" + "p", "hline" + "w", "area" + "q", "bar" + Othwerwise, getting only 1 plot for pfline with no children since the function for plotting children use default_kwargs + + Parameters + ---------- + + value : str + The column to plot. One of {'w', 'q', 'p', 'r'}. + how : str + How to plot the data. One of {'bar', 'area', 'step', 'hline'}. + children: int + The number of children to assign to pfline. + """ + # Create a figure and an array of subplots (2 rows, 2 columns) index = pf.dev.get_index(freq="D") pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=children) pfl2 = pfl1.asfreq("MS") pfl2.print() - pfl2.plot("p", children=True) - # pfl1.plot("p", children=False) - plt.show() - print("The number of children is:", children) + fig, axs = plt.subplots(2, 2) + try: + pfl2.plot_to_ax(axs[0][0], value, how, children=True) + except CategoricalValuesNotSupported: + axs[0, 0].clear() + try: + pfl2.plot_to_ax(axs[0][1], value, how, children=False) + except CategoricalValuesNotSupported: + axs[0, 1].clear() + try: + pfl1.plot_to_ax(axs[1][0], value, how, children=True) + except ContinuousValuesNotSupported: + axs[1, 0].clear() + try: + pfl1.plot_to_ax(axs[1][1], value, how, children=False) + except ContinuousValuesNotSupported: + axs[1, 1].clear() -def plot_bars_to_ax(): - # Create a figure and an array of subplots (2 rows, 2 columns) - index = pf.dev.get_index(freq="D") - pfl1 = pf.dev.get_flatpfline(index) - pfl2 = pfl1.asfreq("MS") + # Set x-axis and y-axis labels dynamically + x_labels = ["with children", "without children"] + y_labels = ["more than a month", "less than a month"] - fig, axs = plt.subplots(1, 2) - pfl2.plot_to_ax(axs[0], "q", "bar", "") - pfl2.plot_to_ax(axs[1], "p", "hline", "") + # Set y-axis labels on the left for each row + for i in range(2): + axs[i, 0].set(ylabel=y_labels[i]) + # Set x-axis labels on top of each column + for j in range(2): + axs[1, j].set(xlabel=x_labels[j]) plt.show() -# plot_bars(4) -plot_bars_to_ax() +plot_pfline_to_ax("w", "bar", 4) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 0690a43..cfb9adf 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -49,7 +49,13 @@ def defaultkwargs(col: str, is_cat: bool): class PfLinePlot: def plot_to_ax( - self: PfLine, ax: plt.Axes, col: str, how: str, labelfmt: str, **kwargs + self: PfLine, + ax: plt.Axes, + col: str, + how: str, + labelfmt: str = "", + children: bool = False, + **kwargs, ) -> None: """Plot a timeseries of the PfLine to a specific axes. @@ -60,19 +66,29 @@ def plot_to_ax( col : str The column to plot. One of {'w', 'q', 'p', 'r'}. how : str - How to plot the data. One of {'jagged', 'bar', 'area', 'step', 'hline'}. + How to plot the data. One of {'bar', 'area', 'step', 'hline'}. labelfmt : str Labels are added to each datapoint in the specified format. ('' to add no labels) Any additional kwargs are passed to the pd.Series.plot function. """ + if col not in self.kind.available: raise ValueError( f"For this PfLine, parameter ``col`` must be one of {', '.join(self.kind.available)}; got {col}." ) - # if len(self.items()) == 0: - # print("This PFline doesn't have any children") - # for (name, child) in self.items(): - # vis.plot_timeseries(ax, getattr(self, name), how, labelfmt, **kwargs) + if children: + # Plot on category axis if freq monthly or longer, else on time axis. + is_category = tools.freq.shortest(self.index.freq, "MS") == "MS" + # adjust kwargs for parent if plotting children + if how == "bar": + kwargs["color"] = "none" + kwargs["edgecolor"] = "seagreen" + kwargs["linewidth"] = 2 + if how == "area": + how = "step" + + self.plot_children(col, ax, is_category) + ax.legend() vis.plot_timeseries(ax, getattr(self, col), how, labelfmt, **kwargs) def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: @@ -126,7 +142,7 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: kwargs["how"] = "step" self.plot_children(col, ax, is_category) - ax.legend(loc="upper right") + ax.legend() kwargs["alpha"] = 0.5 s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) diff --git a/portfolyo/visualize/__init__.py b/portfolyo/visualize/__init__.py index 0cb9e32..0dbb90f 100644 --- a/portfolyo/visualize/__init__.py +++ b/portfolyo/visualize/__init__.py @@ -4,6 +4,5 @@ plot_timeseries_as_area, plot_timeseries_as_bar, plot_timeseries_as_hline, - plot_timeseries_as_jagged, plot_timeseries_as_step, ) diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 5d19040..e913f07 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -6,8 +6,6 @@ import numpy as np import pandas as pd from matplotlib import pyplot as plt - -from .. import tools from .categories import Categories, Category # noqa mpl.style.use("seaborn-v0_8") @@ -55,16 +53,12 @@ MAX_XLABELS = 20 -def use_categories(ax: plt.Axes, s: pd.Series, cat: bool = None) -> bool: - """Determine if plot should be made with category axis (True) or datetime axis (False).""" - # We use categorical data if... - if (ax.lines or ax.collections or ax.containers) and ax.xaxis.have_units(): - return cat # ...ax already has category axis; or - elif cat is None and tools.freq.shortest(s.index.freq, "MS") == "MS": - return True # ...it's the default for the given frequency; or - elif cat is True: - return True # ...user wants it. - return False +class ContinuousValuesNotSupported(Exception): + pass + + +class CategoricalValuesNotSupported(Exception): + pass docstringliteral_plotparameters = """ @@ -89,26 +83,6 @@ def decorator(fn): return decorator -@append_to_doc(docstringliteral_plotparameters) -def plot_timeseries_as_jagged( - ax: plt.Axes, s: pd.Series, labelfmt: str = "", cat: bool = None, **kwargs -) -> None: - """Plot timeseries ``s`` to axis ``ax``, as jagged line and/or as markers. Use kwargs - ``linestyle`` and ``marker`` to specify line style and/or marker style. (Default: line only). - """ - s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) - - if use_categories(ax, s, cat): - categories = Categories(s) - ax.plot(categories.x(), categories.y(), **kwargs) - ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) - set_data_labels(ax, categories.x(), categories.y(), labelfmt, False) - ax.autoscale() - else: - ax.plot(s.index, s.values, **kwargs) - set_data_labels(ax, s.index, s.values, labelfmt, False) - - @append_to_doc(docstringliteral_plotparameters) def plot_timeseries_as_bar( ax: plt.Axes, @@ -121,7 +95,9 @@ def plot_timeseries_as_bar( """Plot timeseries ``s`` to axis ``ax``, as bars. Ideally, only used for plots with categorical (i.e, non-time) x-axis.""" if not is_categorical(s): - raise Exception("This plot is not compatible with continous values") + raise ContinuousValuesNotSupported( + "This plot is not compatible with continous values" + ) check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) @@ -143,7 +119,9 @@ def plot_timeseries_as_area( """Plot timeseries ``s`` to axis ``ax``, as stepped area between 0 and value. Ideally, only used for plots with time (i.e., non-categorical) axis.""" if is_categorical(s): - raise Exception("This plot is not compatible with continous values") + raise CategoricalValuesNotSupported( + "This plot is not compatible with categorical values" + ) check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) @@ -179,7 +157,9 @@ def plot_timeseries_as_step( """Plot timeseries ``s`` to axis ``ax``, as stepped line (horizontal and vertical lines). Ideally, only used for plots with time (i.e., non-categorical) axis.""" if is_categorical(s): - raise Exception("This plot is not compatible with continous values") + raise CategoricalValuesNotSupported( + "This plot is not compatible with categorical values" + ) check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) @@ -199,7 +179,9 @@ def plot_timeseries_as_hline( """Plot timeseries ``s`` to axis ``ax``, as horizontal lines. Ideally, only used for plots with time (i.e., non-categorical) axis.""" if not is_categorical(s): - raise Exception("This plot is not compatible with continous values") + raise ContinuousValuesNotSupported( + "This plot is not compatible with continous values" + ) check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) categories = Categories(s) @@ -215,7 +197,7 @@ def plot_timeseries_as_hline( def plot_timeseries( ax: plt.Axes, s: pd.Series, - how: str = "jagged", + how: str = "bar", labelfmt: str = None, cat: bool = None, **kwargs, @@ -228,16 +210,15 @@ def plot_timeseries( Axes to plot to. s : pd.Series Timeseries to plot - how : str, optional (default: 'jagged') - How to plot the data; one of {'jagged', 'bar', 'area', 'step', 'hline'}. + how : str, optional (default: 'bar') + How to plot the data; one of {'bar', 'area', 'step', 'hline'}. labelfmt : str, optional (default: '') Labels are added to each datapoint in the specified format. ('' to add no labels) cat : bool, optional (default: True if frequency is monthly or larger) Plot as categorical x-axis. """ - if how == "jagged": - plot_timeseries_as_jagged(ax, s, labelfmt, cat, **kwargs) - elif how == "bar": + + if how == "bar": plot_timeseries_as_bar(ax, s, labelfmt, cat, **kwargs) elif how == "area": plot_timeseries_as_area(ax, s, labelfmt, cat, **kwargs) @@ -247,7 +228,7 @@ def plot_timeseries( plot_timeseries_as_hline(ax, s, labelfmt, cat, **kwargs) else: raise ValueError( - f"Parameter ``how`` must be one of 'jagged', 'bar', 'area', 'step', 'hline'; got {how}." + f"Parameter ``how`` must be one of 'bar', 'area', 'step', 'hline'; got {how}." ) From 53affbc445db239b599afe8a0d9ee145b47ee0b2 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Thu, 11 Jan 2024 12:47:53 +0100 Subject: [PATCH 35/59] created slice attr, wrote tests for it --- dev_scripts/panda.py | 18 --------- dev_scripts/plot_state.py | 9 +++-- dev_scripts/slice_test.py | 54 +++++++++++++++++++++++++ portfolyo/core/ndframelike.py | 4 ++ portfolyo/core/pfline/classes.py | 2 + portfolyo/core/pfline/flat_methods.py | 28 +++++++++++++ portfolyo/core/pfline/nested_methods.py | 17 ++++++++ portfolyo/core/pfstate/pfstate.py | 38 +++++++++++++++++ portfolyo/dev/develop.py | 16 ++++++++ portfolyo/visualize/plot.py | 2 +- tests/core/pfline/test_slice.py | 46 +++++++++++++++++++++ tests/core/pfstate/test_slice_state.py | 25 ++++++++++++ 12 files changed, 236 insertions(+), 23 deletions(-) delete mode 100644 dev_scripts/panda.py create mode 100644 dev_scripts/slice_test.py create mode 100644 tests/core/pfline/test_slice.py create mode 100644 tests/core/pfstate/test_slice_state.py diff --git a/dev_scripts/panda.py b/dev_scripts/panda.py deleted file mode 100644 index 3e89e20..0000000 --- a/dev_scripts/panda.py +++ /dev/null @@ -1,18 +0,0 @@ -import pandas as pd - -# Create a sample DataFrame with a DatetimeIndex -df = pd.DataFrame( - index=pd.date_range(start="2022-04-01", end="2023-03-31", freq="M"), - data={"value": range(12)}, -) - -# Display the original DataFrame -print("Original DataFrame:") -print(df) - -# Change the frequency of the DatetimeIndex -df_resampled = df.asfreq(freq="AS") - -# Display the DataFrame with the new frequency -print("\nDataFrame with new Frequency:") -print(df_resampled) diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py index e81ba0b..e9b0f44 100644 --- a/dev_scripts/plot_state.py +++ b/dev_scripts/plot_state.py @@ -5,15 +5,16 @@ """Plot PfState to test of adding axes for un/sourced prices.""" index = pf.dev.get_index(freq="D") -pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=2) pfs = pf.dev.get_pfstate(index) pfs2 = pfs.asfreq("MS") -# unsourced = pfs.unsourcedprice -# unsourced.print() + +# pfl2 = create.nestedpfline(index) +# pfs3 = pf.dev.get_nested_pfstate(index) + # sourced = pfs.sourcedprice # sourced.print() -pfs2.print() +# pfl2.print() pfs2.plot() plt.show() diff --git a/dev_scripts/slice_test.py b/dev_scripts/slice_test.py new file mode 100644 index 0000000..5421c15 --- /dev/null +++ b/dev_scripts/slice_test.py @@ -0,0 +1,54 @@ +import portfolyo as pf +import pandas as pd + +index = pd.date_range("2020", "2024", freq="QS") + + +# FlatPfline +def flat_test(): + pfl1 = pf.dev.get_flatpfline(index) + # pfl2 = pf.dev.get_flatpfline(index) + # pfl3 = pfl1 + # pfl4 = pfl2 + # pfl1 = pfl1.loc[:"2021"] + # pfl3 = pfl2.slice[:"2022"] + # print("Loc version", pfl1) + # print("\n") + # print("Slice version", pfl3) + # print(pfl1 == pfl3) + pfls_to_concat = [pfl1.slice[:"2022"], pfl1.slice["2022":]] + pfls_to_concat2 = [pfl1.loc[:"2021"], pfl1.loc["2022":]] + + print("The slice version", pfls_to_concat) + print("\n") + print("Loc version", pfls_to_concat2) + print(pfls_to_concat == pfls_to_concat2) + + +def nested_test(): + pfl1 = pf.dev.get_nestedpfline(index, childcount=2) + pfl2 = pf.dev.get_nestedpfline(index, childcount=2) + + pfls_to_concat = [pfl1.slice[:"2022"], pfl2.slice["2022":]] + pfls_to_concat2 = [pfl1.loc[:"2021"], pfl2.loc["2022":]] + + print("The slice version", pfls_to_concat) + print("\n") + print("Loc version", pfls_to_concat2) + print(pfls_to_concat == pfls_to_concat2) + + +def state_test(): + pfs = pf.dev.get_pfstate(index) + pfs_to_concat2 = [pfs.loc[:"2021"], pfs.loc["2022":]] + pfs_to_concat = [pfs.slice[:"2022"], pfs.slice["2022":]] + + print("The slice version", pfs_to_concat) + print("\n") + print("Loc version", pfs_to_concat2) + print(pfs_to_concat == pfs_to_concat2) + + +# flat_test() +# nested_test() +state_test() diff --git a/portfolyo/core/ndframelike.py b/portfolyo/core/ndframelike.py index 560a576..f2dfeed 100644 --- a/portfolyo/core/ndframelike.py +++ b/portfolyo/core/ndframelike.py @@ -42,6 +42,10 @@ def loc(self): a boolean array.)""" ... + @abc.abstractproperty + def slice(self): + ... + @abc.abstractmethod def dataframe( self, cols: Iterable[str] = None, has_units: bool = True, *args, **kwargs diff --git a/portfolyo/core/pfline/classes.py b/portfolyo/core/pfline/classes.py index 8c6dd0b..d750db3 100644 --- a/portfolyo/core/pfline/classes.py +++ b/portfolyo/core/pfline/classes.py @@ -286,6 +286,7 @@ class FlatPfLine(PfLine): hedge_with = prices.Flat.hedge_with # map_to_year => on child classes loc = flat_methods.loc + slice = flat_methods.slice # meh __getitem__ = flat_methods.__getitem__ # __bool__ => on child classes __eq__ = flat_methods.__eq__ @@ -300,6 +301,7 @@ class NestedPfLine(PfLine, children.ChildFunctionality): hedge_with = prices.Nested.hedge_with map_to_year = nested_methods.map_to_year loc = nested_methods.loc + slice = nested_methods.slice __bool__ = nested_methods.__bool__ __eq__ = nested_methods.__eq__ diff --git a/portfolyo/core/pfline/flat_methods.py b/portfolyo/core/pfline/flat_methods.py index 90a27e4..9ba10dc 100644 --- a/portfolyo/core/pfline/flat_methods.py +++ b/portfolyo/core/pfline/flat_methods.py @@ -3,6 +3,8 @@ from typing import TYPE_CHECKING, Any from ... import testing +import pandas as pd +from datetime import timedelta if TYPE_CHECKING: from .classes import FlatPfLine @@ -31,6 +33,11 @@ def loc(self: FlatPfLine) -> LocIndexer: return LocIndexer(self) +@property +def slice(self: FlatPfLine) -> SliceIndexer: + return SliceIndexer(self) + + class LocIndexer: """Helper class to obtain FlatPfLine instance, whose index is subset of original index.""" @@ -40,3 +47,24 @@ def __init__(self, pfl: FlatPfLine): def __getitem__(self, arg) -> FlatPfLine: newdf = self.pfl.df.loc[arg] return self.pfl.__class__(newdf) # use same (leaf) class + + +class SliceIndexer: + """Helper class to obtain FlatPfLine instance, whose index is subset of original index. + Exclude end index from the slice""" + + def __init__(self, pfl: FlatPfLine): + self.pfl = pfl + + def __getitem__(self, arg) -> FlatPfLine: + date_start = pd.to_datetime(arg.start) + date_end = pd.to_datetime(arg.stop) + + if arg.stop is not None: + date_end = date_end - timedelta(seconds=1) + + newdf = self.pfl.df.loc[date_start:date_end] + # newdf = self.pfl.df.loc[arg] + # if arg.stop is not None: + # newdf = newdf.iloc[:-1] + return self.pfl.__class__(newdf) # use same (leaf) class diff --git a/portfolyo/core/pfline/nested_methods.py b/portfolyo/core/pfline/nested_methods.py index dbe1c4b..3eff30b 100644 --- a/portfolyo/core/pfline/nested_methods.py +++ b/portfolyo/core/pfline/nested_methods.py @@ -37,6 +37,11 @@ def loc(self: NestedPfLine) -> LocIndexer: return LocIndexer(self) +@property +def slice(self: NestedPfLine) -> SliceIndexer: + return SliceIndexer(self) + + class LocIndexer: """Helper class to obtain NestedPfLine instance, whose index is subset of original index.""" @@ -46,3 +51,15 @@ def __init__(self, pfl: NestedPfLine): def __getitem__(self, arg) -> NestedPfLine: newchildren = {name: child.loc[arg] for name, child in self.pfl.items()} return self.pfl.__class__(newchildren) + + +class SliceIndexer: + """Helper class to obtain NestedPfLine instance, whose index is subset of original index. + Exclude end index from the slice""" + + def __init__(self, pfl: NestedPfLine): + self.pfl = pfl + + def __getitem__(self, arg) -> NestedPfLine: + newchildren = {name: child.slice[arg] for name, child in self.pfl.items()} + return self.pfl.__class__(newchildren) diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index b90b79c..e889108 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -109,6 +109,26 @@ def from_series( sourced = None return cls(offtakevolume, unsourcedprice, sourced) + @classmethod + def from_pfline( + cls, + *, + pu: pd.Series, + qo: Optional[pd.Series] = None, + qs: Optional[pd.Series] = None, + rs: Optional[pd.Series] = None, + wo: Optional[pd.Series] = None, + ws: Optional[pd.Series] = None, + ps: Optional[pd.Series] = None, + ): + offtakevolume = create.nestedpfline({"q": qo, "w": wo}) + unsourcedprice = create.nestedpfline({"p": pu}) + if not (ws is qs is rs is ps is None): + sourced = create.nestedpfline({"w": ws, "q": qs, "r": rs, "p": ps}) + else: + sourced = None + return cls(offtakevolume, unsourcedprice, sourced) + def __post_init__(self): offtakevolume, unsourcedprice, sourced = pfstate_helper.make_pflines( self.offtakevolume, self.unsourcedprice, self.sourced @@ -280,6 +300,10 @@ def __bool__(self): def loc(self) -> _LocIndexer: # from ABC return _LocIndexer(self) + @property + def slice(self) -> _SliceIndexer: # from ABC + return _SliceIndexer(self) + class _LocIndexer: """Helper class to obtain PfState instance, whose index is subset of original index.""" @@ -292,3 +316,17 @@ def __getitem__(self, arg) -> PfState: unsourcedprice = self.pfs.unsourcedprice.loc[arg] sourced = self.pfs.sourced.loc[arg] return PfState(offtakevolume, unsourcedprice, sourced) + + +class _SliceIndexer: + """Helper class to obtain PfState instance, whose index is subset of original index. + Exclude end index from the slice""" + + def __init__(self, pfs): + self.pfs = pfs + + def __getitem__(self, arg) -> PfState: + offtakevolume = self.pfs.offtake.volume.slice[arg] + unsourcedprice = self.pfs.unsourcedprice.slice[arg] + sourced = self.pfs.sourced.slice[arg] + return PfState(offtakevolume, unsourcedprice, sourced) diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index ad1be3d..8299fed 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -320,6 +320,22 @@ def get_pfstate(i: pd.DatetimeIndex = None, avg=None, *, _seed: int = None) -> P return PfState.from_series(wo=wo, pu=pu, ws=ws, ps=ps) +def get_nested_pfstate( + i: pd.DatetimeIndex = None, avg=None, *, _seed: int = None +) -> PfState: + """Get portfolio state.""" + if i is None: + i = get_index(_seed=_seed) + if _seed: + np.random.seed(_seed) + if avg is None: + avg = 200 ** np.random.rand() # between 1 and 200 + wo = -1 * mockup.w_offtake(i, avg) + pu = mockup.p_marketprices(i) + ws, ps = mockup.wp_sourced(wo) + return PfState.from_pfline(wo=wo, pu=pu, ws=ws, ps=ps) + + def get_pfstates( i: pd.DatetimeIndex = None, num=3, *, _seed: int = None ) -> Dict[str, PfState]: diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index e913f07..abc5793 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -300,7 +300,7 @@ def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: s = s.pint.to_base_units() set_portfolyo_attr(ax, "unit", s.pint.units) - ax.set_ylabel(f"{get_portfolyo_attr(ax,'unit'):~P}") + ax.set_ylabel(f"{get_portfolyo_attr(ax, 'unit'):~P}") return s diff --git a/tests/core/pfline/test_slice.py b/tests/core/pfline/test_slice.py new file mode 100644 index 0000000..19eccf8 --- /dev/null +++ b/tests/core/pfline/test_slice.py @@ -0,0 +1,46 @@ +"""Test if slice attributes works properly with portfolio line.""" + +import pytest +import pandas as pd +from portfolyo import dev + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize("slice_start", ["2021", "2022", "2022-01-02"]) +@pytest.mark.parametrize( + "slice_end", + [ + # (, ) + ("2021", "2020"), + ("2022", "2021"), + ("2022-01-02", "2022-01-01"), + ], +) +def test_flat_slice(slice_start, slice_end, freq): + index = pd.date_range("2020", "2024", freq=freq) + pfl1 = dev.get_flatpfline(index) + + pfls_to_concat = [pfl1.slice[: slice_end[0]], pfl1.slice[slice_start:]] + pfls_to_concat2 = [pfl1.loc[: slice_end[1]], pfl1.loc[slice_start:]] + assert pfls_to_concat == pfls_to_concat2 + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize("slice_start", ["2021", "2022", "2022-01-02"]) +@pytest.mark.parametrize("children", [1, 2, 3, 4]) +@pytest.mark.parametrize( + "slice_end", + [ + # (, ) + ("2021", "2020"), + ("2022", "2021"), + ("2022-01-02", "2022-01-01"), + ], +) +def test_nested_slice(slice_start, slice_end, freq, children): + index = pd.date_range("2020", "2024", freq=freq) + pfl1 = dev.get_nestedpfline(index, childcount=children) + + pfls_to_concat = [pfl1.slice[: slice_end[0]], pfl1.slice[slice_start:]] + pfls_to_concat2 = [pfl1.loc[: slice_end[1]], pfl1.loc[slice_start:]] + assert pfls_to_concat == pfls_to_concat2 diff --git a/tests/core/pfstate/test_slice_state.py b/tests/core/pfstate/test_slice_state.py new file mode 100644 index 0000000..53aef7b --- /dev/null +++ b/tests/core/pfstate/test_slice_state.py @@ -0,0 +1,25 @@ +"""Test if slice attributes works properly with portfolio state.""" + +import pytest +import pandas as pd +from portfolyo import dev + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize("slice_start", ["2021", "2022", "2022-01-02"]) +@pytest.mark.parametrize( + "slice_end", + [ + # (, ) + ("2021", "2020"), + ("2022", "2021"), + ("2022-01-02", "2022-01-01"), + ], +) +def test_slice_state(slice_start, slice_end, freq): + index = pd.date_range("2020", "2024", freq=freq) + pfs = dev.get_pfstate(index) + + pfs_to_concat = [pfs.slice[: slice_end[0]], pfs.slice[slice_start:]] + pfs_to_concat2 = [pfs.loc[: slice_end[1]], pfs.loc[slice_start:]] + assert pfs_to_concat == pfs_to_concat2 From c1c9f5b1174c1ae4ea2898651ecf6ee6874f39d2 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 22 Jan 2024 12:18:01 +0100 Subject: [PATCH 36/59] more flexible intersec function with ignore freq, tz, start_of_day + tests --- dev_scripts/intersect_test.py | 20 +++++++ portfolyo/core/ndframelike.py | 3 ++ portfolyo/core/pfstate/pfstate.py | 20 ------- portfolyo/tools/intersect.py | 88 ++++++++++++++++++++++++++++--- tests/tools/test_intersect.py | 81 +++++++++++++++++++++++++--- 5 files changed, 178 insertions(+), 34 deletions(-) create mode 100644 dev_scripts/intersect_test.py diff --git a/dev_scripts/intersect_test.py b/dev_scripts/intersect_test.py new file mode 100644 index 0000000..9c09a08 --- /dev/null +++ b/dev_scripts/intersect_test.py @@ -0,0 +1,20 @@ +import pandas as pd + +from portfolyo import tools + +# create a and b with different frequencies +# create c with the same freq as a +# look how a intersect c behaves + + +a = pd.date_range("2020-01-01", "2022-02-02", freq="15T") +b = pd.date_range("2020-01-20", "2022-02-02", freq="D") +c = pd.date_range("2021-01-01", "2024-01-01", freq="QS") +d = pd.date_range("2022-04-01", "2024-07-01", freq="AS") +intersect = tools.intersect.indices(a, b, ignore_freq=True) +# intersect2 = tools.intersect.indices(a, c) +# intersect3 = tools.intersect.indices(b, d) +print(intersect) +# print("\n") +# print(intersect2) +# print(intersect == intersect3) diff --git a/portfolyo/core/ndframelike.py b/portfolyo/core/ndframelike.py index f2dfeed..bf0f98a 100644 --- a/portfolyo/core/ndframelike.py +++ b/portfolyo/core/ndframelike.py @@ -44,6 +44,9 @@ def loc(self): @abc.abstractproperty def slice(self): + """Create a new instance with a subset of the rows (selection by row label(s) or + a boolean array.) + Different from loc since performs slicing with right-open interval""" ... @abc.abstractmethod diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index e889108..ed127a4 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -109,26 +109,6 @@ def from_series( sourced = None return cls(offtakevolume, unsourcedprice, sourced) - @classmethod - def from_pfline( - cls, - *, - pu: pd.Series, - qo: Optional[pd.Series] = None, - qs: Optional[pd.Series] = None, - rs: Optional[pd.Series] = None, - wo: Optional[pd.Series] = None, - ws: Optional[pd.Series] = None, - ps: Optional[pd.Series] = None, - ): - offtakevolume = create.nestedpfline({"q": qo, "w": wo}) - unsourcedprice = create.nestedpfline({"p": pu}) - if not (ws is qs is rs is ps is None): - sourced = create.nestedpfline({"w": ws, "q": qs, "r": rs, "p": ps}) - else: - sourced = None - return cls(offtakevolume, unsourcedprice, sourced) - def __post_init__(self): offtakevolume, unsourcedprice, sourced = pfstate_helper.make_pflines( self.offtakevolume, self.unsourcedprice, self.sourced diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index fa940a2..29d5718 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -3,7 +3,12 @@ import pandas as pd -def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: +def indices( + *idxs: pd.DatetimeIndex, + ignore_freq: bool = False, + ignore_tz: bool = False, + ignore_start_of_day: bool = False, +) -> pd.DatetimeIndex: """Intersect several DatetimeIndices. Parameters @@ -11,6 +16,20 @@ def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: *idxs : pd.DatetimeIndex The indices to intersect. + ignore_freq: bool + Ignore the frequencies of indices, perform an intersection. + Return the result with the frequencies of the first index from the list. + + ignore_tz: bool + Ignore the timezones of indices, perform an intersection. + Return the result with the timezone of the first index from the list. + + ignore_start_of_day: bool + Ignore the start of the day of indices, perform an intersection. + Return the result with start_of_day time of the first index from the list. + If frequencies are shorter then daily, transforms it into daily freq. + + Returns ------- pd.DatetimeIndex @@ -26,18 +45,19 @@ def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: if len(idxs) == 1: return idxs[0] - + # convert tuple object into a list + idxs = list(idxs) # If we land here, we have at least 2 indices. distinct_freqs = set([i.freq for i in idxs]) - if len(distinct_freqs) != 1: + if len(distinct_freqs) != 1 and ignore_freq is False: raise ValueError(f"Indices must have equal frequencies; got {distinct_freqs}.") distinct_tzs = set([i.tz for i in idxs]) - if len(distinct_tzs) != 1: + if len(distinct_tzs) != 1 and ignore_tz is False: raise ValueError(f"Indices must have equal timezones; got {distinct_tzs}.") - freq, name, tz = idxs[0].freq, idxs[0].name, idxs[0].tz + freq, name, tz = (idxs[0].freq, idxs[0].name, idxs[0].tz) empty_idx = [len(i) == 0 for i in idxs] if any(empty_idx): @@ -46,17 +66,73 @@ def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: # If we land here, we have at least 2 indices, all are not empty, with equal tz and freq. distinct_sod = set([i[0].time() for i in idxs]) - if len(distinct_sod) != 1: + if len(distinct_sod) != 1 and ignore_start_of_day is False: raise ValueError(f"Indices must have equal start-of-day; got {distinct_sod}.") + if ignore_tz is True: + # set timezone to none for all values + for i in range(len(idxs)): + idxs[i] = idxs[i].tz_localize(None) + + if ignore_start_of_day is True: + # Save a copy of the original hours and minutes + start_of_day = idxs[0][0].time() + for i in range(len(idxs)): + if is_less_one_day(idxs[i].freq): + idxs[i] = pd.date_range( + start=idxs[i].min(), end=idxs[i].max(), freq="D" + ) + freq = "D" + # Set the time components to midnight for each timestamp in the list + idxs = [timestamp.normalize() for timestamp in idxs] + + if ignore_freq is True: + # Find the smallest frequency + smallest_freq = min(idxs, key=lambda x: freq_to_timestamp(x.freq)).freq + # change bigger freq into small one + for i in range(len(idxs)): + start = idxs[i].min() + end = idxs[i].max() + if is_less_one_day(smallest_freq): + end = end + pd.Timedelta(hours=23, minutes=59, seconds=59) + idxs[i] = pd.date_range(start, end, freq=smallest_freq) + # Calculation is cumbersome: pandas DatetimeIndex.intersection not working correctly on timezone-aware indices (#46702) values = set(idxs[0]) for i in idxs[1:]: values = values.intersection(set(i)) + if ignore_start_of_day is True: + for timestamp in values.copy(): + new_timestamp = timestamp.replace( + hour=start_of_day.hour, minute=start_of_day.minute + ) + values.remove(timestamp) + values.add(new_timestamp) + + # values turn into timestampt + # add saved start of the day to all of them + # change back into datatimeindex + if len(values) > 0: + values = pd.date_range(start=min(values), end=max(values), freq=freq, tz=tz) + return pd.DatetimeIndex(sorted(list(values)), freq=freq, name=name, tz=tz) +def is_less_one_day(dateoffset): + """Returns True if frequency is shorter than daily + otherwise, returns False.""" + ts = pd.Timestamp("1990-01-01") + day = pd.tseries.offsets.DateOffset(days=1) + return (ts + dateoffset) < (ts + day) + + +def freq_to_timestamp(dateoffset): + """Transform frequency (f.e. "15T") into timestamp to enable comparison between frequencies""" + ts = pd.Timestamp("1990-01-01") + return ts + dateoffset + + def frames( *frames: Union[pd.Series, pd.DataFrame] ) -> List[Union[pd.Series, pd.DataFrame]]: diff --git a/tests/tools/test_intersect.py b/tests/tools/test_intersect.py index fbb83f4..8b95648 100644 --- a/tests/tools/test_intersect.py +++ b/tests/tools/test_intersect.py @@ -85,6 +85,7 @@ def test_intersect( @pytest.mark.parametrize("indexorframe", ["idx", "fr"]) @pytest.mark.parametrize("starttime", ["00:00", "06:00"]) @pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("ignore_freq", [True, False]) def test_intersect_distinctfreq( indexorframe: str, startdates: Iterable[str], @@ -92,6 +93,7 @@ def test_intersect_distinctfreq( tz: str, freq: str, expected_startdate: str, + ignore_freq: bool, ): """Test if intersection of indices with distinct frequencies gives correct result.""" otherfreq = "H" if freq == "D" else "D" @@ -99,13 +101,25 @@ def test_intersect_distinctfreq( get_idx(startdates[0], starttime, tz, freq), get_idx(startdates[1], starttime, tz, otherfreq), ] - do_test_intersect(indexorframe, idxs, ValueError) + if ignore_freq and indexorframe == "idx": + do_test_intersect( + indexorframe, + idxs, + expected_startdate, + expected_tz=tz, + expected_freq=freq, + expected_starttime=starttime, + ignore_freq=ignore_freq, + ) + else: + do_test_intersect(indexorframe, idxs, ValueError) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize("indexorframe", ["idx", "fr"]) @pytest.mark.parametrize("starttime", ["00:00", "06:00"]) @pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("ignore_tz", [True, False]) def test_intersect_distincttz( indexorframe: str, startdates: Iterable[str], @@ -113,6 +127,7 @@ def test_intersect_distincttz( tz: str, freq: str, expected_startdate: str, + ignore_tz: bool, ): """Test if intersection of indices with distinct timezones gives correct result.""" othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" @@ -120,13 +135,25 @@ def test_intersect_distincttz( get_idx(startdates[0], starttime, tz, freq), get_idx(startdates[1], starttime, othertz, freq), ] - do_test_intersect(indexorframe, idxs, ValueError) + if ignore_tz and indexorframe == "idx": + do_test_intersect( + indexorframe, + idxs, + expected_startdate, + expected_tz=tz, + expected_freq=freq, + expected_starttime=starttime, + ignore_tz=ignore_tz, + ) + else: + do_test_intersect(indexorframe, idxs, ValueError) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize("indexorframe", ["idx", "fr"]) @pytest.mark.parametrize("starttime", ["00:00", "06:00"]) @pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("ignore_start_of_day", [True, False]) def test_intersect_distinctstartofday( indexorframe: str, startdates: Iterable[str], @@ -134,6 +161,7 @@ def test_intersect_distinctstartofday( tz: str, freq: str, expected_startdate: str, + ignore_start_of_day: bool, ): """Test if intersection of indices with distinct frequencies gives correct result.""" otherstarttime = "00:00" if starttime == "06:00" else "06:00" @@ -141,7 +169,18 @@ def test_intersect_distinctstartofday( get_idx(startdates[0], starttime, tz, freq), get_idx(startdates[1], otherstarttime, tz, freq), ] - do_test_intersect(indexorframe, idxs, ValueError) + if ignore_start_of_day and indexorframe == "idx": + do_test_intersect( + indexorframe, + idxs, + expected_startdate, + expected_tz=tz, + expected_freq=freq if (freq != "15T" and freq != "H") else "D", + expected_starttime=starttime, + ignore_start_of_day=ignore_start_of_day, + ) + else: + do_test_intersect(indexorframe, idxs, ValueError) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @@ -164,12 +203,25 @@ def do_test_intersect( expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, + ignore_start_of_day: bool = False, + ignore_tz: bool = False, + ignore_freq: bool = False, ): if indexorframe == "idx": - do_test_fn = do_test_intersect_index + do_test_intersect_index( + idxs, + expected_startdate, + expected_starttime, + expected_tz, + expected_freq, + ignore_start_of_day, + ignore_tz, + ignore_freq, + ) else: - do_test_fn = do_test_intersect_frame - do_test_fn(idxs, expected_startdate, expected_starttime, expected_tz, expected_freq) + do_test_intersect_frame( + idxs, expected_startdate, expected_starttime, expected_tz, expected_freq + ) def do_test_intersect_index( @@ -178,16 +230,29 @@ def do_test_intersect_index( expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, + ignore_start_of_day: bool = False, + ignore_tz: bool = False, + ignore_freq: bool = False, ): # Error case. if isinstance(expected_startdate, type) and issubclass( expected_startdate, Exception ): with pytest.raises(expected_startdate): - tools.intersect.indices(*idxs) + tools.intersect.indices( + *idxs, + ignore_start_of_day=ignore_start_of_day, + ignore_tz=ignore_tz, + ignore_freq=ignore_freq, + ) return # Normal case. - result = tools.intersect.indices(*idxs) + result = tools.intersect.indices( + *idxs, + ignore_start_of_day=ignore_start_of_day, + ignore_tz=ignore_tz, + ignore_freq=ignore_freq, + ) expected = get_idx( expected_startdate, expected_starttime, expected_tz, expected_freq ) From ffa4dade96fb22dfe50857c05183dea14d282892 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Tue, 23 Jan 2024 13:40:50 +0100 Subject: [PATCH 37/59] small changes to intersect --- portfolyo/tools/intersect.py | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index 29d5718..9804148 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -2,6 +2,8 @@ import pandas as pd +from portfolyo.tools.freq import longer_or_shorter, shortest + def indices( *idxs: pd.DatetimeIndex, @@ -78,7 +80,7 @@ def indices( # Save a copy of the original hours and minutes start_of_day = idxs[0][0].time() for i in range(len(idxs)): - if is_less_one_day(idxs[i].freq): + if longer_or_shorter(idxs[i].freq, "D") == -1: idxs[i] = pd.date_range( start=idxs[i].min(), end=idxs[i].max(), freq="D" ) @@ -88,12 +90,12 @@ def indices( if ignore_freq is True: # Find the smallest frequency - smallest_freq = min(idxs, key=lambda x: freq_to_timestamp(x.freq)).freq + smallest_freq = shortest(*[x.freq for x in idxs]) # change bigger freq into small one for i in range(len(idxs)): start = idxs[i].min() end = idxs[i].max() - if is_less_one_day(smallest_freq): + if longer_or_shorter(smallest_freq, "D") == -1: end = end + pd.Timedelta(hours=23, minutes=59, seconds=59) idxs[i] = pd.date_range(start, end, freq=smallest_freq) @@ -119,20 +121,6 @@ def indices( return pd.DatetimeIndex(sorted(list(values)), freq=freq, name=name, tz=tz) -def is_less_one_day(dateoffset): - """Returns True if frequency is shorter than daily - otherwise, returns False.""" - ts = pd.Timestamp("1990-01-01") - day = pd.tseries.offsets.DateOffset(days=1) - return (ts + dateoffset) < (ts + day) - - -def freq_to_timestamp(dateoffset): - """Transform frequency (f.e. "15T") into timestamp to enable comparison between frequencies""" - ts = pd.Timestamp("1990-01-01") - return ts + dateoffset - - def frames( *frames: Union[pd.Series, pd.DataFrame] ) -> List[Union[pd.Series, pd.DataFrame]]: From 5a7d3f21e947f37935e5c330cbda4c419e505a4e Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 5 Feb 2024 12:14:17 +0100 Subject: [PATCH 38/59] intersect_flex function is finished, more testing with frames needed --- dev_scripts/heaviness.py | 18 ++ dev_scripts/intersect_test.py | 93 +++++++-- dev_scripts/noncalender_freq_test.py | 5 + dev_scripts/plot_test.py | 2 +- dev_scripts/slice_test.py | 6 +- docs/core/pfline.rst | 29 ++- portfolyo/__init__.py | 1 + portfolyo/core/ndframelike.py | 5 +- portfolyo/core/pfline/concat.py | 0 portfolyo/core/pfline/flat_methods.py | 5 +- portfolyo/core/pfline/nested_methods.py | 2 +- portfolyo/dev/develop.py | 16 -- portfolyo/tools/intersect.py | 200 +++++++++++++------ portfolyo/visualize/plot.py | 7 +- tests/core/pfline/test_slice.py | 69 +++++-- tests/core/pfstate/test_slice_state.py | 43 +++++ tests/tools/test_intersect.py | 81 +------- tests/tools/test_intersect_flex.py | 244 ++++++++++++++++++++++++ 18 files changed, 632 insertions(+), 194 deletions(-) create mode 100644 dev_scripts/heaviness.py create mode 100644 dev_scripts/noncalender_freq_test.py create mode 100644 portfolyo/core/pfline/concat.py create mode 100644 tests/tools/test_intersect_flex.py diff --git a/dev_scripts/heaviness.py b/dev_scripts/heaviness.py new file mode 100644 index 0000000..c01fd8d --- /dev/null +++ b/dev_scripts/heaviness.py @@ -0,0 +1,18 @@ +# import cProfile +# import portfolyo + + +# def main(): +# # Your code here +# pass + + +# if __name__ == "__main__": +# cProfile.run("main()", sort="cumulative") + +import timeit + +t = timeit.Timer("import portfolyo") +print(t.timeit(number=1000000)) +t2 = timeit.Timer("import pandas") +print(t2.timeit(number=1000000)) diff --git a/dev_scripts/intersect_test.py b/dev_scripts/intersect_test.py index 9c09a08..7a3e4a3 100644 --- a/dev_scripts/intersect_test.py +++ b/dev_scripts/intersect_test.py @@ -2,19 +2,80 @@ from portfolyo import tools -# create a and b with different frequencies -# create c with the same freq as a -# look how a intersect c behaves - - -a = pd.date_range("2020-01-01", "2022-02-02", freq="15T") -b = pd.date_range("2020-01-20", "2022-02-02", freq="D") -c = pd.date_range("2021-01-01", "2024-01-01", freq="QS") -d = pd.date_range("2022-04-01", "2024-07-01", freq="AS") -intersect = tools.intersect.indices(a, b, ignore_freq=True) -# intersect2 = tools.intersect.indices(a, c) -# intersect3 = tools.intersect.indices(b, d) -print(intersect) -# print("\n") -# print(intersect2) -# print(intersect == intersect3) + +def freq(): + # ignore freq + a = pd.date_range( + "2022-04-01", + "2024-07-01", + freq="QS", + tz="Asia/Kolkata", + inclusive="left", + ) + b = pd.date_range( + "2021-01-01", + "2024-01-01", + freq="AS", + inclusive="left", + ) + intersect = tools.intersect.indices_flex(a, b, ignore_freq=True, ignore_tz=True) + print(intersect) + + +def start_day(): + a = pd.date_range( + "2022-04-01 00:00", "2022-05-10 00:00", freq="D", inclusive="left" + ) + b = pd.date_range( + "2022-04-01 06:00", "2022-07-15 06:00", freq="D", inclusive="left" + ) + intersect = tools.intersect.indices_flex(a, b, ignore_start_of_day=True) + print(intersect) + + +def tz(): + a = pd.date_range( + "2022-04-01 00:00", + "2022-05-10 00:00", + freq="H", + tz="Europe/Berlin", + inclusive="left", + ) + b = pd.date_range( + "2022-04-25 00:00", + "2022-05-15 00:00", + freq="H", + tz="Europe/Berlin", + inclusive="left", + ) + intersect = tools.intersect.indices_flex( + a, b, ignore_tz=True, ignore_start_of_day=True + ) + print(intersect) + + +def all(): + a = pd.date_range( + "2022-01-01 00:00", + "2023-01-01 00:00", + freq="15T", + tz="Asia/Kolkata", + inclusive="left", + ) + b = pd.date_range( + "2022-01-20 06:00", + "2023-01-01 06:00", + freq="H", + tz=None, + inclusive="left", + ) + intersect = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_tz=True, ignore_start_of_day=True + ) + print(intersect) + + +# tz() +# start_day() +# freq() +all() diff --git a/dev_scripts/noncalender_freq_test.py b/dev_scripts/noncalender_freq_test.py new file mode 100644 index 0000000..344b33b --- /dev/null +++ b/dev_scripts/noncalender_freq_test.py @@ -0,0 +1,5 @@ +import portfolyo as pf + +index = pf.dev.get_index(freq="D") +pfl1 = pf.dev.get_flatpfline(index) +pfl2 = pfl1.asfreq("AS-APR") diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index a9f7cfc..606206e 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -64,4 +64,4 @@ def plot_pfline_to_ax(value: str, how: str, children: int = 1): plt.show() -plot_pfline_to_ax("w", "bar", 4) +plot_pfline_to_ax("q", "hline", 4) diff --git a/dev_scripts/slice_test.py b/dev_scripts/slice_test.py index 5421c15..4f6c5bf 100644 --- a/dev_scripts/slice_test.py +++ b/dev_scripts/slice_test.py @@ -1,7 +1,7 @@ import portfolyo as pf import pandas as pd -index = pd.date_range("2020", "2024", freq="QS") +index = pd.date_range("2020", "2024", freq="QS", inclusive="left") # FlatPfline @@ -49,6 +49,6 @@ def state_test(): print(pfs_to_concat == pfs_to_concat2) -# flat_test() +flat_test() # nested_test() -state_test() +# state_test() diff --git a/docs/core/pfline.rst b/docs/core/pfline.rst index e3a8678..0bf29bb 100644 --- a/docs/core/pfline.rst +++ b/docs/core/pfline.rst @@ -252,6 +252,28 @@ Index slice From ``pandas`` we know the ``.loc[]`` property which allows us to select a slice of the objects. This is implemented also for portfolio lines. Currently, it supports enering a slice of timestamps. It is a wrapper around the ``pandas.DataFrame.loc[]`` property, and therefore follows the same convention, with the end point being included in the result. +Another slicing method is implemented with the ``.slice[]`` property. The improvement to ``.loc[]`` is, that ``.slice[]`` uses the more common convention of excluding the end point. This has several advantages, which stem from the fact that, unlike when using ``.loc``, using ``left = pfl.slice[:a]`` and ``right = pfl.slice[a:]`` returns portfolio lines that are complements - every timestamp in the original portfolio line is found in either the left or the right slice. This is useful when e.g. concatenating portfolio lines (see below.) + +.. exec_code:: + + # --- hide: start --- + import portfolyo as pf, pandas as pd + index = pd.date_range('2024', freq='AS', periods=3) + input_df = pd.DataFrame({'w':[200, 220, 300], 'p': [100, 150, 200]}, index) + pfl = pf.PfLine(input_df) + # --- hide: stop --- + # continuation of previous code example + pfl.slice['2024':'2026'] # excludes 2026; 2026 interpreted as timestamp 2026-01-01 00:00:00 + # --- hide: start --- + print(pfl.slice['2024':'2026']) + # --- hide: stop --- + + +Concatenation +============= + +Portfolio lines can be concatenated with the ``portfolio.concat()`` function. This only works if the input portfolio lines have contain compatible information (the same frequency, timezone, start-of-day, kind, etc) and, crucially, their indices are gapless and without overlap. To remove any overlap, use the ``.slice[]`` property. + .. exec_code:: # --- hide: start --- @@ -261,9 +283,12 @@ From ``pandas`` we know the ``.loc[]`` property which allows us to select a slic pfl = pf.PfLine(input_df) # --- hide: stop --- # continuation of previous code example - pfl.loc['2024':'2025'] # includes 2025 + index2 = pd.date_range('2025', freq='AS', periods=3) # 2 years' overlap with pfl + pfl2 = pf.PfLine(pd.DataFrame({'w':[22, 30, 40], 'p': [15, 20, 21]}, index)) + # first two datapoints (until/excl 2026) from pfl, last two datapoints (from/incl 2026) from pfl2 + pf.concat([pfl.slice[:'2026'], pfl2.slice['2026':]]) # --- hide: start --- - print(pfl.loc['2024':'2025']) + print(pf.concat([pfl.slice[:'2026'], pfl2.slice['2026':]])) # --- hide: stop --- diff --git a/portfolyo/__init__.py b/portfolyo/__init__.py index a10d888..8add0e2 100644 --- a/portfolyo/__init__.py +++ b/portfolyo/__init__.py @@ -16,6 +16,7 @@ from .tools.unit import Q_, ureg, Unit from .tools.wavg import general as wavg + VOLUME = Kind.VOLUME PRICE = Kind.PRICE REVENUE = Kind.REVENUE diff --git a/portfolyo/core/ndframelike.py b/portfolyo/core/ndframelike.py index bf0f98a..60f4aa0 100644 --- a/portfolyo/core/ndframelike.py +++ b/portfolyo/core/ndframelike.py @@ -44,9 +44,8 @@ def loc(self): @abc.abstractproperty def slice(self): - """Create a new instance with a subset of the rows (selection by row label(s) or - a boolean array.) - Different from loc since performs slicing with right-open interval""" + """Create a new instance with a subset of the rows. + Different from loc since performs slicing with right-open interval.""" ... @abc.abstractmethod diff --git a/portfolyo/core/pfline/concat.py b/portfolyo/core/pfline/concat.py new file mode 100644 index 0000000..e69de29 diff --git a/portfolyo/core/pfline/flat_methods.py b/portfolyo/core/pfline/flat_methods.py index 9ba10dc..155ff0f 100644 --- a/portfolyo/core/pfline/flat_methods.py +++ b/portfolyo/core/pfline/flat_methods.py @@ -51,7 +51,7 @@ def __getitem__(self, arg) -> FlatPfLine: class SliceIndexer: """Helper class to obtain FlatPfLine instance, whose index is subset of original index. - Exclude end index from the slice""" + Exclude end point from the slice.""" def __init__(self, pfl: FlatPfLine): self.pfl = pfl @@ -64,7 +64,4 @@ def __getitem__(self, arg) -> FlatPfLine: date_end = date_end - timedelta(seconds=1) newdf = self.pfl.df.loc[date_start:date_end] - # newdf = self.pfl.df.loc[arg] - # if arg.stop is not None: - # newdf = newdf.iloc[:-1] return self.pfl.__class__(newdf) # use same (leaf) class diff --git a/portfolyo/core/pfline/nested_methods.py b/portfolyo/core/pfline/nested_methods.py index 3eff30b..33d37b1 100644 --- a/portfolyo/core/pfline/nested_methods.py +++ b/portfolyo/core/pfline/nested_methods.py @@ -55,7 +55,7 @@ def __getitem__(self, arg) -> NestedPfLine: class SliceIndexer: """Helper class to obtain NestedPfLine instance, whose index is subset of original index. - Exclude end index from the slice""" + Exclude end point from the slice.""" def __init__(self, pfl: NestedPfLine): self.pfl = pfl diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index 8299fed..ad1be3d 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -320,22 +320,6 @@ def get_pfstate(i: pd.DatetimeIndex = None, avg=None, *, _seed: int = None) -> P return PfState.from_series(wo=wo, pu=pu, ws=ws, ps=ps) -def get_nested_pfstate( - i: pd.DatetimeIndex = None, avg=None, *, _seed: int = None -) -> PfState: - """Get portfolio state.""" - if i is None: - i = get_index(_seed=_seed) - if _seed: - np.random.seed(_seed) - if avg is None: - avg = 200 ** np.random.rand() # between 1 and 200 - wo = -1 * mockup.w_offtake(i, avg) - pu = mockup.p_marketprices(i) - ws, ps = mockup.wp_sourced(wo) - return PfState.from_pfline(wo=wo, pu=pu, ws=ws, ps=ps) - - def get_pfstates( i: pd.DatetimeIndex = None, num=3, *, _seed: int = None ) -> Dict[str, PfState]: diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index 9804148..63efa0b 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -1,16 +1,12 @@ -from typing import List, Union +from typing import List, Union, Tuple import pandas as pd -from portfolyo.tools.freq import longer_or_shorter, shortest +from portfolyo.tools.freq import longest +from datetime import datetime -def indices( - *idxs: pd.DatetimeIndex, - ignore_freq: bool = False, - ignore_tz: bool = False, - ignore_start_of_day: bool = False, -) -> pd.DatetimeIndex: +def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: """Intersect several DatetimeIndices. Parameters @@ -18,20 +14,6 @@ def indices( *idxs : pd.DatetimeIndex The indices to intersect. - ignore_freq: bool - Ignore the frequencies of indices, perform an intersection. - Return the result with the frequencies of the first index from the list. - - ignore_tz: bool - Ignore the timezones of indices, perform an intersection. - Return the result with the timezone of the first index from the list. - - ignore_start_of_day: bool - Ignore the start of the day of indices, perform an intersection. - Return the result with start_of_day time of the first index from the list. - If frequencies are shorter then daily, transforms it into daily freq. - - Returns ------- pd.DatetimeIndex @@ -45,6 +27,74 @@ def indices( if len(idxs) == 0: raise ValueError("Must specify at least one index.") + if len(idxs) == 1: + return idxs[0] + + # If we land here, we have at least 2 indices. + + distinct_freqs = set([i.freq for i in idxs]) + if len(distinct_freqs) != 1: + raise ValueError(f"Indices must have equal frequencies; got {distinct_freqs}.") + + distinct_tzs = set([i.tz for i in idxs]) + if len(distinct_tzs) != 1: + raise ValueError(f"Indices must have equal timezones; got {distinct_tzs}.") + + freq, name, tz = idxs[0].freq, idxs[0].name, idxs[0].tz + + empty_idx = [len(i) == 0 for i in idxs] + if any(empty_idx): + return pd.DatetimeIndex([], freq=freq, tz=tz, name=name) + + # If we land here, we have at least 2 indices, all are not empty, with equal tz and freq. + + distinct_sod = set([i[0].time() for i in idxs]) + if len(distinct_sod) != 1: + raise ValueError(f"Indices must have equal start-of-day; got {distinct_sod}.") + + # Calculation is cumbersome: pandas DatetimeIndex.intersection not working correctly on timezone-aware indices (#46702) + values = set(idxs[0]) + for i in idxs[1:]: + values = values.intersection(set(i)) + + return pd.DatetimeIndex(sorted(list(values)), freq=freq, name=name, tz=tz) + + +def indices_flex( + *idxs: pd.DatetimeIndex, + ignore_freq: bool = False, + ignore_tz: bool = False, + ignore_start_of_day: bool = False, +) -> Tuple[pd.DatetimeIndex]: + """Intersect several DatetimeIndices, but allow for more flexibility of ignoring + certain properties. + + Parameters + ---------- + *idxs : pd.DatetimeIndex + The indices to intersect. + ignore_freq: bool, optional (default: False) + If True, do the intersection even if the frequencies do not match; drop the + time periods that do not (fully) exist in either of the frames. + ignore_tz: bool, optional (default: False) + If True, ignore the timezones; perform the intersection using 'wall time'. + ignore_start_of_day: bool, optional (default: False) + If True, perform the intersection even if the frames have a different start-of-day. + The start-of-day of the original frames is preserved, even if the frequency is shorter + than daily. + + Returns + ------- + Tuple[pd.DatetimeIndex] + The intersection for each datetimeindex (in same order as input idxs). + + See also + -------- + indices + """ + if len(idxs) == 0: + raise ValueError("Must specify at least one index.") + if len(idxs) == 1: return idxs[0] # convert tuple object into a list @@ -59,11 +109,15 @@ def indices( if len(distinct_tzs) != 1 and ignore_tz is False: raise ValueError(f"Indices must have equal timezones; got {distinct_tzs}.") - freq, name, tz = (idxs[0].freq, idxs[0].name, idxs[0].tz) + freq, name, tz = [], [], [] + for i in range(len(idxs)): + freq.append(idxs[i].freq) + name.append(idxs[i].name) + tz.append(idxs[i].tz) empty_idx = [len(i) == 0 for i in idxs] if any(empty_idx): - return pd.DatetimeIndex([], freq=freq, tz=tz, name=name) + return pd.DatetimeIndex([]) # If we land here, we have at least 2 indices, all are not empty, with equal tz and freq. @@ -71,6 +125,25 @@ def indices( if len(distinct_sod) != 1 and ignore_start_of_day is False: raise ValueError(f"Indices must have equal start-of-day; got {distinct_sod}.") + # add one interval of the respective freq to each index (this way, a given date-range from A-B that was exclusive + # of B is now inclusive of B - this helps when we need to convert frequencies or times-of-day without loosing + # data. At the end, we exclude the end-date of the final result again.) + idxs = [ + idx.append( + pd.DatetimeIndex([idx[-1] + pd.tseries.frequencies.to_offset(idx.freq)]) + ) + for idx in idxs + ] + + if ignore_freq is True: + # Find the smallest frequency + biggest_freq = longest(*freq) + # change bigger freq into small one + for i in range(len(idxs)): + start = idxs[i].min() + end = idxs[i].max() + idxs[i] = pd.date_range(start, end, freq=biggest_freq, inclusive="both") + if ignore_tz is True: # set timezone to none for all values for i in range(len(idxs)): @@ -78,51 +151,48 @@ def indices( if ignore_start_of_day is True: # Save a copy of the original hours and minutes - start_of_day = idxs[0][0].time() - for i in range(len(idxs)): - if longer_or_shorter(idxs[i].freq, "D") == -1: - idxs[i] = pd.date_range( - start=idxs[i].min(), end=idxs[i].max(), freq="D" - ) - freq = "D" + start_of_day = [x[0].time() for x in idxs] # Set the time components to midnight for each timestamp in the list idxs = [timestamp.normalize() for timestamp in idxs] - if ignore_freq is True: - # Find the smallest frequency - smallest_freq = shortest(*[x.freq for x in idxs]) - # change bigger freq into small one - for i in range(len(idxs)): - start = idxs[i].min() - end = idxs[i].max() - if longer_or_shorter(smallest_freq, "D") == -1: - end = end + pd.Timedelta(hours=23, minutes=59, seconds=59) - idxs[i] = pd.date_range(start, end, freq=smallest_freq) - # Calculation is cumbersome: pandas DatetimeIndex.intersection not working correctly on timezone-aware indices (#46702) values = set(idxs[0]) for i in idxs[1:]: values = values.intersection(set(i)) - if ignore_start_of_day is True: - for timestamp in values.copy(): - new_timestamp = timestamp.replace( - hour=start_of_day.hour, minute=start_of_day.minute + if len(values) == 0: + return tuple([pd.DatetimeIndex([]) for _i in idxs]) + + idxs_out = [] + for i in range(len(idxs)): + start = min(values) + end = max(values) + inclusive = "left" + + if ignore_start_of_day is True: + start = datetime.combine(pd.to_datetime(start).date(), start_of_day[i]) + end = datetime.combine(pd.to_datetime(end).date(), start_of_day[i]) + # inclusive = "left" + + idxs_out.append( + pd.date_range( + start=start, + end=end, + freq=freq[i], + name=name[i], + tz=tz[i], + inclusive=inclusive, ) - values.remove(timestamp) - values.add(new_timestamp) + ) - # values turn into timestampt - # add saved start of the day to all of them - # change back into datatimeindex - if len(values) > 0: - values = pd.date_range(start=min(values), end=max(values), freq=freq, tz=tz) - - return pd.DatetimeIndex(sorted(list(values)), freq=freq, name=name, tz=tz) + return tuple(idxs_out) def frames( - *frames: Union[pd.Series, pd.DataFrame] + *frames: Union[pd.Series, pd.DataFrame], + ignore_freq: bool = False, + ignore_tz: bool = False, + ignore_start_of_day: bool = False, ) -> List[Union[pd.Series, pd.DataFrame]]: """Intersect several dataframes and/or series. @@ -130,6 +200,15 @@ def frames( ---------- *frames : pd.Series and/or pd.DataFrame The frames to intersect. + ignore_freq: bool, optional (default: False) + If True, do the intersection even if the frequencies do not match; drop the + time periods that do not (fully) exist in either of the frames. + ignore_tz: bool, optional (default: False) + If True, ignore the timezones; perform the intersection using 'wall time'. + ignore_start_of_day: bool, optional (default: False) + If True, perform the intersection even if the frames have a different start-of-day. + The start-of-day of the original frames is preserved, even if the frequency is shorter + than daily. Returns ------- @@ -141,5 +220,10 @@ def frames( The indices must have equal frequency, timezone, start-of-day. Otherwise, an error is raised. If there is no overlap, empty frames are returned. """ - common_index = indices(*[fr.index for fr in frames]) - return [fr.loc[common_index] for fr in frames] + new_idx = indices_flex( + *[fr.index for fr in frames], + ignore_freq=ignore_freq, + ignore_tz=ignore_tz, + ignore_start_of_day=ignore_start_of_day, + ) + return [fr.loc[idx] for idx, fr in zip(new_idx, frames)] diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index abc5793..feacf72 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -247,15 +247,12 @@ def get_portfolyo_attr(ax, name, default_val=None): Gets values from dictionary ax._portfolyo, if it doesn't exist returns None. """ pattr = getattr(ax, "_portfolyo", {}) - return pattr[name] if name in pattr else default_val + return pattr.get(name, default_val) def is_categorical(s: pd.Series) -> bool: """The function checks whether frequency of panda Series falls into continous or categorical group""" - if s.index.freq in ["AS", "QS", "MS"]: - return True - else: - return False + return s.index.freq in ["AS", "QS", "MS"] def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: diff --git a/tests/core/pfline/test_slice.py b/tests/core/pfline/test_slice.py index 19eccf8..d7b76e2 100644 --- a/tests/core/pfline/test_slice.py +++ b/tests/core/pfline/test_slice.py @@ -7,40 +7,85 @@ @pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) @pytest.mark.parametrize("slice_start", ["2021", "2022", "2022-01-02"]) +def test_flat_slice_start(slice_start, freq): + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfl1 = dev.get_flatpfline(index) + assert pfl1.slice[slice_start:] == pfl1.loc[slice_start:] + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) @pytest.mark.parametrize( "slice_end", [ # (, ) ("2021", "2020"), ("2022", "2021"), + ("2021-07", "2021-06"), ("2022-01-02", "2022-01-01"), ], ) -def test_flat_slice(slice_start, slice_end, freq): - index = pd.date_range("2020", "2024", freq=freq) +def test_flat_slice_end(slice_end, freq): + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") pfl1 = dev.get_flatpfline(index) + assert pfl1.slice[: slice_end[0]] == pfl1.loc[: slice_end[1]] - pfls_to_concat = [pfl1.slice[: slice_end[0]], pfl1.slice[slice_start:]] - pfls_to_concat2 = [pfl1.loc[: slice_end[1]], pfl1.loc[slice_start:]] - assert pfls_to_concat == pfls_to_concat2 + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize( + "where", + ["2022", "2022-03", "2022-04-21", "2022-05-23 14:34"], +) +def test_flat_slice_whole(where: str, freq: str): + """Test that slicing splits the pfl in 2 non-overlapping pieces without gap + (i.e., ensure that each original timestamp is in exactly one of the resulting pieces.) + """ + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfl1 = dev.get_flatpfline(index) + left, right = pfl1.slice[:where], pfl1.slice[where:] + # Test that each timestamp is present at least once. + pd.testing.assert_index_equal(left.index.union(right.index), index) + # Test that no timestamp is present twice. + assert len(left.index.intersection(right.index)) == 0 @pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) @pytest.mark.parametrize("slice_start", ["2021", "2022", "2022-01-02"]) -@pytest.mark.parametrize("children", [1, 2, 3, 4]) +def test_nested_slice_start(slice_start, freq): + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfl1 = dev.get_nestedpfline(index) + assert pfl1.slice[slice_start:] == pfl1.loc[slice_start:] + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) @pytest.mark.parametrize( "slice_end", [ # (, ) ("2021", "2020"), ("2022", "2021"), + ("2021-07", "2021-06"), ("2022-01-02", "2022-01-01"), ], ) -def test_nested_slice(slice_start, slice_end, freq, children): - index = pd.date_range("2020", "2024", freq=freq) - pfl1 = dev.get_nestedpfline(index, childcount=children) +def test_nested_slice_end(slice_end, freq): + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfl1 = dev.get_nestedpfline(index) + assert pfl1.slice[: slice_end[0]] == pfl1.loc[: slice_end[1]] - pfls_to_concat = [pfl1.slice[: slice_end[0]], pfl1.slice[slice_start:]] - pfls_to_concat2 = [pfl1.loc[: slice_end[1]], pfl1.loc[slice_start:]] - assert pfls_to_concat == pfls_to_concat2 + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize( + "where", + ["2022", "2022-03", "2022-04-21", "2022-05-23 14:34"], +) +def test_nested_slice_whole(where: str, freq: str): + """Test that slicing splits the pfl in 2 non-overlapping pieces without gap + (i.e., ensure that each original timestamp is in exactly one of the resulting pieces.) + """ + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfl1 = dev.get_nestedpfline(index) + left, right = pfl1.slice[:where], pfl1.slice[where:] + # Test that each timestamp is present at least once. + pd.testing.assert_index_equal(left.index.union(right.index), index) + # Test that no timestamp is present twice. + assert len(left.index.intersection(right.index)) == 0 diff --git a/tests/core/pfstate/test_slice_state.py b/tests/core/pfstate/test_slice_state.py index 53aef7b..6a5a960 100644 --- a/tests/core/pfstate/test_slice_state.py +++ b/tests/core/pfstate/test_slice_state.py @@ -23,3 +23,46 @@ def test_slice_state(slice_start, slice_end, freq): pfs_to_concat = [pfs.slice[: slice_end[0]], pfs.slice[slice_start:]] pfs_to_concat2 = [pfs.loc[: slice_end[1]], pfs.loc[slice_start:]] assert pfs_to_concat == pfs_to_concat2 + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize("slice_start", ["2021", "2022", "2022-01-02"]) +def test_state_slice_start(slice_start, freq): + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfs = dev.get_pfstate(index) + assert pfs.slice[slice_start:] == pfs.loc[slice_start:] + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize( + "slice_end", + [ + # (, ) + ("2021", "2020"), + ("2022", "2021"), + ("2021-07", "2021-06"), + ("2022-01-02", "2022-01-01"), + ], +) +def test_state_slice_end(slice_end, freq): + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfs = dev.get_pfstate(index) + assert pfs.slice[: slice_end[0]] == pfs.loc[: slice_end[1]] + + +@pytest.mark.parametrize("freq", ["MS", "AS", "QS", "D", "15T"]) +@pytest.mark.parametrize( + "where", + ["2022", "2022-03", "2022-04-21", "2022-05-23 14:34"], +) +def test_state_slice_whole(where: str, freq: str): + """Test that slicing splits the pfl in 2 non-overlapping pieces without gap + (i.e., ensure that each original timestamp is in exactly one of the resulting pieces.) + """ + index = pd.date_range("2020", "2024", freq=freq, inclusive="left") + pfs = dev.get_pfstate(index) + left, right = pfs.slice[:where], pfs.slice[where:] + # Test that each timestamp is present at least once. + pd.testing.assert_index_equal(left.index.union(right.index), index) + # Test that no timestamp is present twice. + assert len(left.index.intersection(right.index)) == 0 diff --git a/tests/tools/test_intersect.py b/tests/tools/test_intersect.py index 8b95648..fbb83f4 100644 --- a/tests/tools/test_intersect.py +++ b/tests/tools/test_intersect.py @@ -85,7 +85,6 @@ def test_intersect( @pytest.mark.parametrize("indexorframe", ["idx", "fr"]) @pytest.mark.parametrize("starttime", ["00:00", "06:00"]) @pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("ignore_freq", [True, False]) def test_intersect_distinctfreq( indexorframe: str, startdates: Iterable[str], @@ -93,7 +92,6 @@ def test_intersect_distinctfreq( tz: str, freq: str, expected_startdate: str, - ignore_freq: bool, ): """Test if intersection of indices with distinct frequencies gives correct result.""" otherfreq = "H" if freq == "D" else "D" @@ -101,25 +99,13 @@ def test_intersect_distinctfreq( get_idx(startdates[0], starttime, tz, freq), get_idx(startdates[1], starttime, tz, otherfreq), ] - if ignore_freq and indexorframe == "idx": - do_test_intersect( - indexorframe, - idxs, - expected_startdate, - expected_tz=tz, - expected_freq=freq, - expected_starttime=starttime, - ignore_freq=ignore_freq, - ) - else: - do_test_intersect(indexorframe, idxs, ValueError) + do_test_intersect(indexorframe, idxs, ValueError) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize("indexorframe", ["idx", "fr"]) @pytest.mark.parametrize("starttime", ["00:00", "06:00"]) @pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("ignore_tz", [True, False]) def test_intersect_distincttz( indexorframe: str, startdates: Iterable[str], @@ -127,7 +113,6 @@ def test_intersect_distincttz( tz: str, freq: str, expected_startdate: str, - ignore_tz: bool, ): """Test if intersection of indices with distinct timezones gives correct result.""" othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" @@ -135,25 +120,13 @@ def test_intersect_distincttz( get_idx(startdates[0], starttime, tz, freq), get_idx(startdates[1], starttime, othertz, freq), ] - if ignore_tz and indexorframe == "idx": - do_test_intersect( - indexorframe, - idxs, - expected_startdate, - expected_tz=tz, - expected_freq=freq, - expected_starttime=starttime, - ignore_tz=ignore_tz, - ) - else: - do_test_intersect(indexorframe, idxs, ValueError) + do_test_intersect(indexorframe, idxs, ValueError) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize("indexorframe", ["idx", "fr"]) @pytest.mark.parametrize("starttime", ["00:00", "06:00"]) @pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("ignore_start_of_day", [True, False]) def test_intersect_distinctstartofday( indexorframe: str, startdates: Iterable[str], @@ -161,7 +134,6 @@ def test_intersect_distinctstartofday( tz: str, freq: str, expected_startdate: str, - ignore_start_of_day: bool, ): """Test if intersection of indices with distinct frequencies gives correct result.""" otherstarttime = "00:00" if starttime == "06:00" else "06:00" @@ -169,18 +141,7 @@ def test_intersect_distinctstartofday( get_idx(startdates[0], starttime, tz, freq), get_idx(startdates[1], otherstarttime, tz, freq), ] - if ignore_start_of_day and indexorframe == "idx": - do_test_intersect( - indexorframe, - idxs, - expected_startdate, - expected_tz=tz, - expected_freq=freq if (freq != "15T" and freq != "H") else "D", - expected_starttime=starttime, - ignore_start_of_day=ignore_start_of_day, - ) - else: - do_test_intersect(indexorframe, idxs, ValueError) + do_test_intersect(indexorframe, idxs, ValueError) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @@ -203,25 +164,12 @@ def do_test_intersect( expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, - ignore_start_of_day: bool = False, - ignore_tz: bool = False, - ignore_freq: bool = False, ): if indexorframe == "idx": - do_test_intersect_index( - idxs, - expected_startdate, - expected_starttime, - expected_tz, - expected_freq, - ignore_start_of_day, - ignore_tz, - ignore_freq, - ) + do_test_fn = do_test_intersect_index else: - do_test_intersect_frame( - idxs, expected_startdate, expected_starttime, expected_tz, expected_freq - ) + do_test_fn = do_test_intersect_frame + do_test_fn(idxs, expected_startdate, expected_starttime, expected_tz, expected_freq) def do_test_intersect_index( @@ -230,29 +178,16 @@ def do_test_intersect_index( expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, - ignore_start_of_day: bool = False, - ignore_tz: bool = False, - ignore_freq: bool = False, ): # Error case. if isinstance(expected_startdate, type) and issubclass( expected_startdate, Exception ): with pytest.raises(expected_startdate): - tools.intersect.indices( - *idxs, - ignore_start_of_day=ignore_start_of_day, - ignore_tz=ignore_tz, - ignore_freq=ignore_freq, - ) + tools.intersect.indices(*idxs) return # Normal case. - result = tools.intersect.indices( - *idxs, - ignore_start_of_day=ignore_start_of_day, - ignore_tz=ignore_tz, - ignore_freq=ignore_freq, - ) + result = tools.intersect.indices(*idxs) expected = get_idx( expected_startdate, expected_starttime, expected_tz, expected_freq ) diff --git a/tests/tools/test_intersect_flex.py b/tests/tools/test_intersect_flex.py new file mode 100644 index 0000000..822dc39 --- /dev/null +++ b/tests/tools/test_intersect_flex.py @@ -0,0 +1,244 @@ +import pandas as pd +import pytest + +from portfolyo import testing, tools + + +COMMON_END = "2022-02-02" + +TESTCASES = [ # startdates, freq, expected_startdate + # One starts at first day of year. + (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), + (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), + (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), + (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), + (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), + (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), + (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), + # Both start in middle of year. + (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), +] + +COMMON_END_2 = "2023-01-01" +TESTCASES_2 = [ # startdates, freq, expected_dates + # One starts at first day of year. + (("2020-01-01", "2020-01-20"), ("15T", "H"), ("2020-01-20", "2023-01-01")), + (("2020-01-01", "2020-01-20"), ("15T", "D"), ("2020-01-20", "2023-01-01")), + (("2022-04-01", "2021-02-01"), ("H", "MS"), ("2022-04-01", "2023-01-01")), + (("2020-01-01", "2020-04-01"), ("H", "QS"), ("2020-04-01", "2023-01-01")), + (("2020-01-01", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), + # Both start in middle of year. + (("2020-04-21", "2020-06-20"), ("15T", "H"), ("2020-06-20", "2023-01-01")), + (("2020-04-21", "2020-06-20"), ("15T", "D"), ("2020-06-20", "2023-01-01")), + (("2020-04-21", "2020-07-01"), ("H", "MS"), ("2020-07-01", "2023-01-01")), + (("2020-04-21", "2020-07-01"), ("H", "QS"), ("2020-07-01", "2023-01-01")), + (("2020-04-21", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), +] + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) +def test_intersect_flex_ignore_start_of_day( + tz, startdates, freq, starttime, expected_startdate +): + otherstarttime = "00:00" if starttime == "06:00" else "06:00" + a = pd.date_range( + f"{startdates[0]} {starttime}", + f"{COMMON_END} {starttime}", + freq=freq, + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {otherstarttime}", + f"{COMMON_END} {otherstarttime}", + freq=freq, + tz=tz, + inclusive="left", + ) + e = ( + pd.date_range( + f"{expected_startdate} {starttime}", + f"{COMMON_END} {starttime}", + freq=freq, + tz=tz, + inclusive="left", + ), + pd.date_range( + f"{expected_startdate} {otherstarttime}", + f"{COMMON_END} {otherstarttime}", + freq=freq, + tz=tz, + inclusive="left", + ), + ) + # Test error case. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex(a, b, ignore_start_of_day=False) + # Test ok case. + result = tools.intersect.indices_flex(a, b, ignore_start_of_day=True) + + for i in range(0, len(result)): + testing.assert_index_equal(result[i], e[i]) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) +def test_intersect_flex_ignore_tz(tz, startdates, freq, time_a, expected_startdate): + othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" + a = pd.date_range( + f"{startdates[0]} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=othertz, + inclusive="left", + ) + e = ( + pd.date_range( + f"{expected_startdate} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=tz, + inclusive="left", + ), + pd.date_range( + f"{expected_startdate} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=othertz, + inclusive="left", + ), + ) + # Test error case. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex(a, b, ignore_tz=False) + # Test ok case. + result = tools.intersect.indices_flex(a, b, ignore_tz=True) + + for i in range(0, len(result)): + testing.assert_index_equal(result[i], e[i]) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) +@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) +def test_intersect_flex_ignore_freq(tz, startdates, freq, time_a, expected_dates): + """Test if intersection of indices with distinct frequencies gives correct result.""" + a = pd.date_range( + f"{startdates[0]} {time_a}", + f"{COMMON_END_2} {time_a}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {time_a}", + f"{COMMON_END_2} {time_a}", + freq=freq[1], + tz=tz, + inclusive="left", + ) + expected_a = pd.date_range( + f"{expected_dates[0]} {time_a}", + f"{expected_dates[1]} {time_a}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + expected_b = pd.date_range( + f"{expected_dates[0]} {time_a}", + f"{expected_dates[1]} {time_a}", + freq=freq[1], + tz=tz, + inclusive="left", + ) + # Test error case. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex(a, b, ignore_freq=False) + + result_a, result_b = tools.intersect.indices_flex(a, b, ignore_freq=True) + + testing.assert_index_equal(result_a, expected_a) + testing.assert_index_equal(result_b, expected_b) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) +@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) +def test_ignore_all(tz, startdates, freq, starttime, expected_dates): + otherstarttime = "00:00" if starttime == "06:00" else "06:00" + othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" + a = pd.date_range( + f"{startdates[0]} {starttime}", + f"{COMMON_END_2} {starttime}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {otherstarttime}", + f"{COMMON_END_2} {otherstarttime}", + freq=freq[1], + tz=othertz, + inclusive="left", + ) + expected_a = pd.date_range( + f"{expected_dates[0]} {starttime}", + f"{expected_dates[1]} {starttime}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + expected_b = pd.date_range( + f"{expected_dates[0]} {otherstarttime}", + f"{expected_dates[1]} {otherstarttime}", + freq=freq[1], + tz=othertz, + inclusive="left", + ) + # Test error cases. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=False, ignore_start_of_day=False, ignore_tz=False + ) + + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=False, ignore_start_of_day=True, ignore_tz=True + ) + + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_start_of_day=False, ignore_tz=True + ) + + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=False + ) + + # Test ok case. + out_a, out_b = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=True + ) + testing.assert_index_equal(out_a, expected_a) + testing.assert_index_equal(out_b, expected_b) From a99e4fc60b518099c916c2906c34146dd09a1ded Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 5 Feb 2024 12:27:56 +0100 Subject: [PATCH 39/59] finished intersect_flex, more testing with frames needed --- dev_scripts/heaviness.py | 18 ---------- dev_scripts/noncalender_freq_test.py | 5 --- dev_scripts/slice_test.py | 54 ---------------------------- portfolyo/tools/intersect.py | 2 +- 4 files changed, 1 insertion(+), 78 deletions(-) delete mode 100644 dev_scripts/heaviness.py delete mode 100644 dev_scripts/noncalender_freq_test.py delete mode 100644 dev_scripts/slice_test.py diff --git a/dev_scripts/heaviness.py b/dev_scripts/heaviness.py deleted file mode 100644 index c01fd8d..0000000 --- a/dev_scripts/heaviness.py +++ /dev/null @@ -1,18 +0,0 @@ -# import cProfile -# import portfolyo - - -# def main(): -# # Your code here -# pass - - -# if __name__ == "__main__": -# cProfile.run("main()", sort="cumulative") - -import timeit - -t = timeit.Timer("import portfolyo") -print(t.timeit(number=1000000)) -t2 = timeit.Timer("import pandas") -print(t2.timeit(number=1000000)) diff --git a/dev_scripts/noncalender_freq_test.py b/dev_scripts/noncalender_freq_test.py deleted file mode 100644 index 344b33b..0000000 --- a/dev_scripts/noncalender_freq_test.py +++ /dev/null @@ -1,5 +0,0 @@ -import portfolyo as pf - -index = pf.dev.get_index(freq="D") -pfl1 = pf.dev.get_flatpfline(index) -pfl2 = pfl1.asfreq("AS-APR") diff --git a/dev_scripts/slice_test.py b/dev_scripts/slice_test.py deleted file mode 100644 index 4f6c5bf..0000000 --- a/dev_scripts/slice_test.py +++ /dev/null @@ -1,54 +0,0 @@ -import portfolyo as pf -import pandas as pd - -index = pd.date_range("2020", "2024", freq="QS", inclusive="left") - - -# FlatPfline -def flat_test(): - pfl1 = pf.dev.get_flatpfline(index) - # pfl2 = pf.dev.get_flatpfline(index) - # pfl3 = pfl1 - # pfl4 = pfl2 - # pfl1 = pfl1.loc[:"2021"] - # pfl3 = pfl2.slice[:"2022"] - # print("Loc version", pfl1) - # print("\n") - # print("Slice version", pfl3) - # print(pfl1 == pfl3) - pfls_to_concat = [pfl1.slice[:"2022"], pfl1.slice["2022":]] - pfls_to_concat2 = [pfl1.loc[:"2021"], pfl1.loc["2022":]] - - print("The slice version", pfls_to_concat) - print("\n") - print("Loc version", pfls_to_concat2) - print(pfls_to_concat == pfls_to_concat2) - - -def nested_test(): - pfl1 = pf.dev.get_nestedpfline(index, childcount=2) - pfl2 = pf.dev.get_nestedpfline(index, childcount=2) - - pfls_to_concat = [pfl1.slice[:"2022"], pfl2.slice["2022":]] - pfls_to_concat2 = [pfl1.loc[:"2021"], pfl2.loc["2022":]] - - print("The slice version", pfls_to_concat) - print("\n") - print("Loc version", pfls_to_concat2) - print(pfls_to_concat == pfls_to_concat2) - - -def state_test(): - pfs = pf.dev.get_pfstate(index) - pfs_to_concat2 = [pfs.loc[:"2021"], pfs.loc["2022":]] - pfs_to_concat = [pfs.slice[:"2022"], pfs.slice["2022":]] - - print("The slice version", pfs_to_concat) - print("\n") - print("Loc version", pfs_to_concat2) - print(pfs_to_concat == pfs_to_concat2) - - -flat_test() -# nested_test() -# state_test() diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index 63efa0b..03e6a9d 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -99,8 +99,8 @@ def indices_flex( return idxs[0] # convert tuple object into a list idxs = list(idxs) - # If we land here, we have at least 2 indices. + # If we land here, we have at least 2 indices. distinct_freqs = set([i.freq for i in idxs]) if len(distinct_freqs) != 1 and ignore_freq is False: raise ValueError(f"Indices must have equal frequencies; got {distinct_freqs}.") From 8957d9f63145455357c10b42b10408a8aa102f74 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Tue, 5 Mar 2024 13:06:17 +0100 Subject: [PATCH 40/59] added children bool to plot pfstate --- dev_scripts/intersect_test.py | 81 -------------------------- dev_scripts/plot_state.py | 16 ++++-- dev_scripts/plot_test.py | 2 +- portfolyo/core/mixins/plot.py | 105 ++++++++++++++-------------------- portfolyo/dev/develop.py | 2 +- setup.cfg | 2 +- 6 files changed, 59 insertions(+), 149 deletions(-) delete mode 100644 dev_scripts/intersect_test.py diff --git a/dev_scripts/intersect_test.py b/dev_scripts/intersect_test.py deleted file mode 100644 index 7a3e4a3..0000000 --- a/dev_scripts/intersect_test.py +++ /dev/null @@ -1,81 +0,0 @@ -import pandas as pd - -from portfolyo import tools - - -def freq(): - # ignore freq - a = pd.date_range( - "2022-04-01", - "2024-07-01", - freq="QS", - tz="Asia/Kolkata", - inclusive="left", - ) - b = pd.date_range( - "2021-01-01", - "2024-01-01", - freq="AS", - inclusive="left", - ) - intersect = tools.intersect.indices_flex(a, b, ignore_freq=True, ignore_tz=True) - print(intersect) - - -def start_day(): - a = pd.date_range( - "2022-04-01 00:00", "2022-05-10 00:00", freq="D", inclusive="left" - ) - b = pd.date_range( - "2022-04-01 06:00", "2022-07-15 06:00", freq="D", inclusive="left" - ) - intersect = tools.intersect.indices_flex(a, b, ignore_start_of_day=True) - print(intersect) - - -def tz(): - a = pd.date_range( - "2022-04-01 00:00", - "2022-05-10 00:00", - freq="H", - tz="Europe/Berlin", - inclusive="left", - ) - b = pd.date_range( - "2022-04-25 00:00", - "2022-05-15 00:00", - freq="H", - tz="Europe/Berlin", - inclusive="left", - ) - intersect = tools.intersect.indices_flex( - a, b, ignore_tz=True, ignore_start_of_day=True - ) - print(intersect) - - -def all(): - a = pd.date_range( - "2022-01-01 00:00", - "2023-01-01 00:00", - freq="15T", - tz="Asia/Kolkata", - inclusive="left", - ) - b = pd.date_range( - "2022-01-20 06:00", - "2023-01-01 06:00", - freq="H", - tz=None, - inclusive="left", - ) - intersect = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_tz=True, ignore_start_of_day=True - ) - print(intersect) - - -# tz() -# start_day() -# freq() -all() diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py index e9b0f44..16e6f68 100644 --- a/dev_scripts/plot_state.py +++ b/dev_scripts/plot_state.py @@ -1,20 +1,28 @@ import matplotlib.pyplot as plt import portfolyo as pf +from portfolyo import dev +from portfolyo.core.pfline.enums import Kind +from portfolyo.core.pfstate.pfstate import PfState """Plot PfState to test of adding axes for un/sourced prices.""" index = pf.dev.get_index(freq="D") + pfs = pf.dev.get_pfstate(index) pfs2 = pfs.asfreq("MS") - +offtakevolume = dev.get_nestedpfline(index, kind=Kind.VOLUME) +sourced = dev.get_nestedpfline(index, kind=Kind.COMPLETE) +unsourcedprice = dev.get_nestedpfline(index, kind=Kind.PRICE) +pfs3 = PfState(-1 * offtakevolume, unsourcedprice, sourced) # pfl2 = create.nestedpfline(index) # pfs3 = pf.dev.get_nested_pfstate(index) - - +offtakevolume2 = pfs3.offtakevolume +print(offtakevolume2) # sourced = pfs.sourcedprice # sourced.print() # pfl2.print() -pfs2.plot() + +pfs3.plot(children=True) plt.show() diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index 606206e..b123f05 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -64,4 +64,4 @@ def plot_pfline_to_ax(value: str, how: str, children: int = 1): plt.show() -plot_pfline_to_ax("q", "hline", 4) +plot_pfline_to_ax("q", "bar", 4) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index cfb9adf..45926e1 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -172,7 +172,7 @@ def get_stacked_offsets(self: PfLine, col: str) -> Dict[str, List[List[float]]]: return return_val - def get_children_with_colors(self: PfLine) -> List[Tuple(str, PfLine, vis.Color)]: + def get_children_with_colors(self: PfLine) -> List[Tuple[str, PfLine, vis.Color]]: # return a list of child columns with a color for each return [ (name, child, color_enum.value.lighten(0.5)) @@ -212,52 +212,7 @@ def plot_children(self: PfLine, col: str, ax: plt.Axes, is_category: bool) -> No class PfStatePlot: - # def plot_to_ax( - # self: PfState, ax: plt.Axes, line: str = "offtake", col: str = None, **kwargs - # ) -> None: - # """Plot a timeseries of a PfState in the portfolio state to a specific axes. - - # Parameters - # ---------- - # ax : plt.Axes - # The axes object to which to plot the timeseries. - # line : str, optional - # The pfline to plot. One of {'offtake' (default), 'sourced', 'unsourced', - # 'netposition', 'procurement', 'sourcedfraction'}. - # col : str, optional - # The column to plot. Default: plot volume `w` [MW] (if available) or else - # price `p` [Eur/MWh]. - # Any additional kwargs are passed to the pd.Series.plot function. - # """ - # if line == "offtake": - # how = DEFAULTHOW.get(col, "step") - # (-self.offtake).plot_to_ax(ax, col, how) - # ax.bar_label( - # ax.containers[0], label_type="edge", fmt="%,.0f".replace(",", " ") - # ) - - # elif line.endswith("sourcedfraction"): # (un)sourcedfraction - # fractions = getattr(self, line) - # vis.plot_timeseries(ax, fractions, how="bar", color="grey") - # ax.bar_label( - # ax.containers[0], - # label_type="edge", - # labels=fractions.apply("{:.0%}".format), - # ) # print labels on top of each bar - - # elif line == "sourced": - # self.sourced.plot_to_ax( - # ax, - # col, - # ) - # if col == "p": - - # vis.plot_timeseries(ax, self.unsourcedprice["p"], how="bar", alpha=0.0) - # ax.bar_label( - # ax.containers[0], label_type="center", fmt="%.2f" - # ) # print labels on top of each bar - - def plot(self: PfState) -> plt.Figure: + def plot(self: PfState, children: bool = False) -> plt.Figure: """Plot the portfolio state. Parameters @@ -282,28 +237,56 @@ def plot(self: PfState) -> plt.Figure: # If freq is MS or longer: use categorical axes. Plot volumes in MWh. # If freq is D or shorter: use time axes. Plot volumes in MW. is_category = tools.freq.shortest(self.index.freq, "MS") == "MS" - + so, ss, usv = ( + -1 * self.offtakevolume, + self.sourced, + self.unsourced, + ) + pr_kwargs = defaultkwargs("p", is_category) # Volumes. if is_category: - so, ss, usv = -1 * self.offtakevolume.q, self.sourced.q, self.unsourced.q kwargs = defaultkwargs("q", is_category) + value = "q" else: - so, ss, usv = -1 * self.offtakevolume.w, self.sourced.w, self.unsourced.w kwargs = defaultkwargs("w", is_category) - vis.plot_timeseries(axes[0], so, **kwargs) - vis.plot_timeseries(axes[1], ss, **kwargs) + value = "w" + so.plot_to_ax(axes[0], value, children=children, **kwargs) + ss.plot_to_ax(axes[1], value, children=children, **kwargs) # Unsourced volume. - vis.plot_timeseries(axes[2], usv, **kwargs) - + usv.plot_to_ax(axes[2], value, **kwargs) # Procurement Price. - vis.plot_timeseries(axes[3], self.pnl_cost.p, **defaultkwargs("p", is_category)) - # sourced price - vis.plot_timeseries(axes[4], self.sourced.p, **defaultkwargs("p", is_category)) - - # unsourced price - vis.plot_timeseries( - axes[5], self.unsourced.p, **defaultkwargs("p", is_category) + self.pnl_cost.plot_to_ax( + axes[3], + "p", + **pr_kwargs, ) + self.sourced.plot_to_ax( + axes[4], + "p", + children=children, + **pr_kwargs, + ) + # Unsourced price + self.unsourced.plot_to_ax( + axes[5], + "p", + **pr_kwargs, + ) + + # vis.plot_timeseries(axes[0], so, **kwargs) + # vis.plot_timeseries(axes[1], ss, **kwargs) + # # Unsourced volume. + # vis.plot_timeseries(axes[2], usv, **kwargs) + + # # Procurement Price. + # vis.plot_timeseries(axes[3], self.pnl_cost.p, **defaultkwargs("p", is_category)) + # # sourced price + # vis.plot_timeseries(axes[4], self.sourced.p, **defaultkwargs("p", is_category)) + + # # unsourced price + # vis.plot_timeseries( + # axes[5], self.unsourced.p, **defaultkwargs("p", is_category) + # ) # Empty. diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index ad1be3d..ec032bb 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -222,7 +222,7 @@ def get_pfline( Kind.COMPLETE: "qr", }[kind] df = get_dataframe(i, columns, _seed=_seed) - if not positive and np.random.randint(1, 3) == 1: + if not positive and np.random.randint(1, 4) == 1: df = -1 * df # HACK: `-df` leads to error in pint. Maybe fixed in future return create.flatpfline(df) # Create nested PfLine. diff --git a/setup.cfg b/setup.cfg index 4e57090..4edd93f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,7 +12,7 @@ max-line-length = 120 ignore = E501, W503, E202, E226 [tool:pytest] -addopts = --cov=. +#addopts = --cov=. markers = only_on_pr: marks tests as slow (select with -m only_on_pr and deselect with -m "not only_on_pr") pythonpath = ./tests From faab40e1e2d8c998f96a38827cea6a4292eebd25 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 8 Mar 2024 14:49:05 +0100 Subject: [PATCH 41/59] added hash function for colors for children --- dev_scripts/plot_state.py | 11 ++++++---- portfolyo/core/mixins/plot.py | 39 ++++++++++++++--------------------- portfolyo/visualize/colors.py | 30 ++++++++++++++++++--------- 3 files changed, 43 insertions(+), 37 deletions(-) diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py index 16e6f68..b17867c 100644 --- a/dev_scripts/plot_state.py +++ b/dev_scripts/plot_state.py @@ -1,19 +1,22 @@ import matplotlib.pyplot as plt import portfolyo as pf from portfolyo import dev +import pandas as pd from portfolyo.core.pfline.enums import Kind from portfolyo.core.pfstate.pfstate import PfState """Plot PfState to test of adding axes for un/sourced prices.""" -index = pf.dev.get_index(freq="D") +index = pd.date_range( + "2022-01-01", "2022-02-01", freq="D", tz="Europe/Berlin", inclusive="left" +) pfs = pf.dev.get_pfstate(index) pfs2 = pfs.asfreq("MS") -offtakevolume = dev.get_nestedpfline(index, kind=Kind.VOLUME) -sourced = dev.get_nestedpfline(index, kind=Kind.COMPLETE) -unsourcedprice = dev.get_nestedpfline(index, kind=Kind.PRICE) +offtakevolume = dev.get_nestedpfline(index, kind=Kind.VOLUME, childcount=4) +sourced = dev.get_nestedpfline(index, kind=Kind.COMPLETE, childcount=4) +unsourcedprice = dev.get_nestedpfline(index, kind=Kind.PRICE, childcount=4) pfs3 = PfState(-1 * offtakevolume, unsourcedprice, sourced) # pfl2 = create.nestedpfline(index) # pfs3 = pf.dev.get_nested_pfstate(index) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 45926e1..169b72f 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -8,7 +8,6 @@ import matplotlib import numpy as np -import itertools from matplotlib import pyplot as plt from ... import tools @@ -174,13 +173,25 @@ def get_stacked_offsets(self: PfLine, col: str) -> Dict[str, List[List[float]]]: def get_children_with_colors(self: PfLine) -> List[Tuple[str, PfLine, vis.Color]]: # return a list of child columns with a color for each + # return [ + # (name, child, color_enum.value.lighten(0.5)) + # for (name, child), color_enum in zip( + # self.items(), itertools.cycle(vis.Colors.General) + # ) + # ] return [ - (name, child, color_enum.value.lighten(0.5)) - for (name, child), color_enum in zip( - self.items(), itertools.cycle(vis.Colors.General) - ) + (name, child, self.hash_and_map_to_color(name)) + for (name, child) in self.items() ] + def hash_and_map_to_color(self: PfLine, name: str) -> vis.Color: + # Use a hash function to hash the name + hashed_value = hash(name) + # Calculate the index in the General colors enum based on the hashed value + index = hashed_value % len(vis.Colors.General) + # Return the color associated with the index + return list(vis.Colors.General)[index].value + def plot_children(self: PfLine, col: str, ax: plt.Axes, is_category: bool) -> None: """Plot children of the PfLine to the same ax as parent. @@ -272,24 +283,6 @@ def plot(self: PfState, children: bool = False) -> plt.Figure: "p", **pr_kwargs, ) - - # vis.plot_timeseries(axes[0], so, **kwargs) - # vis.plot_timeseries(axes[1], ss, **kwargs) - # # Unsourced volume. - # vis.plot_timeseries(axes[2], usv, **kwargs) - - # # Procurement Price. - # vis.plot_timeseries(axes[3], self.pnl_cost.p, **defaultkwargs("p", is_category)) - # # sourced price - # vis.plot_timeseries(axes[4], self.sourced.p, **defaultkwargs("p", is_category)) - - # # unsourced price - # vis.plot_timeseries( - # axes[5], self.unsourced.p, **defaultkwargs("p", is_category) - # ) - - # Empty. - # Set titles. axes[0].set_title("Offtake volume") axes[1].set_title("Sourced volume") diff --git a/portfolyo/visualize/colors.py b/portfolyo/visualize/colors.py index 284e350..d29e60e 100644 --- a/portfolyo/visualize/colors.py +++ b/portfolyo/visualize/colors.py @@ -29,16 +29,26 @@ def darken(self, value): class Colors: class General(Enum): - PURPLE = Color(0.549, 0.110, 0.706) - GREEN = Color(0.188, 0.463, 0.165) - BLUE = Color(0.125, 0.247, 0.600) - ORANGE = Color(0.961, 0.533, 0.114) - RED = Color(0.820, 0.098, 0.114) - YELLOW = Color(0.945, 0.855, 0.090) - LBLUE = Color(0.067, 0.580, 0.812) - LGREEN = Color(0.325, 0.773, 0.082) - BLACK = Color(0, 0, 0) - WHITE = Color(1, 1, 1) + Color1 = Color(0.12156862745098039, 0.4666666666666667, 0.7058823529411765) + Color2 = Color(0.6823529411764706, 0.7803921568627451, 0.9098039215686274) + Color3 = Color(1.0, 0.4980392156862745, 0.054901960784313725) + Color4 = Color(1.0, 0.7333333333333333, 0.47058823529411764) + Color5 = Color(0.17254901960784313, 0.6274509803921569, 0.17254901960784313) + Color6 = Color(0.596078431372549, 0.8745098039215686, 0.5411764705882353) + Color7 = Color(0.8392156862745098, 0.15294117647058825, 0.1568627450980392) + Color8 = Color(1.0, 0.596078431372549, 0.5882352941176471) + Color9 = Color(0.5803921568627451, 0.403921568627451, 0.7411764705882353) + Color10 = Color(0.7725490196078432, 0.6901960784313725, 0.8352941176470589) + Color11 = Color(0.5490196078431373, 0.33725490196078434, 0.29411764705882354) + Color12 = Color(0.7686274509803922, 0.611764705882353, 0.5803921568627451) + Color13 = Color(0.8901960784313725, 0.4666666666666667, 0.7607843137254902) + Color14 = Color(0.9686274509803922, 0.7137254901960784, 0.8235294117647058) + Color15 = Color(0.4980392156862745, 0.4980392156862745, 0.4980392156862745) + Color16 = Color(0.7803921568627451, 0.7803921568627451, 0.7803921568627451) + Color17 = Color(0.7372549019607844, 0.7411764705882353, 0.13333333333333333) + Color18 = Color(0.8588235294117647, 0.8588235294117647, 0.5529411764705883) + Color19 = Color(0.09019607843137255, 0.7450980392156863, 0.8117647058823529) + Color20 = Color(0.6196078431372549, 0.8549019607843137, 0.8980392156862745) class Wqpr: # Standard colors when plotting a portfolio w = Color(*mpl.colors.to_rgb("#0E524F")).lighten(0.15) From 1cad372c57bacd99d44dcc95751dd22811baea89 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 11 Mar 2024 12:41:47 +0100 Subject: [PATCH 42/59] deleted unnecessary test --- dev_scripts/plot_test.py | 2 +- portfolyo/core/mixins/plot.py | 11 +- portfolyo/tools/intersect.py | 156 +----------------- portfolyo/visualize/colors.py | 44 +++--- test-output.xml | 1 + tests/tools/test_intersect_flex.py | 244 ----------------------------- 6 files changed, 33 insertions(+), 425 deletions(-) create mode 100644 test-output.xml delete mode 100644 tests/tools/test_intersect_flex.py diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index b123f05..9120bd3 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -64,4 +64,4 @@ def plot_pfline_to_ax(value: str, how: str, children: int = 1): plt.show() -plot_pfline_to_ax("q", "bar", 4) +plot_pfline_to_ax("w", "area", 4) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index 169b72f..b379ada 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -142,7 +142,7 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: self.plot_children(col, ax, is_category) ax.legend() - kwargs["alpha"] = 0.5 + kwargs["alpha"] = 0.8 s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) @@ -172,13 +172,6 @@ def get_stacked_offsets(self: PfLine, col: str) -> Dict[str, List[List[float]]]: return return_val def get_children_with_colors(self: PfLine) -> List[Tuple[str, PfLine, vis.Color]]: - # return a list of child columns with a color for each - # return [ - # (name, child, color_enum.value.lighten(0.5)) - # for (name, child), color_enum in zip( - # self.items(), itertools.cycle(vis.Colors.General) - # ) - # ] return [ (name, child, self.hash_and_map_to_color(name)) for (name, child) in self.items() @@ -218,6 +211,8 @@ def plot_children(self: PfLine, col: str, ax: plt.Axes, is_category: bool) -> No colors.append(color) if is_stacked_type: kwargs["bottom"] = offsets[name] + kwargs["hatch"] = ".." + kwargs["alpha"] = 0.7 vis.plot_timeseries(ax, getattr(child, col), **kwargs) diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index 03e6a9d..fa940a2 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -1,10 +1,7 @@ -from typing import List, Union, Tuple +from typing import List, Union import pandas as pd -from portfolyo.tools.freq import longest -from datetime import datetime - def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: """Intersect several DatetimeIndices. @@ -60,139 +57,8 @@ def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: return pd.DatetimeIndex(sorted(list(values)), freq=freq, name=name, tz=tz) -def indices_flex( - *idxs: pd.DatetimeIndex, - ignore_freq: bool = False, - ignore_tz: bool = False, - ignore_start_of_day: bool = False, -) -> Tuple[pd.DatetimeIndex]: - """Intersect several DatetimeIndices, but allow for more flexibility of ignoring - certain properties. - - Parameters - ---------- - *idxs : pd.DatetimeIndex - The indices to intersect. - ignore_freq: bool, optional (default: False) - If True, do the intersection even if the frequencies do not match; drop the - time periods that do not (fully) exist in either of the frames. - ignore_tz: bool, optional (default: False) - If True, ignore the timezones; perform the intersection using 'wall time'. - ignore_start_of_day: bool, optional (default: False) - If True, perform the intersection even if the frames have a different start-of-day. - The start-of-day of the original frames is preserved, even if the frequency is shorter - than daily. - - Returns - ------- - Tuple[pd.DatetimeIndex] - The intersection for each datetimeindex (in same order as input idxs). - - See also - -------- - indices - """ - if len(idxs) == 0: - raise ValueError("Must specify at least one index.") - - if len(idxs) == 1: - return idxs[0] - # convert tuple object into a list - idxs = list(idxs) - - # If we land here, we have at least 2 indices. - distinct_freqs = set([i.freq for i in idxs]) - if len(distinct_freqs) != 1 and ignore_freq is False: - raise ValueError(f"Indices must have equal frequencies; got {distinct_freqs}.") - - distinct_tzs = set([i.tz for i in idxs]) - if len(distinct_tzs) != 1 and ignore_tz is False: - raise ValueError(f"Indices must have equal timezones; got {distinct_tzs}.") - - freq, name, tz = [], [], [] - for i in range(len(idxs)): - freq.append(idxs[i].freq) - name.append(idxs[i].name) - tz.append(idxs[i].tz) - - empty_idx = [len(i) == 0 for i in idxs] - if any(empty_idx): - return pd.DatetimeIndex([]) - - # If we land here, we have at least 2 indices, all are not empty, with equal tz and freq. - - distinct_sod = set([i[0].time() for i in idxs]) - if len(distinct_sod) != 1 and ignore_start_of_day is False: - raise ValueError(f"Indices must have equal start-of-day; got {distinct_sod}.") - - # add one interval of the respective freq to each index (this way, a given date-range from A-B that was exclusive - # of B is now inclusive of B - this helps when we need to convert frequencies or times-of-day without loosing - # data. At the end, we exclude the end-date of the final result again.) - idxs = [ - idx.append( - pd.DatetimeIndex([idx[-1] + pd.tseries.frequencies.to_offset(idx.freq)]) - ) - for idx in idxs - ] - - if ignore_freq is True: - # Find the smallest frequency - biggest_freq = longest(*freq) - # change bigger freq into small one - for i in range(len(idxs)): - start = idxs[i].min() - end = idxs[i].max() - idxs[i] = pd.date_range(start, end, freq=biggest_freq, inclusive="both") - - if ignore_tz is True: - # set timezone to none for all values - for i in range(len(idxs)): - idxs[i] = idxs[i].tz_localize(None) - - if ignore_start_of_day is True: - # Save a copy of the original hours and minutes - start_of_day = [x[0].time() for x in idxs] - # Set the time components to midnight for each timestamp in the list - idxs = [timestamp.normalize() for timestamp in idxs] - - # Calculation is cumbersome: pandas DatetimeIndex.intersection not working correctly on timezone-aware indices (#46702) - values = set(idxs[0]) - for i in idxs[1:]: - values = values.intersection(set(i)) - - if len(values) == 0: - return tuple([pd.DatetimeIndex([]) for _i in idxs]) - - idxs_out = [] - for i in range(len(idxs)): - start = min(values) - end = max(values) - inclusive = "left" - - if ignore_start_of_day is True: - start = datetime.combine(pd.to_datetime(start).date(), start_of_day[i]) - end = datetime.combine(pd.to_datetime(end).date(), start_of_day[i]) - # inclusive = "left" - - idxs_out.append( - pd.date_range( - start=start, - end=end, - freq=freq[i], - name=name[i], - tz=tz[i], - inclusive=inclusive, - ) - ) - - return tuple(idxs_out) - - def frames( - *frames: Union[pd.Series, pd.DataFrame], - ignore_freq: bool = False, - ignore_tz: bool = False, - ignore_start_of_day: bool = False, + *frames: Union[pd.Series, pd.DataFrame] ) -> List[Union[pd.Series, pd.DataFrame]]: """Intersect several dataframes and/or series. @@ -200,15 +66,6 @@ def frames( ---------- *frames : pd.Series and/or pd.DataFrame The frames to intersect. - ignore_freq: bool, optional (default: False) - If True, do the intersection even if the frequencies do not match; drop the - time periods that do not (fully) exist in either of the frames. - ignore_tz: bool, optional (default: False) - If True, ignore the timezones; perform the intersection using 'wall time'. - ignore_start_of_day: bool, optional (default: False) - If True, perform the intersection even if the frames have a different start-of-day. - The start-of-day of the original frames is preserved, even if the frequency is shorter - than daily. Returns ------- @@ -220,10 +77,5 @@ def frames( The indices must have equal frequency, timezone, start-of-day. Otherwise, an error is raised. If there is no overlap, empty frames are returned. """ - new_idx = indices_flex( - *[fr.index for fr in frames], - ignore_freq=ignore_freq, - ignore_tz=ignore_tz, - ignore_start_of_day=ignore_start_of_day, - ) - return [fr.loc[idx] for idx, fr in zip(new_idx, frames)] + common_index = indices(*[fr.index for fr in frames]) + return [fr.loc[common_index] for fr in frames] diff --git a/portfolyo/visualize/colors.py b/portfolyo/visualize/colors.py index d29e60e..9d6fb8b 100644 --- a/portfolyo/visualize/colors.py +++ b/portfolyo/visualize/colors.py @@ -29,26 +29,30 @@ def darken(self, value): class Colors: class General(Enum): - Color1 = Color(0.12156862745098039, 0.4666666666666667, 0.7058823529411765) - Color2 = Color(0.6823529411764706, 0.7803921568627451, 0.9098039215686274) - Color3 = Color(1.0, 0.4980392156862745, 0.054901960784313725) - Color4 = Color(1.0, 0.7333333333333333, 0.47058823529411764) - Color5 = Color(0.17254901960784313, 0.6274509803921569, 0.17254901960784313) - Color6 = Color(0.596078431372549, 0.8745098039215686, 0.5411764705882353) - Color7 = Color(0.8392156862745098, 0.15294117647058825, 0.1568627450980392) - Color8 = Color(1.0, 0.596078431372549, 0.5882352941176471) - Color9 = Color(0.5803921568627451, 0.403921568627451, 0.7411764705882353) - Color10 = Color(0.7725490196078432, 0.6901960784313725, 0.8352941176470589) - Color11 = Color(0.5490196078431373, 0.33725490196078434, 0.29411764705882354) - Color12 = Color(0.7686274509803922, 0.611764705882353, 0.5803921568627451) - Color13 = Color(0.8901960784313725, 0.4666666666666667, 0.7607843137254902) - Color14 = Color(0.9686274509803922, 0.7137254901960784, 0.8235294117647058) - Color15 = Color(0.4980392156862745, 0.4980392156862745, 0.4980392156862745) - Color16 = Color(0.7803921568627451, 0.7803921568627451, 0.7803921568627451) - Color17 = Color(0.7372549019607844, 0.7411764705882353, 0.13333333333333333) - Color18 = Color(0.8588235294117647, 0.8588235294117647, 0.5529411764705883) - Color19 = Color(0.09019607843137255, 0.7450980392156863, 0.8117647058823529) - Color20 = Color(0.6196078431372549, 0.8549019607843137, 0.8980392156862745) + Color1 = Color(0.2235294117647059, 0.23137254901960785, 0.4745098039215686) + Color2 = Color(0.3215686274509804, 0.32941176470588235, 0.6392156862745098) + Color3 = Color(0.4196078431372549, 0.43137254901960786, 0.8117647058823529) + Color4 = Color(0.611764705882353, 0.6196078431372549, 0.8705882352941177) + Color5 = Color(0.19215686274509805, 0.5098039215686274, 0.7411764705882353) + Color6 = Color(0.4196078431372549, 0.6823529411764706, 0.8392156862745098) + Color7 = Color(0.6196078431372549, 0.792156862745098, 0.8823529411764706) + Color8 = Color(0.7764705882352941, 0.8588235294117647, 0.9372549019607843) + Color9 = Color(0.5490196078431373, 0.42745098039215684, 0.19215686274509805) + Color10 = Color(0.7411764705882353, 0.6196078431372549, 0.2235294117647059) + Color11 = Color(0.9058823529411765, 0.7294117647058823, 0.3215686274509804) + Color12 = Color(0.9058823529411765, 0.796078431372549, 0.5803921568627451) + Color13 = Color(0.5176470588235295, 0.23529411764705882, 0.2235294117647059) + Color14 = Color(0.6784313725490196, 0.28627450980392155, 0.2901960784313726) + Color15 = Color(0.8392156862745098, 0.3803921568627451, 0.4196078431372549) + Color16 = Color(0.9058823529411765, 0.5882352941176471, 0.611764705882353) + Color17 = Color(0.4823529411764706, 0.2549019607843137, 0.45098039215686275) + Color18 = Color(0.6470588235294118, 0.3176470588235294, 0.5803921568627451) + Color19 = Color(0.807843137254902, 0.42745098039215684, 0.7411764705882353) + Color20 = Color(0.8705882352941177, 0.6196078431372549, 0.8392156862745098) + Color21 = Color(0.38823529411764707, 0.38823529411764707, 0.38823529411764707) + Color22 = Color(0.5882352941176471, 0.5882352941176471, 0.5882352941176471) + Color23 = Color(0.7411764705882353, 0.7411764705882353, 0.7411764705882353) + Color24 = Color(0.8509803921568627, 0.8509803921568627, 0.8509803921568627) class Wqpr: # Standard colors when plotting a portfolio w = Color(*mpl.colors.to_rgb("#0E524F")).lighten(0.15) diff --git a/test-output.xml b/test-output.xml new file mode 100644 index 0000000..1f7cdeb --- /dev/null +++ b/test-output.xml @@ -0,0 +1 @@ +/Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytest/__main__.py -p vscode_pytest --collect-only teststests \ No newline at end of file diff --git a/tests/tools/test_intersect_flex.py b/tests/tools/test_intersect_flex.py deleted file mode 100644 index 822dc39..0000000 --- a/tests/tools/test_intersect_flex.py +++ /dev/null @@ -1,244 +0,0 @@ -import pandas as pd -import pytest - -from portfolyo import testing, tools - - -COMMON_END = "2022-02-02" - -TESTCASES = [ # startdates, freq, expected_startdate - # One starts at first day of year. - (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), - (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), - (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), - (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), - (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), - (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), - (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), - # Both start in middle of year. - (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), -] - -COMMON_END_2 = "2023-01-01" -TESTCASES_2 = [ # startdates, freq, expected_dates - # One starts at first day of year. - (("2020-01-01", "2020-01-20"), ("15T", "H"), ("2020-01-20", "2023-01-01")), - (("2020-01-01", "2020-01-20"), ("15T", "D"), ("2020-01-20", "2023-01-01")), - (("2022-04-01", "2021-02-01"), ("H", "MS"), ("2022-04-01", "2023-01-01")), - (("2020-01-01", "2020-04-01"), ("H", "QS"), ("2020-04-01", "2023-01-01")), - (("2020-01-01", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), - # Both start in middle of year. - (("2020-04-21", "2020-06-20"), ("15T", "H"), ("2020-06-20", "2023-01-01")), - (("2020-04-21", "2020-06-20"), ("15T", "D"), ("2020-06-20", "2023-01-01")), - (("2020-04-21", "2020-07-01"), ("H", "MS"), ("2020-07-01", "2023-01-01")), - (("2020-04-21", "2020-07-01"), ("H", "QS"), ("2020-07-01", "2023-01-01")), - (("2020-04-21", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), -] - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) -def test_intersect_flex_ignore_start_of_day( - tz, startdates, freq, starttime, expected_startdate -): - otherstarttime = "00:00" if starttime == "06:00" else "06:00" - a = pd.date_range( - f"{startdates[0]} {starttime}", - f"{COMMON_END} {starttime}", - freq=freq, - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {otherstarttime}", - f"{COMMON_END} {otherstarttime}", - freq=freq, - tz=tz, - inclusive="left", - ) - e = ( - pd.date_range( - f"{expected_startdate} {starttime}", - f"{COMMON_END} {starttime}", - freq=freq, - tz=tz, - inclusive="left", - ), - pd.date_range( - f"{expected_startdate} {otherstarttime}", - f"{COMMON_END} {otherstarttime}", - freq=freq, - tz=tz, - inclusive="left", - ), - ) - # Test error case. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex(a, b, ignore_start_of_day=False) - # Test ok case. - result = tools.intersect.indices_flex(a, b, ignore_start_of_day=True) - - for i in range(0, len(result)): - testing.assert_index_equal(result[i], e[i]) - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) -def test_intersect_flex_ignore_tz(tz, startdates, freq, time_a, expected_startdate): - othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" - a = pd.date_range( - f"{startdates[0]} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=othertz, - inclusive="left", - ) - e = ( - pd.date_range( - f"{expected_startdate} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=tz, - inclusive="left", - ), - pd.date_range( - f"{expected_startdate} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=othertz, - inclusive="left", - ), - ) - # Test error case. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex(a, b, ignore_tz=False) - # Test ok case. - result = tools.intersect.indices_flex(a, b, ignore_tz=True) - - for i in range(0, len(result)): - testing.assert_index_equal(result[i], e[i]) - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) -@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) -def test_intersect_flex_ignore_freq(tz, startdates, freq, time_a, expected_dates): - """Test if intersection of indices with distinct frequencies gives correct result.""" - a = pd.date_range( - f"{startdates[0]} {time_a}", - f"{COMMON_END_2} {time_a}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {time_a}", - f"{COMMON_END_2} {time_a}", - freq=freq[1], - tz=tz, - inclusive="left", - ) - expected_a = pd.date_range( - f"{expected_dates[0]} {time_a}", - f"{expected_dates[1]} {time_a}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - expected_b = pd.date_range( - f"{expected_dates[0]} {time_a}", - f"{expected_dates[1]} {time_a}", - freq=freq[1], - tz=tz, - inclusive="left", - ) - # Test error case. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex(a, b, ignore_freq=False) - - result_a, result_b = tools.intersect.indices_flex(a, b, ignore_freq=True) - - testing.assert_index_equal(result_a, expected_a) - testing.assert_index_equal(result_b, expected_b) - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) -@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) -def test_ignore_all(tz, startdates, freq, starttime, expected_dates): - otherstarttime = "00:00" if starttime == "06:00" else "06:00" - othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" - a = pd.date_range( - f"{startdates[0]} {starttime}", - f"{COMMON_END_2} {starttime}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {otherstarttime}", - f"{COMMON_END_2} {otherstarttime}", - freq=freq[1], - tz=othertz, - inclusive="left", - ) - expected_a = pd.date_range( - f"{expected_dates[0]} {starttime}", - f"{expected_dates[1]} {starttime}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - expected_b = pd.date_range( - f"{expected_dates[0]} {otherstarttime}", - f"{expected_dates[1]} {otherstarttime}", - freq=freq[1], - tz=othertz, - inclusive="left", - ) - # Test error cases. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=False, ignore_start_of_day=False, ignore_tz=False - ) - - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=False, ignore_start_of_day=True, ignore_tz=True - ) - - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_start_of_day=False, ignore_tz=True - ) - - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=False - ) - - # Test ok case. - out_a, out_b = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=True - ) - testing.assert_index_equal(out_a, expected_a) - testing.assert_index_equal(out_b, expected_b) From 818019a6930b26bf58296eb056da47fd173b3af3 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 20 Mar 2024 13:48:32 +0100 Subject: [PATCH 43/59] changed hash function, and width of hline --- dev_scripts/plot_state.py | 4 +- dev_scripts/plot_test.py | 2 +- portfolyo/core/mixins/plot.py | 68 +- portfolyo/visualize/colors.py | 38 +- portfolyo/visualize/plot.py | 12 +- profile_data | Bin 0 -> 470294 bytes profile_output.txt | 4735 ++++++++++++++++++++++++++++ test-output.xml | 2 +- tests/tools/test_intersect_flex.py | 244 ++ 9 files changed, 5016 insertions(+), 89 deletions(-) create mode 100755 profile_data create mode 100755 profile_output.txt create mode 100755 tests/tools/test_intersect_flex.py diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py index b17867c..d127e34 100644 --- a/dev_scripts/plot_state.py +++ b/dev_scripts/plot_state.py @@ -10,7 +10,7 @@ index = pd.date_range( - "2022-01-01", "2022-02-01", freq="D", tz="Europe/Berlin", inclusive="left" + "2022-06-01", "2024-02-01", freq="D", tz="Europe/Berlin", inclusive="left" ) pfs = pf.dev.get_pfstate(index) pfs2 = pfs.asfreq("MS") @@ -27,5 +27,5 @@ # pfl2.print() -pfs3.plot(children=True) +pfs2.plot(children=False) plt.show() diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py index 9120bd3..b123f05 100644 --- a/dev_scripts/plot_test.py +++ b/dev_scripts/plot_test.py @@ -64,4 +64,4 @@ def plot_pfline_to_ax(value: str, how: str, children: int = 1): plt.show() -plot_pfline_to_ax("w", "area", 4) +plot_pfline_to_ax("q", "bar", 4) diff --git a/portfolyo/core/mixins/plot.py b/portfolyo/core/mixins/plot.py index b379ada..e4caadf 100644 --- a/portfolyo/core/mixins/plot.py +++ b/portfolyo/core/mixins/plot.py @@ -4,6 +4,7 @@ from __future__ import annotations +import hashlib from typing import TYPE_CHECKING, Dict, List, Tuple import matplotlib @@ -32,7 +33,7 @@ def defaultkwargs(col: str, is_cat: bool): """Styling and type of graph, depending on column ``col`` and whether or not the x-axis is a category axis (``is_cat``).""" kwargs = {} - kwargs["alpha"] = 0.8 + kwargs["alpha"] = 0.7 # Add defaults for each column. kwargs["color"] = getattr(vis.Colors.Wqpr, col, "grey") kwargs["labelfmt"] = DEFAULTFMT.get(col, "{:.2f}") @@ -78,13 +79,6 @@ def plot_to_ax( if children: # Plot on category axis if freq monthly or longer, else on time axis. is_category = tools.freq.shortest(self.index.freq, "MS") == "MS" - # adjust kwargs for parent if plotting children - if how == "bar": - kwargs["color"] = "none" - kwargs["edgecolor"] = "seagreen" - kwargs["linewidth"] = 2 - if how == "area": - how = "step" self.plot_children(col, ax, is_category) ax.legend() @@ -132,45 +126,13 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: kwargs = defaultkwargs(col, is_category) if children: - # adjust kwargs for parent if plotting children - if kwargs["how"] == "bar": - kwargs["color"] = "none" - kwargs["edgecolor"] = "seagreen" - kwargs["linewidth"] = 2 - if kwargs["how"] == "area": - kwargs["how"] = "step" - self.plot_children(col, ax, is_category) ax.legend() - kwargs["alpha"] = 0.8 s = getattr(self, col) vis.plot_timeseries(ax, s, **kwargs) return fig - def get_stacked_offsets(self: PfLine, col: str) -> Dict[str, List[List[float]]]: - # Calculates offset for each child based on the height of the previous child - # It disdinguishes between postive and negative offsets - # Saves values of offsets in 2 dimmensional array: for positive and negative offsets - return_val = {} - - bottom_offset = [[0.0, 0.0] for i in range(0, self.index.size)] - for name, child in self.items(): - bar_heights = getattr(child, col) - offsets = [0.0 for i in range(0, self.index.size)] - for i in range(0, len(bar_heights)): - obj = bar_heights[i] - if obj.magnitude > 0: - offsets[i] = bottom_offset[i][0] - bottom_offset[i][0] += obj.magnitude - else: - offsets[i] = bottom_offset[i][1] - bottom_offset[i][1] += obj.magnitude - - return_val[name] = offsets - - return return_val - def get_children_with_colors(self: PfLine) -> List[Tuple[str, PfLine, vis.Color]]: return [ (name, child, self.hash_and_map_to_color(name)) @@ -178,10 +140,12 @@ def get_children_with_colors(self: PfLine) -> List[Tuple[str, PfLine, vis.Color] ] def hash_and_map_to_color(self: PfLine, name: str) -> vis.Color: - # Use a hash function to hash the name - hashed_value = hash(name) + # Use SHA-256 to hash the name + hashed_value = hashlib.sha256(name.encode()).hexdigest() + # Convert the hashed value to an integer + hashed_int = int(hashed_value, 16) # Calculate the index in the General colors enum based on the hashed value - index = hashed_value % len(vis.Colors.General) + index = hashed_int % len(vis.Colors.General) # Return the color associated with the index return list(vis.Colors.General)[index].value @@ -200,19 +164,19 @@ def plot_children(self: PfLine, col: str, ax: plt.Axes, is_category: bool) -> No """ kwargs = defaultkwargs(col, is_category) kwargs["labelfmt"] = "" - is_stacked_type = kwargs["how"] == "bar" or kwargs["how"] == "area" + kwargs["alpha"] = 0.9 + # is_stacked_type = kwargs["how"] == "bar" or kwargs["how"] == "area" - if is_stacked_type: - offsets = self.get_stacked_offsets(col) colors = [] for name, child, color in self.get_children_with_colors(): kwargs["color"] = color kwargs["label"] = name + print("Color of child", name, "is:", color) colors.append(color) - if is_stacked_type: - kwargs["bottom"] = offsets[name] - kwargs["hatch"] = ".." - kwargs["alpha"] = 0.7 + if kwargs["how"] == "bar": + kwargs["how"] = "hline" + elif kwargs["how"] == "area": + kwargs["how"] = "step" vis.plot_timeseries(ax, getattr(child, col), **kwargs) @@ -297,8 +261,10 @@ def plot(self: PfState, children: bool = False) -> plt.Figure: # Set ticks. axes[0].xaxis.set_tick_params(labeltop=False, labelbottom=True) axes[1].xaxis.set_tick_params(labeltop=False, labelbottom=True) - axes[2].xaxis.set_tick_params(labeltop=False, labelbottom=False) + axes[2].xaxis.set_tick_params(labeltop=False, labelbottom=True) axes[3].xaxis.set_tick_params(labeltop=False, labelbottom=False) + axes[4].xaxis.set_tick_params(labeltop=False, labelbottom=False) + axes[5].xaxis.set_tick_params(labeltop=False, labelbottom=False) fig.tight_layout() return fig diff --git a/portfolyo/visualize/colors.py b/portfolyo/visualize/colors.py index 9d6fb8b..20c27c4 100644 --- a/portfolyo/visualize/colors.py +++ b/portfolyo/visualize/colors.py @@ -29,33 +29,21 @@ def darken(self, value): class Colors: class General(Enum): - Color1 = Color(0.2235294117647059, 0.23137254901960785, 0.4745098039215686) - Color2 = Color(0.3215686274509804, 0.32941176470588235, 0.6392156862745098) - Color3 = Color(0.4196078431372549, 0.43137254901960786, 0.8117647058823529) - Color4 = Color(0.611764705882353, 0.6196078431372549, 0.8705882352941177) - Color5 = Color(0.19215686274509805, 0.5098039215686274, 0.7411764705882353) - Color6 = Color(0.4196078431372549, 0.6823529411764706, 0.8392156862745098) - Color7 = Color(0.6196078431372549, 0.792156862745098, 0.8823529411764706) - Color8 = Color(0.7764705882352941, 0.8588235294117647, 0.9372549019607843) - Color9 = Color(0.5490196078431373, 0.42745098039215684, 0.19215686274509805) - Color10 = Color(0.7411764705882353, 0.6196078431372549, 0.2235294117647059) - Color11 = Color(0.9058823529411765, 0.7294117647058823, 0.3215686274509804) - Color12 = Color(0.9058823529411765, 0.796078431372549, 0.5803921568627451) - Color13 = Color(0.5176470588235295, 0.23529411764705882, 0.2235294117647059) - Color14 = Color(0.6784313725490196, 0.28627450980392155, 0.2901960784313726) - Color15 = Color(0.8392156862745098, 0.3803921568627451, 0.4196078431372549) - Color16 = Color(0.9058823529411765, 0.5882352941176471, 0.611764705882353) - Color17 = Color(0.4823529411764706, 0.2549019607843137, 0.45098039215686275) - Color18 = Color(0.6470588235294118, 0.3176470588235294, 0.5803921568627451) - Color19 = Color(0.807843137254902, 0.42745098039215684, 0.7411764705882353) - Color20 = Color(0.8705882352941177, 0.6196078431372549, 0.8392156862745098) - Color21 = Color(0.38823529411764707, 0.38823529411764707, 0.38823529411764707) - Color22 = Color(0.5882352941176471, 0.5882352941176471, 0.5882352941176471) - Color23 = Color(0.7411764705882353, 0.7411764705882353, 0.7411764705882353) - Color24 = Color(0.8509803921568627, 0.8509803921568627, 0.8509803921568627) + DARK_BURGUNDY = Color(0.2667, 0.0000, 0.0745) + BROWN_SUGAR = Color(0.3765, 0.2902, 0.1804) + DUSTY_GRAY = Color(0.5529, 0.5176, 0.3765) + MOONSTONE = Color(0.7647, 0.7569, 0.6118) + CORAL = Color(0.9608, 0.3412, 0.4980) + ORANGE = Color(0.9608, 0.5098, 0.1140) + RED = Color(0.8196, 0.0980, 0.1137) + YELLOW = Color(0.9451, 0.8549, 0.0902) + LBLUE = Color(0.0667, 0.5804, 0.8118) + LGREEN = Color(0.3255, 0.7725, 0.0824) + BLACK = Color(0.0000, 0.0000, 0.0000) + WHITE = Color(1.0000, 1.0000, 1.0000) class Wqpr: # Standard colors when plotting a portfolio w = Color(*mpl.colors.to_rgb("#0E524F")).lighten(0.15) q = Color(*mpl.colors.to_rgb("#0E524F")) r = Color(*mpl.colors.to_rgb("#8B7557")) - p = Color(*mpl.colors.to_rgb("#E53454")) + p = Color(*mpl.colors.to_rgb("#cd3759")) diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index feacf72..f0b533b 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -128,15 +128,9 @@ def plot_timeseries_as_area( splot = s.copy() # modified with additional (repeated) datapoint splot[splot.index.right[-1]] = splot.values[-1] - if "bottom" in kwargs: - bottom = kwargs["bottom"] - bottom.append(bottom[-1]) - del kwargs["bottom"] - else: - bottom = [0.0 for i in range(0, splot.size)] + bottom = [0.0 for i in range(0, splot.size)] # make bottom into pintarray bottom = bottom * splot.values[0].units - # bottom = bottom * splot.pint.units ax.fill_between( splot.index, @@ -166,7 +160,7 @@ def plot_timeseries_as_step( splot = s.copy() # modified with additional (repeated) datapoint splot[splot.index.right[-1]] = splot.values[-1] - ax.step(splot.index, splot.values, where="post", **kwargs) + ax.step(splot.index, splot.values, where="mid", **kwargs) delta = s.index.right - s.index set_data_labels(ax, s.index + 0.5 * delta, s.values, labelfmt, True) ax.autoscale() @@ -186,7 +180,7 @@ def plot_timeseries_as_hline( s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) categories = Categories(s) # Center around x-tick: - ax.hlines(categories.y(), categories.x() - 0.5, categories.x() + 0.5, **kwargs) + ax.hlines(categories.y(), categories.x() - 0.4, categories.x() + 0.4, **kwargs) ax.set_xticks(categories.x(MAX_XLABELS), categories.labels(MAX_XLABELS)) set_data_labels(ax, categories.x(), categories.y(), labelfmt, True) ax.autoscale() diff --git a/profile_data b/profile_data new file mode 100755 index 0000000000000000000000000000000000000000..79ac9653e00f3439793ee94453d2cb1b75abf957 GIT binary patch literal 470294 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

x@7P(GjDr1zYnl>WE?0Uur%9_{;Qk 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 +157553/155565 0.005 0.000 0.005 0.000 {built-in method builtins.len} + 5 0.005 0.001 0.005 0.001 {built-in method _posixsubprocess.fork_exec} + 4252 0.004 0.000 0.062 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1470(get_valid_values) + 1 0.004 0.004 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/generic.py:226(NDFrame) + 223 0.004 0.000 0.029 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1442(get_aliases) + 56522 0.004 0.000 0.004 0.000 {built-in method builtins.min} + 83972 0.004 0.000 0.005 0.000 {built-in method builtins.isinstance} + 1081 0.004 0.000 0.057 0.000 :1514(find_spec) +21198/21189 0.004 0.000 0.005 0.000 {method 'join' of 'str' objects} + 8 0.004 0.000 0.004 0.000 {built-in method posix.read} + 77916 0.004 0.000 0.004 0.000 {method 'lstrip' of 'str' objects} + 3516 0.003 0.000 0.003 0.000 {built-in method __new__ of type object at 0x1003ab388} + 9629 0.003 0.000 0.003 0.000 {method 'split' of 'str' objects} + 30 0.003 0.000 0.016 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:847(_rc_params_in_file) + 1803/284 0.003 0.000 0.007 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:87(_compile) + 1 0.003 0.003 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:2191(lstsq) + 6212 0.003 0.000 0.015 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2498(__init__) + 45 0.003 0.000 0.005 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:179(__new__) + 819 0.003 0.000 0.066 0.000 :901(_find_spec) + 7443 0.003 0.000 0.034 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:289(_compile) + 7317 0.003 0.000 0.003 0.000 {method 'expandtabs' of 'str' objects} + 1 0.002 0.002 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/scimath.py:1() + 954 0.002 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2781(__init__) + 7315 0.002 0.000 0.041 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:607(getdoc) + 833/1 0.002 0.000 1.007 1.007 :1002(_find_and_load) + 698 0.002 0.000 0.329 0.000 :916(get_code) + 1396 0.002 0.000 0.006 0.000 :361(cache_from_source) + 701 0.002 0.000 0.016 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2152(_signature_from_function) + 746 0.002 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:88(__setitem__) + 14602 0.002 0.000 0.002 0.000 {built-in method builtins.hasattr} + 117 0.002 0.000 0.076 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1598(pprint_setters) + 12710 0.002 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:234(__next) + 5863 0.002 0.000 0.005 0.000 :121(_path_join) + 45160 0.002 0.000 0.002 0.000 {method 'append' of 'list' objects} + 4252 0.002 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1555(aliased_name) + 5863 0.002 0.000 0.002 0.000 :123() + 385 0.002 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:292(_optimize_charset) + 1845 0.002 0.000 0.003 0.000 :166(_get_module_lock) + 794 0.002 0.000 0.008 0.000 :486(_init_module_attrs) + 556 0.002 0.000 0.002 0.000 {built-in method numpy.array} + 2129/633 0.002 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:175(getwidth) + 11722 0.002 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:165(__getitem__) + 794/1 0.001 0.000 1.007 1.007 :659(_load_unlocked) + 829/1 0.001 0.000 1.007 1.007 :967(_find_and_load_unlocked) + 965 0.001 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:35(update_wrapper) + 62 0.001 0.000 0.002 0.000 {built-in method builtins.eval} + 1845 0.001 0.000 0.002 0.000 :112(release) + 1845 0.001 0.000 0.002 0.000 :87(acquire) + 793/715 0.001 0.000 0.019 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2246(_signature_from_callable) + 5771 0.001 0.000 0.019 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:198(search) + 814 0.001 0.000 0.060 0.000 :1383(_get_spec) + 10485 0.001 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:255(get) + 405 0.001 0.000 0.015 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:414(dedent) + 698 0.001 0.000 0.279 0.000 :1036(get_data) + 1162 0.001 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:137(_type_check) + 1 0.001 0.001 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1() + 3451 0.001 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:713(__setattr__) + 1679 0.001 0.000 0.001 0.000 {method 'format' of 'str' objects} + 711/284 0.001 0.000 0.018 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:436(_parse_sub) + 175 0.001 0.000 0.001 0.000 {built-in method builtins.compile} + 44 0.001 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:345(namedtuple) + 7447 0.001 0.000 0.001 0.000 {built-in method builtins.setattr} + 4442 0.001 0.000 0.001 0.000 {built-in method builtins.sorted} + 786 0.001 0.000 0.001 0.000 :696(spec_from_file_location) + 12986 0.001 0.000 0.001 0.000 {method 'get' of 'dict' objects} + 105 0.001 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:170() + 31390 0.001 0.000 0.001 0.000 {built-in method builtins.callable} + 538 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:191(_collect_type_vars) + 1396 0.001 0.000 0.002 0.000 :127(_path_split) + 6320 0.001 0.000 0.001 0.000 :231(_verbose_message) + 5 0.001 0.000 0.001 0.000 {method 'readlines' of '_io._IOBase' objects} + 1678/210 0.001 0.000 0.001 0.000 {built-in method _abc._abc_subclasscheck} + 698/1 0.001 0.000 1.007 1.007 :844(exec_module) + 3783 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:173(append) + 2674 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:405(_strip_comment) + 15436 0.001 0.000 0.001 0.000 {method 'rstrip' of 'str' objects} + 794/792 0.001 0.000 0.193 0.000 :558(module_from_spec) + 1099/5 0.001 0.000 0.943 0.189 :1033(_handle_fromlist) + 515 0.001 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:739(__init__) + 5 0.001 0.000 0.011 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1677(_execute_child) + 698 0.001 0.000 0.041 0.000 :645(_compile_bytecode) + 31 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/function_base.py:24(linspace) + 2094 0.001 0.000 0.001 0.000 :79(_unpack_uint32) + 284 0.001 0.000 0.030 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:783(compile) + 3451 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:665(_is_dunder) + 3061 0.001 0.000 0.013 0.000 :135(_path_stat) + 698 0.001 0.000 0.001 0.000 :560(_classify_pyc) + 284 0.001 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:560(_compile_info) + 2 0.001 0.000 0.001 0.000 {built-in method _ctypes.POINTER} + 6817 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:670(__new__) + 3 0.001 0.000 0.001 0.000 {built-in method posix.open} + 586 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:65(getargs) + 4 0.001 0.000 0.001 0.000 {method 'read' of '_io.TextIOWrapper' objects} + 3283 0.001 0.000 0.001 0.000 :878(__exit__) + 5095 0.001 0.000 0.001 0.000 {method 'rpartition' of 'str' objects} + 195 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1110() + 6447 0.001 0.000 0.001 0.000 {method 'group' of 're.Match' objects} + 2086 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:947() + 9321 0.001 0.000 0.001 0.000 {method 'pop' of 'list' objects} + 830 0.001 0.000 0.001 0.000 :185(cb) + 272 0.001 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:433(_uniq) + 1738 0.001 0.000 0.001 0.000 {built-in method builtins.max} + 220 0.001 0.000 0.001 0.000 {built-in method _abc._abc_init} + 959/871 0.001 0.000 0.010 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:271(inner) + 1012 0.000 0.000 0.003 0.000 :203(_lock_unlock_module) + 317 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:142(decorator) + 786 0.000 0.000 0.004 0.000 :491(_get_cached) + 816 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:462(__setattr__) + 1484 0.000 0.000 0.005 0.000 :385(cached) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:492(inv) + 786 0.000 0.000 0.002 0.000 :1509(_get_spec) + 792 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:494(unwrap) + 3283 0.000 0.000 0.001 0.000 :874(__enter__) +2349/2179 0.000 0.000 0.001 0.000 {method 'update' of 'dict' objects} + 284 0.000 0.000 0.019 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:944(parse) + 3902 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:161(__len__) + 3984 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:250(match) + 830 0.000 0.000 0.001 0.000 :58(__init__) + 462 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/copy.py:66(copy) + 1427 0.000 0.000 0.001 0.000 :398(parent) + 1190 0.000 0.000 0.005 0.000 :145(_path_is_mode_type) + 1017 0.000 0.000 0.006 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:711(__setitem__) + 24 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:186(_collapse_string_to_ranges) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:596(Axis) + 814 0.000 0.000 0.061 0.000 :1415(find_spec) + 1981 0.000 0.000 0.000 0.000 {method 'match' of 're.Pattern' objects} + 92 0.000 0.000 0.035 0.000 :1565(_fill_cache) + 2 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/decoder.py:343(raw_decode) + 2792 0.000 0.000 0.001 0.000 :129() + 1879 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:112(__init__) + 6 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:34(__init__) + 3538/834 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:353(recursive_subclasses) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/islamic.py:42(_IslamicLunar) + 566/4 0.000 0.000 0.943 0.236 {built-in method builtins.__import__} + 33 0.000 0.000 0.009 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:809(_process_class) + 5422 0.000 0.000 0.000 0.000 {method 'find' of 'str' objects} + 5958 0.000 0.000 0.000 0.000 {built-in method _imp.acquire_lock} + 5 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1207(_close_pipe_fds) + 3024 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2830() + 243 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:461(__init__) + 3637 0.000 0.000 0.000 0.000 {method 'endswith' of 'str' objects} + 5958 0.000 0.000 0.000 0.000 {built-in method _imp.release_lock} + 833 0.000 0.000 0.003 0.000 :156(__enter__) + 278 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:83(verify_matching_signatures) + 276 0.000 0.000 0.007 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:360(decorator) + 1126/1 0.000 0.000 1.007 1.007 :220(_call_with_frames_removed) + 1210 0.000 0.000 0.002 0.000 :1346(_path_importer_cache) + 819 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/_distutils_hack/__init__.py:89(find_spec) + 2386 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:287(tell) + 698 0.000 0.000 0.001 0.000 :593(_validate_timestamp_pyc) + 461 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/copy.py:258(_reconstruct) + 136 0.000 0.000 0.013 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:38(__call__) + 173 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:310(_to_rgba_no_colorcycle) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2978(__array_finalize__) + 1081 0.000 0.000 0.000 0.000 :64(_relax_case) + 94 0.000 0.000 0.005 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:1391(_preprocess_data) + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/__init__.py:1() + 160 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/shape_base.py:612(column_stack) + 5981 0.000 0.000 0.000 0.000 {method 'strip' of 'str' objects} + 6769 0.000 0.000 0.000 0.000 {method 'isidentifier' of 'str' objects} + 306/12 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:809(_parseNoCache) + 1096 0.000 0.000 0.005 0.000 :154(_path_isfile) + 7715 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2548(name) + 4798 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1563() + 3698 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.lock' objects} + 356 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:545(_finddoc) + 605 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:96(getargspec) + 162 0.000 0.000 0.006 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:377(_create_fn) + 1 0.000 0.000 0.000 0.000 {method 'dot' of 'numpy.ndarray' objects} + 2686 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:189(is_consecutive) + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:221() + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:58(bitname) + 698 0.000 0.000 0.000 0.000 :523(_check_name_wrapper) + 822 0.000 0.000 0.000 0.000 :351(__init__) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:453(polyfit) + 1 0.000 0.000 0.000 0.000 {method 'accumulate' of 'numpy.ufunc' objects} + 220 0.000 0.000 0.005 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:434(Union) + 1673 0.000 0.000 0.000 0.000 {built-in method _thread.allocate_lock} + 105 0.000 0.000 0.112 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:159(_update_set_signature_and_docstring) + 425 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:356(_escape) + 487 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:928(_json_decode) + 833 0.000 0.000 0.001 0.000 :160(__exit__) + 698 0.000 0.000 0.003 0.000 :1077(path_stats) + 723 0.000 0.000 0.000 0.000 {method 'replace' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:540(_init) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_methods.py:1() + 385 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:265(_compile_charset) + 223 0.000 0.000 0.030 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1422(__init__) + 5 0.000 0.000 0.011 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:756(__init__) + 6560 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2560(kind) + 92 0.000 0.000 0.000 0.000 :1594() + 12 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:462(search) + 284 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:977(__and__) + 700 0.000 0.000 0.000 0.000 :35(_new_module) + 3711 0.000 0.000 0.000 0.000 {built-in method _thread.get_ident} + 10 0.000 0.000 0.000 0.000 {pandas._libs.hashtable.object_hash} + 220 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:232(_remove_dups_flatten) + 746 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:44(_is_private) + 1835 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:159(isfunction) + 6345 0.000 0.000 0.000 0.000 {built-in method builtins.ord} + 831 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:447(_simple) + 954 0.000 0.000 0.005 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1542(is_alias) + 1507 0.000 0.000 0.000 0.000 {method 'rfind' of 'str' objects} + 4253 0.000 0.000 0.000 0.000 {method 'lower' of 'str' objects} + 1664 0.000 0.000 0.001 0.000 {built-in method _abc._abc_instancecheck} + 1215 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:128(_type_convert) + 284 0.000 0.000 0.010 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:622(_code) + 437 0.000 0.000 0.005 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1536(number_of_parameters) + 356 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:535(_findclass) + 2826 0.000 0.000 0.000 0.000 {method 'add' of 'set' objects} + 757 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:203(sub) + 424 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:307(validate_color) + 715 0.000 0.000 0.019 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:3111(signature) + 626 0.000 0.000 0.007 0.000 {built-in method builtins.next} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/helpers.py:643() + 515 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:677(__init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_scalars.py:1() + 1333 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:670(_set) + 317 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/function_base.py:497(add_newdoc) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1588(_guarded_repr_or_str) + 316/273 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:485(_get_literal_prefix) + 276 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:376() + 1 0.000 0.000 0.064 0.064 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:248(git_pieces_from_vcs) + 322 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:71(join) + 3780 0.000 0.000 0.000 0.000 {built-in method posix.fspath} + 461 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:522(copy) + 458 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:268(to_rgba) + 1207 0.000 0.000 0.000 0.000 {method 'extend' of 'list' objects} + 92 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:671(_get_field) + 715 0.000 0.000 0.019 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2859(from_callable) + 2230 0.000 0.000 0.000 0.000 {method 'setdefault' of 'dict' objects} + 295 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:225(__init__) + 345 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:85(opengroup) + 909 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:65(wraps) + 220 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/abc.py:105(__new__) + 88 0.000 0.000 0.184 0.002 :1171(create_module) + 117 0.000 0.000 0.088 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1837(kwdoc) + 256/18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:409(generic_visit) + 65 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:128(deprecate) + 814 0.000 0.000 0.000 0.000 :811(find_spec) + 5 0.000 0.000 0.063 0.013 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:73(run_command) + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:1() + 75 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:3065(__str__) + 1262 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:82(groups) + 705 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:188(match) + 1664 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/abc.py:117(__instancecheck__) + 835 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:690(_get) + 1 0.000 0.000 0.000 0.000 {built-in method utcfromtimestamp} + 744 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:22(_is_dunder) + 286 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:218(_deduplicate) + 91 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:437() + 92 0.000 0.000 0.000 0.000 :1475(__init__) + 2 0.000 0.000 0.000 0.000 {method 'readline' of '_io.BufferedReader' objects} + 70 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:452(register_option) + 885 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:216(_is_nth_color) + 175 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:429(_tokenize) + 1610 0.000 0.000 0.000 0.000 {method 'pop' of 'dict' objects} + 432/357 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:933(__hash__) + 155 0.000 0.000 0.007 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:481(__call__) + 2223 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:743() + 746 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:33(_is_sunder) + 61 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:144() + 104 0.000 0.000 0.111 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:126(__init_subclass__) + 833 0.000 0.000 0.000 0.000 :152(__init__) + 2095 0.000 0.000 0.000 0.000 {built-in method from_bytes} + 5 0.000 0.000 0.052 0.010 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1090(communicate) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/generic.py:36(create_pandas_abc_type) + 849 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:514(_is_wrapper) + 92 0.000 0.000 0.001 0.000 :63(__init__) + 418 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/registry.py:172(__init__) + 650 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:804(fsencode) + 92 0.000 0.000 0.002 0.000 :1333(_path_hooks) + 167 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:958(__hash__) + 134 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:333(__init__) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:452(callback) + 1317 0.000 0.000 0.000 0.000 {method 'find' of 'bytearray' objects} + 241 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:516(_get_charset_prefix) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/frame.py:490(DataFrame) + 284 0.000 0.000 0.000 0.000 {built-in method _sre.compile} + 48 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:1347(_add_data_doc) + 698 0.000 0.000 0.000 0.000 :1006(__init__) + 312 0.000 0.000 0.000 0.000 {built-in method fromkeys} + 1 0.000 0.000 0.227 0.227 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/pyplot.py:4() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_cm_listed.py:1() +1598/1159 0.000 0.000 0.000 0.000 {built-in method builtins.hash} + 66 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:481(Literal) + 32 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1036(from_list) + 19 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:799(validate_cycler) + 863 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:466() + 1 0.000 0.000 0.000 0.000 {function SeedSequence.generate_state at 0x101314dc0} + 461 0.000 0.000 0.000 0.000 {method '__reduce_ex__' of 'object' objects} + 88/54 0.000 0.000 0.133 0.002 :1179(exec_module) + 66 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4540(__init__) + 71 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:832(__getitem__) + 99 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:582(_find_data_type) + 1678/210 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/abc.py:121(__subclasscheck__) + 78/4 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:962(_parseCache) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/accessor.py:147(StringMethods) + 698 0.000 0.000 0.000 0.000 {built-in method _imp._fix_co_filename} + 802 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/types.py:171(__get__) + 574 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:12(_is_descriptor) + 261 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2582(__str__) + 495 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:60(isabs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/html/entities.py:1() + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:894(__init__) + 2636 0.000 0.000 0.000 0.000 {built-in method builtins.issubclass} + 61 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:628(__init__) + 568 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:619(isstring) + 80 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1122(_parse_unit_name) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/fromnumeric.py:1() + 306 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:148(__new__) + 424 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/function_base.py:348(iterable) + 814 0.000 0.000 0.000 0.000 {built-in method _imp.is_frozen} + 1013 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:455(is_egg) + 1510 0.000 0.000 0.000 0.000 {method 'items' of 'dict' objects} + 1 0.000 0.000 0.030 0.030 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/multiarray.py:1() + 158 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:612(_is_type) + 342 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath.add_docstring} + 22/3 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3983(streamline) + 728/559 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:756(__hash__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/series.py:244(Series) + 284 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:928(fix_flags) + 427 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:221(is_color_like) + 980 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:750(__eq__) + 518 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:741(__getitem__) + 67 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3948(__init__) + 150 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:868(_parse_flags) + 33 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:489(_init_fn) + 819 0.000 0.000 0.000 0.000 :736(find_spec) + 91 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:435(_mk_bitmap) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:440(__call__) + 1 0.000 0.000 0.215 0.215 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:1() + 53 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:240(_make_synonym_function) + 18 0.000 0.000 0.000 0.000 {method 'split' of 're.Pattern' objects} + 284 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:76(__init__) + 18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1866(__new__) + 798 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:966() + 177 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:296(_class_escape) + 519 0.000 0.000 0.000 0.000 {built-in method builtins.repr} + 45/12 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:759(__getitem__) + 511 0.000 0.000 0.000 0.000 {built-in method numpy.asanyarray} + 609 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:73(isclass) + 846 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:41(_get_sep) + 847 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:169(__setitem__) + 273 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:325(_subx) + 605 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:13(ismethod) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:619(get_exec_path) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:162(_register_known_types) + 564 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:180(validator) + 936 0.000 0.000 0.000 0.000 {built-in method builtins.iter} + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:489(__exit__) + 247 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:279(validate_color_for_prop_cycle) + 78 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:1840(_signature_bound_method) + 136 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/registry.py:254() + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:618(_find_new_) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:416(by_key) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/chinese.py:26(_ChineseLunisolar) + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:556(_select_from) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/hebrew.py:18(_HebrewLunisolar) + 306 0.000 0.000 0.000 0.000 {built-in method builtins.any} + 276 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:384() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:545() + 1 0.000 0.000 0.000 0.000 {built-in method posix.scandir} + 76 0.000 0.000 0.000 0.000 {method 'strftime' of 'datetime.date' objects} + 2 0.000 0.000 0.012 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/core.py:206(read_style_directory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:407(_Pickler) + 605 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:26(isfunction) + 345 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:97(closegroup) + 32 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:409(to_rgba_array) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_color_data.py:989() + 44/29 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/pint_eval.py:125(build_eval_tree) + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5() + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:140(formatargspec) + 675 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:928(__eq__) + 92 0.000 0.000 0.001 0.000 :1606(path_hook_for_FileFinder) + 86 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3754(__init__) + 737 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:565(__eq__) + 47 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1007(__init_subclass__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/base.py:303(Index) + 126/115 0.000 0.000 0.012 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:79(__call__) + 256/18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:403(visit) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/merge.py:1() + 115 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:88(f) + 1 0.000 0.000 0.092 0.092 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/__init__.py:1() + 586 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:41(iscode) + 45 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:164(__prepare__) + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_axes.py:46(Axes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:21() + 422 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:81(_combine_flags) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:136(ones) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:154(_subst_vars) + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:1() + 2403 0.000 0.000 0.000 0.000 {built-in method builtins.chr} + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:223(define_aliases) + 317 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/function_base.py:465(_needs_add_docstring) + 698 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:244(iter_fields) + 79 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:268(getuntil) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:64(parse_parts) + 55 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/warnings.py:458(__enter__) + 133/64 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3880(copy) + 29 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:597(from_string) + 794 0.000 0.000 0.000 0.000 :406(has_location) + 93 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:131(strseq) + 153 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:524(__init__) + 124 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:192() + 1199 0.000 0.000 0.000 0.000 {built-in method builtins.id} + 461 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/copyreg.py:94(__newobj__) + 40 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1149(__init__) + 132 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:419(visit_Constant) + 12 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:57() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:71(_UFuncCastingError) + 72/12 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4034(parseImpl) + 66 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:249(_flatten_literal_params) + 50 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:872(_ufunc_doc_signature_formatter) + 62/9 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3788(leave_whitespace) + 26 0.000 0.000 0.000 0.000 {built-in method posix.lstat} + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:283(disallowed) + 134 0.000 0.000 0.000 0.000 {built-in method _imp.is_builtin} + 1 0.000 0.000 0.020 0.020 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/__init__.py:25() + 771 0.000 0.000 0.000 0.000 {method 'encode' of 'str' objects} + 7 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2810(__init__) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:63(_add_delegate_accessors) + 822 0.000 0.000 0.000 0.000 {method '__subclasses__' of 'type' objects} + 1 0.000 0.000 0.010 0.010 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1942(_communicate) + 70 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:257(rename_parameter) + 248/220 0.000 0.000 0.005 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:352(__getitem__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:1() + 51 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:909(__getitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/text.py:80(Text) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:63() + 200 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/pyplot.py:164(_copy_docstring_and_deprecators) + 460 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:348() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:294() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:408(__init__) + 42 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:985(__class_getitem__) + 76 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:91() + 557 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:477(_get_iscased) + 30/4 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3828(streamline) + 317 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/function_base.py:483(_add_docstring) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:661(_build_cache) + 1876 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:847() + 927 0.000 0.000 0.000 0.000 {method 'get' of 'mappingproxy' objects} + 698 0.000 0.000 0.000 0.000 :1031(get_filename) + 67 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1108() + 99 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:571(_get_mixins_) + 1 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath.set_typeDict} + 736 0.000 0.000 0.000 0.000 :1481() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:822(StataMissingValue) + 356 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:81(ismethod) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1901(_wait) + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/__init__.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:32(_gen_cmap_registry) + 146 0.000 0.000 0.003 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/compat.py:29(tokenizer) + 111 0.000 0.000 0.000 0.000 {built-in method _codecs.utf_8_decode} + 137 0.000 0.000 0.000 0.000 {built-in method builtins.locals} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimelike.py:187(DatetimeLikeArrayMixin) + 915 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2865(parameters) + 301 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:78(readline) + 585 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:391() + 1 0.000 0.000 0.011 0.011 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/_structures.py:6(InfinityType) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:220(decorate) + 122 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:242(implement_func) + 122 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:841(copy_with) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/managers.py:1() + 22 0.000 0.000 0.000 0.000 {built-in method posix.readlink} + 214/116 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1872(default_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2697(MaskedArray) + 58 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3110(parseImpl) + 170 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:677(__init__) + 48 0.000 0.000 0.000 0.000 {method 'issuperset' of 'set' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:1() + 196 0.000 0.000 0.019 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:250(compile) + 306/282 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:171(__init__) + 792 0.000 0.000 0.000 0.000 {built-in method sys.getrecursionlimit} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/locale.py:1() + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hmac.py:1() + 26 0.000 0.000 0.010 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:416(make_keyword_only) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:218(_parsegen) + 109 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/extension.py:35(_inherit_from_data) + 1 0.000 0.000 0.082 0.082 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:805(copy) + 148 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2873(replace) + 37 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:111(_float_to_str) + 147 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/TiffTags.py:26(__new__) + 39 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:107() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:1() + 111 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/codecs.py:319(decode) + 169 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2422(__new__) + 88 0.000 0.000 0.000 0.000 :1155(__init__) + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1284(getLogger) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/extension.py:128(wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1814(Parser) + 698 0.000 0.000 0.000 0.000 :841(create_module) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:1() + 27 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:154(_deprecated_property) + 190 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1765() + 373 0.000 0.000 0.000 0.000 {built-in method sys.intern} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/range.py:57(RangeIndex) + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:778(string_preprocessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/_mixins.py:97(NDArrayBackedExtensionArray) + 231 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:1748(_signature_get_user_defined_method) + 33 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:998(dataclass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:229(NameValidator) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/helpers.py:2() + 1 0.000 0.000 0.057 0.057 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:1() + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:197() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:16(_binary_method) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:163(_extend_dict) + 317 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:105(array_function_dispatch) + 165 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:140(validate_bool) + 9 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:475(_create_) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/config_init.py:1() + 110 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:416(_field_init) + 269/169 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1899(name) + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:561(_check_for_existing_members) + 1 0.000 0.000 0.073 0.073 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/frame.py:1() + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/series.py:1() + 42 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:234(contextmanager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/uuid.py:84(UUID) + 77 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:674(__getitem__) + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:497() + 1 0.000 0.000 0.019 0.019 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:27() + 133/64 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3883() + 44 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:66(__set_name__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/object_array.py:33(ObjectStringArrayMixin) + 84 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:244(make_alias) + 1 0.000 0.000 0.045 0.045 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/__init__.py:1() + 180 0.000 0.000 0.000 0.000 :175(_path_isabs) + 837 0.000 0.000 0.000 0.000 {method '__getitem__' of 'dict' objects} + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/common.py:40(_unpack_zerodim_and_defer) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/readers.py:1() + 6 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2257() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:685(__init__) + 130 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:967(__init__) + 1 0.000 0.000 0.137 0.137 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/api.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:2() + 276 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:340(doc) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:402(_create_cb_wrapper) + 1 0.000 0.000 0.044 0.044 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_axes.py:1() + 77 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:1866(_signature_is_builtin) + 1015 0.000 0.000 0.000 0.000 {method 'isupper' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:2507(extend_all) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/groupby.py:1() + 166 0.000 0.000 0.000 0.000 {method 'translate' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1839(ConciseDateConverter) + 38 0.000 0.000 0.000 0.000 {method 'remove' of 'list' objects} + 60 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:829(_open_file_or_url) + 1 0.000 0.000 0.057 0.057 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/generic.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/TiffTags.py:420(_populate) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/common.py:8(pyparsing_common) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:982() + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:295(detect_encoding) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:4() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:1() + 28 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:550(_frozen_get_del_attr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:84(TransformNode) + 843 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2552(default) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/_common.py:1() + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:117(Artist) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:73(ToolBase) + 1 0.000 0.000 0.024 0.024 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numerictypes.py:1() + 162 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:256(_node_not_implemented) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/contour.py:716(ContourSet) + 81 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:94(_create_delegator_property) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:471(_parse_headers) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_openpyxl.py:39(OpenpyxlWriter) + 44 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:51(__init__) + 10 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_fontconfig_pattern.py:80(parse_fontconfig_pattern) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:880(_get_root_units) + 6 0.000 0.000 0.000 0.000 {method 'close' of '_io.BufferedReader' objects} + 163 0.000 0.000 0.000 0.000 {built-in method builtins.all} + 1 0.000 0.000 0.313 0.313 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/__init__.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/datetimes.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/core.py:134(Locale) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:186(__init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/function_base.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:492(__new__) + 365 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:419(__hash__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:331(_Stream) + 170 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:771(__copy__) + 18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1846(_make_nmtuple) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:394(ParserElement) + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/base.py:1() + 142 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:753(_set_new_attribute) + 12 0.000 0.000 0.010 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:51(__missing__) + 91 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:432(__eq__) + 42 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2438(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:78() + 67 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1089(reversed) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_array_like.py:1() + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:334(normpath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:351(_sanity_check) + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1335(_fixupParents) + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/categorical.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:55(_chars_for_ranges) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/chebyshev.py:1995(Chebyshev) + 58 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:86(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:857(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_color_data.py:2() + 66 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1410(__add__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/hindu.py:22(_HinduLunisolar) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py:42(Axes3D) + 154 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:790(preParse) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:316(delete_parameter) + 384 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:438() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/groupby.py:826(GroupBy) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:1() + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1() + 75 0.000 0.000 0.000 0.000 {built-in method builtins.sum} + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:682(_parse_args) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:44(from_string) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:1() + 29/15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:952(_get_root_units_recurse) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:150(dirname) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/path.py:24(Path) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/tseries/frequencies.py:1() + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3043(__init__) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:1() + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:81(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/markers.py:155(MarkerStyle) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:56(_make_str_method) + 5 0.000 0.000 0.000 0.000 {built-in method posix.waitpid} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/sample.py:1() + 18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:662(cycler) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/common.py:1656(pandas_dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:1028(BinGrouper) + 40/12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:805(_get_dimensionality_recurse) + 79 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:546(__init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1() + 55 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/warnings.py:477(__exit__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/cast.py:1() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/category.py:52(CategoricalIndex) + 3 0.000 0.000 0.000 0.000 {built-in method posix.uname} + 99 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:66(__call__) + 447 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:825(__iter__) + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:894(__getitem_inner__) + 65 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:442(__iadd__) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/path.py:191(_create_closed) + 423 0.000 0.000 0.000 0.000 {method '__contains__' of 'frozenset' objects} + 604 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1375(cast) + 301 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:128(__next__) + 1 0.000 0.000 0.022 0.022 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:1() + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:71(add_newdoc_for_scalar_type) + 60 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:742(__str__) + 347/1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__config__.py:19(_cleanup) + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1404(__init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:1737(Rolling) + 72 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:344(_tuple_str) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext_data.py:1() + 53 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:478(lru_cache) + 148 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:656(__hash__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:1() + 462 0.000 0.000 0.000 0.000 {built-in method builtins.vars} + 316 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:878(_convert_validator_spec) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:250(_cleanup) + 92 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:322(field) + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:2034(getLogger) + 42 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:517(decorating_function) + 1 0.000 0.000 0.016 0.016 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:1() + 11 0.000 0.000 0.000 0.000 {built-in method posix.pipe} + 257 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hmac.py:18() + 24 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:539(_repr_fn) + 37 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1324(__init_subclass__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:197() + 183 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:477(prefixed_lines) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:17() + 28 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:472(Optional) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:1() + 1 0.000 0.000 0.131 0.131 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/unit.py:1() + 12 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:223(from_string) + 590 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:509() + 16 0.000 0.000 0.000 0.000 {built-in method posix.close} + 10 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1205(_parse_units) + 68 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:293(header_source_parse) + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1() + 166 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/doc.py:11(create_section_header) + 227 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:419() + 479 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:202() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/generic.py:139(SeriesGroupBy) + 92 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:244(__init__) + 78 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:113(set_) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/quiver.py:1() + 49 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:131(get_object_signature) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/multi.py:216(MultiIndex) + 94 0.000 0.000 0.000 0.000 :159(_path_isdir) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/interval.py:186(IntervalArray) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:933(update) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:142(_check_size) + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:456(_generate_overlap_table) + 91 0.000 0.000 0.000 0.000 {method 'translate' of 'bytearray' objects} + 72 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:353() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/defchararray.py:1() + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/path.py:99(__init__) + 26 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6860(getdoc) + 120 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:181() + 235 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:78() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/warnings.py:181(_add_filter) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:1() + 259 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:935(__getitem__) + 137 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1745(set_whitespace_chars) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimelike.py:1() + 236 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:83() + 234 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:407(__iter__) + 1 0.000 0.000 0.064 0.064 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:637(get_versions) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/accessor.py:118(_forbid_nonstring_types) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:1345() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1192(__init_subclass__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:233(_wrap_chunks) + 48 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:572(_define_single_adder) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/interval.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/registry.py:248(load) + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/docstrings.py:7(make_flex_doc) + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_base.py:1() + 222 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1329() + 39/1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__config__.py:25() + 250 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:952(__eq__) + 91 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2384(__init__) + 1 0.000 0.000 1.007 1.007 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/__init__.py:1() + 5 0.000 0.000 0.000 0.000 {built-in method _imp.create_builtin} + 468 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:792(value) + 14 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:115(doc_note) + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:880(__getitem__) + 1 0.000 0.000 0.030 0.030 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:1() + 148 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:206(_check_generic) + 58 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:123(__exit__) + 1 0.000 0.000 0.033 0.033 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1() + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:404(tokenize) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:2() + 192 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:224(implements) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:494(find) + 1 0.000 0.000 0.000 0.000 {function Random.seed at 0x1013bb3a0} + 70 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:772(inner) + 55 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/warnings.py:437(__init__) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1937(__new__) + 238 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:93() + 66 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:358(__getitem__) + 237 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:88() + 1 0.000 0.000 0.252 0.252 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:1() + 263 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3767() + 41 0.000 0.000 0.000 0.000 {built-in method numpy.asarray} + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/algorithms.py:1() + 39 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1153(_dedup_candidates) + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:457() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:542(_AxesBase) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/shape_base.py:1() + 106 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:470(_init_param) + 227 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:410(__len__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:334(__init__) + 185 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:574(__hash__) + 73 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:707(get_name) + 106 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:404(_field_assign) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/npyio.py:1() + 26/14 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4287(parseImpl) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/array_manager.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/generic.py:11304(_add_numeric_operations) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/quoprimime.py:55() + 18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:269(_trim_arity) + 139 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1964(__eq__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/expanding.py:44(Expanding) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1() + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:358(_recursive_repr) + 53/29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/pint_eval.py:87(evaluate) + 170 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:89(__getitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_compat_pickle.py:9() + 83 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:754(encode) + 26 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1013(__next__) + 257 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hmac.py:19() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:1() + 1 0.000 0.000 0.087 0.087 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/generic.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:470(_push_exit_callback) + 171 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:837() + 75 0.000 0.000 0.000 0.000 {method 'copy' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/lzma.py:1() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/compat.py:1() + 233 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:946(_value_and_type_iter) + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:779(_get_dimensionality) + 157 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:597(_is_classvar) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1848() + 207 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/abc.py:7(abstractmethod) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:234(FixedForwardWindowIndexer) + 38/18 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4566(parseImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:1() + 155 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:474(__init__) + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:64() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3940(_ErrorStop) + 26 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:921(__init__) + 76 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:670(__eq__) + 248 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2271() + 194 0.000 0.000 0.000 0.000 {method 'decode' of 'bytes' objects} + 1 0.000 0.000 0.054 0.054 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_dtype_like.py:1() + 33 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:863() + 60 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2564(replace) + 1 0.000 0.000 0.018 0.018 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/secrets.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:1() + 23 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:213(__getattr__) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:981(parse_template) + 88 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:146(__init__) + 44 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:547(copy) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:1() + 222 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2264() + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:507() + 40 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:228(expanduser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/umath.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:1017(_decompose) + 67 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:204(__getitem__) + 30/9 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4577(leave_whitespace) + 160 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/shape_base.py:608(_column_stack_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/interval.py:1() + 7 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:528(_convert_) + 47 0.000 0.000 0.000 0.000 {built-in method numpy.empty} + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:226(_from_iter) + 77 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:1878(_signature_is_functionlike) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/polynomial.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/array.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:1136(_Unpickler) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:187(finalize) + 99 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:270(escape) + 1 0.000 0.000 0.045 0.045 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/random/_pickle.py:1() + 160 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/shape_base.py:207(_arrays_for_stack_dispatcher) + 222 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1335() + 58 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:261(helper) + 43 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:715(_from_parsed_parts) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/dtypes.py:66(_add_dtype_helper) + 103 0.000 0.000 0.000 0.000 {method 'setter' of 'property' objects} + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:1() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5100(parseImpl) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:213(__setitem__) + 135 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:920() + 1 0.000 0.000 0.021 0.021 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1() + 2 0.000 0.000 0.000 0.000 {built-in method posix.access} + 1 0.000 0.000 0.110 0.110 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/figure.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:174(Quantity) + 4/3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:397(_joinrealpath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ctypeslib.py:371() + 14 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hashlib.py:126(__get_openssl_constructor) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:34() + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:506(wrapper) + 237 0.000 0.000 0.000 0.000 {method 'values' of 'mappingproxy' objects} + 1 0.000 0.000 0.058 0.058 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/contour.py:1() + 1 0.000 0.000 0.013 0.013 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/arrow/array.py:1() + 58 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:114(__enter__) + 157 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:605(_is_initvar) + 140 0.000 0.000 0.000 0.000 {method 'pop' of 'collections.deque' objects} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/base64.py:3() + 46 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:725(_format_parsed_parts) + 61 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:550(from_word) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/take.py:1() + 27 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:45(allow_rasterization) + 1 0.000 0.000 0.935 0.935 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/dev/develop.py:1() + 134/34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1904(__str__) + 43 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3107(_generateDefaultName) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:462(get) + 26 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6855(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/buddhist.py:22(_BuddhistLunisolar) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1841(_handle_exitstatus) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:357(validate_fontsize) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1888(_try_wait) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:238(pattern) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:20(Base) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1079(__new__) + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:866(stem) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/numpy/function.py:1() + 19 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:126(from_string) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_tricontour.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/base_parser.py:1() + 1 0.000 0.000 0.011 0.011 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/arrow/array.py:184(ArrowExtensionArray) + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:415(__getattr__) + 78 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:883() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/common.py:1() + 1 0.000 0.000 0.077 0.077 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_libs/tslibs/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/resources.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimes.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/__init__.py:1() + 24/19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:472(_define) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend.py:1() + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/copyreg.py:103(_slotnames) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:1() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1189(reversed) + 1 0.000 0.000 0.020 0.020 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axes3d.py:1() + 145 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:259(__iter__) + 41 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:571(eval_token) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/multi.py:1() + 10 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:438(children) + 102 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:44(__init__) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/asserters.py:1() + 265 0.000 0.000 0.000 0.000 {built-in method _sre.unicode_iscased} + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/lines.py:1() + 1 0.000 0.000 0.019 0.019 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:1() + 25 0.000 0.000 0.000 0.000 {built-in method unicodedata.name} + 170 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:474(predicate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:348(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:282(__init__) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:503(_cmpkey) + 6 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2253(pprint_styles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/construction.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:1() + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/ewm.py:1() + 22 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4989(parseImpl) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:532() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1() + 27 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/warnings.py:165(simplefilter) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:882(wrapper) + 1 0.000 0.000 0.122 0.122 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/__init__.py:1() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/common.py:1() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1() + 215 0.000 0.000 0.000 0.000 {method 'startswith' of 'bytes' objects} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:9() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/melt.py:1() + 1 0.000 0.000 0.022 0.022 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/figure.py:181(FigureBase) + 62 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3796() + 192 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:230(decorator) + 1 0.000 0.000 0.037 0.037 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/text.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:26(__init__) + 50 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1884(set_name) + 22 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/__init__.py:176(flex_method_SERIES) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/categorical.py:246(Categorical) + 22 0.000 0.000 0.004 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:339(yield_from_source_iterator) + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/codecs.py:309(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:107(__calc_date_time) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/accessor.py:68(forbid_nonstring_types) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend.py:342(Legend) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/warnings.py:130(filterwarnings) + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:8406(_replace_return_type) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/uuid.py:1() + 298 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1617(overload) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:271() + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:1233(formatannotation) + 29 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:575(_cmp_fn) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:331(_resolve) + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:144(Block) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/missing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/period.py:1() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/__init__.py:1() + 1 0.000 0.000 0.024 0.024 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:1() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/_io.py:1() + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:876(copy_with) + 228 0.000 0.000 0.000 0.000 {method 'items' of 'mappingproxy' objects} + 48 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:741(config_prefix) + 23 0.000 0.000 0.000 0.000 {built-in method _struct.calcsize} + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:997(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/interval.py:148(IntervalIndex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/pickle_compat.py:1() + 31 0.000 0.000 0.000 0.000 {built-in method numpy.arange} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:705(polyval) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:242(solve_dependencies) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1013(reset_cache) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/twodim_base.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:64(check_isinstance) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:553(_define_adder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/quoprimime.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:578(_ReducedHCT_Element) + 363 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:781(__iter__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/figure.py:2360(Figure) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:62(__init__) + 11 0.000 0.000 0.000 0.000 {method 'sort' of 'list' objects} + 45 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:730(implement_consistent_units_by_argument) + 33 0.000 0.000 0.009 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:1012(wrap) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:1() + 111 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:554() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/holiday_base.py:12() + 1 0.000 0.000 0.038 0.038 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/__init__.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/common.py:2() + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/__init__.py:1() + 170 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:953(copy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/_endian.py:1() + 105 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:86(copy) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:62(_process_keys) + 156 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1973(__hash__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:1() + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:73(_create_methods) + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:1() + 98 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:758(decode) + 23 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:177(decorator) + 2 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:1170(make_dataclass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/grouper.py:1() + 441 0.000 0.000 0.000 0.000 {built-in method builtins.globals} + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:702(_from_parts) + 1 0.000 0.000 0.041 0.041 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/__init__.py:1() + 14 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/__init__.py:438(flex_arith_method_FRAME) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/types.py:69(new_class) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1045(__del__) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha3_224} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/encoder.py:1() + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:8394(getdoc) + 4 0.000 0.000 0.000 0.000 {method 'fileno' of '_io.BufferedReader' objects} + 1 0.000 0.000 0.141 0.141 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/changeyear.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/helpers.py:541(_makeTags) + 16 0.000 0.000 0.000 0.000 {method 'splitlines' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/docstrings.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/_mixins.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/datetimes.py:1() + 1 0.000 0.000 0.021 0.021 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/api.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/holiday_base.py:51(HolidayBase) + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:59(parsestr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:1() + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:1() + 81 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/__init__.py:25(decorator) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1184(wait) + 47 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:752(__fspath__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:94(_add_aliases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:202() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/html.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimes.py:155(DatetimeArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/timedeltas.py:1() + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:667(__init__) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:804(__mro_entries__) + 245 0.000 0.000 0.000 0.000 {built-in method _sre.unicode_tolower} + 65 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:205() + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:8389(__init__) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4263(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/period.py:114(PeriodArray) + 73 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:775(keys) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:299(parse_single) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/plotting/_core.py:1() + 1 0.000 0.000 0.020 0.020 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/compat/__init__.py:1() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:105(__init__) + 1 0.000 0.000 0.029 0.029 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1() + 2 0.000 0.000 0.010 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:403(select) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:150(__init__) + 24/19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2119(_define) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:309(_convert) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/core.py:49(use) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/_common.py:1() + 388 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1646(final) + 1 0.000 0.000 0.045 0.045 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/random/__init__.py:1() + 201 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:59(func) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:613(load_definitions) + 54 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2477(parseImpl) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/datetimelike.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/type_check.py:1() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:33(seterr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:29() + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4077(_generateDefaultName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1969() + 5 0.000 0.000 0.000 0.000 {built-in method _imp.exec_builtin} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/base.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:102(ExtensionArray) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:132(check_shape) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:1() + 14 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:618(set_parse_action) + 12 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1132(parse_string) + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:440() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/concat.py:1() + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1098(_make_child_relpath) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_compile.py:440(_bytes_to_codes) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/function_base.py:2285(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/pivot.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/TiffTags.py:20() + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_string_helpers.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/period.py:1() + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:543() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:235(register) + 72 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:771(wrap) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/timedeltas.py:103(TimedeltaArray) + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:218(_acquireLock) + 334 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:787(name) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/masked.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:264(get_aliased_and_aliases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_cm.py:1() + 17/10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:42(__init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/generic.py:1164(DataFrameGroupBy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:1() + 2 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:173(__init__) + 1 0.000 0.000 0.013 0.013 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/masked.py:100(BaseMaskedArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/xml.py:1() + 39 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:303(splitroot) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1() + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:24(_prevent_rasterization) + 223 0.000 0.000 0.000 0.000 {method 'keys' of 'dict' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/prices/utils.py:1() + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1595(_array_str_implementation) + 114 0.000 0.000 0.000 0.000 {built-in method _struct.unpack} + 22 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5233(parseImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/numbers.py:1() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:377(_mac_os_check) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/array_ops.py:1() + 37 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:16(_fr0) + 53 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:182(_add_module) + 77 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:91(ismethoddescriptor) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hashlib.py:5() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/concat.py:1() + 6 0.000 0.000 0.000 0.000 {method 'append' of 'collections.deque' objects} + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:637(_create_method) + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1166(glob) + 78 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4078() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2271() + 16 0.000 0.000 0.000 0.000 {built-in method time.strftime} + 168 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:183() + 69 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/signal.py:9() + 10/3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:14(__get__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:1() + 204 0.000 0.000 0.000 0.000 {method 'ljust' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/nanfunctions.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:101(Random) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tempfile.py:1() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/base.py:269(IndexOpsMixin) + 1 0.000 0.000 0.015 0.015 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/core.py:1() + 119 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:196() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:210(__init__) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:924() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/align.py:1() + 171 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1734(leave_whitespace) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:111() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/contexts.py:1() + 172 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/multiarray.py:153(concatenate) + 65 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:849(__iter__) + 1 0.000 0.000 0.018 0.018 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/compat/py3k.py:1() + 27 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:176(finalize) + 65 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:99(deprecated) + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:589(_hash_fn) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:4() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expressions.py:1() + 130 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:413(__getitem__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/plot.py:1() + 23/6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4607(streamline) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/signal.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/shape_base.py:1() + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:831(name) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:10() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1() + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/compressors.py:1() + 59 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:98(_compile) + 185 0.000 0.000 0.000 0.000 {method 'endswith' of 'bytes' objects} + 41 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:431(UnitsContainer) + 10/5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:973(__get__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pickle.py:1() + 9 0.000 0.000 0.017 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:729(__init_subclass__) + 22 0.000 0.000 0.000 0.000 {built-in method _abc._abc_register} + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1() + 53 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:284() + 1 0.000 0.000 0.015 0.015 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:1() + 2 0.000 0.000 0.000 0.000 {built-in method posix.mkdir} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:238(Dvi) + 1 0.000 0.000 0.016 0.016 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/api.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:467(Image) + 85 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:993() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:1() + 28 0.000 0.000 0.000 0.000 {method 'fullmatch' of 're.Pattern' objects} + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/utils.py:5() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/bz2.py:1() + 100 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:234() + 77 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:286(isbuiltin) + 102 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:767() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/polynomial.py:1472(Polynomial) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:6133() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:971(__or__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/records.py:1() + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/describe.py:1() + 1 0.000 0.000 0.068 0.068 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:1() + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parquet.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:139(__new__) + 95 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:185(keys) + 81 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/__init__.py:14(set_module) + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:325(find_cookie) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/encoding.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/construction.py:1() + 143 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3970() + 26 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:164(islink) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gettext.py:1() + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5682(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_sysconfigdata__darwin_darwin.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/bezier.py:1() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/__init__.py:14() + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:33(parse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/_polybase.py:18(ABCPolyBase) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:119(clear) + 1 0.000 0.000 0.105 0.105 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/__init__.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/category.py:1() + 21 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:43(update) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:58(__getitem__) + 38 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:24(_fr1) + 1 0.000 0.000 0.010 0.010 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:5() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:2() + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:272(__getitem__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2928(_generateDefaultName) + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/__init__.py:14() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1411(get_type_hints) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:483(__init__) + 2 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:526(read_text) + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:462(_validate_linestyle) + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:77(__getitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/array.py:292(SparseArray) + 82 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:903() + 39 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1097(parse_unit_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/from_dataframe.py:1() + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:194(find_spec) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:300(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/missing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/categories.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry_helpers.py:1() + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:783(copy_with) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/python_parser.py:1() + 134 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/_distutils_hack/__init__.py:96() + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:940() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:736(_make_child) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:132(geterr) + 4 0.000 0.000 0.000 0.000 {built-in method posix.register_at_fork} + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/fft/_pocketfft.py:1() + 84 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:244() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numerictypes.py:441(_construct_lookups) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:21(_fileobj_to_fd) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:680(operate) + 105 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:88(do_copy) + 138 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:247() + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/util/hashing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/range.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:84(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:76(inner) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/struct.py:1() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:771(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:484(__new__) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1955() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/tile.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/pfstate.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/string_.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/accessor.py:1() + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:709(max) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/utils.py:12() + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:482(cycler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/localedata.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_nested_sequence.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/lines.py:216(Line2D) + 105 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:331(wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/testing/testing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:1() + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:227(_releaseLock) + 62 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1089(_init) + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:770(_hash_add) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/mlab.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:711(copy) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/path.py:202(_update_values) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:454(from_definition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:488(_read_tzfile) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/__init__.py:2() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:1() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:506(suppress_matplotlib_deprecation_warning) + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:955(__contains__) + 24/19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1441(_define) + 1 0.000 0.000 0.097 0.097 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:1() + 35 0.000 0.000 0.000 0.000 {method 'astype' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/header.py:5() + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/common.py:34(wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:673() + 85 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1910(streamline) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:110(_create_delegator_method) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/utils.py:1() + 10/4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4271(streamline) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/text.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/fnmatch.py:1() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/eval.py:1() + 23 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5225(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/chebyshev.py:1() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:596(__sub__) + 38 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:91(_float_to_float) + 20 0.000 0.000 0.000 0.000 {built-in method _functools.reduce} + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:44(_bits_of) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:546(_cycler) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:368(__init__) + 1 0.000 0.000 0.083 0.083 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/matplotlib.py:1() + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1561(__or__) + 62 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2285(_register_style) + 141 0.000 0.000 0.000 0.000 {built-in method _warnings._filters_mutated} + 91 0.000 0.000 0.000 0.000 {built-in method sys._getframe} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/datetimelike.py:81(DatetimeIndexOpsMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:388(open) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:1() + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:52(__init__) + 1 0.000 0.000 0.110 0.110 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/numpy/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/ewm.py:124(ExponentialMovingWindow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/helpers.py:1027() + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_dtype_ctypes.py:100(dtype_from_ctypes_type) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:911(construct_from_string) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:760(get) + 84 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:149(lazy) + 97 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:6025() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/proj3d.py:1() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:260() + 127 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2435(__getnewargs__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/prices/convert.py:1() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:135(__hash__) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/textpath.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:799(singledispatch) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/_optional.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/wavg.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:149(PfLineArithmatic) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1689(isEnabledFor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/numeric.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:2() + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:423(register_extension_dtype) + 42 0.000 0.000 0.000 0.000 {method 'update' of 'set' objects} + 39 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:83() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1630(make_norm_from_scale) + 3 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2211(__init_subclass__) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:240(_check_versions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pprint.py:103(PrettyPrinter) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:450() + 31 0.000 0.000 0.000 0.000 {method 'reshape' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/interop.py:1() + 10 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5706(__init__) + 51 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2448(_generateDefaultName) + 129 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:24(__getitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/bz2.py:27(BZ2File) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:938(_create_pseudo_member_) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:219(__seqToRE) + 6 0.000 0.000 0.000 0.000 :415(spec_from_loader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/function_base.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_exceptions.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/managers.py:95(BaseBlockManager) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:12() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:843(is_one_of_factory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/markers.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/sorting.py:1() + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:1337(_to_unmasked_float_array) + 46 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:110(__init__) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:1179(construct_from_string) + 1 0.000 0.000 0.091 0.091 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colorbar.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_fontconfig_pattern.py:57(_make_fontconfig_parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/datetimelike.py:404(DatetimeTimedeltaMixin) + 5 0.000 0.000 0.003 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:178(from_string) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:920() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tokenize.py:319(read_or_stop) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:290(__getattr__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/bisect.py:1() + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:744() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6550(__new__) + 1 0.000 0.000 0.093 0.093 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__config__.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ntpath.py:2() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/_compat.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/gridspec.py:26(GridSpecBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arraylike.py:31(OpsMixin) + 161 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:200(escape_re_range_char) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2952(_update_from) + 92 0.000 0.000 0.000 0.000 {method 'insert' of 'list' objects} + 1 0.000 0.000 0.000 0.000 {method 'reduce' of 'numpy.ufunc' objects} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/decimal.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/contour.py:72(ContourLabeler) + 15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:468(__copy__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext_data.py:464() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:14(lighten) + 62 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:49() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_afm.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:321(extract) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:514(_get_config_or_cache_dir) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/scope.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/selectn.py:1() + 15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:85(_listify_validator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/base.py:19(BaseStringArrayMethods) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:67(zeros_like) + 68 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:479(set_raw) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/array_ops.py:408(get_array_op) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:511() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:336(_validate_cmap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/numpy_.py:1() + 134 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:93(__init__) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/__init__.py:1() + 1 0.000 0.000 0.021 0.021 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_fontconfig_pattern.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1671(FigureCanvasBase) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:3() + 48 0.000 0.000 0.000 0.000 {method 'clear' of 'dict' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/arraysetops.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:1115(StataReader) + 76 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:640() + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:223(split) + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:203(_add_array_type) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axis3d.py:38(Axis) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:340() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:1() + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:46() + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:188(_filter_nodes) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/doc.py:93(window_agg_numba_parameters) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2808(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/__init__.py:182() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_table_schema.py:1() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:140(basename) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/engines.py:1() + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha3_256} + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:515(_cmpkey) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:206(BaseRegistry) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:849(__init__) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:237(getdoc) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:688(__delitem__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:2() + 297 0.000 0.000 0.000 0.000 {method 'popleft' of 'collections.deque' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:434(BakomaFonts) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2607(__hash__) + 108 0.000 0.000 0.000 0.000 {built-in method _struct.pack} + 70 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:794(_is_dim) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/generic.py:1() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:78(_check_methods) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:1() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/api.py:1() + 47 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:697(__iter__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:290(update) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:737(_get_scale_docs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:327(f) + 53 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/pint_eval.py:69(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:1() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:78(__init__) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/decoder.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/string_arrow.py:1() + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:193(_checkLevel) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1479(__mul__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:74(_add_types) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:259(getwhile) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2544(_arraymethod) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:843(register) + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:337(__repr__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:17(TextWrapper) + 2 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/__init__.py:299(loads) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:255(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:34(ParseResults) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1215(__init__) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/boolean.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ctypeslib.py:1() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:431(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/decoder.py:284(__init__) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:725(__truediv__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/c_parser_wrapper.py:1() + 78 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:110(get) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/astype.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:435(joinpath) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/__init__.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_constrained_layout.py:1() + 59 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:601() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:10() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sas/sasreader.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/legendre.py:1() + 13 0.000 0.000 0.002 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:401(validate_font_properties) + 156 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:805(postParse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/timedeltas.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/core.py:1041(default_locale) + 119 0.000 0.000 0.000 0.000 {method 'values' of 'dict' objects} + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/codecs.py:260(__init__) + 1 0.000 0.000 0.238 0.238 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/plot.py:1() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:771() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:123(_add_integer_aliases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:479(HDFStore) + 57 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2275() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/api.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_char_codes.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/relativedelta.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/texmanager.py:1() + 10 0.000 0.000 0.000 0.000 {method 'tolist' of 'memoryview' objects} + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:434(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/nested_helper.py:1() + 55 0.000 0.000 0.000 0.000 {method 'mro' of 'type' objects} + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/abc.py:110(register) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/core.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/datetimes.py:103(DatetimeIndex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:48() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/flags.py:6(Flags) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/base.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/feather_format.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/base64mime.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/categories.py:22(Categories) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2106(IdentityTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/period.py:70(PeriodIndex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:99(_extend_docstrings) + 65 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:257(__bool__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:560(RawConfigParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/groupby.py:612(BaseGroupBy) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2929(charsAsStr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:870(Window) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/printing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/lzma.py:38(LZMAFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/category.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/twodim_base.py:534(vander) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numerictypes.py:514(_scalar_type_key) + 9 0.000 0.000 0.000 0.000 {built-in method numpy.seterrobj} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/laguerre.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:159(Version) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/html/__init__.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:1066(expand_template) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:120(_WindowsFlavour) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:95(BinOp) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs.py:6754(refer_to_array_attribute) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/arrow/dtype.py:1() + 1 0.000 0.000 0.936 0.936 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/dev/__init__.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/uuid.py:138(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_openpyxl.py:1() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:381(__getattr__) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/__init__.py:2() + 1 0.000 0.000 0.020 0.020 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/matrixlib/defmatrix.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3086(ArrowStyle) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:1() + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:180(from_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:171(_expand_vars) + 89 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:802(__init__) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1927(_namedtuple_mro_entries) + 1 0.000 0.000 0.019 0.019 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/__init__.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/table.py:9() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/prices.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/compat/py3k.py:92(contextlib_nullcontext) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/numeric.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/numpy_.py:39(PandasArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:59(NDArrayOperatorsMixin) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:146(_munge_whitespace) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:465(register) + 62 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:96(lazy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzinfo.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/array_manager.py:99(BaseArrayManager) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:212(_validate_pathlike) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:841(outer) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:752(construct_from_string) + 55 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:394() + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:273(validate_color_or_auto) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:313(from_lines) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:76(CFUNCTYPE) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:843(TarInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:667(BaseGrouper) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5979() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/scanner.py:1() + 25 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:106(__eq__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:430(__enter__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextvars.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:450(StringConverter) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/accessor.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colorbar.py:195(Colorbar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/utils.py:1() + 44 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3986() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:90() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_base.py:1404(ExcelFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/numba_.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/GimpGradientFile.py:16() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansitowin32.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/numba_.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2293(BoxStyle) + 41 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:205() + 27 0.000 0.000 0.000 0.000 {method 'rsplit' of 'str' objects} + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:331(Version) + 57 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:152() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/base.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_normalize.py:3() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/changefreq.py:1() + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:249() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/fnmatch.py:80(translate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/orc.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/object_array.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/managers.py:972(BlockManager) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1146(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/plotting/_core.py:613(PlotAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimelike.py:1789(TimelikeOps) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gzip.py:1() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:818(_from_iterable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:269(close) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/custom.py:24(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_cm.py:158() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/numbers.py:4() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/format.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_validators.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:75(__call__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1086(enable_packrat) + 52 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/common.py:21(unpack_zerodim_and_defer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/tzone.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/fft/__init__.py:1() + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_md5} + 36 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:285(line) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:126(seed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:1() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:650(cache) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:307(_get_machar) + 3 0.000 0.000 0.000 0.000 {built-in method _csv.register_dialect} + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/charset.py:5() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:176(add_delegate_accessors) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:43(Tick) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:830(uname) + 64 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:805(__len__) + 25 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:949() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2578(Fixed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:3237(Table) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/thai.py:21(_ThaiLunisolar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/isboundary.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:1712(_add_arithmetic_ops) + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:1855(isscalar) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:360(add) + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:845() + 1 0.000 0.000 0.007 0.007 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arraylike.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:110(BaseWindow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:211(BboxBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pprint.py:11() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:747(get_symbol) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/hermite_e.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1697(Norm) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:83() + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:262() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1174(parse_units) + 57 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:265() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1584(_get_handles) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/__init__.py:1() + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:844() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:85(__call__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:1() + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:996(CheckButtons) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:350() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:631(DatetimeTZDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/array_manager.py:695(ArrayManager) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:44(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/twodim_base.py:158(eye) + 1 0.000 0.000 0.243 0.243 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_secondary_axes.py:11(SecondaryAxis) + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:815(__new__) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/abc.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/timedeltas.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:205(PintArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:25(ParseBaseException) + 96 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:778() + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4332() + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:80() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/texmanager.py:56(TexManager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/concat.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_print_versions.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/doc.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:588(matplotlib_fname) + 38 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:12(code_to_chars) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/arrow/dtype.py:195(construct_from_string) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_secondary_axes.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1434(is_dir) + 4/3 0.000 0.000 0.000 0.000 {method 'view' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/extension.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2264() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/_warnings.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:445(zip_children) + 36 0.000 0.000 0.000 0.000 {method 'acquire' of '_thread.RLock' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/api/types/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_util.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:123(CategoricalDtype) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1446(__radd__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:27(Collection) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2888(_hash_basis) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/table.py:37(Cell) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/base_parser.py:99(ParserBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:85(identchars) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/actions.py:3() + 12/2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1538(makeOptionalList) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_odfreader.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/islamic.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:30() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/hermite.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/registry.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1594(datetime) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5899(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/histograms.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:114(__call__) + 1 0.000 0.000 0.000 0.000 {method 'close' of '_io.TextIOWrapper' objects} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:159(_commonType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:558(DataFrameFormatter) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:943() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:340(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/fractions.py:38(Fraction) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:5() + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:41(parse) + 60 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:956() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:43(Wqpr) + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_string_helpers.py:16(english_lower) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:49(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1209(resolve) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hmac.py:27(HMAC) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:101(push) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:139(finalize) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:69(PfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_text_helpers.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:2231(StataWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/babel_names.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:677(Bbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:153(RendererBase) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/path.py:1() + 60 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:404() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/dtype.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/plotting/_misc.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/common.py:1() + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1847() + 11 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:251(_inner) + 92 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2869(return_annotation) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:248(unregister) + 59 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:409(__subclasshook__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:653(PurePath) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:308(construct_from_string) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:315(_compile_repl) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:489(indent) + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:139(__init__) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:242(__set_name__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/standardize.py:1() + 2/1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:535(get_config_vars) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:91() + 16/4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:79(_convert) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:86(_get_system_version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/dates.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/matrixlib/defmatrix.py:73(matrix) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:30(Unit) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:989(__setitem__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4968(__init__) + 44 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:101(_float_conv) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:341(BaseExprVisitor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/einsumfunc.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/polyutils.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/inference.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:118() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:102(WrappedCythonOp) + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:1851(_str_equal) + 21 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:461(readlink) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/matplotlib.py:60(setup_matplotlib_handlers) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/defchararray.py:1922(chararray) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/api.py:1() + 29 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:112(__post_init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/expanding.py:1() + 53 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:280(replaced_by_pep8) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:27(Patch) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:1008(_sys_version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/freq.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:720(_create_comparison_method) + 1 0.000 0.000 0.011 0.011 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/fractions.py:4() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansitowin32.py:16(StreamWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/trim.py:1() + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_dtype_ctypes.py:71(_from_ctypes_scalar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/tseries/offsets.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:334(_init_dynamic_classes) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:363() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/types.py:100(prepare_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:1604(TarFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:151(_set_up_aliases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/clipboards.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:99(identbodychars) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/flat_helper.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/stride_tricks.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_asarray.py:1() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:990(addgroup) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1552(__call__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:584(_setResultsName) + 44 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:17() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/indexing.py:1() + 2 0.000 0.000 0.000 0.000 {built-in method time.tzset} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gzip.py:120(GzipFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/grouper.py:468(Grouping) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/create.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/dev/mockup.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/memmap.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:294(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_tripcolor.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/putmask.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/frame.py:1() + 32 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:1862(_str_lower_equal) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:378(DistributionFinder) + 72 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:551() + 1 0.000 0.000 0.149 0.149 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:2793(NavigationToolbar2) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/units.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/arrow_parser_wrapper.py:1() + 10 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1429(_parse_units) + 14 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:698() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/linecache.py:80(updatecache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/common.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_typing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/intersect.py:1() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:817(is_instance_factory) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/win32.py:4() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/extendpandas.py:10(apply) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:715(_generate_next_value_) + 56 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4031() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:302(from_string) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:767(__contains__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/categorical.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:102(BasicPythonHeader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:18(PolarTransform) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_odswriter.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/spines.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/win.py:2() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:445() + 55 0.000 0.000 0.000 0.000 {method '__exit__' of '_thread.RLock' objects} + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:694(__mro_entries__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/masked_reductions.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/measurement.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/common.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/mathtext.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/genericpath.py:39(isdir) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4633(_generateDefaultName) + 63 0.000 0.000 0.000 0.000 {method 'pop' of 'set' objects} + 23 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:173(array_function_from_dispatcher) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/__init__.py:37(set_function_name) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:716(_create_arithmetic_method) + 47 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4266() + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/string.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:54(literal_eval) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_bootlocale.py:33(getpreferredencoding) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_encoded_words.py:1() + 5 0.000 0.000 0.000 0.000 {built-in method posix.waitstatus_to_exitcode} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/dtype.py:42(SparseDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/managers.py:1835(SingleBlockManager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:213(_get_version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:1() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:634() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:262(_reset_cache) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:122(_add_methods) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:1564(_load_fontmanager) + 1 0.000 0.000 0.010 0.010 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:344(Slider) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/floor.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:211(_set_array_types) + 60 0.000 0.000 0.000 0.000 {method 'removeprefix' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:3809(PolygonSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/ufunclike.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_shape.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/appdirs.py:6() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:802(__init__) + 56 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:530(_select_from) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:434(__iter__) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/overrides.py:23(set_array_function_like_doc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/_random.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/compat.py:62(_test_array_function_protocol) + 1 0.000 0.000 0.009 0.009 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/flat_methods.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:96(__get__) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:956(getattr_maybe_raise) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/leftandright.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/units.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/layout_engine.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/gridspec.py:1() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/fromnumeric.py:3176(ndim) + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:44(_numeric_methods) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/nested_methods.py:1() + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2269() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:195(add_units) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/quiver.py:445(Quiver) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/__init__.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/__init__.py:8() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:1416(ArtistInspector) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:438() + 46 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:315(__subclasshook__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_distributor_init.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/categorical.py:122(_cat_compare_op) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:851(get_root_units) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1066(Path) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:152(__calc_timezone) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:1324(__init__) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:2259(_make_getset_interval) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:1() + 2 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/decoder.py:332(decode) + 2 0.000 0.000 0.008 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/__init__.py:32(message_from_string) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/_optional.py:91(import_optional_dependency) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_layoutgrid.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1138(home) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/text.py:1615(Annotation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/pfstate_helper.py:1() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:82(RLock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:105(Message) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:582(get_data_path) + 7 0.000 0.000 0.004 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/__init__.py:109(import_module) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:779(items) + 2 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1262(read_text) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:861(_DomainGreater) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/numeric.py:238(NumericArray) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:327(resolve) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:45(parse) + 57 0.000 0.000 0.000 0.000 {method 'copy' of 'dict' objects} + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/re.py:331(filter) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:56(__init_subclass__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/isoparser.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_xlrd.py:1() + 5 0.000 0.000 0.003 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:67(numeric_parse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:763(GraphicsContextBase) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/__init__.py:480(flex_comp_method_FRAME) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4563(recurse) + 47 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4267() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/parsing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:31(DefinitionFile) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:178(_call_parse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_datasource.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/buddhist.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageColor.py:20() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:95(__calc_am_pm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:600(FrameApply) + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:36(_inplace_binary_method) + 96 0.000 0.000 0.000 0.000 {built-in method builtins.abs} + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:465(indent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:97(_determine_error_states) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:920(npy_ctypes_check) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/plotting/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/spss.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:119(Cycler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1419(exists) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha3_512} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3018(Regex) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:366(unregister) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_globals.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_common.py:1() + 1 0.000 0.000 0.084 0.084 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2323(setup_matplotlib) + 28 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:696() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:62(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/fft/helper.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:700(Popen) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6540(MaskedConstant) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:458(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:70(Term) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/merge.py:638(_MergeOperation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/python_parser.py:62(PythonParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:508(Formatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:264() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/peakperiod.py:16(factory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:2242(LogLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:31(General) + 4 0.000 0.000 0.000 0.000 {method 'read' of '_io.StringIO' objects} + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:958(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/api.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/pfstate.py:22(PfState) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/__init__.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/__init__.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/display.py:1() + 52 0.000 0.000 0.000 0.000 {method 'removesuffix' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/localization.py:1() + 2 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/hashlib.py:82(__get_builtin_constructor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/base.py:181(SelectionMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2750(GenericFixed) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/take.py:352(_view_wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_base.py:900(ExcelWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/string_arrow.py:63(ArrowStringArray) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/peakperiod.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/util/numba_.py:1() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5904(__add__) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axis3d.py:5() + 27 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:343() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:233(__init__) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:171(__init__) + 1 0.000 0.000 0.000 0.000 {built-in method posix.urandom} + 1 0.000 0.000 1.007 1.007 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/dev_scripts/heaviness.py:6(main) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/isoparser.py:22(_takes_ascii) + 1 0.000 0.000 0.011 0.011 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/ndframelike.py:1() + 5 0.000 0.000 0.000 0.000 :241(_requires_builtin_wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:664(_LocationIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_pyxlsb.py:18(PyxlsbReader) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1679(_make_norm_from_scale) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1697(__call__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:771() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:352(register) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_shake_128} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/stackplot.py:1() + 2 0.000 0.000 0.000 0.000 {built-in method posix.unsetenv} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/chinese.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:1077(poly1d) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:217(__init_subclass__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:877(to_units_container) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1814(__del__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shlex.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_tester.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:208(OffsetBox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:102(PfStateArithmatic) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:273() + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_shake_256} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:191() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/_constants.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/replace.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:441(_validate_papersize) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3533() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/api/extensions/__init__.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:970(json_load) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/duration.py:1() + 59 0.000 0.000 0.000 0.000 {method 'span' of 're.Match' objects} + 36 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:78() + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/invalid.py:40(make_invalid_op) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_pyxlsb.py:2() + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/fractions.py:276(_operator_fallbacks) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:84() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/grouper.py:57(Grouper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/utils.py:1() + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_tzpath.py:1() + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha3_384} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/ops.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1991(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/numbers.py:32(Complex) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sre_parse.py:289(seek) + 35 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:383(_check_int_field) + 1 0.000 0.000 0.000 0.000 {method 'sum' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:181(LegacyVersion) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:39(ExtensionDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/frozen.py:21(FrozenList) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/constants.py:14() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/initialise.py:2() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:415(_check_date_fields) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:174(_make_type_validator) + 60 0.000 0.000 0.000 0.000 {built-in method builtins.divmod} + 36 0.000 0.000 0.000 0.000 {method 'release' of '_thread.RLock' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/_numba/executor.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tempfile.py:627(SpooledTemporaryFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1615(__init__) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:64(_iter_definitions) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/charset.py:211(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:1034(NonUniformImage) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_base.py:518(BaseExcelReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/prices/hedge.py:1() + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:523() + 2 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5996(srange) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:2533(SpanSelector) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:6023() + 7 0.000 0.000 0.004 0.001 :1018(_gcd_import) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_xlsxwriter.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/gregorian.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/registry.py:167(EntityLoader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3001(Bar) + 2 0.000 0.000 0.011 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:562(version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:1341(TextBox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:390(render_pep440) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:1() + 2 0.000 0.000 0.000 0.000 {built-in method numpy.zeros} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzfile.py:1() + 1 0.000 0.000 0.096 0.096 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_libs/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/_binary.py:15() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageChops.py:18() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5111(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/__future__.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:306(decorator) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:156(has_symbol) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:152(validate_axisbelow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:665(Colormap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3749(ParseExpression) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:435(__exit__) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:131(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/masked_accumulations.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:3158(StataWriter117) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/table.py:239(Table) + 10 0.000 0.000 0.000 0.000 {method 'cast' of 'memoryview' objects} + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5249(_generateDefaultName) + 27 0.000 0.000 0.000 0.000 {method 'partition' of 'str' objects} + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/_mixins.py:77(ravel_compat) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:188(caching_module_getattr) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha224} + 1 0.000 0.000 0.000 0.000 {built-in method math.sqrt} + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:465(maybe_operate_rowwise) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/string_.py:230(StringArray) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2897(__hash__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/winterm.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/floating.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/times.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/api/indexers/__init__.py:1() + 26 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4279() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/common.py:430() + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:221() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:791(Thread) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/children.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/string.py:69(__init_subclass__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:93(raiseerror_if_otherNone) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/core.py:1150(parse_locale) + 35 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/multiarray.py:1080(copyto) + 38 0.000 0.000 0.000 0.000 {method 'groupdict' of 're.Match' objects} + 92 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:141() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:615(RangeSlider) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:716(TableBuilderAbstract) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:53(__init__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1602(__new__) + 1 0.000 0.000 0.000 0.000 {method 'newbyteorder' of 'numpy.generic' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:315(UnitsContainer) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:564(get_content_type) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:94(_append_doc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:821(PeriodDtype) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4331(_generateDefaultName) + 47 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:151() + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:19(type_aliases_gen) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3641(__init__) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cycler/__init__.py:190(change_key) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/base.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_cm_listed.py:2061() + 2 0.000 0.000 0.000 0.000 {built-in method posix.putenv} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1318(mkdir) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:844(SQLTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/startofday.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:162(Distribution) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:46(dont_init_twice) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2658(ConnectionStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/abc.py:59(Traversable) + 1 0.000 0.000 0.021 0.021 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/matrixlib/__init__.py:1() + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/numpy/function.py:48(__init__) + 56 0.000 0.000 0.000 0.000 {method '__init_subclass__' of 'object' objects} + 5 0.000 0.000 0.000 0.000 :1233(_get_parent_path) + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:48(add_flex_arithmetic_methods) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:670(Rectangle) + 5 0.000 0.000 0.000 0.000 :757(create_module) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_fontconfig_pattern.py:59(comma_separated) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:94(iter_definitions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:128(pyparsing_unicode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3612(__init__) + 2 0.000 0.000 0.000 0.000 {built-in method math.log} + 1 0.000 0.000 0.000 0.000 {method 'view' of 'numpy.generic' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:1942(IndexCol) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/round.py:1() + 2 0.000 0.000 0.002 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:536(distribution) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:120(CallbackRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/api.py:23(FFI) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:804(PolarAxes) + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2889() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/locale.py:386(normalize) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/locale.py:577(getlocale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/hindu.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:31(PintType) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:974(__truediv__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/missing.py:873(_datetimelike_compat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/spines.py:14(Spine) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:80(_invalidates_cache) + 38 0.000 0.000 0.000 0.000 {method 'reverse' of 'list' objects} + 85 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_compat_pickle.py:167() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:584(_can_use) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_odswriter.py:30(ODSWriter) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4103(__init__) + 1 0.000 0.000 0.016 0.016 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/__init__.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:127(maybe_split) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:144(method_wraps) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_tight_layout.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:304(GPS) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1590(nocache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:241(parserinfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/_ranges.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:214(socket) + 15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:311(copy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:97(ColorSequenceRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:1037(IntervalDtype) + 1 0.000 0.000 0.088 0.088 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:526(ParserHelper) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:696(min) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:3205(RectangleSelector) + 2 0.000 0.000 0.000 0.000 {built-in method _locale.nl_langinfo} + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:281(__set_name__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_machar.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5322(__init__) + 1 0.000 0.000 0.004 0.004 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:214(parse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:787(JsonReader) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:508(_search_paths) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3089(re) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/arraypad.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:117(_get_system_version_tuple) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:169(_SixMetaPathImporter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/missing.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:289(wrapper) + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:21(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/base.py:37(DataManager) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:200(extract_stack) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1314(__init__) + 38 0.000 0.000 0.000 0.000 {built-in method _ctypes.sizeof} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/quantile.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:231(_ImageBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/colorsys.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:516(select_from) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/accessor.py:137(_map_and_wrap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5412(Forward) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1339(LocationEvent) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/__init__.py:1() + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimes.py:115(_field_accessor) + 74 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:203(no_escape_re_range_char) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:51() + 2 0.000 0.000 0.000 0.000 :1216(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/pint_eval.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/testing.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1212(AnnotationBbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/ndframelike.py:11(NDFrameLike) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:388(realpath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:3127(view) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/concat.py:388(_Concatenator) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:312(_logged_cached) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/excelclipboard.py:22(ExcelClipboardOutput) + 71 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/signal.py:21() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:386(tzfile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:102(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/dataframeexport.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:52() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:118() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_common.py:132(_validate_fromutc_inputs) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/api/interchange/__init__.py:1() + 23 0.000 0.000 0.000 0.000 {method 'discard' of 'set' objects} + 70 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/signal.py:16() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:381(fill) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/_polybase.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/display.py:17(detect_console_encoding) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/tseries/frequencies.py:178(_FrequencyInferer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/string_.py:68(StringDtype) + 2 0.000 0.000 0.009 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:263(version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/quiver.py:235(QuiverKey) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triplot.py:1() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:229() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4535(ParseElementEnhance) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:609(gen_candidates) + 23 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:810(inner) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/datetimelike_accumulations.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/ceil.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/holiday_base.py:970(HolidaySum) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:2() + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/inference.py:328(is_hashable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/pyarrow.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/check.py:1() + 29 0.000 0.000 0.000 0.000 {method 'readline' of '_io.BytesIO' objects} + 43 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_compat_pickle.py:165() + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha1} + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/__init__.py:274(load) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImagePalette.py:19() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1693(Annulus) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6643(__setattr__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:848(Handler) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3685(parseImpl) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:2197(make) + 23 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:152(symbol) + 21 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:996() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:64(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_dtype.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/boolean.py:232(BooleanArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/frozen.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/array_manager.py:1147(SingleArrayManager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/plotting/_misc.py:553(_Options) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:1505(SQLDatabase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:345(PngStream) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_trirefine.py:1() + 3 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1118(_opener) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:489() + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/fromnumeric.py:3172(_ndim_dispatcher) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:471(remove_custom_flags) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:1() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:428(_check_time_fields) + 26 0.000 0.000 0.000 0.000 {method 'index' of 'str' objects} + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:925(clear) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:595(render) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6345(mvoid) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/util.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:214(__init__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:400(_datetimelike_compat) + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:251(__contains__) + 18 0.000 0.000 0.000 0.000 {built-in method numpy.geterrobj} + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:201(register_class) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:70(__init__) + 15 0.000 0.000 0.000 0.000 :1() + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:260(__iter__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/generic.py:11879(_doc_params) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/container.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/function_base.py:2117(vectorize) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/console.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:358(BaseInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2263(DataCol) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5090(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1513(Ellipse) + 12 0.000 0.000 0.000 0.000 {built-in method builtins.round} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/arrow/dtype.py:39(ArrowDtype) + 30 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4278() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:925(copy_with) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:409(_NormalAccessor) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:80(__calc_weekday) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:6033(token_map) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:172() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:148(Calendar) + 1 0.000 0.000 0.014 0.014 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/arrow/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:669(BaseWindowGroupby) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_xlsxwriter.py:175(XlsxWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3173(QuotedString) + 5 0.000 0.000 0.000 0.000 {method 'rfind' of 'bytes' objects} + 33 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:452(_parse_letter_version) + 21 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3780(recurse) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:61(series_property_raising_typeerror) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:200(_Framer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:2123(identity) + 1 0.000 0.000 0.109 0.109 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/__init__.py:2() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:1() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:239(__init__) + 26 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4277() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/quiver.py:866(Barbs) + 27 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1197() + 1 0.000 0.000 0.000 0.000 {method 'squeeze' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_version.py:14(NumpyVersion) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:648(__copy__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_pylab_helpers.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:169(Column) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3099(re_match) + 1 0.000 0.000 0.000 0.000 {built-in method select.poll} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:116(_get_single_key) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3552(__init__) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2265() + 33 0.000 0.000 0.000 0.000 {built-in method _operator.index} + 3 0.000 0.000 0.000 0.000 {method 'toordinal' of 'datetime.date' objects} + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:157(_register_type) + 1 0.000 0.000 0.000 0.000 {built-in method time.localtime} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:2216(timezone) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:263(_Unframer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:445(LibraryLoader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/online.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1302(RegularPolyCollection) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:102(join_parsed_parts) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:2303(__init__) + 2 0.000 0.000 0.009 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:246(metadata) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:229(VolumePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/abc.py:13(ResourceReader) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:382(__exit__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:221(validate_fonttype) + 11 0.000 0.000 0.000 0.000 {method 'index' of 'tuple' objects} + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1227(stat) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/__init__.py:36(__deprecate_private_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/gbq.py:1() + 15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:915() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2007(_init_dynamic_classes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/testing.py:15(pyparsing_test) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:793(date) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2338(CompositeGenericTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:295(NestedPfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:1602(RadioButtons) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triangulation.py:8(Triangulation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:15(GeoAxes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/numbers.py:294(Integral) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:362(__subclasshook__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:4054(FancyArrowPatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/relativedelta.py:18(relativedelta) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/_util.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/dispatch.py:1() + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/__init__.py:1() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:33(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:270(FlatPfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/__init__.py:186(Path) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/interop.py:21(InOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:319(CDLL) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/arrow_parser_wrapper.py:15(ArrowParserWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/excelclipboard.py:1() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:511(update) + 20 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:847(inner) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:426(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/enums.py:4(Kind) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/figure.py:2149(SubFigure) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:928(_missing_) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:115(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:977(_MaskedBinaryOperation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:360(DataFrame) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_openpyxl.py:532(OpenpyxlReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1514(findCaller) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/encoders.py:5() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/genericpath.py:27(isfile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:950(_set_tstate_lock) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4949(__init__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:996(__new__) + 7 0.000 0.000 0.000 0.000 :948(_sanity_check) + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/function_base.py:19(_linspace_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:2289(XAxis) + 31 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/multiarray.py:669(result_type) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:17(_display_as_base) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:31(unicode_set) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3510(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:33() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:179() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:26(InfinityType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:396(PyTablesExprVisitor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_parseaddr.py:207(AddrlistClass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_parseaddr.py:4() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:512(to_rgb) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:2177(_SelectorWidget) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/extension.py:113(inherit_names) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/righttoleft.py:1() + 38 0.000 0.000 0.000 0.000 {method 'end' of 're.Match' objects} + 3 0.000 0.000 0.000 0.000 :1251(__iter__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2892() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:228(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:41() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:441(_setdef) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1283(_replace_dtype_fields_recursive) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2372(_MaskedPrintOption) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1189(ZipFile) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1424(debug) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:159(__call__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:421(validate_whiskers) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:342(wrap) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:3417(dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:405(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:390(ScalarMappable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:716(add_condition) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1270(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1245(time) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_common.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:26(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3588(_apply_env_variables) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansitowin32.py:72(AnsiToWin32) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3807(FancyBboxPatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:2940(ToolLineHandles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:212(Add) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1259(Arrow) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1386(_get_defaults) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:953(__init__) + 3 0.000 0.000 0.000 0.000 :1237(_recalculate) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_weakrefset.py:37(__init__) + 2 0.000 0.000 0.000 0.000 {method 'unregister' of 'select.poll' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/__init__.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_managers.py:32(ToolManager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2589(MaskedIterator) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:26(_getlang) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:1737(_add_comparison_ops) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:1348(RollingAndExpandingMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/compat.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1565(EventCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:876(with_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/legendre.py:1619(Legendre) + 1 0.000 0.000 0.252 0.252 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:97() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4983(stopOn) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:473(timedelta) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/numbers.py:147(Real) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:160(_split) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:190() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/relativedelta.py:13() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:16(_get_method_wrappers) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:127(_compose) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:1346(PandasSQL) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/changeyear.py:44(additional_notes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/thai.py:12() + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:36(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:197(_new_message) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2698(_Base) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:1697(ExtensionOpsMixin) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimelike.py:162(_period_dispatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:2123(NDArrayBackedExtensionBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:573(_StreamProxy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/scope.py:123(Scope) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1041(__next__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1176(PolyCollection) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:704(add_parse_action) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:211() + 21 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:171(__set_name__) + 9 0.000 0.000 0.000 0.000 {built-in method _operator.truediv} + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/signal.py:49(decorator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/hebrew.py:12() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:495(find_distributions) + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:188(_dispatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:383(plus_or_dot) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:216(_fileobj_lookup) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:1() + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/__init__.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/datetimelike.py:1583(DatelikeOps) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/numeric.py:47(NumericDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_odfreader.py:28(ODFReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/quopri.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:131(_validate_date) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:982(FontManager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:249(AitoffTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:844(Poly3DCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_tzpath.py:31(_parse_python_tzpath) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:704(__mul__) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:337(get) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:29(Cursors) + 1 0.000 0.000 0.021 0.021 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:324(compile_pattern) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:1() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:173(invalidate_members) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_pylab_helpers.py:9(Gcf) + 2 0.000 0.000 0.000 0.000 :1452(find_distributions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/mask_ops.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:2026(SQLiteTable) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:357(copy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1260(Manager) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:945(MIMEPart) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:532(FontProperties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_afm.py:358(AFM) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:641(Path3DCollection) + 4 0.000 0.000 0.000 0.000 {built-in method _locale.setlocale} + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:348(_after_init) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:754() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:373(abspath) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:496(popitem) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:136() + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_pytesttester.py:76(__init__) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/_common.py:9(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:1828(ExtensionBlock) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:70(close) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:36(_Version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1090(TimerBase) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:184(close) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImagePalette.py:24(ImagePalette) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:906(AnchoredOffsetbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/version.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/hermite_e.py:1650(HermiteE) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/isoparser.py:42(isoparser) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:216(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:1467(_iLocIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/figure.py:73(_AxesStack) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:2527(YAxis) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:1418(_rrulestr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/container.py:5(Container) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/testing/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:188(InvertedPolarTransform) + 34 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1915(recurse) + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:376(__init__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:122(pushlines) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:341(get_makefile_filename) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/uu.py:27() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3415(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triangulation.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/colorsys.py:75(rgb_to_hls) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/timedeltas.py:33(TimedeltaIndex) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3450(_generateDefaultName) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5765(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:486(_make_selector) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:251() + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:26(_reflected_binary_method) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:841(TableBuilderVerboseMixin) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:282(__len__) + 17 0.000 0.000 0.000 0.000 {method 'index' of 'list' objects} + 2 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/linecache.py:36(getlines) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:785(uname_result) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:117(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzinfo.py:18(memorized_timedelta) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/generic.py:46(_subclasscheck) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/arrays/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_version.py:20(get_versions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:92(Definition) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1675(getEffectiveLevel) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2043() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:221(Fonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:165(__setitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:4394(ConnectionPatch) + 26 0.000 0.000 0.000 0.000 {built-in method _stat.S_ISLNK} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_trifinder.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/tseries/api.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:682(__setitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numerictypes.py:229(obj2sctype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2274(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1216(Normalize) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:375(ScalarFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2486(Keyword) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:3051(ToolHandles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:384(gethomedir) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:70(alphas) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:374(validate_fontweight) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:77() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:44(_get_exports_list) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:8376(_convert2ma) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:1126(_LocIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/right.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:225(format_default) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:156(check_dask_array) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/mathtext.py:37(MathTextParser) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/__init__.py:1() + 3 0.000 0.000 0.000 0.000 {built-in method maketrans} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1145(tzinfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/arrayterator.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/persian.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:197(Context) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:106(Group) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:367(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:645(RcParams) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/colorsys.py:98(hls_to_rgb) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:840(_is_valid_dispatch_type) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:266(validate_color_or_inherit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1153(LockableBbox) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5770(postParse) + 9 0.000 0.000 0.000 0.000 {method 'count' of 'list' objects} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/linecache.py:147(lazycache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:177(git_versions_from_keywords) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1315(_replace_dtype_fields) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/roperator.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1601(ContextRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1976(SystemRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1378(LineCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:2579(FigureManagerBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_managers.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:1073(_nanminmax) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1677(_build_cache) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:816(fsdecode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_tritools.py:1() + 5 0.000 0.000 0.000 0.000 :765(exec_module) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_xlrd.py:19(XlrdReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4245(MatchFirst) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1073(Polygon) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:367(errstate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:39(EigResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:1305(PandasDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:535(_Compiler) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2052(get_group) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:248(DiskCache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:102(PrimitiveType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/GimpPaletteFile.py:17() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3922(And) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/stamp.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/decorators.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/hermite.py:1658(Hermite) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:41(EntryPoint) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:116(__diag__) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3514() + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:860(is_nonnegative_int) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1350(runtime_checkable) + 3 0.000 0.000 0.000 0.000 {built-in method _operator.mul} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:203(__exit__) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_dtype.py:24(_kind_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:18(numeric_type_aliases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/laguerre.py:1606(Laguerre) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:58(_timelex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:19(DirNamesMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/transforms.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/extension.py:138(ExtensionIndex) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:173(feed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PaletteFile.py:19(PaletteFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:261(LogScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:335(NestedVolumePfLine) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/period.py:103(_field_accessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:100(Apply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/indexing.py:31(GroupByIndexingMixin) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/numbers.py:1071(NumberPattern) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:838(_addHandlerRef) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:76(__lt__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:27(JoinStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/gridspec.py:531(SubplotSpec) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:588(get_content_maintype) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:313() + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:404(_exit_wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:217(_getintp_ctype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:778(SystemRandom) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/locale.py:469(_parse_localename) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/shared_docs.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:285(GroupbyIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:399(DiskCacheByHash) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/extendpandas.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:320(__init__) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_tzpath.py:5(reset_tzpath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:41(tzutc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:43(BaseIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/c_parser_wrapper.py:56(CParserWrapper) + 1 0.000 0.000 0.006 0.006 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2012(_after_init) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2379(Token) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:554() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:32() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:451(define) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:104() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:112(Policy) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:209() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_common.py:267(tzrangebase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/selectn.py:40(SelectN) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:264(__init__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:771(getenv) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/genericpath.py:16(exists) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numerictypes.py:589(_register_types) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:249(_ctypes) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:596(_get_root) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:1576(EABackedBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:200(CategoricalFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:29(GroupDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/iterators.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:67(_BaseVersion) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/tools/peakperiod.py:61() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:62(smallest_subnormal) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:359(LightSource) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1763(AffineBase) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:79() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/os.py:1073(__subclasshook__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:81(BaseSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:482(_set_tzdata) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:50(_localized_month) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/ewm.py:850(OnlineExponentialMovingWindow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:49(Properties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:596(MathCall) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2743(Word) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/core.py:238(reload_library) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axis3d.py:732(XAxis) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:2047() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:38(get_config) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:67(__len__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_pytesttester.py:1() + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/__future__.py:83(__init__) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:846(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/generic.py:11882() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/array_manager.py:1317(NullArrayProxy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:411(PercentStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1448(warning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1389(Logger) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:147(Parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:414(DiskCacheByMTime) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:815(Grouper) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:543(validate_bbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:815(LogFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:115() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:83(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:1949(Cursor) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/plot.py:79(decorator) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/__init__.py:1() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:9(__init__) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:55() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:240(PricePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:381(__init__) + 1 0.000 0.000 0.000 0.000 {method 'tobytes' of 'numpy.generic' objects} + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:806(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:779(Expr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:1075(Parser) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/custom.py:25() + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:799() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1413(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1276(Transform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:14(__config_flags) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/initialise.py:9(_wipe_internal_state_for_tests) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1922(Arc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:329(TruetypeFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:3733(LassoSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_layoutgrid.py:31(LayoutGrid) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:1307(rruleset) + 1 0.000 0.000 0.000 0.000 {built-in method _ctypes.dlopen} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:200(BaseBuffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/boolean.py:41(BooleanDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1565(_log) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:8() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/__init__.py:75(register) + 16 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:158() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1224(__init__) + 19 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:18(is_multiplicative) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:175(register_directive) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:510(CFunctionType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:515(get_paths) + 1 0.000 0.000 0.003 0.003 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/api/__init__.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:195() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:135(_makearray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:75(PandasExtensionDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:1403(BaseMaskedDtype) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:136(delegate_names) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:116(Buffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:2170(SQLiteDatabase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1760(LoggerAdapter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/appdirs.py:407(AppDirs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/_util.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/lock.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1305(EngFormatter) + 15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:448() + 4 0.000 0.000 0.000 0.000 {method 'extend' of 'collections.deque' objects} + 3 0.000 0.000 0.001 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1246(open) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:406(_validate_mathtext_fallback) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:2042(MultiCursor) + 22 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:297(_op_maker) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:434(_init_posix) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:56(__init__) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/__init__.py:1() + 12 0.000 0.000 0.000 0.000 {method 'remove' of 'set' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:117(splitext) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:534(_PreciseSelector) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:503(decorating_function) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/__init__.py:213(UTC) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:134(_get_option) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:80(DictReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/flags.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:207(Writer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4715(AppendableMultiFrameTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:83(PluralRule) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1230(append) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:253(formatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:138(Diagnostics) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:434(FlatCompletePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:3371(_Backend) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/core.py:198(update_user_library) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:208(__getattr__) + 7 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:443(__members__) + 12 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:138() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5260(SkipTo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1401(MouseButton) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:595(DrawingArea) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2177(BlendedGenericTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4967(_MultipleMatch) + 5 0.000 0.000 0.000 0.000 :1223(_find_parent_path_names) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:393(Semaphore) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:1112(python_implementation) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/generic.py:37(_check) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/timedeltas.py:81(_field_accessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:661(SocketIO) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:401(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1645(callHandlers) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:356(System) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:304(FuncFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/__init__.py:87(CompleteDirs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/py310compat.py:1() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:509(PYFUNCTYPE) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:153(_realType) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:260(__call__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:446(Registry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:592(DataFrameInfoPrinter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/readers.py:1355(TextFileReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/mathtext.py:48(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/categories.py:10(Category) + 18 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1879() + 5 0.000 0.000 0.000 0.000 {built-in method sys.exc_info} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:221() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:124(_is_python_source_dir) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/core.py:1244(get_locale_identifier) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:653(copy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:256(_validate_toolbar) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1587(__xor__) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha256} + 24 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:465(_parse_letter_version) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:88(__calc_month) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/invalid.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:14(IntegerDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:441(DataFrameInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:2854(AutoLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_tight_bbox.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:258(_AxisWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:76(Text3D) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:356(fill) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:136(Transpose) + 2 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/linecache.py:26(getline) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:493(Module_six_moves_urllib) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:925(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/__init__.py:21(__deprecated_private_func) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/floating.py:14(FloatingDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3624(Exif) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:477(NestedCompletePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/textpath.py:20(TextToPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:297(HammerTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:552(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:30() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:791(getrandbits) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:193(_getuserbase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1545(__init__) + 1 0.000 0.000 0.008 0.008 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/testing.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/xml.py:57(_XMLFrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:119(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:429(add_groups) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:82(__format__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:286(_validate_color_or_linecolor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1685(TransformWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:80(alphanums) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:420(AxisScaleBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:848(AxesImage) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/abc.py:150(TraversableResources) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:45(_compat_get_offset) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:120(__init__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3457(parseImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1751(ParserState) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:823(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:322(register_dataframe_accessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:285(SystemDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:251(RevenuePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_add_newdocs_scalars.py:54(_get_platform_and_machine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_nbit.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6544(__has_singleton) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/string.py:57(Template) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:96(IOHandles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/html.py:164(_HtmlFrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:297(ParsingError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:439(StrFormatStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:764(_get_backend_or_none) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shlex.py:19(shlex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1512(CenteredNorm) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2464(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/text.py:17() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:2780(_Mode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:749(StixFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/layout_engine.py:27(LayoutEngine) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:433(__init__) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha384} + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:836(inner) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:20(DlpackDeviceType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gettext.py:111() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1395(NonMultiplicativeRegistry) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1034(__new__) + 1 0.000 0.000 0.000 0.000 {built-in method math.exp} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6568(__array_finalize__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6744(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:132(tzoffset) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:394(_ymd) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1008(DataFrameRenderer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:49(BaseHeader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/_structures.py:35(NegativeInfinityType) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:576(_validate_greaterequal0_lessequal1) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3474(White) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/plot.py:50(PfLinePlot) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:416(LambertTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sas/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/uuid.py:78(SafeUUID) + 8 0.000 0.000 0.000 0.000 {built-in method builtins.delattr} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:154(py_object) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:772(DataFrameTableBuilder) + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:130(check_implemented) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:11(Color) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1312(_MainThread) + 2 0.000 0.000 0.000 0.000 {method 'register' of 'select.poll' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:155(_NetlocResultMixinBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ctypeslib.py:360(_get_scalar_type_map) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/exceptions.py:1() + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:491(_parse_local_version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:241(Japanese) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3676(StringEnd) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5076(ZeroOrMore) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:119(CapStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:344(MollweideTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_compression.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:49() + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:6028() + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_globals.py:58(__repr__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:966(joinpath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:405(PyDLL) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:195() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:1240(SectionProxy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/measurement.py:17(Measurement) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:164(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1884(Affine2D) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1748(CircleCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:3216(ToolContainerBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:610(Shadow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/enums.py:34(Structure) + 5 0.000 0.000 0.000 0.000 {method 'popitem' of 'dict' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:65(_raise_malformed_node) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:596(Barrier) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:367(_fix_result_transcoding) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_dtype_like.py:65(_DTypeDictBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:903(_MaskedUnaryOperation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1125(_DomainedBinaryOperation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:400(ContextChain) + 13 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:522(_binary_compiler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:478(split_format) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:568(_validate_greaterthan_minushalf) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:158(ToolToggleBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1314(FancyArrow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/enums.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:610(_get_deprecated_option) + 5 0.000 0.000 0.000 0.000 {method 'strip' of 'bytes' objects} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_weakrefset.py:86(add) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:260(_inner) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5110(DelimitedList) + 1 0.000 0.000 0.000 0.000 {method 'union' of 'set' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_globals.py:65(_CopyMode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:137() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:84(MaskedArrayFutureWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6735(_extrema_operation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:568(parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/multi.py:197(names_compat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/concat.py:398(JoinUnit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:775(ZipExtFile) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_util.py:32(register_writer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/excel/_xlsxwriter.py:19(_XlsxStyler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:553(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:858(validate_hist_bins) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:698(PngImageFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/bezier.py:181(BezierSegment) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1627(__invert__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:936(PathPatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:964(StepPatch) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1362(getmask) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_dtype_like.py:71(_DTypeDict) + 1 0.000 0.000 0.005 0.005 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/api.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:361(_register_directives) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:17(_ParseResultsWithOffset) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:181() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:887(RegularPolygon) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1458(DraggableBase) + 1 0.000 0.000 0.000 0.000 {built-in method _hashlib.openssl_sha512} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:797(_DomainCheckInterval) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:201(tzlocal) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/base.py:157(SingleDataManager) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:226(_discover_resolvers) + 2 0.000 0.000 0.000 0.000 :2(__init__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:596(_register_directive) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/__init__.py:99(version_info) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:93(__compat__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:456(DebugActions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/helpers.py:654(OpAssoc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:709(ToolZoom) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:540(UnicodeFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/_common.py:21(package_to_anchor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1141(OffsetImage) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:232(LinearTriInterpolator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:286(CubicTriInterpolator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:183(Divide) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:686() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1172(Wedge) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:4177(Lasso) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:276(_key_from_fd) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/types.py:79(resolve_bases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__init__.py:192() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:996(parents) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:446(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/compressors.py:44(BZ2File) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:354(_get_sysconfigdata_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:394(StorageExtensionDtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:206(Op) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/utils.py:18(ArrowCTypes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/persian.py:17(_Persian) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:227(FrameSummary) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:326(condition_as_parse_action) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1508() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/spines.py:522(Spines) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axis3d.py:740(YAxis) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/colorsys.py:108(_v) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1504(_strip_annotations) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:775(_maintain_shutdown_locks) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_nested_sequence.py:18(_NestedSequence) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/npyio.py:106(NpzFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/matplotlib.py:25(PintConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PaletteFile.py:16() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5106(_generateDefaultName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1823(_MathStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:949(__iter__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:542(set) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:85(_import_module) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4646(IndentedBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:310(AxisConcatenator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_datasource.py:196(DataSource) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/arrayterator.py:16(Arrayterator) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:128() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/base.py:100(PandasObject) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sas/sasreader.py:33(ReaderBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:55(ContextDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1962(MaxNLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4085(Or) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4963(_generateDefaultName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:309(FlatVolumePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1768(EllipseCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1972(_MeshData) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:66(Widget) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:523(Ticker) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:633(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:413(LambertAxes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:534(Patch3DCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/suppresswarnings.py:8(apply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:539(_get_data_path) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageMode.py:16() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:140(isComplexType) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:285(_eval_type) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:1501() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/base.py:244(_maybe_return_indexers) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:2236(Path) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:1203(DataSplitter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tempfile.py:770(TemporaryDirectory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1417(TwoSlopeNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:201(LogTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/__init__.py:106(__version__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:710() + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:1717(suppress) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/lines.py:1467(AxLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_tritools.py:11(TriAnalyzer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:498(_ThetaShift) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:183(Line3D) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/axis3d.py:748(ZAxis) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/collections/__init__.py:932(__missing__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:45(_days_before_year) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:130(get_linalg_error_extobj) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:919(system) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_compression.py:33(DecompressReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1167(_tzicalvtz) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:143(IndexingMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/rolling.py:2686(RollingGroupby) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/engines.py:47(AbstractEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gettext.py:254(NullTranslations) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:618(_UnicodeCompiler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1550(makeRecord) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2237(UnitRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:499(AsinhScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:59(ColormapRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1880(Circle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:65(Text) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:210(_process_plot_var_args) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:186(_get_module) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:583(LogitTransform) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:830(implement_atleast_nd) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/error.py:2() + 3 0.000 0.000 0.000 0.000 {method 'copy' of 'mappingproxy' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:43(EighResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:194() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:1607(MAxisConcatenator) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:129() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:164(_resolve) + 10 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:210() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:72() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:911(FrameColumnApply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/align.py:67(_filter_special_cases) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/merge.py:1867(_AsOfMerge) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:246(_register_at_fork_reinit_lock) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:292(walk_stack) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:168(__init__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/appdirs.py:17() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:235() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3886(_setResultsName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:375(NestedPricePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/winterm.py:28(WinTerm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1909(TriMesh) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:2126(QuadMesh) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/textpath.py:293(TextPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:643(__getitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/html.py:587(_BeautifulSoupHtml5LibFrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:424(_E) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1068(Char) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:272(InvertedAitoffTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/children.py:13(ChildFunctionality) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1814(Affine2DBase) + 15 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:308(__missing__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:859(implement_single_dimensionless_argument_func) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2039(_register_directives) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:281(_sanitize_header) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_encoded_words.py:73(_QByteMap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:108(CalledProcessError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:216(Condition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:32(MachArLike) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:198(joinuser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:205(load_module) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:55(__init__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/__init__.py:43(private_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/string.py:159(Formatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/categorical.py:2321(CategoricalAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:23(Dialect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/accessor.py:226(SparseFrameAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:514(SeriesInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:53(Term) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:400(_Parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1359(_fixupChildren) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:420(major) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_version.py:3() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:548(ColorConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:243(InvertedLogTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/testing.py:124(TestParseResultsAsserts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:17(_AutoStringNameEnum) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:351(FlatPricePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:2239(PolyQuadMesh) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:830(ToolPan) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:707(TextArea) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/category.py:26(StrCategoryConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:94(rrulebase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:246(AitoffAxes) + 2 0.000 0.000 0.000 0.000 {method 'write' of '_io.StringIO' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_dtype_ctypes.py:1() + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:439(customize_config_vars) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:110(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:1310(ConverterMapping) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1265(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:147(Transform) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:144(__lt__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/copyreg.py:12(pickle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:95(_RLock) + 2 0.000 0.000 0.000 0.000 {method 'ravel' of 'numpy.ndarray' objects} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:3433(shape) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/base_parser.py:100(BadLineHandleMethod) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:106(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/numpy_func.py:682(implement_prod_func) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2412(__setattr__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/header.py:541(_Accumulator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:85(ImageFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:391(FlatRevenuePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:418(NestedRevenuePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:386(InvertedMollweideTransform) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:1040() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:116(_ArrayMemoryError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:376(_FuncPtr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:135(_BaseVersion) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:212(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:264(SeriesFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4584(AppendableSeriesTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:440(TracebackException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:394(format_unit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:200(NameByPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:136(FeedParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/charset.py:167(Charset) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:167(check_getitem) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:570(Stack) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:958(LinearSegmentedColormap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:2278(LightSource) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:156(Resampling) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:12(qualify) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:1077(TransformedBbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/lines.py:1601(VertexSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:903(FontConstantsBase) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:319(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:259(DomainMap) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/prices/__init__.py:1() + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:256(__init__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/ops/methods.py:68() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:225() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:128() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:129() + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:50(_days_in_month) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/textwrap.py:336(_split_chunks) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:886(createLock) + 4 0.000 0.000 0.000 0.000 {method 'truncate' of '_io.StringIO' objects} + 14 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:379(__enter__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:2236(_create) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:295(_PosixFlavour) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/records.py:223(record) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/records.py:308(recarray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/memmap.py:22(memmap) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:883(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:246(ReadCsvBuffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:405(Substitution) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/_decorators.py:452(Appender) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_common.py:149(_tzinfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/easter.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:987(SeriesApply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/datetimes.py:105() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gzip.py:401(_GzipReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:603(_FileInFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:317(ZipInfo) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/series.py:215(_coerce_method) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:934(DataFrameTableBuilderVerbose) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:753(PandasExprVisitor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:33(DtypeKind) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/__init__.py:808(SubclassedSeries) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4649(GenericTable) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:404(path) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:30(DefinitionSyntaxError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:138(InvalidateByMultiPathsMtime) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3414(register_open) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:25(BaseTypeByIdentity) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:345(StructOrUnion) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:2706(LogitLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:457(ToolViewsPositions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:140(PolarAffine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:251(Multiply) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1853(_internal_poll) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:665(__neg__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:143() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:47(QRResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:55(SVDResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:410(HTMLCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/string_.py:218(BaseStringArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tempfile.py:411(_TemporaryFileCloser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1591(handle) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:156(wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:1630(_register_directives) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:123(InvalidateByPathMTime) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/matplotlib.py:28(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/__init__.py:5() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:464(AsinhTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:49(AnsiFore) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/contour.py:1478(QuadContourSet) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2204(_Style) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:316(InvertedHammerTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:294(HammerAxes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:48(filter_by) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2631(CaselessKeyword) + 8 0.000 0.000 0.000 0.000 {method 'seek' of '_io.StringIO' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:291(SelectSelector) + 1 0.000 0.000 0.000 0.000 {method 'close' of 'select.kqueue' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_methods.py:47(_sum) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:822(_DomainTan) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzinfo.py:79(StaticTzInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzinfo.py:159(DstTzInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:58(NegativeInfinityType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:13(__call__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:578(_select_options) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:49(PandasDelegate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:2029(EngFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:129(VariableOffsetWindowIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/python_parser.py:1166(FixedWidthReader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_version.py:7() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gettext.py:358(GNUTranslations) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:333(AliasDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:171(NameByFileContent) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:765(_validate_legend_loc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1458(PercentFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2338(_PendingSkip) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2406(Literal) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2656(CloseMatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4361(Each) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5687(Combine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/text.py:1444(_AnnotationBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:1488(CirclePolygon) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:1325(FigureImage) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/glob.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:824(AuxTransformBox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:405(XTick) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:456(InvertedLambertTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:20(Prep) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:103(_safe_realpath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:494(MetadataPathFinder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5183(Opt) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:162(__ge__) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4106() + 12 0.000 0.000 0.000 0.000 {method 'islower' of 'str' objects} + 17 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/inspect.py:2556(annotation) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_type_aliases.py:92() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1001(is_absolute) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/config_init.py:295(is_terminal) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/decoder.py:254(JSONDecoder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:1830(TableIterator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:37(PyTablesScope) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:243(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2375(ApplicationRegistry) + 11 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:518() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:343(Interop) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:150(ChunkStream) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:483(InvertedAsinhTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1109(LogitFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1752(LinearLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5868(Suppress) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:961(_CollectionWithSizes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1033(Box) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:524(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:1215(_Sparse_Matrix_coo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:699(RadialAxis) + 1 0.000 0.000 0.000 0.000 {built-in method atexit.unregister} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:852() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:207(_BaseSelectorImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/numbers.py:267(Rational) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:51(SlogdetResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/__init__.py:398(_FixedOffset) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/_common.py:6(weekday) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:854(FrameRowApply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/encoder.py:104(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:954(_BytesTarFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tempfile.py:128(_RandomNameSequence) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2547(DataIndexableCol) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4485(AppendableFrameTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:45(BufferedSubFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/header.py:413(_ValueFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:134(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:381(InvertedSymmetricalLogTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:609(LogisticTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:198(Formatter) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3532(_generateDefaultName) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3681(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4800(PrecededBy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5346(_update_ignorer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:245(ToolSetCursor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/text.py:1370(OffsetFrom) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1010(Node) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1308(Vlist) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:1188(PcolorImage) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:748(_WedgeBbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:18() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/_structures.py:6() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2996(Char) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:254(__len__) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_inspect.py:142() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:376(BasicInterpolation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:564(_PythonCompiler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:348(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:342(_PollLikeSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__config__.py:14(DisplayModes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_globals.py:52(__new__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_version.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:840(_DomainSafeDivide) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:867(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/encoder.py:73(JSONEncoder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:2189(DatetimeLikeBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:2168(CompleteDirs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/datetimes.py:113(FulldatetimeDict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/indexing.py:287(GroupByNthSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:3541(StataWriterUTF8) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:1195(ConfigParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:201(UnitDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:424(validate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:677(_Stack) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2387(_generateDefaultName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/classes.py:262(CompletePfLine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:179(FontMetrics) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/layout_engine.py:132(TightLayoutEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_trirefine.py:47(UniformTriRefiner) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:223(_GeoTransform) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/functools.py:964(__set_name__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:986(parent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1470(__get_gettz) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:69(_localized_day) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:583(NDFrameApply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:3105(SeriesFixed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:522(LegacyInterpolation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:15(Converter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/localedata.py:216(LocaleDataDict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:271(Compat32) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:188(Quantize) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3479(register_extensions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:348(SymmetricalLogTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:1112(_iterinfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:322(Grid) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:341(MollweideAxes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:402(ThetaAxis) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:98(Disposal) + 9 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4107() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:175(Dither) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:102(CFunctionType) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:56(fget) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:432(validate_ps_distiller) + 1 0.000 0.000 0.000 0.000 {built-in method builtins.format} + 5 0.000 0.000 0.000 0.000 {built-in method posix.WIFSTOPPED} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:528(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1229(_make_invoke_excepthook) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__config__.py:95() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:507(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_ufunc_config.py:360(_unspecified) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:630(iinfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_dtype_like.py:81(_SupportsDType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_datasource.py:536(Repository) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:2378(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:1655(__init__) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:178(_supports_universal_builds) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1475(GettzFunc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:9(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:255(CallableDynamicDoc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:77(disallow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/accessor.py:37(SparseAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/ewm.py:817(ExponentialMovingWindowGroupby) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:186(Constant) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:306(JSONTableWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:2977(StataStrLWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2343(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:189(NameByObj) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/__init__.py:27(classproperty) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:61(_ColorMapping) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:358(Parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/units.py:108(ConversionInterface) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3207(_Curve) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/layout_engine.py:211(ConstrainedLayoutEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/image.py:1388(BboxImage) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:527(PaddedBox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:462(YTick) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1116(DateLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/prices.py:17(Flat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/suppresswarnings.py:1() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1024(block_iter) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3468(register_extension) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:75(nums) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:649(_warn_if_deprecated) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:110() + 3 0.000 0.000 0.000 0.000 {built-in method atexit.register} + 6 0.000 0.000 0.000 0.000 {built-in method _stat.S_ISDIR} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/genericpath.py:121(_splitext) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:46(_ignore_error) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:73(PickleError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_machar.py:17(MachAr) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:529() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:329(register_series_accessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:2097(NumpyBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:378(ExponentialMovingWindowIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/expanding.py:797(ExpandingGroupby) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:547(UnaryOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/html.py:708(_LxmlFrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4258(AppendableTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:506(PyTablesExpr) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:551(set_results_name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/textpath.py:26(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:831(PsfontsMap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1778(DateConverter) + 7 0.000 0.000 0.000 0.000 {method 'upper' of 'str' objects} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/posixpath.py:52(normcase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:1214(IsoCalendarDate) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:61(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/records.py:87(format_parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:616(_Stream) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:877(_DomainGreaterEqual) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/compressors.py:59(LZMAFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_common.py:127(_TZifHeader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:874(tzrange) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/tseries/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:155(Int8Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:928(_BufferedWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:73(FixedWindowIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/plotting/_misc.py:566(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parquet.py:131(PyArrowImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:3138(BlockManagerFixed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:218(NameByMultiPaths) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:210(_pop_message) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:303(set_payload) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_cm.py:66(cubehelix) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2445(CompositeAffine2D) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3394(CharsNotIn) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1409(MouseEvent) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_common.py:13(tzname_in_python2) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:606(get_default_type) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:130() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:1000(SeriesTableBuilder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1840(SymLogNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:262(__subclasshook__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:353(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:428(CompletedProcess) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1358(current_thread) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:97(_Stop) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:255(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:209(_assert_stacked_square) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:16(LazyDict) + 1 0.000 0.000 0.002 0.002 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:614(get_config_var) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/floating.py:142(Float32Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:232(DatetimeProperties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:1046(SeriesTableBuilderVerbose) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:362(BinOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/merge.py:1782(_OrderedMerge) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parquet.py:118(BaseImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2234(GenericIndexCol) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:448(ExtendedInterpolation) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:185() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:288(DimensionDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/localedata.py:183(Alias) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:798(SharedRegistryObject) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/traceback.py:318(StackSummary) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:552(get_configdir) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:83() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ExifTags.py:351(IFD) + 1 0.000 0.000 0.001 0.001 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/helpers.py:599(make_html_tags) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colorbar.py:123(_ColorbarSpine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1008(PathCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1368(StarPolygonCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:664(Vf) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:75(VectorParse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:28(LockDraw) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/gridspec.py:318(GridSpec) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1192(RRuleLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:46(HandlerBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_tricontour.py:8(TriContourSet) + 2 0.000 0.000 0.000 0.000 {built-in method time.time} + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:63(decorate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:809(Quoter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:378(finfo) + 3 0.000 0.000 0.000 0.000 {method '__array_prepare__' of 'numpy.ndarray' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:1329(make_mask_descr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:332(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:64(ColumnNullType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/header.py:179(Header) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:409(SymmetricalLogScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4710(AtStringStart) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:672(DejaVuFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:163(Button) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/mlab.py:770(GaussianKDE) + 7 0.000 0.000 0.000 0.000 {built-in method sys.audit} + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:503(_parse_local_version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1367(StructuredVoidFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:205(dummy_ctype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:238(c_char_p) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:747(_Processor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ctypeslib.py:202(_concrete_ndptr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:893(_MaskedUFunc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:6844(_frommethod) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:293(TextCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:209(DictWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:569(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:1760(ExtensionScalarOpsMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/extension.py:180(NDArrayBackedExtensionIndex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:2241(DatetimeTZBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:424(TextAdjustment) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:1045(_IOWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1104(_ZipWriteFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:216(ExpandingIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/selectn.py:159(SelectNFrame) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/groupby.py:577(GroupByPlot) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/custom.py:13() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:21(PreprocessedDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:123(DefaultsDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2342(LazyRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:489() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:233(__getattr__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:160(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:119(Blend) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2159(_BlendedMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3558(GoToColumn) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/testing.py:20(reset_pyparsing_context) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:71(AnsiBack) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:88(_finalize_rasterization) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1206(Hlist) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1390(Rule) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:305(rrule) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend.py:54(DraggableLegend) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:449(RadialLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:412(Patch3D) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:779(_unknown_as_blank) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:557(validate_sketch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_utils/_convertions.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:830(__init__) + 8 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:80(_add_doc) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:880(add_metaclass) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:637(_translate_key) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:796(is_type_factory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:440(EastAsianTextAdjustment) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/datetimes.py:107(YearMonthDayDict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:46(Relation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1601(addHandler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:18(_PolicyBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:92(_StrongRef) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:261(PngInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/winterm.py:12(WinColor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1849(PatchCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:120(Output) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:3691(EllipseSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/__init__.py:69(InitializedState) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:995(rrulewrapper) + 1 0.000 0.000 0.000 0.000 {method 'rindex' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:905(FloatingFormat) + 1 0.000 0.000 0.000 0.000 {built-in method numpy.promote_types} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_datasource.py:99(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_datasource.py:74(_FileOpeners) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:133(LineSplitter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:331(_check_for_unavailable_sdk) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:328(_ttinfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:219(is_package) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:76(DeprecatedOption) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/_common.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:162(Int16Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:2389(_AtIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:2256(ObjectBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/ops.py:18(BlockPairInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1333(GenericArrayFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:1009(_BytesZipFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexers/objects.py:103(VariableWindowIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:147(ArrowTemporalProperties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:371(TimedeltaProperties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:261(SeriesWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:262(FilterBinOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/xml.py:435(_EtreeFrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/custom.py:13(_CustomCalendarType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:473(Prepared) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:167(PrefixDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:577(_GettextCompiler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:439(default_format) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:61(DefinitionFiles) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/utils.py:51(_has_surrogates) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:851() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:1295() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:298(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:670(PyDecoder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:97(RasterParse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:211(FontInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1162(List) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:361(HandlerStepPatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:724(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_trifinder.py:27(TrapezoidMapTriFinder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:985(_DOF_estimator) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:32(standardize_other) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:19(Prep) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:119(_resolve) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:103(standardize_other) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:1231() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:145(TimeoutExpired) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1164(_remaining_time) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:1706(make_nancomp) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1276(disable) + 5 0.000 0.000 0.000 0.000 :782(is_package) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_collections_abc.py:381(__subclasshook__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:71(_convert_signed_num) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:61(_SelectorMapping) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:507(KqueueSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:38(_UFuncNoLoopError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:148(MAError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_osx_support.py:314(_override_all_archs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:30(LocaleTime) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_strptime.py:170(TimeRE) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/describe.py:98(NDFrameDescriberAbstract) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/describe.py:133(DataFrameDescriber) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1445(FloatArrayFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:83(IOArgs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gzip.py:74(_PaddedFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pprint.py:77(_safe_key) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:73(__str__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_parseaddr.py:508(AddressList) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:51(ValidateInStrings) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/TiffTags.py:23(TagInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2568(BboxTransformTo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:940(_CacheType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2604(CaselessLiteral) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:36(AnsiCursor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/spines.py:487(SpinesProxy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/__init__.py:69(ProjectionRegistry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/gridspec.py:476(GridSpecFromSubplotSpec) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:626(DateFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:656(ConciseDateFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:372(Line3DCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:328(Unite) + 1 0.000 0.000 0.000 0.000 {method 'title' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:947(_set_native_id) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:184(c_int) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/_compression.py:9(BaseStream) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1253(tzical) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:1373(_result) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:1092(GroupByApply) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:120(_compose2) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tempfile.py:454(_TemporaryFileWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:667(StataValueLabel) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:517(PathDistribution) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:86(LogarithmicConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:2380(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/parser.py:134(ImportDefinition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3696(WordStart) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:896(ToolHelpBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:573(DviFont) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1496(Kern) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/_compat.py:32(TraversableResourcesLoader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/category.py:138(StrCategoryFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:430(HandlerRegularPolyCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:15(TriInterpolator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:462(PathPatch3D) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:381(notify_all) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:611(_validate_minor_tick_ndivs) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:486(__enter__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/datetime.py:445(_check_tzinfo_arg) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/getlimits.py:86(_str_smallest_subnormal) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:662(_check_compression) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:311(header_fetch_parse) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/plot.py:78(append_to_doc) + 1 0.000 0.000 0.000 0.000 {method 'seek' of '_io.BufferedReader' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/weakref.py:195(get) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/linecache.py:52(checkcache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:256(__enter__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:517(Event) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:630(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:259(c_wchar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:10(NBitBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/__future__.py:81(_Feature) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:108(MovedModule) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/base.py:1689(ExtensionArraySupportsAnyAll) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/numpy/function.py:47(CompatValidator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:2351(_ScalarAccessIndexer) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1818(close) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/window/online.py:89(EWMMeanState) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/scope.py:28(DeepChainMap) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:273(disallow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/xml.py:546(_LxmlFrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:168(Error) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/context.py:38(Expression) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:469(StringTemplateStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1200(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:2162(NullHandler) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:456(extract_custom_flags) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/measurement.py:174(build_measurement_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:16(Parser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:915(GrouperView) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:6(Substitution) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1878(AsinhNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:490(EnumType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:159(_DummyAxis) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2627(BboxTransformFrom) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2663(ScaledTranslation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4924(NotAny) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5072(_generateDefaultName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5823(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colorbar.py:146(_ColorbarAxesLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:360(ToolQuit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3136(_Base) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/layout_engine.py:106(PlaceHolderLayoutEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:1399(ArtistList) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1592(DraggableAnnotation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:66(weekday) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:380(StreamMask) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:310(ThetaTick) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:20(assert_objects_indexcompatibility) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:527(get_path) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:571(get_cachedir) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:702(get_scale_names) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/colors.py:30(Colors) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/types.py:132(_calculate_meta) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/enum.py:774(__hash__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1304(DatetimeFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:618(ndindex) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:213(_fromnxfunction) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:83(RegisteredOption) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:54(excel) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:165(Sniffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/json/decoder.py:20(JSONDecodeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:574(InfoPrinterAbstract) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:673(SeriesInfoPrinter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:89(ColumnBuffers) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:1286(SeriesParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:5175(Selection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:383(Context) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:52(RedefinitionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:766(Filterer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1194(_StderrHandler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:223(deprecate_privatize_attribute) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:183(Palette) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:239(iTXt) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1568(Locator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:2440(SymmetricalLogLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:129(LRUMemo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3589(LineStart) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5744(Group) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:429(__getattr__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1373(AsteriskPolygonCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1246(Event) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:600(ToolHome) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:713(DejaVuSerifFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1139(Accent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/rrule.py:1315(_genitem) + 1 0.000 0.000 0.000 0.000 {method 'pop' of 'collections.OrderedDict' objects} + 5 0.000 0.000 0.000 0.000 {built-in method _operator.sub} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:434(PollSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_globals.py:32(_NoValueType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:139(_ResultMixinStr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:194(_NetlocResultMixinStr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:77(PicklingError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:254(c_wchar_p) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/mixins.py:51(_unary_method) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:197(_assert_2d) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:203(_assert_stacked_2d) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ctypeslib.py:181(_ndptr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:220(ReadBuffer) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:199(__get_module) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:154(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:419(option_context) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:219(_resultbase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:185(AbstractMethodError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expressions.py:42(set_use_numexpr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:197(UInt32Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/floating.py:54(FloatingArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/apply.py:1118(ResamplerWindowApply) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/common.py:1074(_BytesIOWrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/indexing.py:247(GroupByPositionalSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/__init__.py:825(SubclassedDataFrame) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/_io.py:88(optional_args) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/python_parser.py:1284(FixedWidthFieldParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:276(FrameWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/json/_json.py:1310(FrameParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:425(FastPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:56(OffsetConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:687(BufferingFormatter) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:125(register_unit_format) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:414(set_fmt_locale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:2055(_OrderedSet) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1991(BoundaryNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:294(ArrayType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:719(PyEncoder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:123(FuncTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2525(BboxTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/actions.py:7(OnlyOnce) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4731(AtLineStart) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5677(TokenConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:642(ZoomPanBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:110(AxesWidget) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/zipp/__init__.py:162(FastLookup) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/figure.py:121(SubplotParams) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:34(_axis_method_wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/category.py:118(StrCategoryLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1707(MicrosecondLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1866(_SwitchableDateConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_trifinder.py:7(TriFinder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:548(RadialTick) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/decorators.py:39(map_to_year_warning) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:140(raiseerror_if_otherdimlessseries) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/signal.py:48(_wraps) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:17(__init__) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:21(assert_objects_indexcompatibility) + 6 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_enums.py:20(_generate_next_value_) + 1 0.000 0.000 0.000 0.000 {method 'difference_update' of 'set' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/typing.py:845(__repr__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:273(get_map) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:98(AxisError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/multiarray.py:741(dot) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:57(_Flavour) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:625(_PathParents) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:147(_ResultMixinBytes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:240(_missing_ctypes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:163(c_short) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:192(c_float) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:196(c_double) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:530(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzinfo.py:69(BaseTzInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:226(WriteBuffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:91(_LazyDescr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:178(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:1371(_tzparser) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:220(__get__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:204(UInt64Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:307(_LowLevelFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4228(WORMTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:612(TermValue) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:518(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/converters.py:33(ScaleConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:86(DimensionalityError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:853(PrettyIPython) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:983(SourceIterator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:791(filter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1040(StreamHandler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/formatting.py:21(_join) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/pint_eval.py:60(EvalTreeNode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:2134(build_quantity_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/matplotlib.py:17(PintAxisInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:64(_ArtistPropertiesSubstitution) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageSequence.py:19(Iterator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2719(TransformedPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2459(Empty) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3722(WordEnd) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5781(Dict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:332(RubberbandBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:1877(SubplotTool) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_managers.py:13(ToolTriggerEvent) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:572(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:719(HandlerTuple) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/dataframeexport.py:13(Flat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/pfstate.py:288(_LocIndexer) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:85(returnself_if_otherNone) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:188(c_uint) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_array_like.py:44(_SupportsArrayFunc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:141(is_python_build) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:24(IllegalMonthError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:379(UndefinedVariableError) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:233(_register_accessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:190(UInt16Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/generic.py:109(NamedAgg) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/multi.py:117(MultiIndexUIntEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/base.py:10(OutputKey) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:382(__getitem__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:598(PyCodec) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:310(FuncScaleLog) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:628(LogitScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2689(AffineDeltaTransform) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3473(BracketA) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:1033(_LuatexKpsewhich) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:939(ComputerModernFontConstants) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1448(Glue) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1523(AutoHeightChar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/widgets.py:266(SliderBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1567(DraggableOffsetBox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1268(AutoDateLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:166(HandlerNpoints) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/flat_methods.py:41(LocIndexer) + 2 0.000 0.000 0.000 0.000 {method 'join' of 'bytes' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ast.py:67(_convert_num) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:351(notify) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/style/core.py:217(update_nested_dict) + 1 0.000 0.000 0.000 0.000 {method 'groups' of 're.Match' objects} + 1 0.000 0.000 0.000 0.000 {built-in method _operator.iadd} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1093(name) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1282(Timer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1333(_DummyThread) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numerictypes.py:425(_typedict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:167(c_ushort) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:175(c_ulong) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:221(c_ubyte) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/_endian.py:23(_swapped_meta) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_pytesttester.py:46(PytestTester) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:144(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:562(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/utils.py:104(_Deprecate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/npyio.py:42(BagObj) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/core.py:156(MaskError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:129(_LazyModule) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:236(create_module) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:74(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:558(LocaleTextCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:1589(ParserError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:130(DictWriter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/base.py:147(NoNewAttributesMixin) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/describe.py:121(SeriesDescriber) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1849(Timedelta64Formatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:591(LZMACompressor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:715(_SharedFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:1941(PyZipFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:2218(FastLookup) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/dataframe_protocol.py:106(CategoricalDescription) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parsers/readers.py:466(_DeprecationConfig) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/parquet.py:240(FastParquetImpl) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:86(Constant) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:327(ConditionBinOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:360(Interpolation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/definitions.py:60(_NotNumeric) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/numbers.py:37(UnknownCurrencyError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/numbers.py:856(NumberFormatError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:68(UndefinedUnitError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:416(__contains__) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1010(__iter__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:270(LogRecord) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1749(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:116(InvalidateByExist) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:238(NameByHashIter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:532(BytesFeedParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:93(NonPrintableDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:930(PintSeriesAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:76(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/_util.py:14(DeferredError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:88(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:279(ConstPointerType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:328(StubImageFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/GimpPaletteFile.py:22(GimpPaletteFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageSequence.py:19() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:159(FuncScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:2594(AsinhLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4764(FollowedBy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/text.py:203(PfLineText) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:93(AnsiStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/plot.py:214(PfStatePlot) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:304(ToolCursorPosition) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:934(ToolCopyToClipboardBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2763(Arc3) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1563(AutoWidthChar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:420(PackerBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:1098(AnchoredText) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/category.py:168(UnitData) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/container.py:42(BarContainer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:628(HandlerStem) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:1156(_DOF_estimator_min_E) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_trirefine.py:12(TriRefiner) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/geo.py:18(ThetaFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:281(ThetaLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/dataframeexport.py:43(Nested) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/nested_methods.py:45(LocIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/prices.py:86(Nested) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:112(returnself_if_otherNone) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:120(returnself_if_otherzerofloatseries) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:286(Divide) + 4 0.000 0.000 0.000 0.000 {built-in method _sre.ascii_iscased} + 2 0.000 0.000 0.000 0.000 {method 'acquire' of '_thread.lock' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/contextlib.py:63(_recreate_cm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:650(_use_posix_spawn) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:63(_zeros_like_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:228(c_byte) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:569(ndenumerate) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/stride_tricks.py:15(DummyArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:71(LazyList) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1036(tzstr) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:53() + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:130() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/base.py:462(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:62(IntegerArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:96(_IndexSlice) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:755(_Tellable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/selectn.py:72(SelectNSeries) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:771(PythonExprVisitor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2754() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:4632(AppendableMultiSeriesTable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:119(getLevelName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:305(udict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:165(RegistryCache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:374(Unit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:857(PintDataFrameAccessor) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:341(validate_aspect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageMode.py:22(ModeDescriptor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:29(ScaleBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1833(MultipleLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2271(BlendedAffine2D) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:288(RecursiveGrammarException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2391(NoMatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4652(_Indent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:731(DejaVuSansFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1054(Vbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/_base.py:95(_TransformedBoundsLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1501(YearLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:249(StreamplotSet) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:1071(_DOF_estimator_geom) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:60(register_vcs_handler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/numbers.py:12(Number) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:637(__len__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pickle.py:84(UnpicklingError) + 1 0.000 0.000 0.000 0.000 {built-in method numpy._set_promotion_state} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/_endian.py:46(BigEndianStructure) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:109(nd_grid) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_array_like.py:39(_SupportsArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:449(_polyfit_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:8(_TzSingleton) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:589(LocaleHTMLCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:109(bottleneck_switch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:169(Int32Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/floating.py:149(Float64Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/sparse/accessor.py:26(BaseAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/printing.py:500(PrettyDict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1628(Datetime64Formatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/utils.py:52(Endianness) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/compat/pickle_compat.py:144(Unpickler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:138(PackagePath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:598(_JavaScriptCompiler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/util.py:1029(BlockIterator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:418(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1123(FileHandler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:159(NameByFields) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:33(MessageDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:20(MatplotlibDeprecationWarning) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:387(validate_fontstretch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1121(ListedColormap) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1910(PowerNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/scale.py:89(LinearScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2790(TransformedPatchPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4658(_IndentGreater) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4787(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:19(DuplicateConstraint) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/ansi.py:25(AnsiCodes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/collections.py:1275(BrokenBarHCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:148(SmallFilledCircles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:618(ToolForward) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/font_manager.py:910(_JSONEncoder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1428(_GlueSpec) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_managers.py:4(ToolEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:208(HandlerNpointsYoffsets) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:314(HandlerPatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/flat_methods.py:52(SliceIndexer) + 5 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:767(_hash_set_none) + 4 0.000 0.000 0.000 0.000 {built-in method _sre.ascii_tolower} + 1 0.000 0.000 0.000 0.000 {built-in method sys.getfilesystemencoding} + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:1172(_check_timeout) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/__config__.py:98() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:32(UFuncTypeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:56(_UFuncBinaryResolutionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:224(_NetlocResultMixinBytes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:171(c_long) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:233(c_char) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:303(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:761(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:2187(_lstsq_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/twodim_base.py:529(_vander_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:701(_polyval_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/platform.py:1125(python_version) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:1637(mr_class) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/sysconfig.py:184(_get_default_scheme) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/engines.py:124(PythonEngine) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:169(_is_type) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:1440(SQLAlchemyEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:160() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:154(RegistryMeta) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:506(Lister) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:71(HeaderParser) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/feedparser.py:125(__iter__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/message.py:1168(EmailMessage) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:163(validate_dpi) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:874(_ignorecase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:178(UnknownIntegerType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1658(IndexLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1915(_Edge_integer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:2874(AutoMinorLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:140(BasicMultilingualPlane) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:197(_should_enable_warnings) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3636(LineEnd) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3664(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3659(StringStart) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/units.py:135(DecimalConverter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/artist.py:111(_Unset) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:9(HatchPatternBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:14(HorizontalHatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:132(SmallCircles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1533(KeyEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:609(ToolBack) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2325(Square) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3595(Simple) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1061(Hbox) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/__init__.py:14(SubplotBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:467(VPacker) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axis.py:564(_LazyTickList) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:398(HandlerLineCollection) + 1 0.000 0.000 0.000 0.000 {built-in method _thread._set_sentinel} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:271(_is_owned) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/multiarray.py:85(empty_like) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/dtypes.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:200(c_longdouble) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:249(c_bool) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/__init__.py:313(_CountryTimezoneDict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_tzpath.py:170(InvalidTZPathWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:434(PyperclipWindowsException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:69(unix_dialect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/accessor.py:196(CachedAccessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:791(StataNonCatValueLabel) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:425(invalidate_members) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:529(build_system_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/unit.py:373(build_unit_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3445(register_save) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:328(StructOrUnionOrEnum) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:270(FixedFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/mixins/text.py:229(PfStateText) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/contour.py:29(ClabelText) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:437(ToolYScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:447(ToolXScale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2583(Sawtooth) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/__init__.py:72(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:876(AutoDateFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:521(HandlerErrorbar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/mpl_toolkits/mplot3d/art3d.py:347(Collection3D) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:73(ensure_pflines_flat) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:132(raiseerror_if_otherNone) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:157(Add) + 2 0.000 0.000 0.000 0.000 {method 'copy' of 'list' objects} + 1 0.000 0.000 0.000 0.000 {built-in method posix.getpid} + 2 0.000 0.000 0.000 0.000 {built-in method from_iterable} + 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:80(_UFuncInputCastingError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_exceptions.py:98(_UFuncOutputCastingError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:329(DefragResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1222(IntegerFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/ctypes/__init__.py:244(c_void_p) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:211(MGridClass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/_array_like.py:160(_UnknownType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:263(_fromnxfunction_single) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:121(LazySet) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/tzfile.py:12(_byte_string) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:236(ReadPickleBuffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_typing.py:241(WriteExcelBuffer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:144(MovedAttribute) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:245(_MovedItems) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:340(Module_six_moves_urllib_parse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:55(_TzStrFactory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:31(IllegalWeekdayError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:546(different_locale) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/isoparser.py:43(__init__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:18(IntCastingNaNError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:24(NullFrequencyError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:548(InvalidColumnName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/tseries/frequencies.py:430(_TimedeltaFrequencyInferer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:176(Int64Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/arrays/integer.py:183(UInt8Dtype) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:614(LZMADecompressor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:823(DataFrameTableBuilderNonVerbose) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:518(Div) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/ops.py:612(FuncNode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_testing/__init__.py:837(SubclassedCategorical) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/stata.py:956(StataParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/helpers.py:13() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:1227(SafeConfigParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/core.py:118(UnknownLocaleError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/units.py:13(UnknownUnitError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1218(PlaceHolder) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1280(disable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/measurement.py:178(Measurement) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/registry.py:190(ContextCacheOverlay) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:79(BytesParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:8(MessageError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/_policybase.py:41(__init__) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:276(release) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cbook.py:333(silent_list) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:2119(NoNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/__init__.py:75(UnidentifiedImageError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3456(register_save_all) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/error.py:2(FFIError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:72(BaseType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:85(VoidType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:224(RawFunctionType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/GimpGradientFile.py:66(GradientFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/GimpGradientFile.py:101(GimpGradientFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1687(FixedLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:146(Latin1) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:165(Greek) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:244(Kanji) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:251(Hiragana) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5044(OneOrMore) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5175(_NullToken) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:98(List) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:15(BadRequiredStrength) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/units.py:161(Registry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:87(Shapes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:124(Circles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:157(Stars) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1288(DrawEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1484(PickEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:3475(ShowBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:370(ToolQuitAll) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:380(ToolGrid) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:395(ToolMinorGrid) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:410(ToolFullScreen) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:588(ViewsPositionsBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:634(SaveFigureBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2439(DArrow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3434(Curve) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3492(BracketB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3674(Fancy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3762(Wedge) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:950(STIXFontConstants) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1410(Hrule) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/axes/__init__.py:8(_SubplotBaseMeta) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/container.py:77(ErrorbarContainer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/polar.py:241(ThetaFormatter) + 2 0.000 0.000 0.000 0.000 :1299(exec_module) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:259(__exit__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:522(build_group_class) + 1 0.000 0.000 0.000 0.000 {built-in method _stat.S_ISREG} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:47(ComplexWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:581(_RecursiveWildcardSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1043(PurePosixPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1053(PureWindowsPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1336(TimedeltaFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1341(SubArrayFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/polynomial.py:29(RankWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zoneinfo/_common.py:164(ZoneInfoNotFoundError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:25(_TzOffsetFactory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexing.py:2433(_iAtIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1836(Datetime64TZFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:707(ExFileObject) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:545(CombinedDatetimelikeProperties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:1257(FrameSplitter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:3232(FrameFixed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:377(UnaryOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/sql.py:1421(BaseEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:81(HeaderDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/uu.py:39(Error) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/packaging/version.py:57(InvalidVersion) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:97(BasePrimitiveType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:1077(_fdat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1732(NullLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:168(UnboundedMemo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:3551(PositionToken) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/units.py:72(AxisInfo) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:31(VerticalHatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:140(LargeCircles) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2369(Ellipse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2801(Angle3) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3511(BracketAB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:959(STIXSansFontConstants) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1486(VCentered) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_blocking_input.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1551(MonthLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1578(WeekdayLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:21(get_keywords) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:503(_Selector) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:493(_recursive_guard) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1245(ComplexFloatingFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1278(_TimelikeFormat) + 1 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath._reload_guard} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/_internal.py:244(c_void_p) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:262(OGridClass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:717(IndexExpression) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/exceptions.py:11(Error) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:373(_tzfile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/calendar.py:160(setfirstweekday) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/multi.py:156(MultiIndexPyIntEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/internals/blocks.py:2118(NumericBlock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1617(IntArrayFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:735(SpecialFileError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/groupby/ops.py:1249(SeriesSplitter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:154(FileHash) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:181(NoSectionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:190(DuplicateSectionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:243(NoOptionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/compat.py:36(BehaviorChangeWarning) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:527(_unary_compiler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/numbers.py:559(UnknownCurrencyFormatError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:114(OffsetUnitCalculusError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:127(LogarithmicUnitCalculusError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:729(Filter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:1743(RootLogger) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:98(_Exception) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:117(ireduce_dimensions) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:2135(Quantity) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:523(Group) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:948(Delegated) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:1285(is_interactive) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_docstring.py:50(_ArtistKwdocLoader) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:747(_DunderChecker) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/colors.py:1796(FuncNorm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:2860(ImageTransformHandler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:3430(register_mime) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/error.py:5(CDefError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:204(BaseFunctionType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:239(FunctionPtrType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/PngImagePlugin.py:1066(_idat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:262(NullFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/transforms.py:2607(BboxTransformToMaxOnly) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:80(_UnboundedCache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:8(_lazyclassproperty) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:153(LatinA) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:218(Chinese) + 3 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2469(_generateDefaultName) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/cm.py:95(__iter__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1315(ResizeEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2348(Circle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2711(SimpleEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2905(Arc) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3533(BarAB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3551(BracketCurve) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dviread.py:782(Tfm) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_managers.py:20(ToolManagerMessageEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/projections/__init__.py:85(get_projection_names) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/offsetbox.py:499(HPacker) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1633(HourLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1683(SecondLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/container.py:109(StemContainer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/nested_methods.py:56(SliceIndexer) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:33(assert_pflines_samekind) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/pfstate.py:301(_SliceIndexer) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfstate/arithmatic.py:175(Multiply) + 4 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:5916(postParse) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/copyreg.py:22(constructor) + 2 0.000 0.000 0.000 0.000 {method '__prepare__' of 'type' objects} + 1 0.000 0.000 0.000 0.000 {built-in method _thread.get_native_id} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:1147(daemon) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:51(_is_wildcard_pattern) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:337(SplitResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:356(SplitResultBytes) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/arrayprint.py:1235(BoolFormat) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:435(RClass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/index_tricks.py:537(CClass) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/polynomial/polyutils.py:47(RankWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/random.py:805(seed) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/__init__.py:372(_CountryNameDict) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/_version.py:4() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/_factories.py:19(_TzFactory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:661(_result) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:1378(_attr) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:47(UnsortedIndexError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:55(ParserError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/array_algos/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:69(Error) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:740(AbsoluteLinkError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:745(LinkOutsideDestinationError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/info.py:1032(SeriesTableBuilderNonVerbose) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/engines.py:107(NumExprEngine) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:319(JointFilterBinOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/islamic.py:3398(_CustomIslamicCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/__init__.py:102(get_application_registry) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:216(DuplicateOptionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:26(PintError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:2178(createLock) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/parser.py:126(BytesHeaderParser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:12(MessageParseError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:50(FirstHeaderLineIsContinuationDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:957(DelegatedProperty) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_api/deprecation.py:308(_deprecated_parameter_class) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:2851(ImagePointHandler) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/error.py:17(VerificationError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:261(PointerType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:486(UnionType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:187(TickHelper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:332(FormatStrFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:355(StrMethodFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1030(LogFormatterExponent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1093(LogFormatterSciNotation) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:205(Cyrillic) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:263(Katakana) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:287(Hangul) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:319(Arabic) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:327(Hebrew) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:2476(_SingleCharLiteral) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/results.py:14() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:47(UnsatisfiableConstraint) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/colorama/winterm.py:23(WinStyle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2397(LArrow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2429(RArrow) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2534(Round4) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2642(Roundtooth) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2841(Angle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3573(CurveBracket) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1420(Vrule) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1658(MinuteLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:503(HandlerPathCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:434(InvalidIndexError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/tri/_triinterpolate.py:1061(_DOF_estimator_user) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/plot.py:56(ContinuousValuesNotSupported) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:34(VersioneerConfig) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/dataclasses.py:959() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:105(SubprocessError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/subprocess.py:2044(_save_input) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:476(BoundedSemaphore) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:348(DefragResultBytes) + 1 0.000 0.000 0.000 0.000 {built-in method numpy.core._multiarray_umath._set_madvise_hugepage} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:421(ConverterError) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:91(LazyList) + 2 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/lazy.py:144(LazySet) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:129(InvalidVersion) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:33(PerformanceWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:39(UnsupportedFunctionCall) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/dtypes.py:117(CategoricalDtypeType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/gzip.py:116(BadGzipFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:270(TarError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:723(AbsolutePathError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/custom.py:32(_CustomCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/compat.py:66(FakeArray) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/babel/plural.py:325(RuleError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/quantity.py:148(wrapper) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/__init__.py:346(ExecutableNotFoundError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/rcsetup.py:350(validate_fontsize_None) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:285(NamedPointerType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/ImageFile.py:587(PyCodecState) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/ticker.py:1046(LogFormatterMathtext) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/bezier.py:25(NonIntersectingPathException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:252(ParseException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/core.py:4882(Located) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:26(DuplicateEditVariable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:33(UnknownConstraint) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/kiwisolver/exceptions.py:40(UnknownEditVariable) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:1335(CloseEvent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_bases.py:2574(NonGuiException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:2476(Round) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:864(StixSansFonts) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:1476(HCentered) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/dates.py:1605(DayLocator) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:772(HandlerPolyCollection) + 2 0.000 0.000 0.000 0.000 {method 'clear' of 'list' objects} + 1 0.000 0.000 0.000 0.000 {built-in method sys.getdefaultencoding} + 1 0.000 0.000 0.000 0.000 {method '__exit__' of 'posix.ScandirIterator' objects} + 1 0.000 0.000 0.000 0.000 {method '__enter__' of '_thread.lock' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:750(BrokenBarrierError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:785() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/threading.py:943(_set_ident) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:85(TooHardError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:189(DTypePromotionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:404(_Accessor) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:528(_TerminatingSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:550(_WildcardSelector) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1578(PosixPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/pathlib.py:1585(WindowsPath) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:342(ParseResult) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/parse.py:361(ParseResultBytes) + 1 0.000 0.000 0.000 0.000 {built-in method numpy._using_numpy2_behavior} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:67(LinAlgError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:79(_64Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:429(ConverterLockError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:281(_fromnxfunction_seq) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:294(_fromnxfunction_args) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/ma/extras.py:319(_fromnxfunction_allargs) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/exceptions.py:15(UnknownTimeZoneError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/exceptions.py:38(InvalidTimeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/exceptions.py:42(AmbiguousTimeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/util/version/__init__.py:412(dev) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1156(_tzicalvtzcomp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:239(exec_module) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:454(Module_six_moves_urllib_response) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_config/config.py:104(OptionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/parser/_parser.py:1608(UnknownTimezoneWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/dtypes/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:124(EmptyDataError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:207(NumbaUtilError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:213(DuplicateLabelError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:301(SettingWithCopyWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:323(ChainedAssignmentError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:360(NumExprClobberingError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:405(IndexingError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:448(CSSWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:467(PossibleDataLossError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:479(ClosedFileError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:492(IncompatibilityWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:498(AttributeConflictWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:508(DatabaseError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:521(PossiblePrecisionLoss) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:536(ValueLabelTypeMismatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/csv.py:64(excel_tab) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:72(SameFileError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:82(ReadError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/formats/format.py:1656(ExtensionArrayFormatter) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:273(ExtractError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:288(EmptyHeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:294(EOFHeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:297(InvalidHeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:728(OutsideDestinationError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:42(BadZipFile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/zipfile.py:46(LargeZipFile) + 1 0.000 0.000 0.000 0.000 :1(__create_fn__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/_libs/window/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/accessors.py:478(PeriodProperties) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/socket.py:211(_GiveupOnSendfile) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/pytables.py:371(JointConditionBinOp) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/buddhist.py:440(_CustomBuddhistCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/chinese.py:1264(_CustomChineseCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/hindu.py:440(_CustomHinduCalendar) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/julian_revised.py:12() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/importlib/metadata.py:37(PackageNotFoundError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:254(InterpolationError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:264(InterpolationMissingOptionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:284(InterpolationDepthError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:340(MissingSectionHeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:140(UnitStrippedWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/logging/__init__.py:2172(handle) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:404(Header) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/_vendor/flexcache.py:420(Header) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:16(HeaderParseError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:20(BoundaryError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:24(MultipartConversionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:28(CharsetError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:41(NoBoundaryInMultipartDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:44(StartBoundaryNotFoundDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:47(CloseBoundaryNotFoundDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:67(UndecodableBytesDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:107(NonASCIILocalPartDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:974(DelegatedMethod) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:64(DecompressionBombWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/error.py:28(PkgConfigError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:192(UnknownFloatType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/model.py:482(StructType) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/util.py:101(_FifoCache) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:272(ParseFatalException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:159(LatinB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:309(CJK) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:312(Thai) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/unicode.py:341(Devanagari) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:48(NorthEastHatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/hatch.py:67(SouthEastHatch) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/backend_tools.py:627(ConfigureSubplotsBase) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3443(CurveA) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3448(CurveB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3453(CurveAB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3463(CurveFilledB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:966(DejaVuSerifFontConstants) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/_mathtext.py:970(DejaVuSansFontConstants) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/importlib_resources/abc.py:55(TraversalError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:238(HandlerLine2DCompound) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:275(HandlerLine2D) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/legend_handler.py:513(HandlerCircleCollection) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:438(TerminateTrajectory) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/streamplot.py:510(OutOfBounds) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:45(assert_pflines_distinctkind) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/pfline/arithmatic.py:57(ensure_pflines_samestructure) + 2 0.000 0.000 0.000 0.000 {method 'isalpha' of 'str' objects} + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/_version.py:52(NotThisMethod) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/selectors.py:200(__enter__) + 1 0.000 0.000 0.000 0.000 :1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:58(ModuleDeprecationWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/urllib/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/core/numeric.py:837(_outer_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/linalg/linalg.py:488(_unary_dispatcher) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:88(_8Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:382(Module_six_moves_urllib_error) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:130(ParserWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:179(AccessorRegistrationWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:75(SpecialFileError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/tools/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/reshape/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:285(HeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/_numba/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/interchange/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/configparser.py:276(InterpolationSyntaxError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/compat.py:67(__array_function__) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:53(MisplacedEnvelopeHeaderDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:64(InvalidMultipartContentTransferEncodingDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:73(InvalidBase64CharactersDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:76(InvalidBase64LengthDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/cffi/error.py:22(VerificationMissing) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/units.py:52(ConversionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3458(CurveFilledA) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/exceptions.py:74(VisibleDeprecationWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:70(_128Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:76(_80Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:82(_32Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:85(_16Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/lib/_iotools.py:437(ConversionWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytz/exceptions.py:53(NonExistentTimeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/__init__.py:11(DeprecatedTzFormatWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:627() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/dateutil/tz/tz.py:1818(_get_supported_offset) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:402(Module_six_moves_urllib_request) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/six.py:475(Module_six_moves_urllib_robotparser) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/util/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:69(DtypeWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:171(MergeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:234(InvalidIndexError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:242(DataError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:251(SpecificationError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:279(SettingWithCopyError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:426(PyperclipException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:563(CategoricalConversionWarning) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:577(LossySetitemError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:583(NoBufferPresent) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/config_init.py:637(register_plotting_backend_cb) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/strings/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/nanops.py:67(set_use_bottleneck) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:79(ExecError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:85(RegistryError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/shutil.py:89(_GiveupOnFastCopy) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/indexes/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/methods/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:276(ReadError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:279(CompressionError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:282(StreamError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:291(TruncatedHeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:300(SubsequentHeaderError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/tarfile.py:720(FilterError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/core/computation/expr.py:322(add_ops) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/io/pytables.py:2574(GenericDataIndexableCol) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/errors.py:82(PintTypeError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint/systems.py:530(System) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:61(MultipartInvariantViolationDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:70(InvalidBase64PaddingDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:87(InvalidHeaderDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:90(HeaderMissingRequiredValue) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:104(ObsoleteHeaderDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:970(DelegatedScalarProperty) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pint_pandas/pint_array.py:991(DelegatedScalarMethod) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/_version.py:2() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/PIL/Image.py:68(DecompressionBombError) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:17(ExceptionWordUnicode) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pyparsing/exceptions.py:279(ParseSyntaxException) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/core/__init__.py:1() + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/matplotlib/patches.py:3468(CurveFilledAB) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo/visualize/plot.py:60(CategoricalValuesNotSupported) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:67(_256Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/email/errors.py:56(MissingHeaderBodySeparatorDefect) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/numpy/_typing/__init__.py:73(_96Bit) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pandas/errors/__init__.py:589(InvalidComparison) + 1 0.000 0.000 0.000 0.000 /Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/holidays/calendars/julian.py:12() + + diff --git a/test-output.xml b/test-output.xml index 1f7cdeb..bea187a 100644 --- a/test-output.xml +++ b/test-output.xml @@ -1 +1 @@ -/Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytest/__main__.py -p vscode_pytest --collect-only teststests \ No newline at end of file +/Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytest/__main__.py -p vscode_pytest --collect-only teststests \ No newline at end of file diff --git a/tests/tools/test_intersect_flex.py b/tests/tools/test_intersect_flex.py new file mode 100755 index 0000000..822dc39 --- /dev/null +++ b/tests/tools/test_intersect_flex.py @@ -0,0 +1,244 @@ +import pandas as pd +import pytest + +from portfolyo import testing, tools + + +COMMON_END = "2022-02-02" + +TESTCASES = [ # startdates, freq, expected_startdate + # One starts at first day of year. + (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), + (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), + (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), + (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), + (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), + (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), + (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), + (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), + # Both start in middle of year. + (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), + (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), +] + +COMMON_END_2 = "2023-01-01" +TESTCASES_2 = [ # startdates, freq, expected_dates + # One starts at first day of year. + (("2020-01-01", "2020-01-20"), ("15T", "H"), ("2020-01-20", "2023-01-01")), + (("2020-01-01", "2020-01-20"), ("15T", "D"), ("2020-01-20", "2023-01-01")), + (("2022-04-01", "2021-02-01"), ("H", "MS"), ("2022-04-01", "2023-01-01")), + (("2020-01-01", "2020-04-01"), ("H", "QS"), ("2020-04-01", "2023-01-01")), + (("2020-01-01", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), + # Both start in middle of year. + (("2020-04-21", "2020-06-20"), ("15T", "H"), ("2020-06-20", "2023-01-01")), + (("2020-04-21", "2020-06-20"), ("15T", "D"), ("2020-06-20", "2023-01-01")), + (("2020-04-21", "2020-07-01"), ("H", "MS"), ("2020-07-01", "2023-01-01")), + (("2020-04-21", "2020-07-01"), ("H", "QS"), ("2020-07-01", "2023-01-01")), + (("2020-04-21", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), +] + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) +def test_intersect_flex_ignore_start_of_day( + tz, startdates, freq, starttime, expected_startdate +): + otherstarttime = "00:00" if starttime == "06:00" else "06:00" + a = pd.date_range( + f"{startdates[0]} {starttime}", + f"{COMMON_END} {starttime}", + freq=freq, + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {otherstarttime}", + f"{COMMON_END} {otherstarttime}", + freq=freq, + tz=tz, + inclusive="left", + ) + e = ( + pd.date_range( + f"{expected_startdate} {starttime}", + f"{COMMON_END} {starttime}", + freq=freq, + tz=tz, + inclusive="left", + ), + pd.date_range( + f"{expected_startdate} {otherstarttime}", + f"{COMMON_END} {otherstarttime}", + freq=freq, + tz=tz, + inclusive="left", + ), + ) + # Test error case. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex(a, b, ignore_start_of_day=False) + # Test ok case. + result = tools.intersect.indices_flex(a, b, ignore_start_of_day=True) + + for i in range(0, len(result)): + testing.assert_index_equal(result[i], e[i]) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) +@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) +def test_intersect_flex_ignore_tz(tz, startdates, freq, time_a, expected_startdate): + othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" + a = pd.date_range( + f"{startdates[0]} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=othertz, + inclusive="left", + ) + e = ( + pd.date_range( + f"{expected_startdate} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=tz, + inclusive="left", + ), + pd.date_range( + f"{expected_startdate} {time_a}", + f"{COMMON_END} {time_a}", + freq=freq, + tz=othertz, + inclusive="left", + ), + ) + # Test error case. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex(a, b, ignore_tz=False) + # Test ok case. + result = tools.intersect.indices_flex(a, b, ignore_tz=True) + + for i in range(0, len(result)): + testing.assert_index_equal(result[i], e[i]) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) +@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) +def test_intersect_flex_ignore_freq(tz, startdates, freq, time_a, expected_dates): + """Test if intersection of indices with distinct frequencies gives correct result.""" + a = pd.date_range( + f"{startdates[0]} {time_a}", + f"{COMMON_END_2} {time_a}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {time_a}", + f"{COMMON_END_2} {time_a}", + freq=freq[1], + tz=tz, + inclusive="left", + ) + expected_a = pd.date_range( + f"{expected_dates[0]} {time_a}", + f"{expected_dates[1]} {time_a}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + expected_b = pd.date_range( + f"{expected_dates[0]} {time_a}", + f"{expected_dates[1]} {time_a}", + freq=freq[1], + tz=tz, + inclusive="left", + ) + # Test error case. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex(a, b, ignore_freq=False) + + result_a, result_b = tools.intersect.indices_flex(a, b, ignore_freq=True) + + testing.assert_index_equal(result_a, expected_a) + testing.assert_index_equal(result_b, expected_b) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) +@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) +@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) +def test_ignore_all(tz, startdates, freq, starttime, expected_dates): + otherstarttime = "00:00" if starttime == "06:00" else "06:00" + othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" + a = pd.date_range( + f"{startdates[0]} {starttime}", + f"{COMMON_END_2} {starttime}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + b = pd.date_range( + f"{startdates[1]} {otherstarttime}", + f"{COMMON_END_2} {otherstarttime}", + freq=freq[1], + tz=othertz, + inclusive="left", + ) + expected_a = pd.date_range( + f"{expected_dates[0]} {starttime}", + f"{expected_dates[1]} {starttime}", + freq=freq[0], + tz=tz, + inclusive="left", + ) + expected_b = pd.date_range( + f"{expected_dates[0]} {otherstarttime}", + f"{expected_dates[1]} {otherstarttime}", + freq=freq[1], + tz=othertz, + inclusive="left", + ) + # Test error cases. + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=False, ignore_start_of_day=False, ignore_tz=False + ) + + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=False, ignore_start_of_day=True, ignore_tz=True + ) + + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_start_of_day=False, ignore_tz=True + ) + + with pytest.raises(ValueError): + _ = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=False + ) + + # Test ok case. + out_a, out_b = tools.intersect.indices_flex( + a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=True + ) + testing.assert_index_equal(out_a, expected_a) + testing.assert_index_equal(out_b, expected_b) From a94b6dcf0077b15a0ae5676084c8cd3c8698308d Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 22 Mar 2024 15:03:39 +0100 Subject: [PATCH 44/59] deleted unnecessary test --- test-output.xml | 1 - tests/tools/test_intersect_flex.py | 244 ----------------------------- 2 files changed, 245 deletions(-) delete mode 100755 tests/tools/test_intersect_flex.py diff --git a/test-output.xml b/test-output.xml index bea187a..e69de29 100644 --- a/test-output.xml +++ b/test-output.xml @@ -1 +0,0 @@ -/Users/alina.voilova/miniconda3/envs/env-portfolyo/lib/python3.9/site-packages/pytest/__main__.py -p vscode_pytest --collect-only teststests \ No newline at end of file diff --git a/tests/tools/test_intersect_flex.py b/tests/tools/test_intersect_flex.py deleted file mode 100755 index 822dc39..0000000 --- a/tests/tools/test_intersect_flex.py +++ /dev/null @@ -1,244 +0,0 @@ -import pandas as pd -import pytest - -from portfolyo import testing, tools - - -COMMON_END = "2022-02-02" - -TESTCASES = [ # startdates, freq, expected_startdate - # One starts at first day of year. - (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "15T", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "H", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), - (("2020-01-01", "2020-01-20"), "D", "2020-01-20"), - (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), - (("2020-01-01", "2020-03-01"), "MS", "2020-03-01"), - (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), - (("2020-01-01", "2020-04-01"), "QS", "2020-04-01"), - (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), - (("2020-01-01", "2021-01-01"), "AS", "2021-01-01"), - # Both start in middle of year. - (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "15T", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "H", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), - (("2020-04-21", "2020-06-20"), "D", "2020-06-20"), -] - -COMMON_END_2 = "2023-01-01" -TESTCASES_2 = [ # startdates, freq, expected_dates - # One starts at first day of year. - (("2020-01-01", "2020-01-20"), ("15T", "H"), ("2020-01-20", "2023-01-01")), - (("2020-01-01", "2020-01-20"), ("15T", "D"), ("2020-01-20", "2023-01-01")), - (("2022-04-01", "2021-02-01"), ("H", "MS"), ("2022-04-01", "2023-01-01")), - (("2020-01-01", "2020-04-01"), ("H", "QS"), ("2020-04-01", "2023-01-01")), - (("2020-01-01", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), - # Both start in middle of year. - (("2020-04-21", "2020-06-20"), ("15T", "H"), ("2020-06-20", "2023-01-01")), - (("2020-04-21", "2020-06-20"), ("15T", "D"), ("2020-06-20", "2023-01-01")), - (("2020-04-21", "2020-07-01"), ("H", "MS"), ("2020-07-01", "2023-01-01")), - (("2020-04-21", "2020-07-01"), ("H", "QS"), ("2020-07-01", "2023-01-01")), - (("2020-04-21", "2021-01-01"), ("D", "AS"), ("2021-01-01", "2023-01-01")), -] - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) -def test_intersect_flex_ignore_start_of_day( - tz, startdates, freq, starttime, expected_startdate -): - otherstarttime = "00:00" if starttime == "06:00" else "06:00" - a = pd.date_range( - f"{startdates[0]} {starttime}", - f"{COMMON_END} {starttime}", - freq=freq, - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {otherstarttime}", - f"{COMMON_END} {otherstarttime}", - freq=freq, - tz=tz, - inclusive="left", - ) - e = ( - pd.date_range( - f"{expected_startdate} {starttime}", - f"{COMMON_END} {starttime}", - freq=freq, - tz=tz, - inclusive="left", - ), - pd.date_range( - f"{expected_startdate} {otherstarttime}", - f"{COMMON_END} {otherstarttime}", - freq=freq, - tz=tz, - inclusive="left", - ), - ) - # Test error case. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex(a, b, ignore_start_of_day=False) - # Test ok case. - result = tools.intersect.indices_flex(a, b, ignore_start_of_day=True) - - for i in range(0, len(result)): - testing.assert_index_equal(result[i], e[i]) - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_startdate"), TESTCASES) -@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) -def test_intersect_flex_ignore_tz(tz, startdates, freq, time_a, expected_startdate): - othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" - a = pd.date_range( - f"{startdates[0]} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=othertz, - inclusive="left", - ) - e = ( - pd.date_range( - f"{expected_startdate} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=tz, - inclusive="left", - ), - pd.date_range( - f"{expected_startdate} {time_a}", - f"{COMMON_END} {time_a}", - freq=freq, - tz=othertz, - inclusive="left", - ), - ) - # Test error case. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex(a, b, ignore_tz=False) - # Test ok case. - result = tools.intersect.indices_flex(a, b, ignore_tz=True) - - for i in range(0, len(result)): - testing.assert_index_equal(result[i], e[i]) - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) -@pytest.mark.parametrize("time_a", ["00:00", "06:00"]) -def test_intersect_flex_ignore_freq(tz, startdates, freq, time_a, expected_dates): - """Test if intersection of indices with distinct frequencies gives correct result.""" - a = pd.date_range( - f"{startdates[0]} {time_a}", - f"{COMMON_END_2} {time_a}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {time_a}", - f"{COMMON_END_2} {time_a}", - freq=freq[1], - tz=tz, - inclusive="left", - ) - expected_a = pd.date_range( - f"{expected_dates[0]} {time_a}", - f"{expected_dates[1]} {time_a}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - expected_b = pd.date_range( - f"{expected_dates[0]} {time_a}", - f"{expected_dates[1]} {time_a}", - freq=freq[1], - tz=tz, - inclusive="left", - ) - # Test error case. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex(a, b, ignore_freq=False) - - result_a, result_b = tools.intersect.indices_flex(a, b, ignore_freq=True) - - testing.assert_index_equal(result_a, expected_a) - testing.assert_index_equal(result_b, expected_b) - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) -@pytest.mark.parametrize(("startdates", "freq", "expected_dates"), TESTCASES_2) -@pytest.mark.parametrize("starttime", ["00:00", "06:00"]) -def test_ignore_all(tz, startdates, freq, starttime, expected_dates): - otherstarttime = "00:00" if starttime == "06:00" else "06:00" - othertz = None if tz == "Europe/Berlin" else "Europe/Berlin" - a = pd.date_range( - f"{startdates[0]} {starttime}", - f"{COMMON_END_2} {starttime}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - b = pd.date_range( - f"{startdates[1]} {otherstarttime}", - f"{COMMON_END_2} {otherstarttime}", - freq=freq[1], - tz=othertz, - inclusive="left", - ) - expected_a = pd.date_range( - f"{expected_dates[0]} {starttime}", - f"{expected_dates[1]} {starttime}", - freq=freq[0], - tz=tz, - inclusive="left", - ) - expected_b = pd.date_range( - f"{expected_dates[0]} {otherstarttime}", - f"{expected_dates[1]} {otherstarttime}", - freq=freq[1], - tz=othertz, - inclusive="left", - ) - # Test error cases. - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=False, ignore_start_of_day=False, ignore_tz=False - ) - - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=False, ignore_start_of_day=True, ignore_tz=True - ) - - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_start_of_day=False, ignore_tz=True - ) - - with pytest.raises(ValueError): - _ = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=False - ) - - # Test ok case. - out_a, out_b = tools.intersect.indices_flex( - a, b, ignore_freq=True, ignore_start_of_day=True, ignore_tz=True - ) - testing.assert_index_equal(out_a, expected_a) - testing.assert_index_equal(out_b, expected_b) From 3a1975af7e3f3e988edd76c3e22249ad9f8d440f Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 17 Apr 2024 19:45:55 +0200 Subject: [PATCH 45/59] plot with children --- portfolyo/core/pfline/classes.py | 4 +- portfolyo/core/shared/plot.py | 228 +++++++++++++++---------------- portfolyo/visualize/__init__.py | 1 - portfolyo/visualize/plot.py | 73 +++------- 4 files changed, 128 insertions(+), 178 deletions(-) diff --git a/portfolyo/core/pfline/classes.py b/portfolyo/core/pfline/classes.py index 740bea2..1408218 100644 --- a/portfolyo/core/pfline/classes.py +++ b/portfolyo/core/pfline/classes.py @@ -8,16 +8,16 @@ import pandas as pd from ... import tools -from ..shared import ExcelClipboardOutput, PfLinePlot, PfLineText from ..ndframelike import NDFrameLike +from ..shared import ExcelClipboardOutput, PfLinePlot, PfLineText from . import ( + children, create, dataframeexport, decorators, flat_methods, nested_methods, prices, - children, ) from .arithmatic import PfLineArithmatic from .enums import Kind, Structure diff --git a/portfolyo/core/shared/plot.py b/portfolyo/core/shared/plot.py index e4caadf..7d23de0 100644 --- a/portfolyo/core/shared/plot.py +++ b/portfolyo/core/shared/plot.py @@ -5,21 +5,23 @@ from __future__ import annotations import hashlib -from typing import TYPE_CHECKING, Dict, List, Tuple +from typing import TYPE_CHECKING, Dict, Tuple import matplotlib import numpy as np +import pandas as pd from matplotlib import pyplot as plt from ... import tools from ... import visualize as vis +from ..pfline import classes +from ..pfline.enums import Kind if TYPE_CHECKING: # needed to avoid circular imports from ..pfline import PfLine from ..pfstate import PfState -DEFAULTHOW = {"r": "bar", "q": "bar", "p": "hline", "w": "area", "f": "area"} DEFAULTFMT = { "w": "{:,.1f}", "q": "{:,.0f}", @@ -29,70 +31,119 @@ } -def defaultkwargs(col: str, is_cat: bool): - """Styling and type of graph, depending on column ``col`` and whether or not the x-axis - is a category axis (``is_cat``).""" - kwargs = {} - kwargs["alpha"] = 0.7 - # Add defaults for each column. - kwargs["color"] = getattr(vis.Colors.Wqpr, col, "grey") - kwargs["labelfmt"] = DEFAULTFMT.get(col, "{:.2f}") - kwargs["how"] = DEFAULTHOW.get(col, "hline") - kwargs["cat"] = is_cat - # Override specific cases. - if not is_cat and col == "p": - kwargs["how"] = "step" - if is_cat and col == "f": - kwargs["how"] = "bar" - return kwargs +def plotfn_and_kwargs( + col: str, freq: str, name: str +) -> Tuple[vis.PlotTimeseriesToAxFunction, Dict]: + """Get correct function to plot as well as default kwargs. ``col``: one of 'qwprf', + ``freq``: frequency; ``name``: name of the child. If name is emptystring, it is the + parent of a plot which also has children. If it is None, there are no children.""" + # Get plot function. + if tools.freq.shortest(freq, "MS") == "MS": # categorical + if name == "" or name is None: # parent + fn = vis.plot_timeseries_as_bar + else: # child + fn = vis.plot_timeseries_as_hline + else: # timeaxis + if col in ["w", "q"]: + if name == "" or name is None: # parent + fn = vis.plot_timeseries_as_area + else: # child + fn = vis.plot_timeseries_as_step + else: # col in ['p', 'r'] + if name == "" or name is None: # parent + fn = vis.plot_timeseries_as_step + else: # child + fn = vis.plot_timeseries_as_step + + # Get plot default kwargs. + if name is None: # no children + kwargs = { + "color": getattr(vis.Colors.Wqpr, col, "grey"), + "alpha": 0.7, + "labelfmt": DEFAULTFMT.get(col, "{:.2f}"), + } + elif name == "": # parent with children + kwargs = { + "color": "grey", + "alpha": 0.7, + "labelfmt": DEFAULTFMT.get(col, "{:.2f}"), + } + else: # child with name + hashed_value = hashlib.sha256(name.encode()).hexdigest() + hashed_int = int(hashed_value, 16) + index = hashed_int % len(vis.Colors.General) + kwargs = { + "color": list(vis.Colors.General)[index].value, + "alpha": 0.9, + "labelfmt": "", # no labels on children + "label": name, + "linewidth": 0.5, + } + + return fn, kwargs class PfLinePlot: def plot_to_ax( - self: PfLine, - ax: plt.Axes, - col: str, - how: str, - labelfmt: str = "", - children: bool = False, - **kwargs, + self, ax: plt.Axes, children: bool = False, kind: Kind = None, **kwargs ) -> None: - """Plot a timeseries of the PfLine to a specific axes. + """Plot a specific dimension (i.e., kind) of the PfLine to a specific axis. Parameters ---------- ax : plt.Axes The axes object to which to plot the timeseries. - col : str - The column to plot. One of {'w', 'q', 'p', 'r'}. - how : str - How to plot the data. One of {'bar', 'area', 'step', 'hline'}. - labelfmt : str - Labels are added to each datapoint in the specified format. ('' to add no labels) - Any additional kwargs are passed to the pd.Series.plot function. - """ + children : bool, optional (default: False) + If True, plot also the direct children of the PfLine. + kind : Kind, optional (default: None) + What dimension of the data to plot. Ignored unless PfLine.kind is COMPLETE. + **kwargs + Any additional kwargs are passed to the pd.Series.plot function when drawing + the parent. - if col not in self.kind.available: + Returns + ------- + None + """ + # Ensure ``kind`` is volume, price, or revenue. + if self.kind is not Kind.COMPLETE: + kind = self.kind + elif kind not in [Kind.VOLUME, Kind.PRICE, Kind.REVENUE]: raise ValueError( - f"For this PfLine, parameter ``col`` must be one of {', '.join(self.kind.available)}; got {col}." + "To plot a complete portfolio line, the dimension to be plotted must be specified. " + f"Parameter ``kind`` must be one of {{Kind.VOLUME, Kind.PRICE, Kind.REVENUE}}; got {kind}." ) - if children: - # Plot on category axis if freq monthly or longer, else on time axis. - is_category = tools.freq.shortest(self.index.freq, "MS") == "MS" - self.plot_children(col, ax, is_category) - ax.legend() - vis.plot_timeseries(ax, getattr(self, col), how, labelfmt, **kwargs) + # Create function to select correct series of the pfline. + def col_and_series(pfl: PfLine) -> Tuple[str, pd.Series]: + if kind is Kind.PRICE: + return "p", pfl.p + elif kind is Kind.REVENUE: + return "r", pfl.r + elif tools.freq.longest(pfl.index.freq, "D") == "D": # timeaxis + return "w", pfl.w # kind is Kind.VOLUME + else: + return "q", pfl.q # kind is Kind.VOLUME - def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: - """Plot one or more timeseries of the PfLine. + # Plot top-level data first. + col, s = col_and_series(self) + fn, d_kwargs = plotfn_and_kwargs(col, self.index.freq, "" if children else None) + fn(ax, s, **(d_kwargs | kwargs)) + + # Plot children if wanted and available. + if not children or not isinstance(self, classes.NestedPfLine): + return + for name, child in self.items(): + col, s = col_and_series(child) + fn, d_kwargs = plotfn_and_kwargs(col, self.index.freq, name) + fn(ax, s, **d_kwargs) + ax.legend() + + def plot(self, children: bool = False) -> plt.Figure: + """Plot the PfLine. Parameters ---------- - cols : str, optional - The columns to plot. Default: plot volume (in [MW] for daily values and - shorter, [MWh] for monthly values and longer) and price `p` [Eur/MWh] - (if available). children : bool, optional (default: False) If True, plot also the direct children of the PfLine. @@ -101,84 +152,25 @@ def plot(self: PfLine, cols: str = None, children: bool = False) -> plt.Figure: plt.Figure The figure object to which the series was plotted. """ - # Plot on category axis if freq monthly or longer, else on time axis. - is_category = tools.freq.shortest(self.index.freq, "MS") == "MS" - # If columns are specified, plot these. Else: take defaults, based on what's available - if cols is None: - cols = "" - if "q" in self.kind.available: - cols += "q" if is_category else "w" - if "p" in self.kind.available: - cols += "p" - else: - cols = [col for col in cols if col in self.kind.available] - if not cols: - raise ValueError("No columns to plot.") - - # Create the plots. - size = (10, len(cols) * 3) - fig, axes = plt.subplots( - len(cols), 1, sharex=True, sharey=False, squeeze=False, figsize=size - ) + if self.kind is not Kind.COMPLETE: + # one axes + fig, ax = plt.subplots(1, 1, squeeze=True, figsize=(10, 3)) + self.plot_to_ax(ax, children) - for col, ax in zip(cols, axes.flatten()): - kwargs = defaultkwargs(col, is_category) - - if children: - self.plot_children(col, ax, is_category) - ax.legend() - s = getattr(self, col) - vis.plot_timeseries(ax, s, **kwargs) + else: + fig, axes = plt.subplots(3, 1, sharex=True, squeeze=True, figsize=(10, 9)) + for ax, kind in zip(axes, [Kind.VOLUME, Kind.PRICE, Kind.REVENUE]): + self.plot_to_ax(ax, children, kind) return fig - def get_children_with_colors(self: PfLine) -> List[Tuple[str, PfLine, vis.Color]]: - return [ - (name, child, self.hash_and_map_to_color(name)) - for (name, child) in self.items() - ] - def hash_and_map_to_color(self: PfLine, name: str) -> vis.Color: - # Use SHA-256 to hash the name - hashed_value = hashlib.sha256(name.encode()).hexdigest() - # Convert the hashed value to an integer - hashed_int = int(hashed_value, 16) - # Calculate the index in the General colors enum based on the hashed value - index = hashed_int % len(vis.Colors.General) - # Return the color associated with the index - return list(vis.Colors.General)[index].value +# TODO: ----- below here must still be rewritten --- - def plot_children(self: PfLine, col: str, ax: plt.Axes, is_category: bool) -> None: - """Plot children of the PfLine to the same ax as parent. - Parameters - ---------- - cols : str, optional - The columns to plot. Default: plot volume (in [MW] for daily values and - shorter, [MWh] for monthly values and longer) and price `p` [Eur/MWh] - (if available). - ax : plt.Axes - The axes object to which to plot the timeseries. - - """ - kwargs = defaultkwargs(col, is_category) - kwargs["labelfmt"] = "" - kwargs["alpha"] = 0.9 - # is_stacked_type = kwargs["how"] == "bar" or kwargs["how"] == "area" - - colors = [] - for name, child, color in self.get_children_with_colors(): - kwargs["color"] = color - kwargs["label"] = name - print("Color of child", name, "is:", color) - colors.append(color) - if kwargs["how"] == "bar": - kwargs["how"] = "hline" - elif kwargs["how"] == "area": - kwargs["how"] = "step" - - vis.plot_timeseries(ax, getattr(child, col), **kwargs) +def defaultkwargs(*args): + return {} class PfStatePlot: diff --git a/portfolyo/visualize/__init__.py b/portfolyo/visualize/__init__.py index 0dbb90f..c678a33 100644 --- a/portfolyo/visualize/__init__.py +++ b/portfolyo/visualize/__init__.py @@ -1,6 +1,5 @@ from .colors import Color, Colors from .plot import ( - plot_timeseries, plot_timeseries_as_area, plot_timeseries_as_bar, plot_timeseries_as_hline, diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index f0b533b..595befd 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -2,10 +2,13 @@ Visualize portfolio lines, etc. """ +from typing import Callable + import matplotlib as mpl import numpy as np import pandas as pd from matplotlib import pyplot as plt +from ..tools import freq as tools_freq from .categories import Categories, Category # noqa mpl.style.use("seaborn-v0_8") @@ -61,17 +64,13 @@ class CategoricalValuesNotSupported(Exception): pass +PlotTimeseriesToAxFunction = Callable[[plt.Axes, pd.Series, ...], None] + docstringliteral_plotparameters = """ Other parameters ---------------- labelfmt : str, optional (default: '') Labels are added to each datapoint in the specified format. ('' to add no labels) -cat : bool, optional - If False, plots x-axis as timeline with timestamps spaced according to their - duration. If True, plots x-axis categorically, with timestamps spaced equally. - Disregarded if ``ax`` already has values (then: use whatever is already set). - Default: use True if ``s`` has a monthly frequency or longer, False if the frequency - is shorter than monthly. **kwargs : any formatting are passed to the Axes plot method being used.""" @@ -88,12 +87,11 @@ def plot_timeseries_as_bar( ax: plt.Axes, s: pd.Series, labelfmt: str = "", - cat: bool = None, # don't need width: float = 0.8, **kwargs, ) -> None: - """Plot timeseries ``s`` to axis ``ax``, as bars. Ideally, only used for plots with - categorical (i.e, non-time) x-axis.""" + """Plot timeseries ``s`` to axis ``ax``, as bars. + On plots with categorical (i.e, non-continuous) time axis.""" if not is_categorical(s): raise ContinuousValuesNotSupported( "This plot is not compatible with continous values" @@ -113,11 +111,10 @@ def plot_timeseries_as_area( ax: plt.Axes, s: pd.Series, labelfmt: str = "", - cat: bool = None, **kwargs, ) -> None: - """Plot timeseries ``s`` to axis ``ax``, as stepped area between 0 and value. Ideally, - only used for plots with time (i.e., non-categorical) axis.""" + """Plot timeseries ``s`` to axis ``ax``, as stepped area between 0 and value. + On plots with continuous (i.e., non-categorical) time axis.""" if is_categorical(s): raise CategoricalValuesNotSupported( "This plot is not compatible with categorical values" @@ -146,10 +143,10 @@ def plot_timeseries_as_area( @append_to_doc(docstringliteral_plotparameters) def plot_timeseries_as_step( - ax: plt.Axes, s: pd.Series, labelfmt: str = "", cat: bool = None, **kwargs + ax: plt.Axes, s: pd.Series, labelfmt: str = "", **kwargs ) -> None: """Plot timeseries ``s`` to axis ``ax``, as stepped line (horizontal and vertical lines). - Ideally, only used for plots with time (i.e., non-categorical) axis.""" + On plots with continuous (i.e., non-categorical) time axis.""" if is_categorical(s): raise CategoricalValuesNotSupported( "This plot is not compatible with categorical values" @@ -168,13 +165,13 @@ def plot_timeseries_as_step( @append_to_doc(docstringliteral_plotparameters) def plot_timeseries_as_hline( - ax: plt.Axes, s: pd.Series, labelfmt: str = "", cat: bool = None, **kwargs + ax: plt.Axes, s: pd.Series, labelfmt: str = "", **kwargs ) -> None: - """Plot timeseries ``s`` to axis ``ax``, as horizontal lines. Ideally, only used for - plots with time (i.e., non-categorical) axis.""" + """Plot timeseries ``s`` to axis ``ax``, as horizontal lines. + On plots with categorical (i.e., non-continuous) time axis.""" if not is_categorical(s): raise ContinuousValuesNotSupported( - "This plot is not compatible with continous values" + "This plot is not compatible with continous time axis" ) check_ax_s_compatible(ax, s) s = prepare_ax_and_s(ax, s) # ensure unit compatibility (if possible) @@ -188,44 +185,6 @@ def plot_timeseries_as_hline( ax.margins(x=0.2, y=0.2) -def plot_timeseries( - ax: plt.Axes, - s: pd.Series, - how: str = "bar", - labelfmt: str = None, - cat: bool = None, - **kwargs, -) -> None: - """Plot timeseries to given axis. - - Parameters - ---------- - ax : plt.Axes - Axes to plot to. - s : pd.Series - Timeseries to plot - how : str, optional (default: 'bar') - How to plot the data; one of {'bar', 'area', 'step', 'hline'}. - labelfmt : str, optional (default: '') - Labels are added to each datapoint in the specified format. ('' to add no labels) - cat : bool, optional (default: True if frequency is monthly or larger) - Plot as categorical x-axis. - """ - - if how == "bar": - plot_timeseries_as_bar(ax, s, labelfmt, cat, **kwargs) - elif how == "area": - plot_timeseries_as_area(ax, s, labelfmt, cat, **kwargs) - elif how == "step": - plot_timeseries_as_step(ax, s, labelfmt, cat, **kwargs) - elif how == "hline": - plot_timeseries_as_hline(ax, s, labelfmt, cat, **kwargs) - else: - raise ValueError( - f"Parameter ``how`` must be one of 'bar', 'area', 'step', 'hline'; got {how}." - ) - - def set_portfolyo_attr(ax, name, val): """ Sets attribute ax._portfolyo which is a dictionary: ._portfolyo = {'unit': ..., 'freq': ..., ...} @@ -246,7 +205,7 @@ def get_portfolyo_attr(ax, name, default_val=None): def is_categorical(s: pd.Series) -> bool: """The function checks whether frequency of panda Series falls into continous or categorical group""" - return s.index.freq in ["AS", "QS", "MS"] + return tools_freq.longest(s.index.freq, "MS") == "MS" def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: From 0b274ac99369c9bc35d38811c154cd459319951d Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 22 Apr 2024 14:28:02 +0200 Subject: [PATCH 46/59] changed plot_pfstate to work with new logic --- dev_scripts/plot_state.py | 31 ----------- dev_scripts/plot_test.py | 67 ------------------------ portfolyo/core/shared/plot.py | 98 +++++++++++++---------------------- portfolyo/visualize/plot.py | 12 ++++- 4 files changed, 47 insertions(+), 161 deletions(-) delete mode 100644 dev_scripts/plot_state.py delete mode 100644 dev_scripts/plot_test.py diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py deleted file mode 100644 index d127e34..0000000 --- a/dev_scripts/plot_state.py +++ /dev/null @@ -1,31 +0,0 @@ -import matplotlib.pyplot as plt -import portfolyo as pf -from portfolyo import dev -import pandas as pd -from portfolyo.core.pfline.enums import Kind -from portfolyo.core.pfstate.pfstate import PfState - - -"""Plot PfState to test of adding axes for un/sourced prices.""" - - -index = pd.date_range( - "2022-06-01", "2024-02-01", freq="D", tz="Europe/Berlin", inclusive="left" -) -pfs = pf.dev.get_pfstate(index) -pfs2 = pfs.asfreq("MS") -offtakevolume = dev.get_nestedpfline(index, kind=Kind.VOLUME, childcount=4) -sourced = dev.get_nestedpfline(index, kind=Kind.COMPLETE, childcount=4) -unsourcedprice = dev.get_nestedpfline(index, kind=Kind.PRICE, childcount=4) -pfs3 = PfState(-1 * offtakevolume, unsourcedprice, sourced) -# pfl2 = create.nestedpfline(index) -# pfs3 = pf.dev.get_nested_pfstate(index) -offtakevolume2 = pfs3.offtakevolume -print(offtakevolume2) -# sourced = pfs.sourcedprice -# sourced.print() - -# pfl2.print() - -pfs2.plot(children=False) -plt.show() diff --git a/dev_scripts/plot_test.py b/dev_scripts/plot_test.py deleted file mode 100644 index b123f05..0000000 --- a/dev_scripts/plot_test.py +++ /dev/null @@ -1,67 +0,0 @@ -"""Create several plots to see if plotting still works.""" - -import matplotlib.pyplot as plt -import portfolyo as pf -from portfolyo.visualize.plot import ( - CategoricalValuesNotSupported, - ContinuousValuesNotSupported, -) - - -def plot_pfline_to_ax(value: str, how: str, children: int = 1): - """Plot a timeseries of the PfLine to 4 axes: (daily, monthly) x (children, no children). - Proper values to parameters: - "p", "step" - "p", "hline" - "w", "area" - "q", "bar" - Othwerwise, getting only 1 plot for pfline with no children since the function for plotting children use default_kwargs - - Parameters - ---------- - - value : str - The column to plot. One of {'w', 'q', 'p', 'r'}. - how : str - How to plot the data. One of {'bar', 'area', 'step', 'hline'}. - children: int - The number of children to assign to pfline. - """ - # Create a figure and an array of subplots (2 rows, 2 columns) - index = pf.dev.get_index(freq="D") - pfl1 = pf.dev.get_pfline(index, nlevels=2, childcount=children) - pfl2 = pfl1.asfreq("MS") - pfl2.print() - fig, axs = plt.subplots(2, 2) - try: - pfl2.plot_to_ax(axs[0][0], value, how, children=True) - except CategoricalValuesNotSupported: - axs[0, 0].clear() - try: - pfl2.plot_to_ax(axs[0][1], value, how, children=False) - except CategoricalValuesNotSupported: - axs[0, 1].clear() - - try: - pfl1.plot_to_ax(axs[1][0], value, how, children=True) - except ContinuousValuesNotSupported: - axs[1, 0].clear() - try: - pfl1.plot_to_ax(axs[1][1], value, how, children=False) - except ContinuousValuesNotSupported: - axs[1, 1].clear() - - # Set x-axis and y-axis labels dynamically - x_labels = ["with children", "without children"] - y_labels = ["more than a month", "less than a month"] - - # Set y-axis labels on the left for each row - for i in range(2): - axs[i, 0].set(ylabel=y_labels[i]) - # Set x-axis labels on top of each column - for j in range(2): - axs[1, j].set(xlabel=x_labels[j]) - plt.show() - - -plot_pfline_to_ax("q", "bar", 4) diff --git a/portfolyo/core/shared/plot.py b/portfolyo/core/shared/plot.py index 2f3fc8b..461482a 100644 --- a/portfolyo/core/shared/plot.py +++ b/portfolyo/core/shared/plot.py @@ -30,30 +30,7 @@ } -def plotfn_and_kwargs( - col: str, freq: str, name: str -) -> Tuple[vis.PlotTimeseriesToAxFunction, Dict]: - """Get correct function to plot as well as default kwargs. ``col``: one of 'qwprf', - ``freq``: frequency; ``name``: name of the child. If name is emptystring, it is the - parent of a plot which also has children. If it is None, there are no children.""" - # Get plot function. - if tools.freq.shortest(freq, "MS") == "MS": # categorical - if name == "" or name is None: # parent - fn = vis.plot_timeseries_as_bar - else: # child - fn = vis.plot_timeseries_as_hline - else: # timeaxis - if col in ["w", "q"]: - if name == "" or name is None: # parent - fn = vis.plot_timeseries_as_area - else: # child - fn = vis.plot_timeseries_as_step - else: # col in ['p', 'r'] - if name == "" or name is None: # parent - fn = vis.plot_timeseries_as_step - else: # child - fn = vis.plot_timeseries_as_step - +def defaultkwargs(name: str, col: str): # Get plot default kwargs. if name is None: # no children kwargs = { @@ -79,6 +56,35 @@ def plotfn_and_kwargs( "linewidth": 0.5, } + return kwargs + + +def plotfn_and_kwargs( + col: str, freq: str, name: str +) -> Tuple[vis.PlotTimeseriesToAxFunction, Dict]: + """Get correct function to plot as well as default kwargs. ``col``: one of 'qwprf', + ``freq``: frequency; ``name``: name of the child. If name is emptystring, it is the + parent of a plot which also has children. If it is None, there are no children.""" + # Get plot function. + if tools.freq.shortest(freq, "MS") == "MS": # categorical + if name == "" or name is None: # parent + fn = vis.plot_timeseries_as_bar + else: # child + fn = vis.plot_timeseries_as_hline + else: # timeaxis + if col in ["w", "q"]: + if name == "" or name is None: # parent + fn = vis.plot_timeseries_as_area + else: # child + fn = vis.plot_timeseries_as_step + else: # col in ['p', 'r'] + if name == "" or name is None: # parent + fn = vis.plot_timeseries_as_step + else: # child + fn = vis.plot_timeseries_as_step + + kwargs = defaultkwargs(name, col) + return fn, kwargs @@ -165,13 +171,6 @@ def plot(self, children: bool = False) -> plt.Figure: return fig -# TODO: ----- below here must still be rewritten --- - - -def defaultkwargs(*args): - return {} - - class PfStatePlot: def plot(self: PfState, children: bool = False) -> plt.Figure: """Plot the portfolio state. @@ -195,44 +194,21 @@ def plot(self: PfState, children: bool = False) -> plt.Figure: axes[4].sharey(axes[3]) axes[5].sharey(axes[3]) - # If freq is MS or longer: use categorical axes. Plot volumes in MWh. - # If freq is D or shorter: use time axes. Plot volumes in MW. - is_category = tools.freq.shortest(self.index.freq, "MS") == "MS" so, ss, usv = ( -1 * self.offtakevolume, self.sourced, self.unsourced, ) - pr_kwargs = defaultkwargs("p", is_category) - # Volumes. - if is_category: - kwargs = defaultkwargs("q", is_category) - value = "q" - else: - kwargs = defaultkwargs("w", is_category) - value = "w" - so.plot_to_ax(axes[0], value, children=children, **kwargs) - ss.plot_to_ax(axes[1], value, children=children, **kwargs) + + so.plot_to_ax(axes[0], children=children, kind=so.kind) + ss.plot_to_ax(axes[1], children=children, kind=Kind.VOLUME) # Unsourced volume. - usv.plot_to_ax(axes[2], value, **kwargs) + usv.plot_to_ax(axes[2], kind=Kind.VOLUME) # Procurement Price. - self.pnl_cost.plot_to_ax( - axes[3], - "p", - **pr_kwargs, - ) - self.sourced.plot_to_ax( - axes[4], - "p", - children=children, - **pr_kwargs, - ) + self.pnl_cost.plot_to_ax(axes[3], kind=Kind.PRICE) + self.sourced.plot_to_ax(axes[4], children=children, kind=Kind.PRICE) # Unsourced price - self.unsourced.plot_to_ax( - axes[5], - "p", - **pr_kwargs, - ) + self.unsourced.plot_to_ax(axes[5], kind=Kind.PRICE) # Set titles. axes[0].set_title("Offtake volume") axes[1].set_title("Sourced volume") diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 595befd..1f1e99a 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -205,7 +205,7 @@ def get_portfolyo_attr(ax, name, default_val=None): def is_categorical(s: pd.Series) -> bool: """The function checks whether frequency of panda Series falls into continous or categorical group""" - return tools_freq.longest(s.index.freq, "MS") == "MS" + return tools_freq.longer_or_shorter(s.index.freq, "D") == 1 def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: @@ -274,7 +274,7 @@ def check_ax_s_compatible(ax: plt.Axes, s: pd.Series): def set_data_labels( - ax: plt.Axes, xx, yy, labelfmt, outside: bool = False, maxcount: int = 24 + ax: plt.Axes, xx, yy, labelfmt, outside: bool = False, maxcount: int = 12 ): """Add labels to axis ``ax``, at locations (``xx``, ``yy``), formatted with ``labelfmt``. Don't add labels if more than ``maxcount`` datapoints. If ``outside``, @@ -292,6 +292,14 @@ def set_data_labels( xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) ax.annotate(lbl, (x, y), textcoords="offset points", xytext=xytext, ha="center") + # # Add labels only to every third data point. + # for i in range(0, len(xx), 3): # Iterate every third index + # x = xx[i] + # y = yy[i] + # lbl = labelfmt.format(y.magnitude).replace(",", " ") + # xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) + # ax.annotate(lbl, (x, y), textcoords="offset points", xytext=xytext, ha="center") + # Increase axis range to give label space to stay inside box. ylim = list(ax.get_ylim()) if not np.isclose(ylim[0], 0) and ylim[0] < 0: From 22a81fbbce92e469f3b23e52c9ab52bd61d3aa64 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Wed, 24 Apr 2024 14:37:51 +0200 Subject: [PATCH 47/59] tests for plot function --- portfolyo/core/shared/plot.py | 57 +++++++++++++------------ portfolyo/visualize/plot.py | 60 +++++++++++++++++++------- tests/visualize/test_plot.py | 79 +++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 44 deletions(-) create mode 100644 tests/visualize/test_plot.py diff --git a/portfolyo/core/shared/plot.py b/portfolyo/core/shared/plot.py index 461482a..9df1f80 100644 --- a/portfolyo/core/shared/plot.py +++ b/portfolyo/core/shared/plot.py @@ -53,7 +53,7 @@ def defaultkwargs(name: str, col: str): "alpha": 0.9, "labelfmt": "", # no labels on children "label": name, - "linewidth": 0.5, + "linewidth": 0.9, } return kwargs @@ -90,7 +90,7 @@ def plotfn_and_kwargs( class PfLinePlot: def plot_to_ax( - self, ax: plt.Axes, children: bool = False, kind: Kind = None, **kwargs + self: PfLine, ax: plt.Axes, children: bool = False, kind: Kind = None, **kwargs ) -> None: """Plot a specific dimension (i.e., kind) of the PfLine to a specific axis. @@ -132,6 +132,7 @@ def col_and_series(pfl: PfLine) -> Tuple[str, pd.Series]: # Plot top-level data first. col, s = col_and_series(self) + # s = s.pint.m fn, d_kwargs = plotfn_and_kwargs(col, self.index.freq, "" if children else None) fn(ax, s, **(d_kwargs | kwargs)) @@ -140,6 +141,7 @@ def col_and_series(pfl: PfLine) -> Tuple[str, pd.Series]: return for name, child in self.items(): col, s = col_and_series(child) + # s = s.pint.m fn, d_kwargs = plotfn_and_kwargs(col, self.index.freq, name) fn(ax, s, **d_kwargs) ax.legend() @@ -185,14 +187,13 @@ def plot(self: PfState, children: bool = False) -> plt.Figure: The figure object to which the series was plotted. """ gridspec = {"width_ratios": [1, 1, 1], "height_ratios": [4, 1]} - fig, axes = plt.subplots( - 2, 3, sharex=True, gridspec_kw=gridspec, figsize=(10, 6) + fig, (volumeaxes, priceaxes) = plt.subplots( + 2, 3, sharex=True, sharey="row", gridspec_kw=gridspec, figsize=(10, 6) ) - axes = axes.flatten() - axes[1].sharey(axes[0]) - axes[2].sharey(axes[0]) - axes[4].sharey(axes[3]) - axes[5].sharey(axes[3]) + # axes[1].sharey(axes[0]) + # axes[2].sharey(axes[0]) + # axes[4].sharey(axes[3]) + # axes[5].sharey(axes[3]) so, ss, usv = ( -1 * self.offtakevolume, @@ -200,38 +201,36 @@ def plot(self: PfState, children: bool = False) -> plt.Figure: self.unsourced, ) - so.plot_to_ax(axes[0], children=children, kind=so.kind) - ss.plot_to_ax(axes[1], children=children, kind=Kind.VOLUME) + so.plot_to_ax(volumeaxes[0], children=children, kind=so.kind) + ss.plot_to_ax(volumeaxes[1], children=children, kind=Kind.VOLUME) # Unsourced volume. - usv.plot_to_ax(axes[2], kind=Kind.VOLUME) + usv.plot_to_ax(volumeaxes[2], kind=Kind.VOLUME) # Procurement Price. - self.pnl_cost.plot_to_ax(axes[3], kind=Kind.PRICE) - self.sourced.plot_to_ax(axes[4], children=children, kind=Kind.PRICE) + self.pnl_cost.plot_to_ax(priceaxes[0], kind=Kind.PRICE) + self.sourced.plot_to_ax(priceaxes[1], children=children, kind=Kind.PRICE) # Unsourced price - self.unsourced.plot_to_ax(axes[5], kind=Kind.PRICE) + self.unsourced.plot_to_ax(priceaxes[2], kind=Kind.PRICE) # Set titles. - axes[0].set_title("Offtake volume") - axes[1].set_title("Sourced volume") - axes[2].set_title("Unsourced volume") - axes[3].set_title("Procurement price") - axes[4].set_title("Sourced price") - axes[5].set_title("Unsourced price") + volumeaxes[0].set_title("Offtake volume") + volumeaxes[1].set_title("Sourced volume") + volumeaxes[2].set_title("Unsourced volume") + priceaxes[0].set_title("Procurement price") + priceaxes[1].set_title("Sourced price") + priceaxes[2].set_title("Unsourced price") # Format tick labels. formatter = matplotlib.ticker.FuncFormatter( lambda x, p: "{:,.0f}".format(x).replace(",", " ") ) - axes[0].yaxis.set_major_formatter(formatter) - axes[1].yaxis.set_major_formatter(formatter) + volumeaxes[0].yaxis.set_major_formatter(formatter) + priceaxes[0].yaxis.set_major_formatter(formatter) # axes[3].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)) # Set ticks. - axes[0].xaxis.set_tick_params(labeltop=False, labelbottom=True) - axes[1].xaxis.set_tick_params(labeltop=False, labelbottom=True) - axes[2].xaxis.set_tick_params(labeltop=False, labelbottom=True) - axes[3].xaxis.set_tick_params(labeltop=False, labelbottom=False) - axes[4].xaxis.set_tick_params(labeltop=False, labelbottom=False) - axes[5].xaxis.set_tick_params(labeltop=False, labelbottom=False) + for ax in volumeaxes: + ax.xaxis.set_tick_params(labeltop=False, labelbottom=True) + for ax in priceaxes: + ax.xaxis.set_tick_params(labeltop=False, labelbottom=False) fig.tight_layout() return fig diff --git a/portfolyo/visualize/plot.py b/portfolyo/visualize/plot.py index 1f1e99a..709ee76 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/visualize/plot.py @@ -8,6 +8,9 @@ import numpy as np import pandas as pd from matplotlib import pyplot as plt + +from portfolyo.tools.unit import to_name +from portfolyo.visualize.colors import Colors from ..tools import freq as tools_freq from .categories import Categories, Category # noqa @@ -53,7 +56,7 @@ # pick the correct graph type. # -MAX_XLABELS = 20 +MAX_XLABELS = 15 class ContinuousValuesNotSupported(Exception): @@ -249,8 +252,21 @@ def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: # No custom unit provided. Convert series to base units. s = s.pint.to_base_units() set_portfolyo_attr(ax, "unit", s.pint.units) - - ax.set_ylabel(f"{get_portfolyo_attr(ax, 'unit'):~P}") + # Get unit attribute + unit = get_portfolyo_attr(ax, "unit") + name_unit = to_name(unit) + # Define color mapping based on 'Wqpr' class attributes + unit_colors = { + "w": Colors.Wqpr.w, + "q": Colors.Wqpr.q, + "r": Colors.Wqpr.r, + "p": Colors.Wqpr.p, + } + # Set default color if name_unit not found + default_color = "white" + # Get background color based on name_unit + background_color = unit_colors.get(name_unit, default_color) + ax.set_ylabel(f"{unit:~P}", backgroundcolor=background_color.lighten(0.2)) return s @@ -274,7 +290,7 @@ def check_ax_s_compatible(ax: plt.Axes, s: pd.Series): def set_data_labels( - ax: plt.Axes, xx, yy, labelfmt, outside: bool = False, maxcount: int = 12 + ax: plt.Axes, xx, yy, labelfmt, outside: bool = False, maxcount: int = 24 ): """Add labels to axis ``ax``, at locations (``xx``, ``yy``), formatted with ``labelfmt``. Don't add labels if more than ``maxcount`` datapoints. If ``outside``, @@ -286,19 +302,33 @@ def set_data_labels( if len(xx) > maxcount: return - # Add labels. - for x, y in zip(xx, yy): - lbl = labelfmt.format(y.magnitude).replace(",", " ") - xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) - ax.annotate(lbl, (x, y), textcoords="offset points", xytext=xytext, ha="center") - - # # Add labels only to every third data point. - # for i in range(0, len(xx), 3): # Iterate every third index - # x = xx[i] - # y = yy[i] + # # Add labels. + # for x, y in zip(xx, yy): # lbl = labelfmt.format(y.magnitude).replace(",", " ") # xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) - # ax.annotate(lbl, (x, y), textcoords="offset points", xytext=xytext, ha="center") + # ax.annotate( + # lbl, + # (x, y), + # textcoords="offset points", + # xytext=xytext, + # ha="center", + # rotation=45, + # ) + + # Add labels only to every third data point. + for i in range(0, len(xx), 3): # Iterate every third index + x = xx[i] + y = yy[i] + lbl = labelfmt.format(y.magnitude).replace(",", " ") + xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) + ax.annotate( + lbl, + (x, y), + textcoords="offset points", + xytext=xytext, + ha="center", + rotation=90, + ) # Increase axis range to give label space to stay inside box. ylim = list(ax.get_ylim()) diff --git a/tests/visualize/test_plot.py b/tests/visualize/test_plot.py new file mode 100644 index 0000000..1b15d8a --- /dev/null +++ b/tests/visualize/test_plot.py @@ -0,0 +1,79 @@ +"""Test if portfolio line can be plotted.""" + +import pytest +import pandas as pd +import portfolyo as pf +from portfolyo.core.pfline.enums import Kind +from portfolyo.core.pfstate.pfstate import PfState +import matplotlib.pyplot as plt + + +@pytest.mark.parametrize("levels", [1, 2, 3]) +@pytest.mark.parametrize("childcount", [1, 2, 3]) +@pytest.mark.parametrize("children", ["True", "False"]) +@pytest.mark.parametrize("kind", [Kind.VOLUME, Kind.PRICE, Kind.REVENUE, Kind.COMPLETE]) +@pytest.mark.parametrize("freq", ["MS", "D"]) +def test_pfline_plot( + levels: int, childcount: int, children: str, kind: Kind, freq: str +): + """Test if data can be plotted with plot() function.""" + index = pd.date_range("2020-01-01", "2021-01-01", freq=freq, tz=None) + pfl = pf.dev.get_pfline(index, nlevels=levels, childcount=childcount, kind=kind) + pfl.plot(children=children) + + +@pytest.mark.parametrize("childcount", [1, 2, 3]) +@pytest.mark.parametrize("children", ["True", "False"]) +@pytest.mark.parametrize("freq", ["MS", "D"]) +def test_pfstate_plot( + childcount: int, + children: str, + freq: str, +): + """Test if pfstate can be plotted with plot() function.""" + index = pd.date_range( + "2022-06-01", "2024-02-01", freq=freq, tz="Europe/Berlin", inclusive="left" + ) + offtakevolume = pf.dev.get_nestedpfline( + index, kind=Kind.VOLUME, childcount=childcount + ) + sourced = pf.dev.get_nestedpfline(index, kind=Kind.COMPLETE, childcount=childcount) + unsourcedprice = pf.dev.get_nestedpfline( + index, kind=Kind.PRICE, childcount=childcount + ) + pfs = PfState(-1 * offtakevolume, unsourcedprice, sourced) + pfs.plot(children=children) + + +@pytest.mark.parametrize("children", ["True", "False"]) +def test_flatpfline_plot(children: str): + """Test if plotting flatpfline with children attribute gives an error.""" + pfl = pf.dev.get_flatpfline() + pfl.plot(children=children) + + +@pytest.mark.parametrize("freq", ["MS", "D"]) +@pytest.mark.parametrize("children", ["True", "False"]) +@pytest.mark.parametrize("levels", [1, 2, 3]) +@pytest.mark.parametrize("childcount", [1, 2, 3]) +def test_plot_to_ax(levels: int, childcount: int, children: str, freq: str): + """Test if frunction plot_to_ax works with every kind of pfline.""" + index = pd.date_range("2020-01-01", "2021-01-01", freq=freq, tz=None) + pfl_compl = pf.dev.get_pfline( + index, nlevels=levels, childcount=childcount, kind=Kind.COMPLETE + ) + pfl_vol = pf.dev.get_pfline( + index, nlevels=levels, childcount=childcount, kind=Kind.VOLUME + ) + pfl_price = pf.dev.get_pfline( + index, nlevels=levels, childcount=childcount, kind=Kind.PRICE + ) + pfl_rev = pf.dev.get_pfline( + index, nlevels=levels, childcount=childcount, kind=Kind.REVENUE + ) + fig, axs = plt.subplots(2, 2) + with pytest.raises(ValueError): + _ = pfl_compl.plot_to_ax(axs[0][0], children=children, kind=Kind.COMPLETE) + pfl_vol.plot_to_ax(axs[0][1], children=children, kind=Kind.VOLUME) + pfl_price.plot_to_ax(axs[1][0], children=children, kind=Kind.PRICE) + pfl_rev.plot_to_ax(axs[1][1], children=children, kind=Kind.REVENUE) From 730bf7e64e5221da743d3032031f49f23c816d0e Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Fri, 10 May 2024 11:53:23 +0200 Subject: [PATCH 48/59] error with refactoring :3 --- dev_scripts/plot_state.py | 15 + dev_scripts/tree.py | 16 + portfolyo/__init__.py | 7 +- portfolyo/core/pfline/arithmatic.py | 4 +- portfolyo/core/pfline/children.py | 4 +- portfolyo/core/pfline/classes.py | 6 +- portfolyo/core/pfline/concat.py | 0 portfolyo/core/pfline/flat_methods.py | 7 +- portfolyo/core/pfline/interop.py | 10 +- portfolyo/core/{shared => pfline}/plot.py | 112 +- portfolyo/core/pfline/prices.py | 4 +- portfolyo/core/pfline/text.py | 132 ++ portfolyo/core/pfstate/arithmatic.py | 4 +- portfolyo/core/pfstate/pfstate.py | 6 +- portfolyo/core/pfstate/pfstate_helper.py | 7 +- portfolyo/core/pfstate/plot.py | 83 + portfolyo/core/pfstate/text.py | 41 + portfolyo/core/shared/__init__.py | 5 +- portfolyo/core/shared/excelclipboard.py | 2 +- portfolyo/core/{ => shared}/ndframelike.py | 9 +- portfolyo/core/shared/text.py | 177 +- portfolyo/dev/mockup.py | 3 +- portfolyo/testing/__init__.py | 7 - portfolyo/tools/intersect.py | 9 +- portfolyo/{ => tools}/prices/__init__.py | 0 portfolyo/{ => tools}/prices/convert.py | 13 +- portfolyo/{ => tools}/prices/hedge.py | 2 +- portfolyo/{ => tools}/prices/utils.py | 4 +- portfolyo/{testing => tools}/testing.py | 27 +- portfolyo/{ => tools}/visualize/__init__.py | 0 portfolyo/{ => tools}/visualize/categories.py | 9 +- portfolyo/{ => tools}/visualize/colors.py | 0 portfolyo/{ => tools}/visualize/plot.py | 47 +- portfolyo/tools2/concat.py | 2 +- portfolyo/tools2/intersect.py | 2 +- portfolyo/tools2/plot.py | 4 +- tests/core/test-output.xml | 1961 ----------------- tests/{ => tools}/prices/test_convert.py.bak | 0 .../{ => tools}/prices/test_convert_data.xlsx | Bin tests/{ => tools}/prices/test_hedge.py.bak | 0 tests/{ => tools}/prices/test_hedge_data.xlsx | Bin tests/{ => tools}/prices/test_utils.py | 2 +- tests/{ => tools}/visualize/test_plot.py | 0 .../test_concat_error_cases.py | 0 .../shared => tools2}/test_concat_pfline.py | 0 .../shared => tools2}/test_concat_pfstate.py | 0 tests/utils.py | 1 + 47 files changed, 399 insertions(+), 2345 deletions(-) create mode 100644 dev_scripts/plot_state.py create mode 100644 dev_scripts/tree.py delete mode 100644 portfolyo/core/pfline/concat.py rename portfolyo/core/{shared => pfline}/plot.py (57%) create mode 100644 portfolyo/core/pfline/text.py create mode 100644 portfolyo/core/pfstate/plot.py create mode 100644 portfolyo/core/pfstate/text.py rename portfolyo/core/{ => shared}/ndframelike.py (94%) delete mode 100644 portfolyo/testing/__init__.py rename portfolyo/{ => tools}/prices/__init__.py (100%) rename portfolyo/{ => tools}/prices/convert.py (97%) rename portfolyo/{ => tools}/prices/hedge.py (99%) rename portfolyo/{ => tools}/prices/utils.py (99%) rename portfolyo/{testing => tools}/testing.py (76%) rename portfolyo/{ => tools}/visualize/__init__.py (100%) rename portfolyo/{ => tools}/visualize/categories.py (95%) rename portfolyo/{ => tools}/visualize/colors.py (100%) rename portfolyo/{ => tools}/visualize/plot.py (89%) delete mode 100644 tests/core/test-output.xml rename tests/{ => tools}/prices/test_convert.py.bak (100%) rename tests/{ => tools}/prices/test_convert_data.xlsx (100%) rename tests/{ => tools}/prices/test_hedge.py.bak (100%) rename tests/{ => tools}/prices/test_hedge_data.xlsx (100%) rename tests/{ => tools}/prices/test_utils.py (99%) rename tests/{ => tools}/visualize/test_plot.py (100%) rename tests/{core/shared => tools2}/test_concat_error_cases.py (100%) rename tests/{core/shared => tools2}/test_concat_pfline.py (100%) rename tests/{core/shared => tools2}/test_concat_pfstate.py (100%) diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py new file mode 100644 index 0000000..402e741 --- /dev/null +++ b/dev_scripts/plot_state.py @@ -0,0 +1,15 @@ +import portfolyo as pf +import pandas as pd +from portfolyo.core.pfline.enums import Kind +from portfolyo.core.pfstate.pfstate import PfState +import matplotlib.pyplot as plt + +index = pd.date_range( + "2022-06-01", "2024-02-01", freq="MS", tz="Europe/Berlin", inclusive="left" +) +offtakevolume = pf.dev.get_nestedpfline(index, kind=Kind.VOLUME, childcount=2) +sourced = pf.dev.get_nestedpfline(index, kind=Kind.COMPLETE, childcount=2) +unsourcedprice = pf.dev.get_nestedpfline(index, kind=Kind.PRICE, childcount=2) +pfs = PfState(-1 * offtakevolume, unsourcedprice, sourced) +pfs.plot(children=True) +plt.show() diff --git a/dev_scripts/tree.py b/dev_scripts/tree.py new file mode 100644 index 0000000..00a9920 --- /dev/null +++ b/dev_scripts/tree.py @@ -0,0 +1,16 @@ +import os + + +def list_files(startpath): + for root, dirs, files in os.walk(startpath): + level = root.replace(startpath, "").count(os.sep) + indent = " " * 4 * (level) + print("{}{}/".format(indent, os.path.basename(root))) + subindent = " " * 4 * (level + 1) + for f in files: + print("{}{}".format(subindent, f)) + + +list_files( + "/Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo" +) diff --git a/portfolyo/__init__.py b/portfolyo/__init__.py index 42a8584..771e8ac 100644 --- a/portfolyo/__init__.py +++ b/portfolyo/__init__.py @@ -1,13 +1,13 @@ """Package to analyse and manipulate timeseries related to power and gas offtake portfolios.""" -from . import _version, dev, testing, tools +from . import _version, dev, tools from .core import extendpandas # extend functionalty of pandas from .core import suppresswarnings from .core.pfline import Kind, PfLine, Structure, create from .tools.freq import FREQUENCIES from .core.pfstate import PfState -from .prices.hedge import hedge -from .prices.utils import is_peak_hour +from .tools.prices.hedge import hedge +from .tools.prices.utils import is_peak_hour from .tools2.concat import general as concat from .tools2.intersect import indexable as intersection from .tools2.plot import plot_pfstates @@ -18,6 +18,7 @@ from .tools.tzone import force_agnostic, force_aware from .tools.unit import Q_, Unit, ureg from .tools.wavg import general as wavg +from .tools import testing VOLUME = Kind.VOLUME PRICE = Kind.PRICE diff --git a/portfolyo/core/pfline/arithmatic.py b/portfolyo/core/pfline/arithmatic.py index bf0d41f..9a845a2 100644 --- a/portfolyo/core/pfline/arithmatic.py +++ b/portfolyo/core/pfline/arithmatic.py @@ -7,7 +7,7 @@ import numpy as np import pandas as pd -from ... import testing, tools +from ... import tools from . import classes, create, interop from .enums import Kind, Structure @@ -23,7 +23,7 @@ def assert_objects_indexcompatibility(fn): def wrapper(o1, o2, *args, **kwargs): try: - testing.assert_indices_compatible(o1.index, o2.index) + tools.testing.assert_indices_compatible(o1.index, o2.index) except AssertionError as e: raise NotImplementedError from e return fn(o1, o2, *args, **kwargs) diff --git a/portfolyo/core/pfline/children.py b/portfolyo/core/pfline/children.py index 18942ec..824dfc5 100644 --- a/portfolyo/core/pfline/children.py +++ b/portfolyo/core/pfline/children.py @@ -3,7 +3,7 @@ import warnings from typing import TYPE_CHECKING, Any, Mapping, Union -from ... import testing, tools +from ... import tools from . import create if TYPE_CHECKING: @@ -28,7 +28,7 @@ def set_child( f"Incompatible kinds; the portfolio line has {self.kind} but the child has {child.kind}." ) try: - testing.assert_indices_compatible(self.index, child.index) + tools.testing.assert_indices_compatible(self.index, child.index) except AssertionError as e: raise ValueError( "Index of new child is not compatible with the existing data." diff --git a/portfolyo/core/pfline/classes.py b/portfolyo/core/pfline/classes.py index 1408218..440144d 100644 --- a/portfolyo/core/pfline/classes.py +++ b/portfolyo/core/pfline/classes.py @@ -8,8 +8,10 @@ import pandas as pd from ... import tools -from ..ndframelike import NDFrameLike -from ..shared import ExcelClipboardOutput, PfLinePlot, PfLineText +from ..shared.ndframelike import NDFrameLike +from .text import PfLineText +from .plot import PfLinePlot +from ..shared.excelclipboard import ExcelClipboardOutput from . import ( children, create, diff --git a/portfolyo/core/pfline/concat.py b/portfolyo/core/pfline/concat.py deleted file mode 100644 index e69de29..0000000 diff --git a/portfolyo/core/pfline/flat_methods.py b/portfolyo/core/pfline/flat_methods.py index 5511f02..6c9570b 100644 --- a/portfolyo/core/pfline/flat_methods.py +++ b/portfolyo/core/pfline/flat_methods.py @@ -1,10 +1,7 @@ from __future__ import annotations from typing import TYPE_CHECKING, Any - -from portfolyo import tools - -from ... import testing +from ... import tools import pandas as pd if TYPE_CHECKING: @@ -19,7 +16,7 @@ def __eq__(self: FlatPfLine, other: Any) -> bool: if not isinstance(other, self.__class__): return False try: - testing.assert_frame_equal(self.df, other.df, rtol=1e-7) + tools.testing.assert_frame_equal(self.df, other.df, rtol=1e-7) return True except AssertionError: return False diff --git a/portfolyo/core/pfline/interop.py b/portfolyo/core/pfline/interop.py index d0c7534..f59e2ae 100644 --- a/portfolyo/core/pfline/interop.py +++ b/portfolyo/core/pfline/interop.py @@ -9,7 +9,7 @@ import numpy as np import pandas as pd -from ... import testing, tools +from ... import tools from . import classes, create if TYPE_CHECKING: # needed to avoid circular imports @@ -116,7 +116,9 @@ def make_consistent(self) -> InOp: # Volumes. if w is not None and q is not None: try: - testing.assert_series_equal(w, q / q.index.duration, check_names=False) + tools.testing.assert_series_equal( + w, q / q.index.duration, check_names=False + ) except AssertionError as e: raise ValueError("Values for w and q are not consistent.") from e elif w is not None and q is None: @@ -157,7 +159,7 @@ def make_consistent(self) -> InOp: ign2 = np.isclose(p.pint.m, 0) & (q.isna() | np.isinf(q.pint.m)) ignore = ign1 | ign2 try: - testing.assert_series_equal( + tools.testing.assert_series_equal( r[~ignore], p[~ignore] * q[~ignore], check_names=False ) except AssertionError as e: @@ -399,7 +401,7 @@ def _equal(inop1: InOp, inop2: InOp) -> InOp: return False if isinstance(val1, pd.Series): try: - testing.assert_series_equal(val1, val2, check_names=False) + tools.testing.assert_series_equal(val1, val2, check_names=False) except AssertionError: return False elif val1 != val2: diff --git a/portfolyo/core/shared/plot.py b/portfolyo/core/pfline/plot.py similarity index 57% rename from portfolyo/core/shared/plot.py rename to portfolyo/core/pfline/plot.py index caa414e..ac407f6 100644 --- a/portfolyo/core/shared/plot.py +++ b/portfolyo/core/pfline/plot.py @@ -7,18 +7,15 @@ import hashlib from typing import TYPE_CHECKING, Dict, Tuple -import matplotlib import pandas as pd from matplotlib import pyplot as plt from ... import tools -from ... import visualize as vis -from ..pfline import classes -from ..pfline.enums import Kind +from . import classes +from .enums import Kind -if TYPE_CHECKING: # needed to avoid circular imports - from ..pfline import PfLine - from ..pfstate import PfState +if TYPE_CHECKING: + from .classes import PfLine DEFAULTFMT = { @@ -34,7 +31,7 @@ def defaultkwargs(name: str, col: str): # Get plot default kwargs. if name is None: # no children kwargs = { - "color": getattr(vis.Colors.Wqpr, col, "grey"), + "color": getattr(tools.visualise.Colors.Wqpr, col, "grey"), "alpha": 0.7, "labelfmt": DEFAULTFMT.get(col, "{:.2f}"), } @@ -47,9 +44,9 @@ def defaultkwargs(name: str, col: str): else: # child with name hashed_value = hashlib.sha256(name.encode()).hexdigest() hashed_int = int(hashed_value, 16) - index = hashed_int % len(vis.Colors.General) + index = hashed_int % len(tools.visualise.Colors.General) kwargs = { - "color": list(vis.Colors.General)[index].value, + "color": list(tools.visualise.Colors.General)[index].value, "alpha": 0.9, "labelfmt": "", # no labels on children "label": name, @@ -61,27 +58,27 @@ def defaultkwargs(name: str, col: str): def plotfn_and_kwargs( col: str, freq: str, name: str -) -> Tuple[vis.PlotTimeseriesToAxFunction, Dict]: +) -> Tuple[tools.visualise.PlotTimeseriesToAxFunction, Dict]: """Get correct function to plot as well as default kwargs. ``col``: one of 'qwprf', ``freq``: frequency; ``name``: name of the child. If name is emptystring, it is the parent of a plot which also has children. If it is None, there are no children.""" # Get plot function. if tools.freq.shortest(freq, "MS") == "MS": # categorical if name == "" or name is None: # parent - fn = vis.plot_timeseries_as_bar + fn = tools.visualise.plot_timeseries_as_bar else: # child - fn = vis.plot_timeseries_as_hline + fn = tools.visualise.plot_timeseries_as_hline else: # timeaxis if col in ["w", "q"]: if name == "" or name is None: # parent - fn = vis.plot_timeseries_as_area + fn = tools.visualise.plot_timeseries_as_area else: # child - fn = vis.plot_timeseries_as_step + fn = tools.visualise.plot_timeseries_as_step else: # col in ['p', 'r'] if name == "" or name is None: # parent - fn = vis.plot_timeseries_as_step + fn = tools.visualise.plot_timeseries_as_step else: # child - fn = vis.plot_timeseries_as_step + fn = tools.visualise.plot_timeseries_as_step kwargs = defaultkwargs(name, col) @@ -90,7 +87,11 @@ def plotfn_and_kwargs( class PfLinePlot: def plot_to_ax( - self: PfLine, ax: plt.Axes, children: bool = False, kind: Kind = None, **kwargs + self: PfLine, + ax: plt.Axes, + children: bool = False, + kind: Kind = None, + **kwargs, ) -> None: """Plot a specific dimension (i.e., kind) of the PfLine to a specific axis. @@ -120,7 +121,7 @@ def plot_to_ax( ) # Create function to select correct series of the pfline. - def col_and_series(pfl: PfLine) -> Tuple[str, pd.Series]: + def col_and_series(pfl: classes.PfLine) -> Tuple[str, pd.Series]: if kind is Kind.PRICE: return "p", pfl.p elif kind is Kind.REVENUE: @@ -171,76 +172,3 @@ def plot(self, children: bool = False) -> plt.Figure: self.plot_to_ax(ax, children, kind) return fig - - -class PfStatePlot: - def plot(self: PfState, children: bool = False) -> plt.Figure: - """Plot the portfolio state. - - Parameters - ---------- - None - - Returns - ------- - plt.Figure - The figure object to which the series was plotted. - """ - gridspec = {"width_ratios": [1, 1, 1], "height_ratios": [4, 1]} - fig, (volumeaxes, priceaxes) = plt.subplots( - 2, 3, sharex=True, sharey="row", gridspec_kw=gridspec, figsize=(10, 6) - ) - - so, ss, usv = ( - -1 * self.offtakevolume, - self.sourced, - self.unsourced, - ) - - so.plot_to_ax(volumeaxes[0], children=children, kind=so.kind, labelfmt="") - ss.plot_to_ax(volumeaxes[1], children=children, kind=Kind.VOLUME, labelfmt="") - # Unsourced volume. - usv.plot_to_ax(volumeaxes[2], kind=Kind.VOLUME, labelfmt="") - # Procurement Price. - self.pnl_cost.plot_to_ax(priceaxes[0], kind=Kind.PRICE, labelfmt="") - self.sourced.plot_to_ax( - priceaxes[1], children=children, kind=Kind.PRICE, labelfmt="" - ) - # Unsourced price - self.unsourced.plot_to_ax(priceaxes[2], kind=Kind.PRICE, labelfmt="") - # Set titles. - volumeaxes[0].set_title("Offtake volume") - volumeaxes[1].set_title("Sourced volume") - volumeaxes[2].set_title("Unsourced volume") - priceaxes[0].set_title("Procurement price") - priceaxes[1].set_title("Sourced price") - priceaxes[2].set_title("Unsourced price") - - limits_vol = [ax.get_ylim() for ax in volumeaxes] - limits_pr = [ax.get_ylim() for ax in priceaxes] - PfStatePlot.set_max_min_limits(volumeaxes, limits_vol) - PfStatePlot.set_max_min_limits(priceaxes, limits_pr) - - # Format tick labels. - formatter = matplotlib.ticker.FuncFormatter( - lambda x, p: "{:,.0f}".format(x).replace(",", " ") - ) - volumeaxes[0].yaxis.set_major_formatter(formatter) - priceaxes[0].yaxis.set_major_formatter(formatter) - # axes[3].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)) - - # Set ticks. - for ax in volumeaxes: - ax.xaxis.set_tick_params(labeltop=False, labelbottom=True) - for ax in priceaxes: - ax.xaxis.set_tick_params(labeltop=False, labelbottom=False) - - fig.tight_layout() - return fig - - def set_max_min_limits(axes: plt.Axes, limit: int): - mins_vol, maxs_vol = zip(*limit) - - themin, themax = min(mins_vol), max(maxs_vol) - for ax in axes: - ax.set_ylim(themin * 1.1, themax * 1.1) diff --git a/portfolyo/core/pfline/prices.py b/portfolyo/core/pfline/prices.py index df00b61..9d224bf 100644 --- a/portfolyo/core/pfline/prices.py +++ b/portfolyo/core/pfline/prices.py @@ -5,8 +5,8 @@ import pandas as pd from ... import tools -from ...prices import convert, hedge -from ...prices.utils import duration_bpo +from ...tools.prices import convert, hedge +from ...tools.prices.utils import duration_bpo from . import classes from .enums import Kind, Structure diff --git a/portfolyo/core/pfline/text.py b/portfolyo/core/pfline/text.py new file mode 100644 index 0000000..cf30fc3 --- /dev/null +++ b/portfolyo/core/pfline/text.py @@ -0,0 +1,132 @@ +from typing import TYPE_CHECKING, Iterable + +import colorama +import pandas as pd +from ..shared import text +from .enums import Kind +from . import classes + +if TYPE_CHECKING: + from .classes import PfLine + + +def _what(pfl: PfLine) -> str: + return { + Kind.VOLUME: "volume", + Kind.PRICE: "price", + Kind.REVENUE: "revenue", + Kind.COMPLETE: "complete", + }[pfl.kind] + + +def _children_info(pfl: PfLine) -> Iterable[str]: + """Info about the children of the portfolio line.""" + childtxt = [f"'{name}' ({_what(child)})" for name, child in pfl.items()] + return [". Children: " + ("none" if not childtxt else ", ".join(childtxt))] + + +def _nestedtree( + name: str, + pfl: PfLine, + cols: Iterable[str], + num_of_ts: int, + depth: int = 0, + is_last: bool = True, + is_only: bool = False, +) -> Iterable[str]: + """Treeview of the portfolio line.""" + out = [] + tree = text.treedict(depth, is_last, isinstance(pfl, classes.NestedPfLine)) + # Name. + out.append(tree["00"] + tree["01"] + name) + # Top-level body block. + if is_only and depth > 0: + txtlines = ["(only contributor to parent data; has same values)"] + else: + txtlines = _flatdatablock(pfl, cols, num_of_ts) + for txtline in txtlines: + out.append(tree["10"] + tree["11"] + colorama.Style.RESET_ALL + txtline) + # Add children if any. + for txtline in _childrenlines(pfl, cols, num_of_ts, depth): + out.append(tree["10"] + txtline) + return out + + +def _flatdatablock(pfl: PfLine, cols: Iterable[str], num_of_ts: int) -> Iterable[str]: + """The timestamps and data to be shown in a block, next to the tree.""" + # Obtain dataframe with index = timestamp as string and columns = one or more of 'qwpr'. + df = pfl.df[list(cols)] + # . (roughly) reduce number of timestamps to increase speed of conversion to strings. + if len(df.index) > num_of_ts * 2: + df = pd.concat([df.iloc[:num_of_ts, :], df.iloc[-num_of_ts:, :]], axis=0) + # . turn values into strings. + df = text.df_with_strvalues(df) + # . turn index into strings and reduce to wanted number of datapoints + df = text.df_with_strindex(df, num_of_ts) + # . column withs + col_space = {k: v for k, v in text.COLWIDTHS.items() if k in df} + # Turn into list of strings. + df_str = df.to_string(col_space=col_space, index_names=False, header=False) + return df_str.split("\n") + + +def _childrenlines( + pfl: PfLine, cols: Iterable[str], num_of_ts: int, depth: int +) -> Iterable[str]: + """Treeview of only the children.""" + out = [] + if isinstance(pfl, classes.FlatPfLine): + return out + for c, (name, child) in enumerate(pfl.items()): + is_last, is_only = (c == len(pfl) - 1), (len(pfl) == 1) + out.extend( + _nestedtree(name, child, cols, num_of_ts, depth + 1, is_last, is_only) + ) + return out + + +# Highest-level functions. + + +def pfl_as_string(pfl: PfLine, flatten: bool, num_of_ts: int, color: bool) -> str: + lines = [f"PfLine object with {_what(pfl)} information."] + lines.extend(text.index_info(pfl.index)) + if isinstance(pfl, classes.NestedPfLine): + lines.extend(_children_info(pfl)) + cols = pfl.kind.available + if flatten: + lines.extend(text.dataheader(cols)) + lines.extend([""]) + lines.extend(_flatdatablock(pfl, cols, num_of_ts)) + else: + spaces = " " * (text.MAX_DEPTH + 5) + lines.extend([spaces + txtline for txtline in text.dataheader(cols)]) + lines.extend(_nestedtree("(this pfline)", pfl, cols, num_of_ts)) + txt = "\n".join(lines) + return txt if color else text.remove_color(txt) + + +class PfLineText: + def __repr__(self): + return pfl_as_string(self, True, 20, False) + + def print( + self: PfLine, flatten: bool = False, num_of_ts: int = 5, color: bool = True + ) -> None: + """Treeview of the portfolio line. + + Parameters + ---------- + flatten : bool, optional (default: False) + if True, show only the top-level (aggregated) information. + num_of_ts : int, optional (default: 5) + How many timestamps to show for each PfLine. + color : bool, optional (default: True) + Make tree structure clearer by including colors. May not work on all output + devices. + + Returns + ------- + None + """ + print(pfl_as_string(self, flatten, num_of_ts, color)) diff --git a/portfolyo/core/pfstate/arithmatic.py b/portfolyo/core/pfstate/arithmatic.py index b31f925..2319734 100644 --- a/portfolyo/core/pfstate/arithmatic.py +++ b/portfolyo/core/pfstate/arithmatic.py @@ -13,8 +13,6 @@ if TYPE_CHECKING: # needed to avoid circular imports from . import PfState -from ... import testing - class Prep: def assert_objects_indexcompatibility(fn): @@ -22,7 +20,7 @@ def assert_objects_indexcompatibility(fn): def wrapper(o1, o2, *args, **kwargs): try: - testing.assert_indices_compatible(o1.index, o2.index) + tools.testing.assert_indices_compatible(o1.index, o2.index) except AssertionError as e: raise NotImplementedError from e return fn(o1, o2, *args, **kwargs) diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index cd634ac..2792cfc 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -12,11 +12,13 @@ import pandas as pd from ... import tools -from ..shared import ExcelClipboardOutput, PfStatePlot, PfStateText -from ..ndframelike import NDFrameLike +from ..shared.excelclipboard import ExcelClipboardOutput +from ..shared.ndframelike import NDFrameLike from ..pfline import PfLine, create from . import pfstate_helper from .arithmatic import PfStateArithmatic +from .plot import PfStatePlot +from .text import PfStateText @dataclasses.dataclass(frozen=True, repr=False) diff --git a/portfolyo/core/pfstate/pfstate_helper.py b/portfolyo/core/pfstate/pfstate_helper.py index 550ad70..4500540 100644 --- a/portfolyo/core/pfstate/pfstate_helper.py +++ b/portfolyo/core/pfstate/pfstate_helper.py @@ -1,12 +1,11 @@ """Prepare/verify input data for PfState initialisation.""" - import warnings from typing import Any, Iterable import pandas as pd -from ... import testing, tools +from ... import tools from ..pfline import Kind, PfLine, create @@ -55,7 +54,7 @@ def prepare_unsourcedprice(unsourcedprice: Any, ref_idx: pd.DatetimeIndex) -> Pf ) unsourcedprice = unsourcedprice.price try: - testing.assert_indices_compatible(ref_idx, unsourcedprice.index) + tools.testing.assert_indices_compatible(ref_idx, unsourcedprice.index) except AssertionError as e: raise ValueError from e if len(tools.intersect.indices(ref_idx, unsourcedprice.index)) < len(ref_idx): @@ -74,7 +73,7 @@ def prepare_sourced(sourced: Any, ref_idx: pd.DatetimeIndex) -> PfLine: if sourced.kind is not Kind.COMPLETE: raise ValueError("Parameter ``sourced`` does not contain price and volume.") try: - testing.assert_indices_compatible(ref_idx, sourced.index) + tools.testing.assert_indices_compatible(ref_idx, sourced.index) except AssertionError as e: raise ValueError from e # HACK: Workaround for error in pandas intersection (#46702): diff --git a/portfolyo/core/pfstate/plot.py b/portfolyo/core/pfstate/plot.py new file mode 100644 index 0000000..622393f --- /dev/null +++ b/portfolyo/core/pfstate/plot.py @@ -0,0 +1,83 @@ +from __future__ import annotations +from typing import TYPE_CHECKING + +import matplotlib +from matplotlib import pyplot as plt + +from ..pfline import Kind + + +if TYPE_CHECKING: + from .pfstate import PfState + + +class PfStatePlot: + def plot(self: PfState, children: bool = False) -> plt.Figure: + """Plot the portfolio state. + + Parameters + ---------- + None + + Returns + ------- + plt.Figure + The figure object to which the series was plotted. + """ + gridspec = {"width_ratios": [1, 1, 1], "height_ratios": [4, 1]} + fig, (volumeaxes, priceaxes) = plt.subplots( + 2, 3, sharex=True, sharey="row", gridspec_kw=gridspec, figsize=(10, 6) + ) + + so, ss, usv = ( + -1 * self.offtakevolume, + self.sourced, + self.unsourced, + ) + + so.plot_to_ax(volumeaxes[0], children=children, kind=so.kind, labelfmt="") + ss.plot_to_ax(volumeaxes[1], children=children, kind=Kind.VOLUME, labelfmt="") + # Unsourced volume. + usv.plot_to_ax(volumeaxes[2], kind=Kind.VOLUME, labelfmt="") + # Procurement Price. + self.pnl_cost.plot_to_ax(priceaxes[0], kind=Kind.PRICE, labelfmt="") + self.sourced.plot_to_ax( + priceaxes[1], children=children, kind=Kind.PRICE, labelfmt="" + ) + # Unsourced price + self.unsourced.plot_to_ax(priceaxes[2], kind=Kind.PRICE, labelfmt="") + # Set titles. + volumeaxes[0].set_title("Offtake volume") + volumeaxes[1].set_title("Sourced volume") + volumeaxes[2].set_title("Unsourced volume") + priceaxes[0].set_title("Procurement price") + priceaxes[1].set_title("Sourced price") + priceaxes[2].set_title("Unsourced price") + + PfStatePlot.set_max_min_limits(volumeaxes) + PfStatePlot.set_max_min_limits(priceaxes) + + # Format tick labels. + formatter = matplotlib.ticker.FuncFormatter( + lambda x, p: "{:,.0f}".format(x).replace(",", " ") + ) + volumeaxes[0].yaxis.set_major_formatter(formatter) + priceaxes[0].yaxis.set_major_formatter(formatter) + # axes[3].yaxis.set_major_formatter(matplotlib.ticker.PercentFormatter(1.0)) + + # Set ticks. + for ax in volumeaxes: + ax.xaxis.set_tick_params(labeltop=False, labelbottom=True) + for ax in priceaxes: + ax.xaxis.set_tick_params(labeltop=False, labelbottom=False) + + fig.tight_layout() + return fig + + def set_max_min_limits(axes: plt.Axes): + limit = [ax.get_ylim() for ax in axes] + mins_vol, maxs_vol = zip(*limit) + + themin, themax = min(mins_vol), max(maxs_vol) + for ax in axes: + ax.set_ylim(themin * 1.1, themax * 1.1) diff --git a/portfolyo/core/pfstate/text.py b/portfolyo/core/pfstate/text.py new file mode 100644 index 0000000..5accf73 --- /dev/null +++ b/portfolyo/core/pfstate/text.py @@ -0,0 +1,41 @@ +from typing import TYPE_CHECKING +from ..pfline.text import _nestedtree + + +from ..shared import text + +if TYPE_CHECKING: + from .pfstate import PfState + + +def pfs_as_string(pfs: PfState, num_of_ts: int, color: bool) -> str: + lines = ["PfState object."] + lines.extend(text.index_info(pfs.index)) + spaces = " " * (text.MAX_DEPTH + 5) + lines.extend([spaces + txtline for txtline in text.dataheader("wqpr")]) + lines.extend(_nestedtree("offtake", pfs.offtakevolume, "wq", num_of_ts)) + lines.extend(_nestedtree("pnl_cost", pfs.pnl_cost, "wqpr", num_of_ts)) + txt = "\n".join(lines) + return txt if color else text.remove_color(txt) + + +class PfStateText: + def __repr__(self): + return pfs_as_string(self, 5, False) + + def print(self: PfState, num_of_ts: int = 5, color: bool = True) -> None: + """Treeview of the portfolio state. + + Parameters + ---------- + num_of_ts : int, optional (default: 5) + How many timestamps to show for each PfLine. + color : bool, optional (default: True) + Make tree structure clearer by including colors. May not work on all output + devices. + + Returns + ------- + None + """ + print(pfs_as_string(self, num_of_ts, color)) diff --git a/portfolyo/core/shared/__init__.py b/portfolyo/core/shared/__init__.py index 70a6808..8b13789 100644 --- a/portfolyo/core/shared/__init__.py +++ b/portfolyo/core/shared/__init__.py @@ -1,4 +1 @@ -from . import text -from .excelclipboard import ExcelClipboardOutput -from .plot import PfLinePlot, PfStatePlot -from .text import PfLineText, PfStateText + diff --git a/portfolyo/core/shared/excelclipboard.py b/portfolyo/core/shared/excelclipboard.py index 9e003f1..7499515 100644 --- a/portfolyo/core/shared/excelclipboard.py +++ b/portfolyo/core/shared/excelclipboard.py @@ -7,7 +7,7 @@ import functools import pandas as pd -from ..ndframelike import NDFrameLike +from .ndframelike import NDFrameLike def prepare_df(ndframelike: NDFrameLike) -> pd.DataFrame: diff --git a/portfolyo/core/ndframelike.py b/portfolyo/core/shared/ndframelike.py similarity index 94% rename from portfolyo/core/ndframelike.py rename to portfolyo/core/shared/ndframelike.py index 60f4aa0..ad9e512 100644 --- a/portfolyo/core/ndframelike.py +++ b/portfolyo/core/shared/ndframelike.py @@ -14,7 +14,8 @@ class NDFrameLike(abc.ABC): # Abstract methods to be implemented by descendents. - @abc.abstractproperty + @property + @abc.abstractmethod def index(self) -> pd.DatetimeIndex: """Left timestamp of time period corresponding to each data row.""" ... @@ -36,13 +37,15 @@ def asfreq(self, freq: str = "MS") -> NDFrameLike: """ ... - @abc.abstractproperty + @property + @abc.abstractmethod def loc(self): """Create a new instance with a subset of the rows (selection by row label(s) or a boolean array.)""" ... - @abc.abstractproperty + @property + @abc.abstractmethod def slice(self): """Create a new instance with a subset of the rows. Different from loc since performs slicing with right-open interval.""" diff --git a/portfolyo/core/shared/text.py b/portfolyo/core/shared/text.py index 5945006..aafb3a8 100644 --- a/portfolyo/core/shared/text.py +++ b/portfolyo/core/shared/text.py @@ -1,17 +1,14 @@ """String representation of PfLine and PfState objects.""" + from __future__ import annotations -from typing import TYPE_CHECKING, Dict, Iterable +from typing import Dict, Iterable import colorama import pandas as pd from ... import tools -from .. import pfline -if TYPE_CHECKING: - from ..pfline import PfLine - from ..pfstate import PfState COLORS = ["WHITE", "YELLOW", "CYAN", "GREEN", "RED", "BLUE", "MAGENTA", "BLACK"] TREECOLORS = [colorama.Style.BRIGHT + getattr(colorama.Fore, f) for f in COLORS] @@ -22,14 +19,14 @@ MAX_DEPTH = 6 -def _remove_color(text: str) -> str: +def remove_color(text: str) -> str: """Remove all color from text.""" for color in [colorama.Style.RESET_ALL, *TREECOLORS]: text = text.replace(color, "") return text -def _df_with_strvalues(df: pd.DataFrame, units: Dict = _UNITS): +def df_with_strvalues(df: pd.DataFrame, units: Dict = _UNITS): """Turn dataframe with single column names ('w', 'p', etc) into text strings.""" if isinstance(df.columns, pd.MultiIndex): raise ValueError("Dataframe must have single column index; has MultiIndex.") @@ -42,7 +39,7 @@ def _df_with_strvalues(df: pd.DataFrame, units: Dict = _UNITS): return pd.DataFrame(str_series) -def _df_with_strindex(df: pd.DataFrame, num_of_ts: int): +def df_with_strindex(df: pd.DataFrame, num_of_ts: int): """Turn datetime index of dataframe into text, and reduce number of rows.""" df.index = df.index.map( lambda ts: ts.strftime(DATETIMEFORMAT).ljust(COLWIDTHS["ts"]) @@ -54,16 +51,7 @@ def _df_with_strindex(df: pd.DataFrame, num_of_ts: int): return df -def _what(pfl: PfLine) -> str: - return { - pfline.Kind.VOLUME: "volume", - pfline.Kind.PRICE: "price", - pfline.Kind.REVENUE: "revenue", - pfline.Kind.COMPLETE: "complete", - }[pfl.kind] - - -def _index_info(i: pd.DatetimeIndex) -> Iterable[str]: +def index_info(i: pd.DatetimeIndex) -> Iterable[str]: """Info about the index.""" return [ f". Start: {i[0] } (incl) . Timezone : {i.tz or 'none'} ", @@ -72,13 +60,7 @@ def _index_info(i: pd.DatetimeIndex) -> Iterable[str]: ] -def _children_info(pfl: PfLine) -> Iterable[str]: - """Info about the children of the portfolio line.""" - childtxt = [f"'{name}' ({_what(child)})" for name, child in pfl.items()] - return [". Children: " + ("none" if not childtxt else ", ".join(childtxt))] - - -def _treedict(depth: int, is_last_child: bool, has_children: bool) -> Dict[str, str]: +def treedict(depth: int, is_last_child: bool, has_children: bool) -> Dict[str, str]: """Dictionary with 4 strings ('00', '01', '10', '11') that are used in drawing the tree.""" colors = {"0": TREECOLORS[depth], "1": TREECOLORS[depth + 1]} tree = {} @@ -96,153 +78,10 @@ def _treedict(depth: int, is_last_child: bool, has_children: bool) -> Dict[str, return tree -def _dataheader(cols: Iterable[str] = "wqpr", units: Dict = _UNITS) -> Iterable[str]: +def dataheader(cols: Iterable[str] = "wqpr", units: Dict = _UNITS) -> Iterable[str]: out = [" " * 25] * 2 # width of timestamps for c in cols: width = COLWIDTHS[c] + 1 out[0] += f"{c:>{width}}" out[1] += f"{units[c]:>{width}}" return out - - -# Main 3 functions that recursively call each other. - - -def _nestedtree( - name: str, - pfl: PfLine, - cols: Iterable[str], - num_of_ts: int, - depth: int = 0, - is_last: bool = True, - is_only: bool = False, -) -> Iterable[str]: - """Treeview of the portfolio line.""" - out = [] - tree = _treedict(depth, is_last, isinstance(pfl, pfline.NestedPfLine)) - # Name. - out.append(tree["00"] + tree["01"] + name) - # Top-level body block. - if is_only and depth > 0: - txtlines = ["(only contributor to parent data; has same values)"] - else: - txtlines = _flatdatablock(pfl, cols, num_of_ts) - for txtline in txtlines: - out.append(tree["10"] + tree["11"] + colorama.Style.RESET_ALL + txtline) - # Add children if any. - for txtline in _childrenlines(pfl, cols, num_of_ts, depth): - out.append(tree["10"] + txtline) - return out - - -def _flatdatablock(pfl: PfLine, cols: Iterable[str], num_of_ts: int) -> Iterable[str]: - """The timestamps and data to be shown in a block, next to the tree.""" - # Obtain dataframe with index = timestamp as string and columns = one or more of 'qwpr'. - df = pfl.df[list(cols)] - # . (roughly) reduce number of timestamps to increase speed of conversion to strings. - if len(df.index) > num_of_ts * 2: - df = pd.concat([df.iloc[:num_of_ts, :], df.iloc[-num_of_ts:, :]], axis=0) - # . turn values into strings. - df = _df_with_strvalues(df) - # . turn index into strings and reduce to wanted number of datapoints - df = _df_with_strindex(df, num_of_ts) - # . column withs - col_space = {k: v for k, v in COLWIDTHS.items() if k in df} - # Turn into list of strings. - df_str = df.to_string(col_space=col_space, index_names=False, header=False) - return df_str.split("\n") - - -def _childrenlines( - pfl: PfLine, cols: Iterable[str], num_of_ts: int, depth: int -) -> Iterable[str]: - """Treeview of only the children.""" - out = [] - if isinstance(pfl, pfline.FlatPfLine): - return out - for c, (name, child) in enumerate(pfl.items()): - is_last, is_only = (c == len(pfl) - 1), (len(pfl) == 1) - out.extend( - _nestedtree(name, child, cols, num_of_ts, depth + 1, is_last, is_only) - ) - return out - - -# Highest-level functions. - - -def pfl_as_string(pfl: PfLine, flatten: bool, num_of_ts: int, color: bool) -> str: - lines = [f"PfLine object with {_what(pfl)} information."] - lines.extend(_index_info(pfl.index)) - if isinstance(pfl, pfline.NestedPfLine): - lines.extend(_children_info(pfl)) - cols = pfl.kind.available - if flatten: - lines.extend(_dataheader(cols)) - lines.extend([""]) - lines.extend(_flatdatablock(pfl, cols, num_of_ts)) - else: - spaces = " " * (MAX_DEPTH + 5) - lines.extend([spaces + txtline for txtline in _dataheader(cols)]) - lines.extend(_nestedtree("(this pfline)", pfl, cols, num_of_ts)) - txt = "\n".join(lines) - return txt if color else _remove_color(txt) - - -def pfs_as_string(pfs: PfState, num_of_ts: int, color: bool) -> str: - lines = ["PfState object."] - lines.extend(_index_info(pfs.index)) - spaces = " " * (MAX_DEPTH + 5) - lines.extend([spaces + txtline for txtline in _dataheader("wqpr")]) - lines.extend(_nestedtree("offtake", pfs.offtakevolume, "wq", num_of_ts)) - lines.extend(_nestedtree("pnl_cost", pfs.pnl_cost, "wqpr", num_of_ts)) - txt = "\n".join(lines) - return txt if color else _remove_color(txt) - - -class PfLineText: - def __repr__(self): - return pfl_as_string(self, True, 20, False) - - def print( - self: PfLine, flatten: bool = False, num_of_ts: int = 5, color: bool = True - ) -> None: - """Treeview of the portfolio line. - - Parameters - ---------- - flatten : bool, optional (default: False) - if True, show only the top-level (aggregated) information. - num_of_ts : int, optional (default: 5) - How many timestamps to show for each PfLine. - color : bool, optional (default: True) - Make tree structure clearer by including colors. May not work on all output - devices. - - Returns - ------- - None - """ - print(pfl_as_string(self, flatten, num_of_ts, color)) - - -class PfStateText: - def __repr__(self): - return pfs_as_string(self, 5, False) - - def print(self: PfState, num_of_ts: int = 5, color: bool = True) -> None: - """Treeview of the portfolio state. - - Parameters - ---------- - num_of_ts : int, optional (default: 5) - How many timestamps to show for each PfLine. - color : bool, optional (default: True) - Make tree structure clearer by including colors. May not work on all output - devices. - - Returns - ------- - None - """ - print(pfs_as_string(self, num_of_ts, color)) diff --git a/portfolyo/dev/mockup.py b/portfolyo/dev/mockup.py index bb1bed7..3944f01 100644 --- a/portfolyo/dev/mockup.py +++ b/portfolyo/dev/mockup.py @@ -1,10 +1,11 @@ """Create somewhat realistic curves.""" + from typing import Tuple import numpy as np import pandas as pd -from ..prices.utils import is_peak_hour +from ..tools.prices.utils import is_peak_hour from ..tools import unit # noqa # ensure we use current ureg diff --git a/portfolyo/testing/__init__.py b/portfolyo/testing/__init__.py deleted file mode 100644 index 98cdf23..0000000 --- a/portfolyo/testing/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -from .testing import ( - assert_frame_equal, - assert_index_equal, - assert_indices_compatible, - assert_series_equal, - assert_value_equal, -) diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index d28cdac..3ec0996 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -1,10 +1,9 @@ from typing import List, Union, Tuple import pandas as pd -from portfolyo import tools - -from portfolyo.tools.right import stamp -from portfolyo.tools.freq import longest, longer_or_shorter +from .right import stamp +from .freq import longest, longer_or_shorter from datetime import datetime +from . import trim as tools_trim def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: @@ -139,7 +138,7 @@ def indices_flex( for i in range(len(idxs)): # if idxs[i].freq is not the same as longest freq, we trim idxs[i] if idxs[i].freq != longest_freq: - idxs[i] = tools.trim.index(idxs[i], longest_freq) + idxs[i] = tools_trim.index(idxs[i], longest_freq) if ignore_tz is True and len(distinct_tzs) != 1: # set timezone to none for all values diff --git a/portfolyo/prices/__init__.py b/portfolyo/tools/prices/__init__.py similarity index 100% rename from portfolyo/prices/__init__.py rename to portfolyo/tools/prices/__init__.py diff --git a/portfolyo/prices/convert.py b/portfolyo/tools/prices/convert.py similarity index 97% rename from portfolyo/prices/convert.py rename to portfolyo/tools/prices/convert.py index 36fd045..0bfe732 100644 --- a/portfolyo/prices/convert.py +++ b/portfolyo/tools/prices/convert.py @@ -17,11 +17,14 @@ import numpy as np import pandas as pd -from .. import tools +from .. import unit as tools_unit +from .. import trim as tools_trim +from .. import freq as tools_freq +from .. import changefreq as tools_changefreq from . import utils Stamp = Union[dt.datetime, pd.Timestamp] -Value = Union[float, int, tools.unit.Q_] +Value = Union[float, int, tools_unit.Q_] BPO = ("base", "peak", "offpeak") @@ -300,7 +303,7 @@ def tseries2bpoframe(s: pd.Series, freq: str = "MS", prefix: str = "") -> pd.Dat ) # Remove partial data - s = tools.trim.frame(s, freq) + s = tools_trim.frame(s, freq) # Handle possible units. sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) @@ -371,7 +374,7 @@ def bpoframe2tseries( df = bpoframe.rename({f"{prefix}{bpo}": bpo for bpo in BPO}, axis=1) # remove prefx df = complete_bpoframe(df) # make sure we have peak and offpeak columns - df = tools.changefreq.averagable(df[["peak", "offpeak"]], freq) + df = tools_changefreq.averagable(df[["peak", "offpeak"]], freq) df["ispeak"] = utils.is_peak_hour(df.index) return df["offpeak"].where(df["ispeak"], df["peak"]) @@ -494,7 +497,7 @@ def bpoframe2bpoframe( raise ValueError( f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got {freq}." ) - if tools.freq.up_or_down(bpoframe.index.freq, freq) == 1: + if tools_freq.up_or_down(bpoframe.index.freq, freq) == 1: warnings.warn( "This conversion includes upsampling, e.g. from yearly to monthly values." ) diff --git a/portfolyo/prices/hedge.py b/portfolyo/tools/prices/hedge.py similarity index 99% rename from portfolyo/prices/hedge.py rename to portfolyo/tools/prices/hedge.py index 30e9f7e..cbb46be 100644 --- a/portfolyo/prices/hedge.py +++ b/portfolyo/tools/prices/hedge.py @@ -4,7 +4,7 @@ import pandas as pd -from .. import tools +from ... import tools from . import convert, utils diff --git a/portfolyo/prices/utils.py b/portfolyo/tools/prices/utils.py similarity index 99% rename from portfolyo/prices/utils.py rename to portfolyo/tools/prices/utils.py index e872d42..cdc17ce 100644 --- a/portfolyo/prices/utils.py +++ b/portfolyo/tools/prices/utils.py @@ -6,8 +6,8 @@ import pandas as pd -from .. import tools -from ..tools.unit import Q_ +from ... import tools +from ...tools.unit import Q_ german_peakperiod = tools.peakperiod.factory(dt.time(8), dt.time(20), [1, 2, 3, 4, 5]) diff --git a/portfolyo/testing/testing.py b/portfolyo/tools/testing.py similarity index 76% rename from portfolyo/testing/testing.py rename to portfolyo/tools/testing.py index a90f901..1844e92 100644 --- a/portfolyo/testing/testing.py +++ b/portfolyo/tools/testing.py @@ -6,8 +6,7 @@ import numpy as np import pandas as pd import pint -from .. import tools -from ..tools.unit import Q_ +from . import unit as tools_unit def assert_value_equal(left: Any, right: Any): @@ -35,8 +34,8 @@ def assert_frame_equal(left: pd.DataFrame, right: pd.DataFrame, *args, **kwargs) @functools.wraps(pd.testing.assert_series_equal) def assert_series_equal(left: pd.Series, right: pd.Series, *args, **kwargs): - leftm, leftu = tools.unit.split_magn_unit(left) - rightm, rightu = tools.unit.split_magn_unit(right) + leftm, leftu = tools_unit.split_magn_unit(left) + rightm, rightu = tools_unit.split_magn_unit(right) # Magnitudes must be the same. leftm = leftm.replace([np.inf, -np.inf], np.nan) @@ -65,21 +64,21 @@ def assert_indices_compatible(left: pd.DatetimeIndex, right: pd.DatetimeIndex): def assert_w_q_compatible(freq: str, w: pd.Series, q: pd.Series): """Assert if timeseries with power- and energy-values are consistent.""" if freq == "15T": - assert_series_equal(q, w * Q_(0.25, "h"), check_names=False) + assert_series_equal(q, w * tools_unit.Q_(0.25, "h"), check_names=False) elif freq == "H": - assert_series_equal(q, w * Q_(1.0, "h"), check_names=False) + assert_series_equal(q, w * tools_unit.Q_(1.0, "h"), check_names=False) elif freq == "D": - assert (q >= w * Q_(22.99, "h")).all() - assert (q <= w * Q_(25.01, "h")).all() + assert (q >= w * tools_unit.Q_(22.99, "h")).all() + assert (q <= w * tools_unit.Q_(25.01, "h")).all() elif freq == "MS": - assert (q >= w * 27 * Q_(24.0, "h")).all() - assert (q <= w * 32 * Q_(24.0, "h")).all() + assert (q >= w * 27 * tools_unit.Q_(24.0, "h")).all() + assert (q <= w * 32 * tools_unit.Q_(24.0, "h")).all() elif freq == "QS": - assert (q >= w * 89 * Q_(24.0, "h")).all() - assert (q <= w * 93 * Q_(24.0, "h")).all() + assert (q >= w * 89 * tools_unit.Q_(24.0, "h")).all() + assert (q <= w * 93 * tools_unit.Q_(24.0, "h")).all() elif freq == "AS": - assert (q >= w * Q_(8759.9, "h")).all() - assert (q <= w * Q_(8784.1, "h")).all() + assert (q >= w * tools_unit.Q_(8759.9, "h")).all() + assert (q <= w * tools_unit.Q_(8784.1, "h")).all() else: raise ValueError(f"Uncaught value for freq: {freq}.") diff --git a/portfolyo/visualize/__init__.py b/portfolyo/tools/visualize/__init__.py similarity index 100% rename from portfolyo/visualize/__init__.py rename to portfolyo/tools/visualize/__init__.py diff --git a/portfolyo/visualize/categories.py b/portfolyo/tools/visualize/categories.py similarity index 95% rename from portfolyo/visualize/categories.py rename to portfolyo/tools/visualize/categories.py index 7fc7efa..e21a9c8 100644 --- a/portfolyo/visualize/categories.py +++ b/portfolyo/tools/visualize/categories.py @@ -3,8 +3,7 @@ import numpy as np import pandas as pd - -from .. import tools +from .. import unit as tools_unit @dataclass @@ -35,16 +34,16 @@ def categories(self, max_count: int = None) -> Iterable[Category]: def _get_subset(self, attr: str, max_count: int = None) -> Iterable: values = [getattr(cat, attr) for cat in self.categories(max_count)] - if not isinstance(values[0], tools.unit.Q_): + if not isinstance(values[0], tools_unit.Q_): return np.array(values) unit = values[0].units magnitudes = [value.to(unit).m for value in values] - return tools.unit.PA_(magnitudes, unit) + return tools_unit.PA_(magnitudes, unit) def x(self, max_count: int = None) -> Iterable[int]: return self._get_subset("x", max_count) - def y(self, max_count: int = None) -> Iterable[Union[float, tools.unit.Q_]]: + def y(self, max_count: int = None) -> Iterable[Union[float, tools_unit.Q_]]: return self._get_subset("y", max_count) def ts(self, max_count: int = None) -> Iterable[pd.Timestamp]: diff --git a/portfolyo/visualize/colors.py b/portfolyo/tools/visualize/colors.py similarity index 100% rename from portfolyo/visualize/colors.py rename to portfolyo/tools/visualize/colors.py diff --git a/portfolyo/visualize/plot.py b/portfolyo/tools/visualize/plot.py similarity index 89% rename from portfolyo/visualize/plot.py rename to portfolyo/tools/visualize/plot.py index bb50690..3204277 100644 --- a/portfolyo/visualize/plot.py +++ b/portfolyo/tools/visualize/plot.py @@ -8,9 +8,9 @@ import pandas as pd from matplotlib import pyplot as plt -from portfolyo.tools.unit import to_name -from portfolyo.visualize.colors import Colors -from ..tools import freq as tools_freq +from .. import unit as tools_unit +from .colors import Colors +from .. import freq as tools_freq from .categories import Categories, Category # noqa mpl.style.use("seaborn-v0_8") @@ -255,7 +255,7 @@ def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: set_portfolyo_attr(ax, "unit", s.pint.units) # Get unit attribute unit = get_portfolyo_attr(ax, "unit") - name_unit = to_name(unit) + name_unit = tools_unit.to_name(unit) # Define color mapping based on 'Wqpr' class attributes unit_colors = { "w": Colors.Wqpr.w, @@ -303,23 +303,8 @@ def set_data_labels( if len(xx) > maxcount: return - # # Add labels. - # for x, y in zip(xx, yy): - # lbl = labelfmt.format(y.magnitude).replace(",", " ") - # xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) - # ax.annotate( - # lbl, - # (x, y), - # textcoords="offset points", - # xytext=xytext, - # ha="center", - # rotation=45, - # ) - - # Add labels only to every third data point. - for i in range(0, len(xx), 3): # Iterate every third index - x = xx[i] - y = yy[i] + # Add labels. + for x, y in zip(xx, yy): lbl = labelfmt.format(y.magnitude).replace(",", " ") xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) ax.annotate( @@ -332,28 +317,8 @@ def set_data_labels( rotation=90, ) - # # Add labels only to every third data point. - # for i in range(0, len(xx), 3): # Iterate every third index - # x = xx[i] - # y = yy[i] - # lbl = labelfmt.format(y.magnitude).replace(",", " ") - # xytext = (0, -10) if outside and y.magnitude < 0 else (0, 10) - # ax.annotate( - # lbl, - # (x, y), - # textcoords="offset points", - # xytext=xytext, - # ha="center", - # rotation=90, - # ) - # Increase axis range to give label space to stay inside box. - # ylim = list(ax.get_ylim()) miny, maxy = ax.get_ylim() delta = 0.5 miny2, maxy2 = (1 + delta) * miny - delta * maxy, (1 + delta) * maxy - delta * miny - # if not np.isclose(ylim[0], 0) and ylim[0] < 0: - # ylim[0] *= 1.1 - # if not np.isclose(ylim[1], 0) and ylim[1] > 0: - # ylim[1] *= 1.1 ax.set_ylim(miny2, maxy2) diff --git a/portfolyo/tools2/concat.py b/portfolyo/tools2/concat.py index bcb5dce..10b797f 100644 --- a/portfolyo/tools2/concat.py +++ b/portfolyo/tools2/concat.py @@ -3,7 +3,7 @@ from __future__ import annotations from typing import Iterable import pandas as pd -from portfolyo import tools +from .. import tools from ..core.pfstate import PfState from ..core.pfline.enums import Structure diff --git a/portfolyo/tools2/intersect.py b/portfolyo/tools2/intersect.py index 8b0664c..43f74a5 100644 --- a/portfolyo/tools2/intersect.py +++ b/portfolyo/tools2/intersect.py @@ -1,4 +1,4 @@ -from portfolyo.tools.intersect import indices_flex +from ..tools.intersect import indices_flex from ..core.pfline import PfLine from ..core.pfstate import PfState from typing import List, Union diff --git a/portfolyo/tools2/plot.py b/portfolyo/tools2/plot.py index 59fcaa6..8d4bf9b 100644 --- a/portfolyo/tools2/plot.py +++ b/portfolyo/tools2/plot.py @@ -6,10 +6,10 @@ import numpy as np from matplotlib import pyplot as plt -from portfolyo.core.shared.plot import defaultkwargs +from ..core.pfline.plot import defaultkwargs from .. import tools -from .. import visualize as vis +from ..tools import visualize as vis from ..core.pfstate import PfState diff --git a/tests/core/test-output.xml b/tests/core/test-output.xml deleted file mode 100644 index aeb9a15..0000000 --- a/tests/core/test-output.xml +++ /dev/null @@ -1,1961 +0,0 @@ -/Users/ruud.wijtvliet/.local/share/nvim/lazy/neotest-python/neotest.py --results-file /var/folders/4l/jxhd2x_x0x15bwll5w9f_5rr0000gq/T/nvim.ruud.wijtvliet/bxjGD4/9 --stream-file /var/folders/4l/jxhd2x_x0x15bwll5w9f_5rr0000gq/T/nvim.ruud.wijtvliet/bxjGD4/10 --runner pytest -- /Users/ruud.wijtvliet/python/portfolyo/tests/core/pfstate/test_slice_state.py/Users/ruud.wijtvliet/python/portfolyo/tests/core/pfstate/test_slice_state.py \ No newline at end of file diff --git a/tests/prices/test_convert.py.bak b/tests/tools/prices/test_convert.py.bak similarity index 100% rename from tests/prices/test_convert.py.bak rename to tests/tools/prices/test_convert.py.bak diff --git a/tests/prices/test_convert_data.xlsx b/tests/tools/prices/test_convert_data.xlsx similarity index 100% rename from tests/prices/test_convert_data.xlsx rename to tests/tools/prices/test_convert_data.xlsx diff --git a/tests/prices/test_hedge.py.bak b/tests/tools/prices/test_hedge.py.bak similarity index 100% rename from tests/prices/test_hedge.py.bak rename to tests/tools/prices/test_hedge.py.bak diff --git a/tests/prices/test_hedge_data.xlsx b/tests/tools/prices/test_hedge_data.xlsx similarity index 100% rename from tests/prices/test_hedge_data.xlsx rename to tests/tools/prices/test_hedge_data.xlsx diff --git a/tests/prices/test_utils.py b/tests/tools/prices/test_utils.py similarity index 99% rename from tests/prices/test_utils.py rename to tests/tools/prices/test_utils.py index 866b888..bc45dde 100644 --- a/tests/prices/test_utils.py +++ b/tests/tools/prices/test_utils.py @@ -4,7 +4,7 @@ import pytest from portfolyo import tools -from portfolyo.prices import utils +from portfolyo.tools.prices import utils # TODO: where are the hedge and conversion tests?? --> check git history diff --git a/tests/visualize/test_plot.py b/tests/tools/visualize/test_plot.py similarity index 100% rename from tests/visualize/test_plot.py rename to tests/tools/visualize/test_plot.py diff --git a/tests/core/shared/test_concat_error_cases.py b/tests/tools2/test_concat_error_cases.py similarity index 100% rename from tests/core/shared/test_concat_error_cases.py rename to tests/tools2/test_concat_error_cases.py diff --git a/tests/core/shared/test_concat_pfline.py b/tests/tools2/test_concat_pfline.py similarity index 100% rename from tests/core/shared/test_concat_pfline.py rename to tests/tools2/test_concat_pfline.py diff --git a/tests/core/shared/test_concat_pfstate.py b/tests/tools2/test_concat_pfstate.py similarity index 100% rename from tests/core/shared/test_concat_pfstate.py rename to tests/tools2/test_concat_pfstate.py diff --git a/tests/utils.py b/tests/utils.py index bd14c9e..730ca65 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,4 +1,5 @@ """Create uniform ids for testcases.""" + from typing import Any, Dict import pandas as pd From 3e6ccccc4d56f30230bf05c8b87fbcd703d97772 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Mon, 13 May 2024 01:33:53 +0200 Subject: [PATCH 49/59] refactoring --- README.rst | 17 + dev_scripts/plot_state.py | 5 +- portfolyo/__init__.py | 12 +- portfolyo/core/pfline/classes.py | 163 +++---- portfolyo/core/pfline/decorators.py | 15 - portfolyo/core/pfline/flat_methods.py | 71 ++- portfolyo/core/pfline/nested_methods.py | 26 +- portfolyo/core/pfline/plot.py | 20 +- portfolyo/core/pfline/prices.py | 97 ---- portfolyo/core/pfline/text.py | 81 ++-- portfolyo/core/pfstate/pfstate.py | 2 +- portfolyo/core/pfstate/plot.py | 2 +- portfolyo/core/pfstate/text.py | 19 +- portfolyo/core/shared/excelclipboard.py | 1 + portfolyo/core/shared/text.py | 3 - portfolyo/dev/mockup.py | 6 +- portfolyo/tools/__init__.py | 14 +- portfolyo/tools/changefreq.py | 35 +- portfolyo/tools/duration.py | 27 +- portfolyo/tools/hedge.py | 142 ++++++ portfolyo/tools/intersect.py | 10 +- portfolyo/tools/peakconvert.py | 423 ++++++++++++++++++ portfolyo/tools/peakfn.py | 228 ++++++++++ portfolyo/tools/peakperiod.py | 119 ----- portfolyo/tools/prices/__init__.py | 1 - .../prices/{convert.py => convert.py.bak} | 80 +--- portfolyo/tools/prices/hedge.py | 146 ------ portfolyo/tools/prices/utils.py | 190 -------- portfolyo/tools/product.py | 198 ++++++++ portfolyo/tools/testing.py | 1 + portfolyo/tools/trim.py | 20 +- portfolyo/tools/types.py | 7 + portfolyo/tools/visualize/__init__.py | 1 + portfolyo/tools/visualize/categories.py | 1 + portfolyo/tools/visualize/colors.py | 2 +- portfolyo/tools/visualize/plot.py | 4 +- portfolyo/tools2/changeyear.py | 79 ++++ portfolyo/tools2/concat.py | 11 +- portfolyo/tools2/intersect.py | 7 +- portfolyo/tools2/plot.py | 6 +- .../core/pfline/test_pfline_excelclipboard.py | 2 +- tests/core/pfline/test_pfline_text.py | 1 + tests/core/pfline/test_slice.py | 3 +- .../pfstate/test_pfstate_excelclipboard.py | 3 +- tests/core/pfstate/test_slice_state.py | 3 +- .../{test_peakperiod.py => test_peakfn.py} | 86 +++- .../{prices/test_utils.py => test_product.py} | 97 +--- tests/tools/visualize/test_plot.py | 26 +- tests/tools2/test_concat_error_cases.py | 1 - tests/tools2/test_concat_pfline.py | 2 +- tests/tools2/test_concat_pfstate.py | 2 +- tests/tools2/test_indexable.py | 1 + 52 files changed, 1505 insertions(+), 1014 deletions(-) delete mode 100644 portfolyo/core/pfline/prices.py create mode 100644 portfolyo/tools/hedge.py create mode 100644 portfolyo/tools/peakconvert.py create mode 100644 portfolyo/tools/peakfn.py delete mode 100644 portfolyo/tools/peakperiod.py delete mode 100644 portfolyo/tools/prices/__init__.py rename portfolyo/tools/prices/{convert.py => convert.py.bak} (86%) delete mode 100644 portfolyo/tools/prices/hedge.py delete mode 100644 portfolyo/tools/prices/utils.py create mode 100644 portfolyo/tools/product.py create mode 100644 portfolyo/tools/types.py create mode 100644 portfolyo/tools2/changeyear.py rename tests/tools/{test_peakperiod.py => test_peakfn.py} (70%) rename tests/tools/{prices/test_utils.py => test_product.py} (54%) diff --git a/README.rst b/README.rst index 4d6b5c3..62d5318 100644 --- a/README.rst +++ b/README.rst @@ -1,3 +1,4 @@ +========= portfolyo ========= @@ -28,6 +29,8 @@ portfolyo Portfolyo is a Python package to analyse and manipulate timeseries related to power and gas offtake portfolios. + +------------ Installation ------------ @@ -45,6 +48,7 @@ NB: this package is under active development and the API will change without pri portfolyo = "x.y.z" +------------- Documentation ------------- @@ -52,6 +56,8 @@ Documentation is hosted on readthedocs: https://portfolyo.readthedocs.io/ + +---------- Repository ---------- @@ -60,6 +66,7 @@ The git repository is hosted on github: http://www.github.com/rwijtvliet/portfolyo +---------- Developing ---------- @@ -74,6 +81,16 @@ the commit hooks. Feature branches are merged into the ``develop`` branch via pull request. + +Internal dependencies +--------------------- + +Inside the package, modules depend on each other in the following chain. A module may depend on another module if it is further to the left: + +tools >> pfline >> pfstate >> tools2 + + +---------- Publishing ---------- diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py index 402e741..16a6a87 100644 --- a/dev_scripts/plot_state.py +++ b/dev_scripts/plot_state.py @@ -1,8 +1,9 @@ -import portfolyo as pf +import matplotlib.pyplot as plt import pandas as pd + +import portfolyo as pf from portfolyo.core.pfline.enums import Kind from portfolyo.core.pfstate.pfstate import PfState -import matplotlib.pyplot as plt index = pd.date_range( "2022-06-01", "2024-02-01", freq="MS", tz="Europe/Berlin", inclusive="left" diff --git a/portfolyo/__init__.py b/portfolyo/__init__.py index 771e8ac..93c6b78 100644 --- a/portfolyo/__init__.py +++ b/portfolyo/__init__.py @@ -4,21 +4,23 @@ from .core import extendpandas # extend functionalty of pandas from .core import suppresswarnings from .core.pfline import Kind, PfLine, Structure, create -from .tools.freq import FREQUENCIES from .core.pfstate import PfState -from .tools.prices.hedge import hedge -from .tools.prices.utils import is_peak_hour +from .tools import testing +from .tools2.changeyear import map_to_year from .tools2.concat import general as concat from .tools2.intersect import indexable as intersection from .tools2.plot import plot_pfstates from .tools.changefreq import averagable as asfreq_avg from .tools.changefreq import summable as asfreq_sum from .tools.changeyear import characterize_index, map_frame_to_year +from .tools.freq import FREQUENCIES +from .tools.hedge import hedge +from .tools.peakfn import PeakFunction +from .tools.product import germanpower_peakfn, is_peak_hour from .tools.standardize import frame as standardize from .tools.tzone import force_agnostic, force_aware from .tools.unit import Q_, Unit, ureg from .tools.wavg import general as wavg -from .tools import testing VOLUME = Kind.VOLUME PRICE = Kind.PRICE @@ -29,4 +31,4 @@ suppresswarnings.apply() __version__ = _version.get_versions()["version"] -__all__ = ["tools", "dev", "testing", "PfLine", "PfState"] +__all__ = ["tools", "dev", "PfLine", "PfState"] diff --git a/portfolyo/core/pfline/classes.py b/portfolyo/core/pfline/classes.py index 440144d..2506fca 100644 --- a/portfolyo/core/pfline/classes.py +++ b/portfolyo/core/pfline/classes.py @@ -2,27 +2,19 @@ import abc import dataclasses -from typing import Any, Callable, Dict, Iterable, Mapping, Union # noqa +from typing import Callable, Dict # noqa import numpy as np import pandas as pd from ... import tools -from ..shared.ndframelike import NDFrameLike -from .text import PfLineText -from .plot import PfLinePlot from ..shared.excelclipboard import ExcelClipboardOutput -from . import ( - children, - create, - dataframeexport, - decorators, - flat_methods, - nested_methods, - prices, -) +from ..shared.ndframelike import NDFrameLike +from . import children, create, dataframeexport, flat_methods, nested_methods from .arithmatic import PfLineArithmatic from .enums import Kind, Structure +from .plot import PfLinePlot +from .text import PfLineText def constructor(structure: Structure, kind: Kind) -> type: @@ -88,43 +80,60 @@ def __post_init__(self): err = f"Expected columns {self.kind.available}, received {self.df.columns}." assert set(self.df.columns) == set(self.kind.available), err + @property + @abc.abstractmethod + def kind(self) -> Kind: + ... + + @property + @abc.abstractmethod + def structure(self) -> Structure: + ... + @property def index(self) -> pd.DatetimeIndex: """Index of the data, containing the left-bound timestamps of the delivery periods.""" return self.df.index - @abc.abstractproperty - def w(self) -> pd.Series: # override if applicable + @property + @abc.abstractmethod + def w(self) -> pd.Series: """Return (flat) volume timeseries in [MW].""" ... - @abc.abstractproperty - def q(self) -> pd.Series: # override if applicable + @property + @abc.abstractmethod + def q(self) -> pd.Series: """Return (flat) volume timeseries in [MWh].""" ... - @abc.abstractproperty - def p(self) -> pd.Series: # override if applicable + @property + @abc.abstractmethod + def p(self) -> pd.Series: """Return (flat) price timeseries in [Eur/MWh].""" ... - @abc.abstractproperty - def r(self) -> pd.Series: # override if applicable + @property + @abc.abstractmethod + def r(self) -> pd.Series: """Return (flat) revenue timeseries in [Eur].""" ... - @abc.abstractproperty - def volume(self) -> PfLine: # override if applicable + @property + @abc.abstractmethod + def volume(self) -> PfLine: """Return volume-only PfLine.""" ... - @abc.abstractproperty - def price(self) -> PfLine: # override if applicable + @property + @abc.abstractmethod + def price(self) -> PfLine: """Return price-only PfLine.""" ... - @abc.abstractproperty - def revenue(self) -> PfLine: # override if applicable + @property + @abc.abstractmethod + def revenue(self) -> PfLine: """Return revenue-only PfLine""" ... @@ -134,40 +143,16 @@ def flatten(self) -> PfLine: ... @abc.abstractmethod - def map_to_year(self, year: int, holiday_country: str = None) -> PfLine: - """Transfer the data to a hypothetical other year. - - Parameters - ---------- - year : int - Year to transfer the data to. - holiday_country : str, optional (default: None) - Country or region for which to assume the holidays. E.g. 'DE' (Germany), 'NL' - (Netherlands), or 'USA'. See ``holidays.list_supported_countries()`` for - allowed values. - - Returns - ------- - PfLine - - Notes - ----- - Useful for daily (and shorter) data. Copies over the data but takes weekdays (and - holidays) of target year into consideration. See ``portfolyo.map_frame_as_year()`` - for more information. - Inaccurate for monthly data and longer, because we only have one value per month, - and can therefore not take different number of holidays/weekends (i.e., offpeak - hours) into consideration. - """ - ... - - @abc.abstractmethod - def po(self: PfLine, freq: str = "MS") -> pd.DataFrame: - """Decompose the portfolio line into peak and offpeak values. Takes simple averages - of volume [MW] and price [Eur/MWh] - does not hedge! + def po( + self: PfLine, peak_fn: tools.peakfn.PeakFunction, freq: str = "MS" + ) -> pd.DataFrame: + """Decompose the portfolio line into peak and offpeak values. Takes simple (duration- + weighted) averages of volume [MW] and price [Eur/MWh] - does not hedge! Parameters ---------- + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. freq : {'MS' (months, default), 'QS' (quarters), 'AS' (years)} Frequency of resulting dataframe. @@ -187,8 +172,8 @@ def hedge_with( self: PfLine, p: PricePfLine, how: str = "val", + peak_fn: tools.peakfn.PeakFunction = None, freq: str = "MS", - po: bool = None, ) -> PfLine: """Hedge the volume in the portfolio line with a price curve. @@ -198,11 +183,11 @@ def hedge_with( Portfolio line with prices to be used in the hedge. how : str, optional (Default: 'val') Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. + peak_fn : PeakFunction, optional (default: None) + Function that returns boolean Series indicating if timestamps in index lie in peak period. + If None, hedge with base products. freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} Frequency of hedging products. E.g. 'QS' to hedge with quarter products. - po : bool, optional - Type of hedging products. Set to True to split hedge into peak and offpeak. - (Default: split if volume timeseries has hourly values or shorter.) Returns ------- @@ -269,24 +254,13 @@ class CompletePfLine: r: pd.Series = property(lambda self: self.df["r"]) -class FlatPfLine(PfLine): - """Flat portfolio line, i.e., without children. Only has a single dataframe. - - Notes - ----- - * If the timeseries or values in ``data`` do not have a ``pint`` data type, the - standard units are assumed (MW, MWh, Eur, Eur/MWh). - * If the timeseries or values in ``data`` do have a ``pint`` data type, they are - converted into the standard units. - """ - +class FlatPfLine: structure = Structure.FLAT dataframe = dataframeexport.Flat.dataframe flatten = flat_methods.flatten - po = prices.Flat.po - hedge_with = prices.Flat.hedge_with - # map_to_year => on child classes + po = flat_methods.po + hedge_with = flat_methods.hedge_with loc = flat_methods.loc slice = flat_methods.slice __getitem__ = flat_methods.__getitem__ @@ -294,14 +268,13 @@ class FlatPfLine(PfLine): __eq__ = flat_methods.__eq__ -class NestedPfLine(PfLine, children.ChildFunctionality): +class NestedPfLine(children.ChildFunctionality): structure = Structure.NESTED dataframe = dataframeexport.Nested.dataframe flatten = nested_methods.flatten - po = prices.Nested.po - hedge_with = prices.Nested.hedge_with - map_to_year = nested_methods.map_to_year + po = nested_methods.po + hedge_with = nested_methods.hedge_with loc = nested_methods.loc slice = nested_methods.slice __bool__ = nested_methods.__bool__ @@ -323,13 +296,6 @@ def asfreq(self, freq: str = "MS") -> FlatVolumePfLine: newdf["w"] = newdf["q"] / tools.duration.index(newdf.index) # TODO: check unit return FlatVolumePfLine(newdf) - @decorators.map_to_year_warning - def map_to_year(self, year: int, holiday_country: str = None) -> FlatVolumePfLine: - df = self.df[["w"]] # Averageble data to allow mapping unequal-length periods - newdf = tools.changeyear.map_frame_to_year(df, year, holiday_country) - newdf["q"] = newdf["w"] * tools.duration.index(newdf.index) - return FlatVolumePfLine(newdf) - def __bool__(self) -> bool: return not np.allclose(self.df["w"].pint.magnitude, 0.0) @@ -364,12 +330,6 @@ def asfreq(self, freq: str = "MS") -> FlatPricePfLine: ) return FlatPricePfLine(newdf) - @decorators.map_to_year_warning - def map_to_year(self, year: int, holiday_country: str = None) -> FlatVolumePfLine: - df = self.df[["p"]] # Averageble data to allow mapping unequal-length periods - newdf = tools.changeyear.map_frame_to_year(df, year, holiday_country) - return FlatPricePfLine(newdf) - def __bool__(self) -> bool: return not np.allclose(self.df["p"].pint.magnitude, 0.0) @@ -404,15 +364,6 @@ def asfreq(self, freq: str = "MS") -> FlatRevenuePfLine: ) return FlatRevenuePfLine(newdf) - @decorators.map_to_year_warning - def map_to_year(self, year: int, holiday_country: str = None) -> FlatVolumePfLine: - # Assume that revenue is scales proportionately with duration of period. - # E.g. 290 Eur in leapyear Feb --> 280 Eur in non-leapyear Feb. - df = self.df[["r"]] * tools.duration.index(self.df.index) # Make averageble - newdf = tools.changeyear.map_frame_to_year(df, year, holiday_country) - newdf = newdf / tools.duration.index(newdf.index) # Make summable again - return FlatRevenuePfLine(newdf) - def __bool__(self) -> bool: return not np.allclose(self.df["r"].pint.magnitude, 0.0) @@ -461,14 +412,6 @@ def asfreq(self, freq: str = "MS") -> FlatCompletePfLine: newdf["p"] = newdf["r"] / newdf["q"] return FlatCompletePfLine(newdf) - @decorators.map_to_year_warning - def map_to_year(self, year: int, holiday_country: str = None) -> FlatVolumePfLine: - df = self.df[["w", "p"]] # Averagable - newdf = tools.changeyear.map_frame_to_year(df, year, holiday_country) - newdf["q"] = newdf["w"] * tools.duration.index(newdf.index) - newdf["r"] = newdf["q"] * newdf["p"] - return FlatCompletePfLine(newdf) - def __bool__(self) -> bool: return not ( np.allclose(self.df["w"].pint.magnitude, 0.0) diff --git a/portfolyo/core/pfline/decorators.py b/portfolyo/core/pfline/decorators.py index dfbf707..129b854 100644 --- a/portfolyo/core/pfline/decorators.py +++ b/portfolyo/core/pfline/decorators.py @@ -1,8 +1,5 @@ """Module with decorators to catch (and possibly correct) common situations.""" - -import warnings - from ... import tools @@ -34,15 +31,3 @@ def wrapped(self, *args, **kwargs): return wrapped return decorator - - -def map_to_year_warning(map_to_year): - def wrapped(self, *args, **kwargs): - if tools.freq.shortest(self.index.freq, "MS") == "MS": - warnings.warn( - "This PfLine has a monthly frequency or longer; changing the year is inaccurate, as" - " details (number of holidays, weekends, offpeak hours, etc) cannot be taken into account." - ) - return map_to_year(self, *args, **kwargs) - - return wrapped diff --git a/portfolyo/core/pfline/flat_methods.py b/portfolyo/core/pfline/flat_methods.py index 6c9570b..fbb372f 100644 --- a/portfolyo/core/pfline/flat_methods.py +++ b/portfolyo/core/pfline/flat_methods.py @@ -1,17 +1,84 @@ from __future__ import annotations from typing import TYPE_CHECKING, Any -from ... import tools + import pandas as pd +from ... import tools +from . import classes +from .enums import Kind, Structure + if TYPE_CHECKING: - from .classes import FlatPfLine + from .classes import FlatPfLine, PfLine, PricePfLine def flatten(self: FlatPfLine) -> FlatPfLine: return self +def po( + self: PfLine, peak_fn: tools.peakfn.PeakFunction, freq: str = "MS" +) -> pd.DataFrame: + if self.index.freq not in ["15T", "H"]: + raise ValueError( + "Only PfLines with (quarter)hourly values can be turned into peak and offpeak values." + ) + if freq not in ["MS", "QS", "AS"]: + raise ValueError( + f"Value of paramater ``freq`` must be one of {'MS', 'QS', 'AS'} (got: {freq})." + ) + + df_dict = {} + prods = ("peak", "offpeak") + + # Get values. + for col in ("w", "p"): + if col in self.kind.available: + vals = tools.peakconvert.tseries2bpoframe(self.df[col], peak_fn, freq)[ + prods + ] + df_dict[col] = vals + + # Add duration. + i = next(iter(df_dict.values())).index # index of any of the dataframes + b = tools.duration.index(i) # pint-series + p = tools.peakfn.peak_duration(i, peak_fn) # pint-series + df_dict["duration"] = pd.DataFrame({"peak": p, "offpeak": b - p}) + + # Turn into dataframe. + df = pd.DataFrame(df_dict).swaplevel(axis=1) # 'peak', 'offpeak' on top + + # Add additional values and sort. + for prod in prods: + if "q" in self.kind.available: + df[(prod, "q")] = df[(prod, "w")] * df[(prod, "duration")] + if "r" in self.kind.available: + df[(prod, "r")] = (df[(prod, "q")] * df[(prod, "p")]).pint.to_base_units() + # colidx = pd.MultiIndex.from_product([prods, ("duration", *self.kind.available)]) + return df.sort_index(axis=1) # [colidx] + + +def hedge_with( + self: PfLine, + p: PricePfLine, + how: str = "val", + peak_fn: tools.peakfn.PeakFunction = None, + freq: str = "MS", +) -> FlatPfLine: + if self.kind not in [Kind.VOLUME, Kind.COMPLETE]: + raise ValueError( + "Cannot hedge a PfLine that does not contain volume information." + ) + if self.index.freq not in ["15T", "H", "D"]: + raise ValueError( + "Can only hedge a PfLine with daily or (quarter)hourly information." + ) + + wout, pout = tools.hedge.hedge(self.w, p.p, how, peak_fn, freq) + constructor = classes.constructor(Structure.FLAT, Kind.COMPLETE) + return constructor({"w": wout, "p": pout}) + + def __eq__(self: FlatPfLine, other: Any) -> bool: if not isinstance(other, self.__class__): return False diff --git a/portfolyo/core/pfline/nested_methods.py b/portfolyo/core/pfline/nested_methods.py index 33d37b1..7a04946 100644 --- a/portfolyo/core/pfline/nested_methods.py +++ b/portfolyo/core/pfline/nested_methods.py @@ -2,23 +2,35 @@ from typing import TYPE_CHECKING, Any -if TYPE_CHECKING: - from .classes import NestedPfLine, FlatPfLine +import pandas as pd +from ... import tools from . import classes from .enums import Structure +if TYPE_CHECKING: + from .classes import FlatPfLine, NestedPfLine, PricePfLine + def flatten(self: NestedPfLine) -> FlatPfLine: constructor = classes.constructor(Structure.FLAT, self.kind) return constructor(self.df) # use flattened toplevel dataframe for initialisation -def map_to_year(self: NestedPfLine, year: int, holiday_country: str) -> NestedPfLine: - newchildren = { - name: child.map_to_year(year, holiday_country) for name, child in self.items() - } - return self.__class__(newchildren) +def po( + self: NestedPfLine, peak_fn: tools.peakfn.PeakFunction, freq: str = "MS" +) -> pd.DataFrame: + return self.flatten().po(peak_fn, freq) + + +def hedge_with( + self: NestedPfLine, + p: PricePfLine, + how: str = "val", + peak_fn: tools.peakfn.PeakFunction = None, + freq: str = "MS", +) -> FlatPfLine: + return self.flatten().hedge_with(p, how, peak_fn, freq) def __bool__(self: NestedPfLine) -> bool: diff --git a/portfolyo/core/pfline/plot.py b/portfolyo/core/pfline/plot.py index ac407f6..a59ff1c 100644 --- a/portfolyo/core/pfline/plot.py +++ b/portfolyo/core/pfline/plot.py @@ -31,7 +31,7 @@ def defaultkwargs(name: str, col: str): # Get plot default kwargs. if name is None: # no children kwargs = { - "color": getattr(tools.visualise.Colors.Wqpr, col, "grey"), + "color": getattr(tools.visualize.Colors.Wqpr, col, "grey"), "alpha": 0.7, "labelfmt": DEFAULTFMT.get(col, "{:.2f}"), } @@ -44,9 +44,9 @@ def defaultkwargs(name: str, col: str): else: # child with name hashed_value = hashlib.sha256(name.encode()).hexdigest() hashed_int = int(hashed_value, 16) - index = hashed_int % len(tools.visualise.Colors.General) + index = hashed_int % len(tools.visualize.Colors.General) kwargs = { - "color": list(tools.visualise.Colors.General)[index].value, + "color": list(tools.visualize.Colors.General)[index].value, "alpha": 0.9, "labelfmt": "", # no labels on children "label": name, @@ -58,27 +58,27 @@ def defaultkwargs(name: str, col: str): def plotfn_and_kwargs( col: str, freq: str, name: str -) -> Tuple[tools.visualise.PlotTimeseriesToAxFunction, Dict]: +) -> Tuple[tools.visualize.PlotTimeseriesToAxFunction, Dict]: """Get correct function to plot as well as default kwargs. ``col``: one of 'qwprf', ``freq``: frequency; ``name``: name of the child. If name is emptystring, it is the parent of a plot which also has children. If it is None, there are no children.""" # Get plot function. if tools.freq.shortest(freq, "MS") == "MS": # categorical if name == "" or name is None: # parent - fn = tools.visualise.plot_timeseries_as_bar + fn = tools.visualize.plot_timeseries_as_bar else: # child - fn = tools.visualise.plot_timeseries_as_hline + fn = tools.visualize.plot_timeseries_as_hline else: # timeaxis if col in ["w", "q"]: if name == "" or name is None: # parent - fn = tools.visualise.plot_timeseries_as_area + fn = tools.visualize.plot_timeseries_as_area else: # child - fn = tools.visualise.plot_timeseries_as_step + fn = tools.visualize.plot_timeseries_as_step else: # col in ['p', 'r'] if name == "" or name is None: # parent - fn = tools.visualise.plot_timeseries_as_step + fn = tools.visualize.plot_timeseries_as_step else: # child - fn = tools.visualise.plot_timeseries_as_step + fn = tools.visualize.plot_timeseries_as_step kwargs = defaultkwargs(name, col) diff --git a/portfolyo/core/pfline/prices.py b/portfolyo/core/pfline/prices.py deleted file mode 100644 index 9d224bf..0000000 --- a/portfolyo/core/pfline/prices.py +++ /dev/null @@ -1,97 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING - -import pandas as pd - -from ... import tools -from ...tools.prices import convert, hedge -from ...tools.prices.utils import duration_bpo -from . import classes -from .enums import Kind, Structure - -if TYPE_CHECKING: - from .classes import FlatPfLine, NestedPfLine, PfLine, PricePfLine - - -class Flat: - def po(self: FlatPfLine, freq: str = "MS") -> pd.DataFrame: - if self.index.freq not in ["15T", "H"]: - raise ValueError( - "Only PfLines with (quarter)hourly values can be turned into peak and offpeak values." - ) - if freq not in ["MS", "QS", "AS"]: - raise ValueError( - f"Value of paramater ``freq`` must be one of {'MS', 'QS', 'AS'} (got: {freq})." - ) - - prods = ("peak", "offpeak") - - # Get values. - dfs = [] - for col in ("w", "p"): - if col in self.kind.available: - vals = convert.tseries2bpoframe(self.df[col], freq) - vals.columns = pd.MultiIndex.from_product([vals.columns, [col]]) - dfs.append(vals) - df = pd.concat(dfs, axis=1) - - # Add duration. - durs = duration_bpo(df.index) - durs.columns = pd.MultiIndex.from_product([durs.columns, ["duration"]]) - df = pd.concat([df, durs], axis=1) - - # Add additional values and sort. - for prod in prods: - if "q" in self.kind.available: - df[(prod, "q")] = df[(prod, "w")] * df[(prod, "duration")] - if "r" in self.kind.available: - df[(prod, "r")] = ( - df[(prod, "q")] * df[(prod, "p")] - ).pint.to_base_units() - colidx = pd.MultiIndex.from_product([prods, ("duration", *self.kind.available)]) - return df[colidx] - - def hedge_with( - self: FlatPfLine, - p: PricePfLine, - how: str = "val", - freq: str = "MS", - po: bool = None, - ) -> FlatPfLine: - if self.kind is Kind.PRICE: - raise ValueError( - "Cannot hedge a PfLine that does not contain volume information." - ) - if self.index.freq not in ["15T", "H", "D"]: - raise ValueError( - "Can only hedge a PfLine with daily or (quarter)hourly information." - ) - if po is None: - po = self.index.freq in ["15T", "H"] # default: peak/offpeak if possible - if po and self.index.freq not in ["15T", "H"]: - raise ValueError( - "Can only hedge with peak and offpeak products if PfLine has (quarter)hourly information." - ) - - wout, pout = hedge.hedge(self.w, p.p, how, freq, po) - df = pd.DataFrame({"w": wout, "p": pout}) - df["q"] = df["w"] * tools.duration.index(df.index) - df["r"] = df["p"] * df["q"] - constructor = classes.constructor(Structure.FLAT, Kind.COMPLETE) - return constructor(df) - # TODO: move to tools or elsewhere, and reference from there. - - -class Nested: - def po(self: NestedPfLine, freq: str = "MS") -> pd.DataFrame: - return self.flatten().po(freq) - - def hedge_with( - self: NestedPfLine, - p: PfLine, - how: str = "val", - freq: str = "MS", - po: bool = None, - ) -> FlatPfLine: - return self.flatten().hedge_with(p, how, freq, po) diff --git a/portfolyo/core/pfline/text.py b/portfolyo/core/pfline/text.py index cf30fc3..a8c196a 100644 --- a/portfolyo/core/pfline/text.py +++ b/portfolyo/core/pfline/text.py @@ -1,10 +1,13 @@ +from __future__ import annotations + from typing import TYPE_CHECKING, Iterable import colorama import pandas as pd -from ..shared import text -from .enums import Kind + +from ..shared import text as shared_text from . import classes +from .enums import Kind if TYPE_CHECKING: from .classes import PfLine @@ -25,33 +28,6 @@ def _children_info(pfl: PfLine) -> Iterable[str]: return [". Children: " + ("none" if not childtxt else ", ".join(childtxt))] -def _nestedtree( - name: str, - pfl: PfLine, - cols: Iterable[str], - num_of_ts: int, - depth: int = 0, - is_last: bool = True, - is_only: bool = False, -) -> Iterable[str]: - """Treeview of the portfolio line.""" - out = [] - tree = text.treedict(depth, is_last, isinstance(pfl, classes.NestedPfLine)) - # Name. - out.append(tree["00"] + tree["01"] + name) - # Top-level body block. - if is_only and depth > 0: - txtlines = ["(only contributor to parent data; has same values)"] - else: - txtlines = _flatdatablock(pfl, cols, num_of_ts) - for txtline in txtlines: - out.append(tree["10"] + tree["11"] + colorama.Style.RESET_ALL + txtline) - # Add children if any. - for txtline in _childrenlines(pfl, cols, num_of_ts, depth): - out.append(tree["10"] + txtline) - return out - - def _flatdatablock(pfl: PfLine, cols: Iterable[str], num_of_ts: int) -> Iterable[str]: """The timestamps and data to be shown in a block, next to the tree.""" # Obtain dataframe with index = timestamp as string and columns = one or more of 'qwpr'. @@ -60,11 +36,11 @@ def _flatdatablock(pfl: PfLine, cols: Iterable[str], num_of_ts: int) -> Iterable if len(df.index) > num_of_ts * 2: df = pd.concat([df.iloc[:num_of_ts, :], df.iloc[-num_of_ts:, :]], axis=0) # . turn values into strings. - df = text.df_with_strvalues(df) + df = shared_text.df_with_strvalues(df) # . turn index into strings and reduce to wanted number of datapoints - df = text.df_with_strindex(df, num_of_ts) + df = shared_text.df_with_strindex(df, num_of_ts) # . column withs - col_space = {k: v for k, v in text.COLWIDTHS.items() if k in df} + col_space = {k: v for k, v in shared_text.COLWIDTHS.items() if k in df} # Turn into list of strings. df_str = df.to_string(col_space=col_space, index_names=False, header=False) return df_str.split("\n") @@ -80,7 +56,7 @@ def _childrenlines( for c, (name, child) in enumerate(pfl.items()): is_last, is_only = (c == len(pfl) - 1), (len(pfl) == 1) out.extend( - _nestedtree(name, child, cols, num_of_ts, depth + 1, is_last, is_only) + nestedtree(name, child, cols, num_of_ts, depth + 1, is_last, is_only) ) return out @@ -88,22 +64,49 @@ def _childrenlines( # Highest-level functions. +def nestedtree( + name: str, + pfl: PfLine, + cols: Iterable[str], + num_of_ts: int, + depth: int = 0, + is_last: bool = True, + is_only: bool = False, +) -> Iterable[str]: + """Treeview of the portfolio line.""" + out = [] + tree = shared_text.treedict(depth, is_last, isinstance(pfl, classes.NestedPfLine)) + # Name. + out.append(tree["00"] + tree["01"] + name) + # Top-level body block. + if is_only and depth > 0: + txtlines = ["(only contributor to parent data; has same values)"] + else: + txtlines = _flatdatablock(pfl, cols, num_of_ts) + for txtline in txtlines: + out.append(tree["10"] + tree["11"] + colorama.Style.RESET_ALL + txtline) + # Add children if any. + for txtline in _childrenlines(pfl, cols, num_of_ts, depth): + out.append(tree["10"] + txtline) + return out + + def pfl_as_string(pfl: PfLine, flatten: bool, num_of_ts: int, color: bool) -> str: lines = [f"PfLine object with {_what(pfl)} information."] - lines.extend(text.index_info(pfl.index)) + lines.extend(shared_text.index_info(pfl.index)) if isinstance(pfl, classes.NestedPfLine): lines.extend(_children_info(pfl)) cols = pfl.kind.available if flatten: - lines.extend(text.dataheader(cols)) + lines.extend(shared_text.dataheader(cols)) lines.extend([""]) lines.extend(_flatdatablock(pfl, cols, num_of_ts)) else: - spaces = " " * (text.MAX_DEPTH + 5) - lines.extend([spaces + txtline for txtline in text.dataheader(cols)]) - lines.extend(_nestedtree("(this pfline)", pfl, cols, num_of_ts)) + spaces = " " * (shared_text.MAX_DEPTH + 5) + lines.extend([spaces + txtline for txtline in shared_text.dataheader(cols)]) + lines.extend(nestedtree("(this pfline)", pfl, cols, num_of_ts)) txt = "\n".join(lines) - return txt if color else text.remove_color(txt) + return txt if color else shared_text.remove_color(txt) class PfLineText: diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index 2792cfc..aa36b20 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -12,9 +12,9 @@ import pandas as pd from ... import tools +from ..pfline import PfLine, create from ..shared.excelclipboard import ExcelClipboardOutput from ..shared.ndframelike import NDFrameLike -from ..pfline import PfLine, create from . import pfstate_helper from .arithmatic import PfStateArithmatic from .plot import PfStatePlot diff --git a/portfolyo/core/pfstate/plot.py b/portfolyo/core/pfstate/plot.py index 622393f..975dac9 100644 --- a/portfolyo/core/pfstate/plot.py +++ b/portfolyo/core/pfstate/plot.py @@ -1,4 +1,5 @@ from __future__ import annotations + from typing import TYPE_CHECKING import matplotlib @@ -6,7 +7,6 @@ from ..pfline import Kind - if TYPE_CHECKING: from .pfstate import PfState diff --git a/portfolyo/core/pfstate/text.py b/portfolyo/core/pfstate/text.py index 5accf73..0c70036 100644 --- a/portfolyo/core/pfstate/text.py +++ b/portfolyo/core/pfstate/text.py @@ -1,8 +1,9 @@ -from typing import TYPE_CHECKING -from ..pfline.text import _nestedtree +from __future__ import annotations +from typing import TYPE_CHECKING -from ..shared import text +from ..pfline import text as pfline_text +from ..shared import text as shared_text if TYPE_CHECKING: from .pfstate import PfState @@ -10,13 +11,13 @@ def pfs_as_string(pfs: PfState, num_of_ts: int, color: bool) -> str: lines = ["PfState object."] - lines.extend(text.index_info(pfs.index)) - spaces = " " * (text.MAX_DEPTH + 5) - lines.extend([spaces + txtline for txtline in text.dataheader("wqpr")]) - lines.extend(_nestedtree("offtake", pfs.offtakevolume, "wq", num_of_ts)) - lines.extend(_nestedtree("pnl_cost", pfs.pnl_cost, "wqpr", num_of_ts)) + lines.extend(shared_text.index_info(pfs.index)) + spaces = " " * (shared_text.MAX_DEPTH + 5) + lines.extend([spaces + txtline for txtline in shared_text.dataheader("wqpr")]) + lines.extend(pfline_text.nestedtree("offtake", pfs.offtakevolume, "wq", num_of_ts)) + lines.extend(pfline_text.nestedtree("pnl_cost", pfs.pnl_cost, "wqpr", num_of_ts)) txt = "\n".join(lines) - return txt if color else text.remove_color(txt) + return txt if color else shared_text.remove_color(txt) class PfStateText: diff --git a/portfolyo/core/shared/excelclipboard.py b/portfolyo/core/shared/excelclipboard.py index 7499515..80d77ad 100644 --- a/portfolyo/core/shared/excelclipboard.py +++ b/portfolyo/core/shared/excelclipboard.py @@ -5,6 +5,7 @@ from __future__ import annotations import functools + import pandas as pd from .ndframelike import NDFrameLike diff --git a/portfolyo/core/shared/text.py b/portfolyo/core/shared/text.py index aafb3a8..91332f8 100644 --- a/portfolyo/core/shared/text.py +++ b/portfolyo/core/shared/text.py @@ -1,7 +1,5 @@ """String representation of PfLine and PfState objects.""" -from __future__ import annotations - from typing import Dict, Iterable import colorama @@ -9,7 +7,6 @@ from ... import tools - COLORS = ["WHITE", "YELLOW", "CYAN", "GREEN", "RED", "BLUE", "MAGENTA", "BLACK"] TREECOLORS = [colorama.Style.BRIGHT + getattr(colorama.Fore, f) for f in COLORS] _UNITS = {"w": "MW", "q": "MWh", "p": "Eur/MWh", "r": "Eur"} diff --git a/portfolyo/dev/mockup.py b/portfolyo/dev/mockup.py index 3944f01..210e69f 100644 --- a/portfolyo/dev/mockup.py +++ b/portfolyo/dev/mockup.py @@ -5,8 +5,8 @@ import numpy as np import pandas as pd -from ..tools.prices.utils import is_peak_hour from ..tools import unit # noqa # ensure we use current ureg +from ..tools.product import germanpower_peakfn def w_offtake( @@ -107,7 +107,7 @@ def p_marketprices( if i.freq == "15T": # repeat every value 4 times b = np.array([[bb, bb, bb, bb] for bb in b]).flatten() b = b[: len(i)] # slice in case i is very short - pa = np.convolve(-1 + 2 * is_peak_hour(i), b / sum(b), mode="same") + pa = np.convolve(-1 + 2 * germanpower_peakfn(i), b / sum(b), mode="same") else: pa = np.zeros(len(i)) # Values @@ -168,7 +168,7 @@ def group_and_calc(s): return s.resample(freq, group_keys=False).apply(calc_wp) if sin.index.freq in ["15T", "H"]: - is_peak = is_peak_hour(sin.index) # avoid running on each ts individually + is_peak = germanpower_peakfn(sin.index) # avoid running on each ts individually df = sin.groupby(is_peak, group_keys=False).apply(group_and_calc) else: df = group_and_calc(sin) diff --git a/portfolyo/tools/__init__.py b/portfolyo/tools/__init__.py index 8e6f519..fa49fa8 100644 --- a/portfolyo/tools/__init__.py +++ b/portfolyo/tools/__init__.py @@ -1,6 +1,6 @@ """General tools; mainly to use on pandas objects.""" -# Unsure why this is needed, but remove and can no longer import portfolyo +# Unsure why this is needed. from . import ( ceil, changefreq, @@ -9,16 +9,24 @@ floor, frame, freq, + hedge, intersect, isboundary, leftandright, - peakperiod, + peakconvert, + peakfn, + prices, + product, right, righttoleft, + round, + stamp, standardize, + startofday, trim, + types, tzone, unit, + visualize, wavg, - startofday, ) diff --git a/portfolyo/tools/changefreq.py b/portfolyo/tools/changefreq.py index 72d3477..dd6a0f9 100644 --- a/portfolyo/tools/changefreq.py +++ b/portfolyo/tools/changefreq.py @@ -1,14 +1,15 @@ """Functions to change frequency of a pandas dataframe.""" -from typing import Any, Union +from typing import Any import pandas as pd - -from . import startofday as tools_startofday +from . import duration as tools_duration from . import freq as tools_freq from . import right as tools_right +from . import startofday as tools_startofday from . import trim as tools_trim +from .types import Series_or_DataFrame def _astype(s: pd.Series, dtype: Any) -> pd.Series: @@ -28,9 +29,11 @@ def _emptyseries(s_ref: pd.Series, freq) -> pd.Series: def _downsample_avgable(s: pd.Series, freq: str) -> pd.Series: """Downsample averagble series.""" # For averagable series: first make summable. - summable = s.mul(s.index.duration, axis=0) # now has a pint dtype + duration = tools_duration.frame(s) + summable = s.mul(duration, axis=0) # now has a pint dtype summable2 = _downsample_summable(summable, freq) - s2 = summable2.div(summable2.index.duration, axis=0) + duration2 = tools_duration.frame(summable2) + s2 = summable2.div(duration2, axis=0) s2 = _astype(s2, s.dtype) return s2.rename(s.name) @@ -69,9 +72,11 @@ def _downsample_summable(s: pd.Series, freq: str) -> pd.Series: def _upsample_summable(s: pd.Series, freq: str) -> pd.Series: """Upsample summable series.""" # For summable series: first make averagable. - avgable = s.div(s.index.duration, axis=0) # now has a pint dtype + duration = tools_duration.frame(s) + avgable = s.div(duration, axis=0) # now has a pint dtype avgable2 = _upsample_avgable(avgable, freq) - s2 = avgable2.mul(avgable2.index.duration, axis=0) + duration2 = tools_duration.frame(avgable2) + s2 = avgable2.mul(duration2, axis=0) s2 = _astype(s2, s.dtype) return s2.rename(s.name) @@ -190,22 +195,20 @@ def index(i: pd.DatetimeIndex, freq: str = "MS") -> pd.DatetimeIndex: return _upsample_avgable(pd.Series(0, i), freq).index -def summable( - fr: Union[pd.Series, pd.DataFrame], freq: str = "MS" -) -> Union[pd.Series, pd.DataFrame]: +def summable(fr: Series_or_DataFrame, freq: str = "MS") -> Series_or_DataFrame: f""" Resample and aggregate a DataFrame or Series with 'time-summable' quantities. Parameters ---------- - fr : pd.Series or pd.DataFrame + fr : Series or DataFrame Pandas Series or DataFrame to be resampled. freq : {{{', '.join(tools_freq.FREQUENCIES)}}}, optional (default: 'MS') Target frequency. Returns ------- - DataFrame or Series + Series or DataFrame Notes ----- @@ -228,22 +231,20 @@ def summable( return _general(True, fr, freq) -def averagable( - fr: Union[pd.Series, pd.DataFrame], freq: str = "MS" -) -> Union[pd.Series, pd.DataFrame]: +def averagable(fr: Series_or_DataFrame, freq: str = "MS") -> Series_or_DataFrame: f""" Resample and aggregate a DataFrame or Series with 'time-averagable' quantities. Parameters ---------- - fr : pd.Series or pd.DataFrame + fr : Series or DataFrame Pandas Series or DataFrame to be resampled. freq : {{{', '.join(tools_freq.FREQUENCIES)}}}, optional (default: 'MS') Target frequency. Returns ------- - DataFrame or Series + Series or DataFrame Notes ----- diff --git a/portfolyo/tools/duration.py b/portfolyo/tools/duration.py index b003717..cc5dded 100644 --- a/portfolyo/tools/duration.py +++ b/portfolyo/tools/duration.py @@ -1,7 +1,4 @@ -""" -Duration of delivery periods. -""" - +"""Duration of delivery periods.""" import pandas as pd @@ -41,11 +38,11 @@ def stamp(ts: pd.Timestamp, freq: str) -> tools_unit.Q_: def index(i: pd.DatetimeIndex) -> pd.Series: - """Duration of a timestamp. + """Duration of the timestamps in an index. Parameters ---------- - i : pd.DatetimeIndex + i : DatetimeIndex Index for which to calculate the duration. Returns @@ -60,4 +57,20 @@ def index(i: pd.DatetimeIndex) -> pd.Series: # Individual calculations for non-fixed-duration frequencies. h = (tools_right.index(i) - i).map(lambda td: td.total_seconds() / 3600) - return pd.Series(h, i).astype("pint[h]").rename("duration") + return pd.Series(h, i, dtype="pint[h]").rename("duration") + + +def frame(fr: pd.Series | pd.DataFrame) -> pd.Series: + """Duration of the timestamps in the index of a Series or DataFrame. + + Parameters + ---------- + fr : Series or DataFrame + Object with index for which to calculate the duration. + + Returns + ------- + pint-Series + With ``i`` as its index, and the corresponding duration as the values. + """ + return index(fr.index) diff --git a/portfolyo/tools/hedge.py b/portfolyo/tools/hedge.py new file mode 100644 index 0000000..372c351 --- /dev/null +++ b/portfolyo/tools/hedge.py @@ -0,0 +1,142 @@ +"""Functionality to hedge an offtake profile with a price profile.""" + +from typing import Tuple + +import pandas as pd + +from . import duration as tools_duration +from . import intersect as tools_intersect +from . import peakconvert as tools_peakconvert +from . import peakfn as tools_peakfn +from . import trim as tools_trim +from . import wavg as tools_wavg + + +def _hedge( + df: pd.DataFrame, + how: str, + peak_fn: tools_peakfn.PeakFunction = None, + freq: str = "MS", +) -> pd.Series: + """ + Hedge a power timeseries, for given price timeseries. + + Parameters + ---------- + df : pd.DataFrame + with 'w' [MW] and 'p' [Eur/MWh] columns. + how : str. One of {'vol', 'val'} + Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. + peak_fn : PeakFunction, optional (default: None) + Function that returns boolean Series indicating if timestamps in index lie in peak period. + If None, hedge with base products. + freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} + Frequency of hedging products. E.g. 'QS' to hedge with quarter products. + + Returns + ------- + pd.Series + With float values or quantities. + If peak_fn is None, Series with index with 2 values (['w', 'p']; power and + price in entire period). + If peak_fn is not None, Series with multiindex (['peak', 'offpeak'] x ['w', 'p']; + power and price, split between peak and offpeak intervals in the period). + """ + df = df.copy() + + # Use magnitude of duration only, so that, if w and p are float series, their + # return series are also floats (instead of dimensionless Quantities). + df["duration"] = tools_duration.frame(df).pint.m + + # Prepare weights. + if how == "vol": # volume hedge + # solve for w_hedge: sum(w * duration) == w_hedge * sum(duration) + # so: w_hedge = sum(w * duration) / sum(duration) + df["weights"] = df["duration"] + elif how == "val": # value hedge + # solve for w_hedge: sum(w * duration * p) == w_hedge * sum(duration * p) + # so: w_hedge = sum(w * duration * p) / sum(duration * p) + df["weights"] = df["p"] * df["duration"] + else: + raise ValueError(f"Parameter `how` must be 'val' or 'vol'; got {how}.") + + # Grouping. + grouping = tools_peakconvert.group_arrays(df.index, freq, peak_fn) + + # Do hedge. + def do_hedge(sub_df): + p_hedge = tools_wavg.series(sub_df["p"], sub_df["duration"]) + w_hedge = tools_wavg.series(sub_df["w"], sub_df["weights"]) + return pd.Series({"w": w_hedge, "p": p_hedge}) + + return df.groupby(grouping).transform(do_hedge) + + +def hedge( + w: pd.Series, + p: pd.Series, + how: str = "val", + peak_fn: tools_peakfn.PeakFunction = None, + freq: str = "MS", +) -> Tuple[pd.Series, pd.Series]: + """ + Make hedge of power timeseries, for given price timeseries. + + Parameters + ---------- + w : Series + Power timeseries with hourly or quarterhourly frequency. + p: Series + Price timeseries with same frequency. + how : str, optional (Default: 'val') + Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. + peak_fn : PeakFunction, optional (default: None) + Function that returns boolean Series indicating if timestamps in index lie in peak period. + If None, hedge with base products. + freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} + Frequency of hedging products. E.g. 'QS' to hedge with quarter products. + + Returns + ------- + Tuple[Series, Series] + Power timeseries and price timeseries with hedge of ``w`` (with same index). + """ + if w.index.freq is None or p.index.freq is None: + raise ValueError( + "Parameters ``w`` and ``p`` must have a DatetimeIndex with a set frequency attribute." + ) + if w.index.freq != p.index.freq: + raise ValueError( + f"Parameters ``w`` and ``p`` must have same frequency; got {w.index.freq} and {p.index.freq}." + ) + if w.index.freq not in ["15T", "H", "D"]: + raise ValueError("Can only hedge a timeseries with daily (or shorter) values.") + if freq not in ["D", "MS", "QS", "AS"]: + raise ValueError( + f"Parameter ``freq`` must be one of 'D', 'MS', 'QS', 'AS'; got '{freq}'." + ) + if peak_fn is not None and not (w.index.freq in ["15T", "H"] and freq != "D"): + raise ValueError( + "Split into peak and offpeak only possible when (a) hedging with monthly (or " + "longer) products, and (b) if timeseries have hourly (or shorter) values." + ) + + # Handle possible units. + win, wunits = (w.pint.magnitude, w.pint.units) if hasattr(w, "pint") else (w, None) + pin, punits = (p.pint.magnitude, p.pint.units) if hasattr(p, "pint") else (p, None) + + # Only keep full periods of overlapping timestamps. + + win, pin = tools_intersect.frames(win, pin) + df = tools_trim.frame(pd.DataFrame({"w": win, "p": pin}), freq) + if len(df) == 0: + return df["w"], df["p"] # No full periods; don't do hedge; return empty series + + # Do actual hedge. + df2 = _hedge(df, how, freq, peak_fn) + + # Handle possible units. + if wunits or punits: + df2 = df2.astype({"w": f"pint[{wunits}]", "p": f"pint[{punits}]"}) + + return df2["w"], df2["p"] diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index 3ec0996..b8fbb83 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -1,9 +1,11 @@ -from typing import List, Union, Tuple -import pandas as pd -from .right import stamp -from .freq import longest, longer_or_shorter from datetime import datetime +from typing import List, Tuple, Union + +import pandas as pd + from . import trim as tools_trim +from .freq import longer_or_shorter, longest +from .right import stamp def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: diff --git a/portfolyo/tools/peakconvert.py b/portfolyo/tools/peakconvert.py new file mode 100644 index 0000000..dbff294 --- /dev/null +++ b/portfolyo/tools/peakconvert.py @@ -0,0 +1,423 @@ +"""Module to convert between timeseries and base/peak/offpeak-values.""" + +import warnings +from typing import List + +import numpy as np +import pandas as pd + +from . import changefreq as tools_changefreq +from . import duration as tools_duration +from . import freq as tools_freq +from . import peakfn as tools_peakfn +from . import trim as tools_trim +from . import wavg as tools_wavg + +BPO = ("base", "peak", "offpeak") + + +def group_arrays( + i: pd.DatetimeIndex, freq: str, peak_fn: tools_peakfn.PeakFunction = None +) -> List: + """Function to group all rows that belong to same delivery period.""" + # Grouping due to delivery period. + groups = [i.year] + if freq == "MS": + groups.append(i.month) + elif freq == "QS": + groups.append(i.quarter) + elif freq == "AS": + pass + else: + raise ValueError( + f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got '{freq}'." + ) + + # Add grouping due to peak. + if peak_fn is not None: + groups.append(peak_fn(i)) + + return groups + + +def complete_bpoframe( + df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction +) -> pd.DataFrame: + """Complete a dataframe so it contains arbitrage-free base, peak, and offpeak values. + + Parameters + ---------- + df : DataFrame + With at least 2 of following columns: {'base', 'peak', 'offpeak'}. If all 3 are + present, no verification is done. Additional columns are dropped. DatetimeIndex + with freq in {'MS', 'QS', 'AS'}. + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. + + Returns + ------- + DataFrame + Same as ``df``, with all 3 columns ('base', 'peak', 'offpeak'). + + Notes + ----- + Can only be used for values that are 'averagable' over a time period, like power [MW] + and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. + + In: + + peak offpeak + ts_left + 2020-01-01 00:00:00+01:00 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 33.295167 15.931557 + ... ... + 2020-11-01 00:00:00+01:00 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 57.872246 35.055449 + 12 rows × 2 columns + + Out: + + base peak offpeak + ts_left + 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 + ... ... ... + 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 + 12 rows × 3 columns + """ + # Guard clauses. + found = [c for c in df.columns if c in BPO] + if len(found) <= 1: # too few present + raise ValueError( + f"At least 2 of 'base', 'peak', 'offpeak' must be in columns; found {found}." + ) + elif len(found) == 3: # all present, nothing to do + return df[BPO] # correct order + + # Make copy of relevant columns, and fill. + df = df[found].copy() + b = tools_duration.index(df.index) + p = tools_peakfn.peak_duration(df.index, peak_fn) + # Solve: peak * duration_peak + offpeak * duration_offpeak = base * duration_base + # with: duration_offpeak = duration_base - duration_peak + if "peak" not in df.columns: + # df["peak"] = (df["base"] * b - df["offpeak"] * (b - p)) / p + df["peak"] = (df["base"] - df["offpeak"]) * b / p + df["offpeak"] + elif "offpeak" not in df.columns: + df["offpeak"] = (df["base"] * b - df["peak"] * p) / (b - p) + else: # 'base' not in fr.columns + # df["base"] = (df["peak"] * p + df["offpeak"] * (b - p)) / b + df["base"] = (df["peak"] - df["offpeak"]) * p / b + df["offpeak"] + + return df[BPO] # correct order + + +def _tseries2singlebpo(s: pd.Series, peak_fn: tools_peakfn.PeakFunction) -> pd.Series: + """ + Aggregate timeseries with varying (float) values to a single base, peak and offpeak + (float) value. + + In: + + ts_left + 2020-01-01 00:00:00+01:00 41.88 + 2020-01-01 01:00:00+01:00 38.60 + 2020-01-01 02:00:00+01:00 36.55 + ... + 2020-12-31 21:00:00+01:00 52.44 + 2020-12-31 22:00:00+01:00 51.86 + 2020-12-31 23:00:00+01:00 52.26 + Freq: H, Name: p, Length: 8784, dtype: float64 + + Out: + + base 31.401369 + peak 51.363667 + offpeak 20.311204 + dtype: float64 + """ + is_peak = peak_fn(s.index) + duration = tools_duration.index(s.index).pint.m # floats + if duration.nunique() == 1: # All have same duration: use normal mean (faster). + return pd.Series( + { + "base": s.mean(), + "peak": s[is_peak].mean(), + "offpeak": s[~is_peak].mean(), + } + ) + else: + return pd.Series( + { + "base": tools_wavg.series(s, duration), + "peak": tools_wavg.series(s[is_peak], duration[is_peak]), + "offpeak": tools_wavg.series(s[~is_peak], duration[~is_peak]), + } + ) + + +def tseries2bpoframe( + s: pd.Series, peak_fn: tools_peakfn.PeakFunction, freq: str = "MS" +) -> pd.DataFrame: + """ + Aggregate timeseries with varying values to a dataframe with base, peak and offpeak + timeseries, grouped by provided time interval. + + Parameters + ---------- + s : Series + Timeseries with hourly or quarterhourly frequency. + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. + freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} + Target frequency. + + Returns + ------- + DataFrame + Dataframe with base, peak and offpeak values (as columns). Index: downsampled + timestamps at provided frequency. + + Notes + ----- + Can only be used for values that are 'averagable' over a time period, like power [MW] + and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. + + In: + + ts_left + 2020-01-01 00:00:00+01:00 41.88 + 2020-01-01 01:00:00+01:00 38.60 + 2020-01-01 02:00:00+01:00 36.55 + ... + 2020-12-31 21:00:00+01:00 52.44 + 2020-12-31 22:00:00+01:00 51.86 + 2020-12-31 23:00:00+01:00 52.26 + Freq: H, Name: p, Length: 8784, dtype: float64 + + Out: + + base peak offpeak + ts_left + 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 + ... ... ... + 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 + 12 rows × 3 columns + """ + if freq not in ("MS", "QS", "AS"): + raise ValueError( + f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got '{freq}'." + ) + + # Remove partial data. + s = tools_trim.frame(s, freq) + + # Handle possible units. + sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) + + # Do calculations. + sout = sin.resample(freq, group_keys=True).apply( + lambda s: _tseries2singlebpo(s, peak_fn) + ) + + # Handle possible units. + if units is not None: + sout = sout.astype(f"pint[{units}]") + return sout.unstack() # base, peak, offpeak as columns + + +def bpoframe2tseries( + df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction, freq: str = "H" +) -> pd.Series: + """ + Convert a dataframe with base, peak and/or offpeak values, to a single (quarter)hourly + timeseries. + + Parameters + ---------- + df : DataFrame + Dataframe with values. Columns must include at least 2 of {'peak', 'offpeak', + 'base'}. Datetimeindex with frequency in {'MS', 'QS', 'AS'}. + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. + freq : {'H' (hour, default) '15T' (quarterhour)} + Target frequency. + + Returns + ------- + Series + Timeseries with values as provided in ``df``. + + Notes + ----- + Can only be used for values that are 'averagable' over a time period, like power [MW] + and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. + + In: + + peak offpeak + ts_left + 2020-01-01 00:00:00+01:00 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 33.295167 15.931557 + ... ... + 2020-11-01 00:00:00+01:00 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 57.872246 35.055449 + 12 rows × 2 columns + + Out: + + ts_left + 2020-01-01 00:00:00+01:00 30.614701 + 2020-01-01 01:00:00+01:00 30.614701 + 2020-01-01 02:00:00+01:00 30.614701 + ... + 2020-12-31 21:00:00+01:00 35.055449 + 2020-12-31 22:00:00+01:00 35.055449 + 2020-12-31 23:00:00+01:00 35.055449 + Freq: H, Length: 8784, dtype: float64 + """ + if "peak" not in df or "offpeak" not in df: # ensure peak and offpeak available + df = complete_bpoframe(df, peak_fn) + + # Stretch the dataframe to higher frequency (repeat parent value) + df2 = tools_changefreq.averagable(df[["peak", "offpeak"]], freq) + df2["ispeak"] = peak_fn(df2.index) + + return df2["offpeak"].where(df2["ispeak"], df2["peak"]) + + +def tseries2tseries( + s: pd.Series, peak_fn: tools_peakfn.PeakFunction = None, freq: str = "MS" +) -> pd.Series: + """ + Transform timeseries (with possibly variable values) to one with (at certain + frequency) uniform peak and offpeak values. + + Parameters + ---------- + s : Series + Timeseries with hourly or quarterhourly frequency. + peak_fn : PeakFunction, optional (default: None) + Function that returns boolean Series indicating if timestamps in index lie in peak period. + If None, calculate uniform base values. + freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} + Target frequency within which peak and offpeak values will be uniform. + + Returns + ------- + Series + Timeseries where each peak hour within the target frequency has the same + value. Idem for offpeak hours. Index: as original series. + + Notes + ----- + Can only be used for values that are 'averagable' over a time period, like power [MW] + and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. + + In: + + ts_left + 2020-01-01 00:00:00+01:00 41.88 + 2020-01-01 01:00:00+01:00 38.60 + 2020-01-01 02:00:00+01:00 36.55 + ... + 2020-12-31 21:00:00+01:00 52.44 + 2020-12-31 22:00:00+01:00 51.86 + 2020-12-31 23:00:00+01:00 52.26 + Freq: H, Name: p, Length: 8784, dtype: float64 + + Out: + + ts_left + 2020-01-01 00:00:00+01:00 30.614701 + 2020-01-01 01:00:00+01:00 30.614701 + 2020-01-01 02:00:00+01:00 30.614701 + ... + 2020-12-31 21:00:00+01:00 35.055449 + 2020-12-31 22:00:00+01:00 35.055449 + 2020-12-31 23:00:00+01:00 35.055449 + Freq: H, Name: p, Length: 8784, dtype: float64 + """ + if s.index.freq not in ("H", "15T"): + raise ValueError( + f"Frequency of provided timeseries must be hourly or quarterhourly; got '{s.index.freq}'." + ) + + # Remove partial data. + s = tools_trim.frame(s, freq) + + # Handle possible units. + sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) + + # Return normal mean, because all rows have same duration. + grouping = group_arrays(freq, peak_fn) + sout = sin.groupby(grouping).transform(np.mean) + + # Handle possible units. + if units is not None: + sout = sout.astype(f"pint[{units}]") + return sout + + +def bpoframe2bpoframe( + df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction, freq: str = "AS" +) -> pd.DataFrame: + """ + Convert a dataframe with base, peak and/or offpeak values to a similar dataframe + with a different frequency. + + Parameters + ---------- + df : DataFrame + Columns must include at least 2 of {'peak', 'offpeak', 'base'}. Datetimeindex + with frequency in {'MS', 'QS', 'AS'}. + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. + freq : {'MS' (month), 'QS' (quarter), 'AS' (year, default)} + Target frequency. + + Returns + ------- + DataFrame + Dataframe with base, peak and offpeak values (as columns). Index: timestamps at + specified frequency. + + Notes + ----- + Can only be used for values that are 'averagable' over a time period, like power [MW] + and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. + + In: + + base peak offpeak + ts_left + 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 + ... ... ... + 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 + 12 rows × 3 columns + + Out: + + base peak offpeak + ts_left + 2020-01-01 00:00:00+01:00 30.490036 38.003536 26.312894 + 2020-04-01 00:00:00+02:00 25.900919 35.295167 20.681892 + 2020-07-01 00:00:00+02:00 32.706785 44.033511 26.371498 + 2020-10-01 00:00:00+02:00 39.455197 54.468722 31.063728 + """ + if freq not in ("MS", "QS", "AS"): + raise ValueError( + f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got {freq}." + ) + if tools_freq.up_or_down(df.index.freq, freq) == 1: + warnings.warn( + "This conversion includes upsampling, e.g. from yearly to monthly values." + " The result will be uniform at the frequency of the original frame ``df``." + ) + + return tseries2bpoframe(bpoframe2tseries(df, peak_fn, "H"), peak_fn, freq) diff --git a/portfolyo/tools/peakfn.py b/portfolyo/tools/peakfn.py new file mode 100644 index 0000000..888e7c9 --- /dev/null +++ b/portfolyo/tools/peakfn.py @@ -0,0 +1,228 @@ +""" Module to work with peak and offpeak periods. """ + +import datetime as dt +from typing import Callable, Iterable + +import numpy as np +import pandas as pd + +from . import changefreq as tools_changefreq +from . import duration as tools_duration +from . import freq as tools_freq +from . import right as tools_right + +PeakFunction = Callable[[pd.DatetimeIndex], pd.Series] + +MIDNIGHT = dt.time(hour=0) + + +def factory( + peak_left: dt.time = None, + peak_right: dt.time = None, + isoweekdays: Iterable[int] = None, +) -> PeakFunction: + """Create function to identify which timestamps in an index are peakhours and which are offpeak. + + Parameters + ---------- + peak_left : dt.time, optional (default: midnight) + Start time of peak period on days that have a peak period (left-bound, incl). + peak_right : dt.time, optional (default: midnight of following day) + End time of peak period on days that have a peak period (right-bound, excl). + isoweekdays : Iterable[int], optional (default: Monday through Friday) + Which days of the week have a peak period. (1=Monday, 7=Sunday) + + Returns + ------- + PeakhourFunction + That takes a DatetimeIndex input and returns a Series of booleans with that index, + indicating for each timestamp if it is part of the peak period or not. + + Notes + ----- + The values for ``peak_left`` and ``peak_right`` are used to determine the longest + frequency for which the function makes sense. This is the longest frequency of which + the timestamps are either entirely peak or entirely offpeak. + - If one of them does not fall on the full hour (but on a full quarter-hour), e.g. + 07:30, the function can only be used for indices with quarterhour frequency (as + there are some hours which are partly peak and partly offpeak). + - If they are both full hours, e.g. 08:00, the function can be used for indices with + quarterhourly and hourly frequency. + - If they are both None, each day is entirely peak or entirely offpeak. The function + can be used for indices with a daily frequency or shorter. + """ + if peak_left is None: + peak_left = MIDNIGHT + if peak_right is None: + peak_right = MIDNIGHT + if isoweekdays is None: + isoweekdays = [1, 2, 3, 4, 5] + + # Characterize the input. + must_check_time = not (peak_left == MIDNIGHT and peak_right == MIDNIGHT) + weekday_count = sum(wd in isoweekdays for wd in (1, 2, 3, 4, 5, 6, 7)) + must_check_date = 0 < weekday_count < 7 + if not must_check_time and not must_check_date: + raise ValueError( + "Input specifies no special cases; all time periods included or all time periods " + f"excluded; got {peak_left}-{peak_right} on {weekday_count} days of the week." + ) + + # Find longest frequency for which peak and offpeak can be calculated + if not must_check_time: + longest_freq = "D" + elif peak_left.minute == 0 and peak_right.minute == 0: + longest_freq = "H" + elif peak_left.minute % 15 == 0 and peak_right.minute % 15 == 0: + longest_freq = "15T" + else: + raise ValueError( + f"Input specifies times that are not 'round' quarter-hours; got {peak_left} and {peak_right}." + ) + + def filter_date(i: pd.DatetimeIndex) -> np.ndarray: + return i.map(lambda ts: ts.isoweekday() in isoweekdays).values.astype(bool) + + def filter_time(i: pd.DatetimeIndex) -> np.ndarray: + time_left = i.time + time_right = tools_right.index(i).time + mask = True + if peak_left != MIDNIGHT: + cond1 = time_left >= peak_left + cond2 = time_right > peak_left + if any(offenders := ~cond1 & cond2): + raise ValueError( + f"Found timestamps that are partly peak and partly offpeak: {i[offenders]}" + ) + mask &= cond1 + if peak_right != MIDNIGHT: + cond1 = time_left < peak_right + cond2 = time_right <= peak_right + if any(offenders := cond1 & ~cond2): + raise ValueError( + f"Found timestamps that are partly peak and partly offpeak: {i[offenders]}" + ) + mask &= cond1 + return mask + + def peak_fn(i: pd.DatetimeIndex) -> pd.Series: + # Check if function works for this frequency. + if tools_freq.up_or_down(i.freq, longest_freq) > 0: + raise ValueError( + f"Peak periods can only be calculated for indices with frequency of {longest_freq} or shorter." + ) + mask = True + if must_check_time: + mask &= filter_time(i) + if must_check_date: + mask &= filter_date(i) + return pd.Series(mask, i) + + return peak_fn + + +def base_duration(i: pd.DatetimeIndex) -> pd.Series: + """ + Duration of base periods in each element of a datetimeindex. + + Parameters + ---------- + i : pd.DatetimeIndex + Index for which to calculate the duration of the base product (= total duration) + + Returns + ------- + Series + with ``i`` as index, and duration of base hours during each timeperiod in ``i``. + """ + return tools_duration.index(i) + + +def peak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series: + """ + Duration of peak periods in each element of a datetimeindex. + + Parameters + ---------- + i : pd.DatetimeIndex + Index for which to calculate the durations. + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. + + Returns + ------- + Series + with ``i`` as index, and duration of peak hours during each timeperiod in ``i``. + + Notes + ----- + ``peak_fn`` might only work on indices with daily-or-shorter, hourly-or-shorter, or + quarterhourly-or-shorter frequency. ``i`` is resampled to account for this. + """ + eval_i = i # index to evaluate if peak or offpeak + for eval_freq in ("D", "H", "15T"): + if tools_freq.up_or_down(eval_i.freq, eval_freq) > 0: # upsampling necessary + eval_i = tools_changefreq.index(eval_i, eval_freq) + try: + eval_bool = peak_fn(eval_i) # boolean series + except ValueError: + pass # maybe we need to upsample more + else: + eval_duration = eval_bool * tools_duration.index(eval_i) # pint-series + return tools_changefreq.summable(eval_duration, i.freq).rename("duration") + + # Couldn't determine the duration. + raise ValueError( + "Couldn't calculate the duration of the peak period for the provided index." + ) + + +def offpeak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series: + """ + Duration of offpeak periods in each element of a datetimeindex. + + Parameters + ---------- + i : pd.DatetimeIndex + Index for which to calculate the durations. + peak_fn : PeakFunction + Function that returns boolean Series indicating if timestamps in index lie in peak period. + + Returns + ------- + Series + with ``i`` as index, and duration of offpeak hours during each timeperiod in ``i``. + + Notes + ----- + ``peak_fn`` might only work on indices with daily-or-shorter, hourly-or-shorter, or + quarterhourly-or-shorter frequency. ``i`` is resampled to account for this. + """ + return tools_duration.index(i) - peak_duration(i, peak_fn) + + +# def bpo_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.DataFrame: +# """ +# Duration of base, peak, and offpeak periods in each element of a datetimeindex. +# +# Parameters +# ---------- +# i : pd.DatetimeIndex +# Index for which to calculate the durations. +# peak_fn : PeakFunction +# Function that returns boolean Series indicating if timestamps in index lie in peak period. +# +# Returns +# ------- +# DataFrame +# with ``i`` as index, and columns 'base', 'peak', 'offpeak', with resp. durations +# in each timeperiod in ``i``. +# +# Notes +# ----- +# ``peak_fn`` might only work on indices with daily-or-shorter, hourly-or-shorter, or +# quarterhourly-or-shorter frequency. ``i`` is resampled to account for this. +# """ +# b = tools_duration.index(i) # pint-series +# p = peak_duration(i, peak_fn) # pint-series +# return pd.DataFrame({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") diff --git a/portfolyo/tools/peakperiod.py b/portfolyo/tools/peakperiod.py deleted file mode 100644 index 3ce1bf1..0000000 --- a/portfolyo/tools/peakperiod.py +++ /dev/null @@ -1,119 +0,0 @@ -""" -Module to work with peak and offpeak hours. -""" -import datetime as dt -from typing import Callable, Iterable - -import numpy as np -import pandas as pd - -from . import freq as tools_freq -from . import right as tools_right - -PeakFunction = Callable[[pd.DatetimeIndex], pd.Series] - - -def factory( - peak_left: dt.time = None, - peak_right: dt.time = None, - isoweekdays: Iterable[int] = None, -) -> PeakFunction: - """Create function to identify which timestamps in an index are peakhours and which are offpeak. - - Parameters - ---------- - peak_left : dt.time, optional (default: midnight) - Start time of peak period on days that have a peak period (left-bound, incl). - peak_right : dt.time, optional (default: midnight of following day) - End time of peak period on days that have a peak period (right-bound, excl). - isoweekdays : Iterable[int], optional (default: Monday through Friday) - Which days of the week have a peak period. (1=Monday, 7=Sunday) - - Returns - ------- - PeakhourFunction - That takes a DatetimeIndex input and returns a Series of booleans with that index, - indicating for each timestamp if it is part of the peak period or not. - - Notes - ----- - The values for ``peak_left`` and ``peak_right`` are used to determine the longest - frequency for which the function makes sense. This is the longest frequency of which - the timestamps are either entirely peak or entirely offpeak. - - If one of them does not fall on the full hour (but on a full quarter-hour), e.g. - 07:30, the function can only be used for indices with quarterhour frequency (as - there are some hours which are partly peak and partly offpeak). - - If they are both full hours, e.g. 08:00, the function can be used for indices with - quarterhourly and hourly frequency. - - If they are both None, each day is entirely peak or entirely offpeak. The function - can be used for indices with a daily frequency or shorter. - """ - midnight = dt.time(hour=0) - if peak_left is None: - peak_left = midnight - if peak_right is None: - peak_right = midnight - if isoweekdays is None: - isoweekdays = [1, 2, 3, 4, 5] - - # Characterize the input. - check_time = not (peak_left == midnight and peak_right == midnight) - weekday_count = sum(wd in isoweekdays for wd in (1, 2, 3, 4, 5, 6, 7)) - check_date = 0 < weekday_count < 7 - if not check_time and not check_date: - raise ValueError( - "Input specifies no special cases; all time periods included or all time periods " - f"excluded; got {peak_left}-{peak_right} on {weekday_count} days of the week." - ) - - # Find longest frequency for which peak and offpeak can be calculated - if not check_time: - longest_freq = "D" - elif peak_left.minute == 0 and peak_right.minute == 0: - longest_freq = "H" - elif peak_left.minute % 15 == 0 and peak_right.minute % 15 == 0: - longest_freq = "15T" - else: - raise ValueError( - f"Input specifies times that are not 'round' quarter-hours; got {peak_left} and {peak_right}." - ) - - def filter_date(i: pd.DatetimeIndex) -> np.ndarray: - return i.map(lambda ts: ts.isoweekday() in isoweekdays).values.astype(bool) - - def filter_time(i: pd.DatetimeIndex) -> np.ndarray: - time_left = i.time - time_right = tools_right.index(i).time - mask = True - if peak_left != midnight: - cond1 = time_left >= peak_left - cond2 = time_right > peak_left - if any(offenders := ~cond1 & cond2): - raise ValueError( - f"Found timestamps that are partly peak and partly offpeak: {i[offenders]}" - ) - mask &= cond1 - if peak_right != midnight: - cond1 = time_left < peak_right - cond2 = time_right <= peak_right - if any(offenders := cond1 & ~cond2): - raise ValueError( - f"Found timestamps that are partly peak and partly offpeak: {i[offenders]}" - ) - mask &= cond1 - return mask - - def is_peakhour(i: pd.DatetimeIndex) -> pd.Series: - # Check if function works for this frequency. - if tools_freq.up_or_down(i.freq, longest_freq) > 0: - raise ValueError( - f"Peak periods can only be calculated for indices with frequency of {longest_freq} or shorter." - ) - mask = True - if check_time: - mask &= filter_time(i) - if check_date: - mask &= filter_date(i) - return pd.Series(mask, i) - - return is_peakhour diff --git a/portfolyo/tools/prices/__init__.py b/portfolyo/tools/prices/__init__.py deleted file mode 100644 index 99a9527..0000000 --- a/portfolyo/tools/prices/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from . import convert diff --git a/portfolyo/tools/prices/convert.py b/portfolyo/tools/prices/convert.py.bak similarity index 86% rename from portfolyo/tools/prices/convert.py rename to portfolyo/tools/prices/convert.py.bak index 0bfe732..1f05af2 100644 --- a/portfolyo/tools/prices/convert.py +++ b/portfolyo/tools/prices/convert.py.bak @@ -12,15 +12,15 @@ import datetime as dt import warnings -from typing import Iterable, Union +from typing import Union import numpy as np import pandas as pd -from .. import unit as tools_unit -from .. import trim as tools_trim -from .. import freq as tools_freq from .. import changefreq as tools_changefreq +from .. import freq as tools_freq +from .. import trim as tools_trim +from .. import unit as tools_unit from . import utils Stamp = Union[dt.datetime, pd.Timestamp] @@ -52,76 +52,6 @@ def group_function(freq: str, po: bool = False): ) -def offpeak( - base: Union[Value, Iterable[Value]], - peak: Union[Value, Iterable[Value]], - ts_left: Union[Stamp, Iterable[Stamp]], - freq: str = None, -) -> Union[Value, pd.Series]: - """Offpeak value, given base and peak value and time interval they apply to. - - Parameters - ---------- - base : Union[Value, Iterable[Value]] - Base value - peak : Union[Value, Iterable[Value]] - Peak value - ts_left : Union[Stamp, Iterable[Stamp]] - (Left-bound) timestamp of period. - freq : {'MS' (month), 'QS' (quarter), 'AS' (year)}, optional - Length of delivery period. If none specified, use ``.freq`` attribute of - ``ts_left``. - - Returns - ------- - offpeak value(s) - """ - fr = utils.duration_bpo(ts_left, freq) # Series or DataFrame - b, p, o = fr["base"], fr["peak"], fr["offpeak"] - if isinstance(fr, pd.DataFrame): - b, p, o = b.values, p.values, o.values - return (base * b - peak * p) / o - - -def peak( - base: Union[Value, Iterable[Value]], - offpeak: Union[Value, Iterable[Value]], - ts_left: Union[Stamp, Iterable[Stamp]], - freq: str = None, -) -> Union[Value, pd.Series]: - """Peak value, given base and offpeak value and time interval they apply to. - - See also - -------- - .offpeak - """ - fr = utils.duration_bpo(ts_left, freq) # Series or DataFrame - b, p, o = fr["base"], fr["peak"], fr["offpeak"] - if isinstance(fr, pd.DataFrame): - b, p, o = b.values, p.values, o.values - - return (base * b - offpeak * o) / p - - -def base( - peak: Union[Value, Iterable[Value]], - offpeak: Union[Value, Iterable[Value]], - ts_left: Union[Stamp, Iterable[Stamp]], - freq: str = None, -) -> Union[Value, pd.Series]: - """Base value, given peak and offpeak value and time interval they apply to. - - See also - -------- - .offpeak - """ - fr = utils.duration_bpo(ts_left, freq) # Series or DataFrame - b, p, o = fr["base"], fr["peak"], fr["offpeak"] - if isinstance(fr, pd.DataFrame): - b, p, o = b.values, p.values, o.values - return (peak * p + offpeak * o) / b - - def complete_bpoframe(partial_bpoframe: pd.DataFrame, prefix: str = "") -> pd.DataFrame: """ Add missing information to bpoframe (Dataframe with base, peak, offpeak values). @@ -308,7 +238,7 @@ def tseries2bpoframe(s: pd.Series, freq: str = "MS", prefix: str = "") -> pd.Dat # Handle possible units. sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) - # Do calculations. Use normal mean, because all rows have same duration. + # Do calculations. sout = sin.resample(freq, group_keys=True).apply( lambda s: tseries2singlebpo(s, prefix) ) diff --git a/portfolyo/tools/prices/hedge.py b/portfolyo/tools/prices/hedge.py deleted file mode 100644 index cbb46be..0000000 --- a/portfolyo/tools/prices/hedge.py +++ /dev/null @@ -1,146 +0,0 @@ -"""Functionality to hedge an offtake profile with a price profile.""" - -from typing import Tuple - -import pandas as pd - -from ... import tools -from . import convert, utils - - -def _hedge(df: pd.DataFrame, how: str, po: bool) -> pd.Series: - """ - Hedge a power timeseries, for given price timeseries. - - Parameters - ---------- - df : pd.DataFrame - with 'w' [MW] and 'p' [Eur/MWh] columns. - how : str. One of {'vol', 'val'} - Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. - po : bool - Set to True to split hedge into peak and offpeak values. (Only sensible - for timeseries with freq=='H' or shorter.) - - Returns - ------- - pd.Series - With float values or quantities. - If po==False, Series with index ['w', 'p'] (power and price in entire period). - If po==True, Series with multiindex ['peak', 'offpeak'] x ['w', 'p'] (power and - price, split between peak and offpeak intervals in the period.) - - Notes - ----- - If the index of `df` doesn't have a .duration attribute, all rows are assumed to be - of equal duration. - """ - - # Split into peak and offpeak. - - if po: - apply_f = lambda df: _hedge(df, how, po=False) # noqa - # s = df.groupby(utils.is_peak_hour).apply(apply_f) # calls group_f on EACH ts - is_peak_hour = utils.is_peak_hour(df.index) - s = df.groupby(is_peak_hour).apply(apply_f) # calls group_f on index - return s.rename(index={True: "peak", False: "offpeak"}).stack() - - # Don't split into peak and offpeak. - - if df.index.freq: - # Use magnitude only, so that, if w and p are float series, their return - # series are also floats (instead of dimensionless Quantities). - df["dur"] = df.index.duration.pint.m - else: - df["dur"] = 1 - - # Get single power and price values. - p_hedge = (df.p * df.dur).sum() / df.dur.sum() - if how == "vol": # volume hedge - # solve for w_hedge: sum (w * duration) == w_hedge * sum (duration) - w_hedge = (df.w * df.dur).sum() / df.dur.sum() - elif how == "val": # value hedge - # solve for w_hedge: sum (w * duration * p) == w_hedge * sum (duration * p) - w_hedge = (df.w * df.dur * df.p).sum() / (df.dur * df.p).sum() - else: - raise ValueError(f"Parameter `how` must be 'val' or 'vol'; got {how}.") - return pd.Series({"w": w_hedge, "p": p_hedge}) - - -def hedge( - w: pd.Series, - p: pd.Series, - how: str = "val", - freq: str = "MS", - po: bool = None, -) -> Tuple[pd.Series]: - """ - Make hedge of power timeseries, for given price timeseries. - - Parameters - ---------- - w : Series - Power timeseries with hourly or quarterhourly frequency. - p: Series - Price timeseries with same frequency. - how : str, optional (Default: 'val') - Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. - freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} - Frequency of hedging products. E.g. 'QS' to hedge with quarter products. - po : bool, optional - Type of hedging products. Set to True to split hedge into peak and offpeak. - (Default: split if volume timeseries has hourly values or shorter and hedging - products have monthly frequency or longer.) - - Returns - ------- - Tuple[pd.Series] - Power timeseries and price timeseries with hedge of `w` (with same index). - """ - if w.index.freq is None or p.index.freq is None: - raise ValueError( - "Parameters ``w`` and ``p`` must have a DatetimeIndex with a set frequency attribute." - ) - if w.index.freq != p.index.freq: - raise ValueError( - f"Parameters ``w`` and ``p`` must have same frequency; got {w.index.freq} and {p.index.freq}." - ) - if w.index.freq not in ["15T", "H", "D"]: - raise ValueError("Can only hedge a timeseries with daily (or shorter) values.") - if freq not in ["D", "MS", "QS", "AS"]: - raise ValueError( - f"Parameter ``freq`` must be one of 'D', 'MS', 'QS', 'AS'; got '{freq}'." - ) - if po is None: # default: split in peak/offpeak if frequency is short enough - po = w.index.freq in ["15T", "H"] and freq != "D" - if po and not (w.index.freq in ["15T", "H"] and freq != "D"): - raise ValueError( - "Split into peak and offpeak only possible when (a) hedging with monthly (or " - "longer) products, and (b) if timeseries have hourly (or shorter) values." - ) - - # Handle possible units. - win, wunits = (w.pint.magnitude, w.pint.units) if hasattr(w, "pint") else (w, None) - pin, punits = (p.pint.magnitude, p.pint.units) if hasattr(p, "pint") else (p, None) - - # Only keep full periods of overlapping timestamps. - i = win.index.intersection(pin.index) - df = tools.trim.frame(pd.DataFrame({"w": win, "p": pin}).loc[i, :], freq) - if len(df) == 0: - return df["w"], df["p"] # No full periods; don't do hedge; return empty series - - # Do actual hedge. - group_f = convert.group_function(freq, po) - grouped_i = pd.MultiIndex.from_arrays(group_f(df.index)) # calls group_f on index - apply_f = lambda df: _hedge(df, how, False) # noqa - # vals = df.groupby(group_f).apply(apply_f) # calls group_f on EACH ts - vals = df.groupby(grouped_i).apply(apply_f) - vals.index = pd.MultiIndex.from_tuples(vals.index) - for c in ["w", "p"]: - df[c] = df[c].groupby(grouped_i).transform(lambda gr: vals.loc[gr.name, c]) - - # Handle possible units. - if wunits or punits: - df = df.astype({"w": f"pint[{wunits:P}]", "p": f"pint[{punits:P}]"}) - - return df["w"], df["p"] diff --git a/portfolyo/tools/prices/utils.py b/portfolyo/tools/prices/utils.py deleted file mode 100644 index cdc17ce..0000000 --- a/portfolyo/tools/prices/utils.py +++ /dev/null @@ -1,190 +0,0 @@ -"""Utilities for calculating / manipulating price data.""" - -import datetime as dt -import warnings -from typing import Tuple, Union - -import pandas as pd - -from ... import tools -from ...tools.unit import Q_ - -german_peakperiod = tools.peakperiod.factory(dt.time(8), dt.time(20), [1, 2, 3, 4, 5]) - - -def is_peak_hour( - ts_left: Union[pd.Timestamp, pd.DatetimeIndex] -) -> Union[bool, pd.Series]: - """ - Boolean value indicating if a timestamp is in a peak period or not. - - Parameters - ---------- - ts_left : Union[pd.Timestamp, pd.DatetimeIndex] - Timestamp(s) for which to calculate if it falls in a peak period. - - More precisely: if timestamp lies in one of the (left-closed) time intervals that - define the peak hour periods. - - Returns - ------- - bool (if ts_left is Timestamp) or Series (if ts_left is DatetimeIndex). - """ - if isinstance(ts_left, pd.Timestamp): - warnings.warn( - "Calling this function with a single timestamp is deprecated and will be removed in a future version", - FutureWarning, - ) - return is_peak_hour(pd.DatetimeIndex([ts_left], freq="15T"))[0] - - return german_peakperiod(ts_left) - - -def duration_base( - ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -) -> Union[Q_, pd.Series]: - """ - Total duration of base periods in a timestamp. - - See also - -------- - .tools.duration - """ - if isinstance(ts_left, pd.DatetimeIndex): - hours = (duration_base(ts, freq) for ts in ts_left) # has unit - return pd.Series(hours, ts_left, dtype="pint[h]") - - # Assume it's a single timestamp. - return tools.duration.stamp(ts_left, freq) - - -def duration_peak( - ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -) -> Union[Q_, pd.Series]: - """ - Total duration of peak periods in a timestamp. - - See also - -------- - .tools.duration - """ - if freq is None: - freq = ts_left.freq - - if freq not in tools.freq.FREQUENCIES: - raise ValueError( - f"Parameter ``freq`` must be one of {', '.join(tools.freq.FREQUENCIES)}; got {freq}." - ) - - if isinstance(ts_left, pd.DatetimeIndex): - if freq in ["15T", "H"]: - return tools.duration.index(ts_left, freq) * is_peak_hour(ts_left) - elif freq == "D": - hours = ts_left.map(lambda ts: ts.isoweekday() < 6) * 12.0 # no unit - return pd.Series(hours, ts_left, dtype="pint[h]") # works even during dst - else: - # dur = ts_left.map(duration_peak) # crashes due to behaviour of .map method - hours = (duration_peak(ts, freq) for ts in ts_left) # has unit - return pd.Series(hours, ts_left, dtype="pint[h]") - - # Assume it's a single timestamp. - if freq in ["15T", "H"]: - return tools.duration.stamp(ts_left, freq) * is_peak_hour(ts_left) - elif freq == "D": - return Q_(0.0 if ts_left.isoweekday() >= 6 else 12.0, "h") - else: - ts_right = tools.right.stamp(ts_left, freq) - days = pd.date_range(ts_left, ts_right, freq="D", inclusive="left") - return Q_(sum(days.map(lambda day: day.isoweekday() < 6) * 12.0), "h") - - -def duration_offpeak( - ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -) -> Union[Q_, pd.Series]: - """ - Total duration of offpeak periods in a timestamp. - - See also - -------- - .tools.duration - """ - return duration_base(ts_left, freq) - duration_peak(ts_left, freq) - - -def duration_bpo( - ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -) -> Union[pd.Series, pd.DataFrame]: - """ - Duration of base, peak and offpeak periods in a timestamp. - - Parameters - ---------- - ts_left : Union[pd.Timestamp, pd.DatetimeIndex] - Timestamp(s) for which to calculate the base, peak and offpeak durations. - freq : {'15T' (quarter-hour), 'H' (hour), 'D' (day), 'MS' (month), 'QS' (quarter), - 'AS' (year)}, optional - Frequency to use in determining the durations. - If none specified, use ``.freq`` attribute of ``ts_left``. - - Returns - ------- - Series (if ts_left is Timestamp) or DataFrame (if ts_left is DatetimeIndex). - """ - if freq is None and isinstance(ts_left, pd.DatetimeIndex): - freq = ts_left.freq - - b = duration_base(ts_left, freq) # quantity or pint-series - p = duration_peak(ts_left, freq) # quantity or pint-series - - if isinstance(ts_left, pd.DatetimeIndex): - return pd.DataFrame({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") - - # Assume it's a single timestamp. - return pd.Series({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") - - -def delivery_period( - ts_trade: pd.Timestamp, - period_type: str = "m", - front_count: int = 1, - start_of_day: dt.time = None, -) -> Tuple[pd.Timestamp]: - """ - Find start and end of delivery period. - - Parameters - ---------- - ts_trade : pd.Timestamp - Trading day. The time part of the timestamp is ignored and assumed to be after - the start_of_day of the market. - period_type : {'d' (day), 'm' (month, default), 'q' (quarter), 's' (season), 'a' (year)} - front_count : int, optional (default: 1) - 1 = next/coming (full) period, 2 = period after that, etc. - start_of_day : dt.time, optional (default: midnight) - Start of day for delivery periods with a longer-than-daily frequency. - - Returns - ------- - (pd.Timestamp, pd.Timestamp) - Left (inclusive) and right (exclusive) timestamp of delivery period. - """ - ts_trade = ts_trade.replace(hour=23, minute=59) # ensure after start_of_day - if period_type in ["m", "q", "a"]: - freq = period_type.upper() + "S" - ts_left = tools.floor.stamp(ts_trade, freq, front_count, start_of_day) - ts_right = tools.right.stamp(ts_left, freq) - elif period_type == "d": - ts_left = tools.floor.stamp(ts_trade, "D", front_count, start_of_day) - ts_right = tools.right.stamp(ts_left, "D") - elif period_type == "s": - front_count_q = front_count * 2 - 1 - ts_left, ts_right = delivery_period(ts_trade, "q", front_count_q, start_of_day) - ts_right = tools.right.stamp(ts_right, "QS") # make 6 months long - if ts_left.month % 2 == 1: # season must start on even month - ts_left = tools.right.stamp(ts_left, "QS") - ts_right = tools.right.stamp(ts_right, "QS") - else: - raise ValueError( - f"Parameter ``period_type`` must be one of 'd', 'm', 'q', 's', 'a'; got '{period_type}'." - ) - return ts_left, ts_right diff --git a/portfolyo/tools/product.py b/portfolyo/tools/product.py new file mode 100644 index 0000000..9faf61e --- /dev/null +++ b/portfolyo/tools/product.py @@ -0,0 +1,198 @@ +"""Utilities for calculating / manipulating price data.""" + +import datetime as dt +import warnings +from typing import Tuple + +import pandas as pd + +from . import floor as tools_floor +from . import peakfn as tools_peakfn +from . import right as tools_right + +germanpower_peakfn = tools_peakfn.factory(dt.time(8), dt.time(20), [1, 2, 3, 4, 5]) + + +def is_peak_hour(i: pd.DatetimeIndex) -> pd.Series: + """ + Calculate if a timestamp is in a peak period or not. + + Parameters + ---------- + i : pd.DatetimeIndex + Timestamps for which to calculate if it falls in a peak period. + + More precisely: if timestamp lies in one of the (left-closed) time intervals that + define the peak hour periods. + + Returns + ------- + Series + with boolean values and same index. + """ + if isinstance(i, pd.Timestamp): + raise TypeError("no longer supported") + warnings.warn( + "Calling this function with a single timestamp is deprecated and will be removed in a future version", + FutureWarning, + ) + return is_peak_hour(pd.DatetimeIndex([i], freq="15T"))[0] + + return germanpower_peakfn(i) + + +# def duration_base( +# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None +# ) -> Union[tools_unit.Q_, pd.Series]: +# """ +# Total duration of base periods in a timestamp. +# +# Parameters +# ---------- +# ts_left : pd.Timestamp | pd.DatetimeIndex +# Timestamp or index for which to calculate the duration. +# +# See also +# -------- +# .tools.duration +# """ +# if isinstance(ts_left, pd.DatetimeIndex): +# return tools_duration.index(ts_left) +# +# # Assume it's a single timestamp. +# return tools_duration.stamp(ts_left, freq) +# +# +# def duration_peak( +# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None +# ) -> Union[tools_unit.Q_, pd.Series]: +# """ +# Total duration of peak periods in a timestamp. +# +# See also +# -------- +# .tools.duration +# """ +# if freq is None: +# freq = ts_left.freq +# +# if freq not in tools_freq.FREQUENCIES: +# raise ValueError( +# f"Parameter ``freq`` must be one of {', '.join(tools_freq.FREQUENCIES)}; got {freq}." +# ) +# +# if isinstance(ts_left, pd.DatetimeIndex): +# if freq in ["15T", "H"]: +# return tools_duration.index(ts_left) * is_peak_hour(ts_left) +# elif freq == "D": +# hours = ts_left.map(lambda ts: ts.isoweekday() < 6) * 12.0 # no unit +# return pd.Series(hours, ts_left, dtype="pint[h]") # works even during dst +# else: +# # dur = ts_left.map(duration_peak) # crashes due to behaviour of .map method +# hours = (duration_peak(ts, freq) for ts in ts_left) # has unit +# return pd.Series(hours, ts_left, dtype="pint[h]") +# +# # Assume it's a single timestamp. +# if freq in ["15T", "H"]: +# return tools_duration.stamp(ts_left, freq) * is_peak_hour(ts_left) +# elif freq == "D": +# return tools_unit.Q_(0.0 if ts_left.isoweekday() >= 6 else 12.0, "h") +# else: +# ts_right = tools_right.stamp(ts_left, freq) +# days = pd.date_range(ts_left, ts_right, freq="D", inclusive="left") +# return tools_unit.Q_( +# sum(days.map(lambda day: day.isoweekday() < 6) * 12.0), "h" +# ) +# +# +# def duration_offpeak( +# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None +# ) -> Union[tools_unit.Q_, pd.Series]: +# """ +# Total duration of offpeak periods in a timestamp. +# +# See also +# -------- +# .tools.duration +# """ +# return duration_base(ts_left, freq) - duration_peak(ts_left, freq) +# +# +# def duration_bpo( +# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None +# ) -> Union[pd.Series, pd.DataFrame]: +# """ +# Duration of base, peak and offpeak periods in a timestamp. +# +# Parameters +# ---------- +# ts_left : Union[pd.Timestamp, pd.DatetimeIndex] +# Timestamp(s) for which to calculate the base, peak and offpeak durations. +# freq : {'15T' (quarter-hour), 'H' (hour), 'D' (day), 'MS' (month), 'QS' (quarter), +# 'AS' (year)}, optional +# Frequency to use in determining the durations. +# If none specified, use ``.freq`` attribute of ``ts_left``. +# +# Returns +# ------- +# Series (if ts_left is Timestamp) or DataFrame (if ts_left is DatetimeIndex). +# """ +# if freq is None and isinstance(ts_left, pd.DatetimeIndex): +# freq = ts_left.freq +# +# b = duration_base(ts_left, freq) # quantity or pint-series +# p = duration_peak(ts_left, freq) # quantity or pint-series +# +# if isinstance(ts_left, pd.DatetimeIndex): +# return pd.DataFrame({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") +# +# # Assume it's a single timestamp. +# return pd.Series({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") +# # + + +def delivery_period( + ts_trade: pd.Timestamp, + period_type: str = "m", + front_count: int = 1, + start_of_day: dt.time = None, +) -> Tuple[pd.Timestamp, pd.Timestamp]: + """ + Find start and end of delivery period. + + Parameters + ---------- + ts_trade : pd.Timestamp + Trading day. The time part of the timestamp is ignored and assumed to be after + the start_of_day of the market. + period_type : {'d' (day), 'm' (month, default), 'q' (quarter), 's' (season), 'a' (year)} + front_count : int, optional (default: 1) + 1 = next/coming (full) period, 2 = period after that, etc. + start_of_day : dt.time, optional (default: midnight) + Start of day for delivery periods with a longer-than-daily frequency. + + Returns + ------- + (pd.Timestamp, pd.Timestamp) + Left (inclusive) and right (exclusive) timestamp of delivery period. + """ + ts_trade = ts_trade.replace(hour=23, minute=59) # ensure after start_of_day + if period_type in ["m", "q", "a"]: + freq = period_type.upper() + "S" + ts_left = tools_floor.stamp(ts_trade, freq, front_count, start_of_day) + ts_right = tools_right.stamp(ts_left, freq) + elif period_type == "d": + ts_left = tools_floor.stamp(ts_trade, "D", front_count, start_of_day) + ts_right = tools_right.stamp(ts_left, "D") + elif period_type == "s": + front_count_q = front_count * 2 - 1 + ts_left, ts_right = delivery_period(ts_trade, "q", front_count_q, start_of_day) + ts_right = tools_right.stamp(ts_right, "QS") # make 6 months long + if ts_left.month % 2 == 1: # season must start on even month + ts_left = tools_right.stamp(ts_left, "QS") + ts_right = tools_right.stamp(ts_right, "QS") + else: + raise ValueError( + f"Parameter ``period_type`` must be one of 'd', 'm', 'q', 's', 'a'; got '{period_type}'." + ) + return ts_left, ts_right diff --git a/portfolyo/tools/testing.py b/portfolyo/tools/testing.py index 1844e92..b3a9933 100644 --- a/portfolyo/tools/testing.py +++ b/portfolyo/tools/testing.py @@ -6,6 +6,7 @@ import numpy as np import pandas as pd import pint + from . import unit as tools_unit diff --git a/portfolyo/tools/trim.py b/portfolyo/tools/trim.py index 01f8ca9..2322f86 100644 --- a/portfolyo/tools/trim.py +++ b/portfolyo/tools/trim.py @@ -2,7 +2,7 @@ Trim objects to only contain 'full' delivery periods. """ -from typing import Union +from typing import overload import pandas as pd @@ -47,21 +47,29 @@ def index(i: pd.DatetimeIndex, freq: str) -> pd.DatetimeIndex: return i[mask_start & mask_end] -def frame( - fr: Union[pd.Series, pd.DataFrame], freq: str -) -> Union[pd.Series, pd.DataFrame]: +@overload +def frame(fr: pd.Series, freq: str) -> pd.Series: + ... + + +@overload +def frame(fr: pd.DataFrame, freq: str) -> pd.DataFrame: + ... + + +def frame(fr: pd.Series | pd.DataFrame, freq: str) -> pd.Series | pd.DataFrame: f"""Trim index of series or dataframe to only keep full periods of certain frequency. Parameters ---------- - fr : Union[pd.Series, pd.DataFrame] + fr : Series or DataFrame The (untrimmed) pandas series or dataframe. freq : {{{', '.join(tools_freq.FREQUENCIES)}}} Frequency to trim to. E.g. 'MS' to only keep full months. Returns ------- - Union[pd.Series, pd.DataFrame] + Series or DataFrame Subset of ``fr``, with same frequency. Notes diff --git a/portfolyo/tools/types.py b/portfolyo/tools/types.py new file mode 100644 index 0000000..5e9ba5d --- /dev/null +++ b/portfolyo/tools/types.py @@ -0,0 +1,7 @@ +"""Help the type checker.""" + +from typing import TypeVar + +import pandas as pd + +Series_or_DataFrame = TypeVar("Series_or_DataFrame", pd.Series, pd.DataFrame) diff --git a/portfolyo/tools/visualize/__init__.py b/portfolyo/tools/visualize/__init__.py index c678a33..bfbe431 100644 --- a/portfolyo/tools/visualize/__init__.py +++ b/portfolyo/tools/visualize/__init__.py @@ -1,5 +1,6 @@ from .colors import Color, Colors from .plot import ( + PlotTimeseriesToAxFunction, plot_timeseries_as_area, plot_timeseries_as_bar, plot_timeseries_as_hline, diff --git a/portfolyo/tools/visualize/categories.py b/portfolyo/tools/visualize/categories.py index e21a9c8..2ebff9c 100644 --- a/portfolyo/tools/visualize/categories.py +++ b/portfolyo/tools/visualize/categories.py @@ -3,6 +3,7 @@ import numpy as np import pandas as pd + from .. import unit as tools_unit diff --git a/portfolyo/tools/visualize/colors.py b/portfolyo/tools/visualize/colors.py index 20c27c4..3a86c12 100644 --- a/portfolyo/tools/visualize/colors.py +++ b/portfolyo/tools/visualize/colors.py @@ -1,8 +1,8 @@ """Creating colors for use in plotting.""" import colorsys -from enum import Enum from collections import namedtuple +from enum import Enum import matplotlib as mpl import numpy as np diff --git a/portfolyo/tools/visualize/plot.py b/portfolyo/tools/visualize/plot.py index 3204277..5d59d78 100644 --- a/portfolyo/tools/visualize/plot.py +++ b/portfolyo/tools/visualize/plot.py @@ -8,10 +8,10 @@ import pandas as pd from matplotlib import pyplot as plt +from .. import freq as tools_freq from .. import unit as tools_unit +from .categories import Categories from .colors import Colors -from .. import freq as tools_freq -from .categories import Categories, Category # noqa mpl.style.use("seaborn-v0_8") diff --git a/portfolyo/tools2/changeyear.py b/portfolyo/tools2/changeyear.py new file mode 100644 index 0000000..b3274ab --- /dev/null +++ b/portfolyo/tools2/changeyear.py @@ -0,0 +1,79 @@ +"""Map series with quarterhourly, hourly, or daily values onto another index or year, +trying to align weekdays, holidays, and dst-changeover days. Always takes values from +same calender month (but different year).""" + +import warnings + +from .. import tools +from ..core.pfline import Kind, PfLine, Structure + + +def map_to_year(pfl: PfLine, year: int, holiday_country: str) -> PfLine: + """Transfer the data to a hypothetical other year. + + Parameters + ---------- + pfl : PfLine + Portfolio line that must be mapped. + year : int + Year to transfer the data to. + holiday_country : str, optional (default: None) + Country or region for which to assume the holidays. E.g. 'DE' (Germany), 'NL' + (Netherlands), or 'USA'. See ``holidays.list_supported_countries()`` for + allowed values. + + Returns + ------- + PfLine + + Notes + ----- + Useful for daily (and shorter) data. Copies over the data but takes weekdays (and + holidays) of target year into consideration. See ``portfolyo.map_frame_as_year()`` + for more information. + Inaccurate for monthly data and longer, because we only have one value per month, + and can therefore not take different number of holidays/weekends (i.e., offpeak + hours) into consideration. + """ + + # Guard clause. + if tools.freq.shortest(pfl.index.freq, "MS") == "MS": + warnings.warn( + "This PfLine has a monthly frequency or longer; changing the year is inaccurate, as" + " details (number of holidays, weekends, offpeak hours, etc) cannot be taken into account." + ) + + # Do mapping. + + if pfl.structure is Structure.NESTED: + return PfLine( + { + name: map_to_year(child, year, holiday_country) + for name, child in pfl.items() + } + ) + + # pfl is FlatPfLine. + + if pfl.kind is Kind.VOLUME: + df = pfl.dataframe( + "w" + ) # Averageble data to allow mapping unequal-length periods + df2 = tools.changeyear.map_frame_to_year(df, year, holiday_country) + elif pfl.kind is Kind.PRICE: + df = pfl.dataframe( + "p" + ) # Averageble data to allow mapping unequal-length periods + df2 = tools.changeyear.map_frame_to_year(df, year, holiday_country) + elif pfl.kind is Kind.REVENUE: + # Assume that revenue is scales proportionately with duration of period. + # E.g. 290 Eur in leapyear Feb --> 280 Eur in non-leapyear Feb. + df = pfl.dataframe("r") + df *= tools.duration.index(df.index) # Make averageble + df2 = tools.changeyear.map_frame_to_year(df, year, holiday_country) + df2 /= tools.duration.index(df2.index) # Make summable again + else: # CompletePfLine + df = pfl.dataframe(["w", "p"]) # Averagable + df2 = tools.changeyear.map_frame_to_year(df, year, holiday_country) + + return PfLine(df2) diff --git a/portfolyo/tools2/concat.py b/portfolyo/tools2/concat.py index 10b797f..ff13e1b 100644 --- a/portfolyo/tools2/concat.py +++ b/portfolyo/tools2/concat.py @@ -1,15 +1,16 @@ # import pandas as pd # import portfolyo as pf from __future__ import annotations + from typing import Iterable -import pandas as pd -from .. import tools -from ..core.pfstate import PfState -from ..core.pfline.enums import Structure +import pandas as pd -from ..core.pfline import PfLine, create +from .. import tools from ..core import pfstate +from ..core.pfline import PfLine, create +from ..core.pfline.enums import Structure +from ..core.pfstate import PfState def general(pfl_or_pfs: Iterable[PfLine | PfState]) -> None: diff --git a/portfolyo/tools2/intersect.py b/portfolyo/tools2/intersect.py index 43f74a5..a8b50a1 100644 --- a/portfolyo/tools2/intersect.py +++ b/portfolyo/tools2/intersect.py @@ -1,10 +1,11 @@ -from ..tools.intersect import indices_flex -from ..core.pfline import PfLine -from ..core.pfstate import PfState from typing import List, Union import pandas as pd +from ..core.pfline import PfLine +from ..core.pfstate import PfState +from ..tools.intersect import indices_flex + def indexable( *frames: Union[pd.Series, pd.DataFrame, PfLine, PfState], diff --git a/portfolyo/tools2/plot.py b/portfolyo/tools2/plot.py index 8d4bf9b..9117b36 100644 --- a/portfolyo/tools2/plot.py +++ b/portfolyo/tools2/plot.py @@ -6,12 +6,10 @@ import numpy as np from matplotlib import pyplot as plt -from ..core.pfline.plot import defaultkwargs - from .. import tools -from ..tools import visualize as vis - +from ..core.pfline.plot import defaultkwargs from ..core.pfstate import PfState +from ..tools import visualize as vis def plot_pfstates(dic: Dict[str, PfState], freq: str = "MS") -> plt.Figure: diff --git a/tests/core/pfline/test_pfline_excelclipboard.py b/tests/core/pfline/test_pfline_excelclipboard.py index 08c0829..f6b092f 100644 --- a/tests/core/pfline/test_pfline_excelclipboard.py +++ b/tests/core/pfline/test_pfline_excelclipboard.py @@ -1,9 +1,9 @@ """Test if portfolio line can be exported.""" +import pandas as pd import pytest import portfolyo as pf -import pandas as pd @pytest.mark.parametrize("levels", [1, 2, 3]) diff --git a/tests/core/pfline/test_pfline_text.py b/tests/core/pfline/test_pfline_text.py index 5f8c980..5e62e82 100644 --- a/tests/core/pfline/test_pfline_text.py +++ b/tests/core/pfline/test_pfline_text.py @@ -1,6 +1,7 @@ """Test if portfolio line can be printed.""" import pytest + import portfolyo as pf diff --git a/tests/core/pfline/test_slice.py b/tests/core/pfline/test_slice.py index 63447d2..87b8f6e 100644 --- a/tests/core/pfline/test_slice.py +++ b/tests/core/pfline/test_slice.py @@ -1,7 +1,8 @@ """Test if slice attributes works properly with portfolio line.""" -import pytest import pandas as pd +import pytest + from portfolyo import dev diff --git a/tests/core/pfstate/test_pfstate_excelclipboard.py b/tests/core/pfstate/test_pfstate_excelclipboard.py index d2a2a47..61b3853 100644 --- a/tests/core/pfstate/test_pfstate_excelclipboard.py +++ b/tests/core/pfstate/test_pfstate_excelclipboard.py @@ -1,8 +1,9 @@ """Test if portfolio line can be exported.""" +import pandas as pd import pytest + import portfolyo as pf -import pandas as pd def test_pfstate_toexcel(): diff --git a/tests/core/pfstate/test_slice_state.py b/tests/core/pfstate/test_slice_state.py index 7a472c3..a3e0e0c 100644 --- a/tests/core/pfstate/test_slice_state.py +++ b/tests/core/pfstate/test_slice_state.py @@ -1,7 +1,8 @@ """Test if slice attributes works properly with portfolio state.""" -import pytest import pandas as pd +import pytest + from portfolyo import dev diff --git a/tests/tools/test_peakperiod.py b/tests/tools/test_peakfn.py similarity index 70% rename from tests/tools/test_peakperiod.py rename to tests/tools/test_peakfn.py index 4aa4066..7f97aa2 100644 --- a/tests/tools/test_peakperiod.py +++ b/tests/tools/test_peakfn.py @@ -15,7 +15,7 @@ def index(start: str, end: str, freq: str, tz: str) -> pd.DatetimeIndex: return pd.date_range(start, end, freq=freq, inclusive="left", tz=tz) -f_germanpower = tools.peakperiod.factory(dt.time(hour=8), dt.time(hour=20)) +f_germanpower = tools.peakfn.factory(dt.time(hour=8), dt.time(hour=20)) TESTCASES_GERMANPOWER = [ # end, freq, count, stretch ("2020-01-08", "15T", 5 * 12 * 4, (32, 79)), ("2020-01-08", "H", 5 * 12, (8, 19)), @@ -29,7 +29,7 @@ def index(start: str, end: str, freq: str, tz: str) -> pd.DatetimeIndex: ("2021", "AS", ValueError, None), ] -f_everyday_13half = tools.peakperiod.factory( +f_everyday_13half = tools.peakfn.factory( dt.time(hour=8), dt.time(hour=21, minute=30), [1, 2, 3, 4, 5, 6, 7] ) TESTCASES_13HALF = [ # end, freq, count, stretch @@ -43,7 +43,7 @@ def index(start: str, end: str, freq: str, tz: str) -> pd.DatetimeIndex: ("2021", "AS", ValueError, None), ] -f_workingdays_full = tools.peakperiod.factory(None, None, [1, 2, 3, 4, 5]) +f_workingdays_full = tools.peakfn.factory(None, None, [1, 2, 3, 4, 5]) TESTCASES_WORKINGDAYS = [ # end, freq, count, stretch ("2020-01-08", "15T", 5 * 24 * 4, (0, 72 * 4 - 1)), ("2020-01-08", "H", 5 * 24, (0, 72 - 1)), @@ -59,9 +59,7 @@ def index(start: str, end: str, freq: str, tz: str) -> pd.DatetimeIndex: ("2021", "AS", ValueError, None), ] -f_everyday_until6 = tools.peakperiod.factory( - None, dt.time(hour=6), [1, 2, 3, 4, 5, 6, 7] -) +f_everyday_until6 = tools.peakfn.factory(None, dt.time(hour=6), [1, 2, 3, 4, 5, 6, 7]) TESTCASES_EVERYDAY6 = [ # month, freq, tz, count, stretch (1, "15T", None, 31 * 6 * 4, (24 * 4, 30 * 4 - 1)), (1, "15T", "Europe/Berlin", 31 * 6 * 4, (24 * 4, 30 * 4 - 1)), @@ -111,14 +109,14 @@ def test_functioncreation( """Test if an error is raised when creating impossible functions.""" if type(expected) is type and issubclass(expected, Exception): with pytest.raises(expected): - tools.peakperiod.factory(peak_left, peak_right, isoweekdays) + tools.peakfn.factory(peak_left, peak_right, isoweekdays) else: - tools.peakperiod.factory(peak_left, peak_right, isoweekdays) + tools.peakfn.factory(peak_left, peak_right, isoweekdays) @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize(("end", "freq", "count", "stretch"), TESTCASES_GERMANPOWER) -def test_peakperiod_germanpower( +def test_peakfn_germanpower( end: str, freq: str, tz: str, count: int, stretch: Iterable[int] ): """Test if the peak periods are correctly calculated.""" @@ -129,7 +127,7 @@ def test_peakperiod_germanpower( @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize(("end", "freq", "count", "stretch"), TESTCASES_13HALF) -def test_peakperiod_everyday13half( +def test_peakfn_everyday13half( end: str, freq: str, tz: str, count: int, stretch: Iterable[int] ): """Test if the peak periods are correctly calculated.""" @@ -140,7 +138,7 @@ def test_peakperiod_everyday13half( @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) @pytest.mark.parametrize(("end", "freq", "count", "stretch"), TESTCASES_WORKINGDAYS) -def test_peakperiod_workingdaysfull( +def test_peakfn_workingdaysfull( end: str, freq: str, tz: str, count: int, stretch: Iterable[int] ): """Test if the peak periods are correctly calculated.""" @@ -152,7 +150,7 @@ def test_peakperiod_workingdaysfull( @pytest.mark.parametrize( ("month", "freq", "tz", "count", "stretch"), TESTCASES_EVERYDAY6 ) -def test_peakperiod_everydayuntil6( +def test_peakfn_everydayuntil6( month: int, tz: str, freq: str, count: int, stretch: Iterable[int] ): """Test if the peak periods are correctly calculated.""" @@ -162,7 +160,7 @@ def test_peakperiod_everydayuntil6( def do_test( i: pd.DatetimeIndex, - f: tools.peakperiod.PeakFunction, + f: tools.peakfn.PeakFunction, count: int, stretch: Iterable[int] = None, ): @@ -182,3 +180,65 @@ def do_test( assert not peak.iloc[first - 1] if last != -1: assert not peak.iloc[last + 1] + + +@pytest.mark.parametrize(("tz", "mar_b_corr"), [(None, 0), ("Europe/Berlin", -1)]) +@pytest.mark.parametrize("month", [1, 2, 3]) +@pytest.mark.parametrize("freq", ["D", "MS", "QS", "AS"]) +@pytest.mark.parametrize( + ("year", "bp", "jan_1_weekday", "jan_p", "feb_p", "mar_p"), + [ + (2020, (366, 262), True, 23, 20, 22), + (2021, (365, 261), True, 21, 20, 23), + (2022, (365, 260), False, 21, 20, 23), + ], +) +def test_duration( + year, bp, jan_1_weekday, jan_p, feb_p, mar_p, tz, mar_b_corr, freq, month +): + """Test if the correct number of base, peak and offpeak hours are calculated. + bp = tuple with number of base days and days with peak hours; jan_p, feb_p, mar_p = + number of days with peak hours in each month; mar_b_corr = correction to number of + base HOURS.""" + + if tz is None: + return # TODO: make sure the duration_base, duration_peak etc functions accept timezone-agnostic data + + if month > 1 and freq != "MS": + return + + start = pd.Timestamp(f"{year}-{month}", tz=tz) + i = pd.date_range(start, freq=freq, periods=1) + + # Expected values. + if freq == "AS": + b = 24 * bp[0] + p = 12 * bp[1] + elif freq == "QS": + b = 24 * (31 + 28 + 31 + (bp[0] - 365)) + mar_b_corr + p = 12 * (jan_p + feb_p + mar_p) + elif freq == "MS": + if month == 1: + b = 24 * 31 + p = 12 * jan_p + elif month == 2: + b = 24 * (28 + (bp[0] - 365)) + p = 12 * feb_p + else: # month == 3: + b = 24 * 31 + mar_b_corr + p = 12 * mar_p + else: # freq == 'D' + b = 24 + p = 12 * jan_1_weekday + expected_b = pd.Series([float(b)], i, dtype="pint[h]", name="duration") + expected_p = pd.Series([float(p)], i, dtype="pint[h]", name="duration") + expected_o = expected_b - expected_p + + result_b = tools.peakfn.base_duration(i) + result_p = tools.peakfn.peak_duration(i, f_germanpower) + result_o = tools.peakfn.offpeak_duration(i, f_germanpower) + + # Test values. + tools.testing.assert_series_equal(expected_b, result_b) + tools.testing.assert_series_equal(expected_p, result_p) + tools.testing.assert_series_equal(expected_o, result_o) diff --git a/tests/tools/prices/test_utils.py b/tests/tools/test_product.py similarity index 54% rename from tests/tools/prices/test_utils.py rename to tests/tools/test_product.py index bc45dde..aabaa15 100644 --- a/tests/tools/prices/test_utils.py +++ b/tests/tools/test_product.py @@ -4,99 +4,6 @@ import pytest from portfolyo import tools -from portfolyo.tools.prices import utils - -# TODO: where are the hedge and conversion tests?? --> check git history - -TESTCASES_ISPEAK = [ # ts, ispeak - ("2020-01-01 01:00", False), - ("2020-01-01 07:00", False), - ("2020-01-01 08:00", True), - ("2020-01-01 19:00", True), - ("2020-01-01 20:00", False), - ("2020-01-03 07:45", False), - ("2020-01-03 08:00", True), - ("2020-01-03 19:45", True), - ("2020-01-03 20:00", False), - ("2020-01-04 07:45", False), - ("2020-01-04 08:00", False), - ("2020-01-04 19:45", False), - ("2020-01-04 20:00", False), - ("2020-01-05 07:45", False), - ("2020-01-05 08:00", False), - ("2020-01-05 19:45", False), - ("2020-01-05 20:00", False), - ("2020-03-29 01:00", False), - ("2020-03-29 03:00", False), - ("2020-10-25 01:00", False), - ("2020-10-25 03:00", False), -] - - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin"]) -@pytest.mark.parametrize(("ts", "ispeak"), TESTCASES_ISPEAK) -def test_is_peak_hour(ts, tz, ispeak): - """Test if individual timestamps are correctly identified as laying inside the peak - hour periods.""" - ts = pd.Timestamp(ts, tz=tz) - assert utils.is_peak_hour(ts) == ispeak - - -@pytest.mark.parametrize(("tz", "mar_b_corr"), [(None, 0), ("Europe/Berlin", -1)]) -@pytest.mark.parametrize("month", [1, 2, 3]) -@pytest.mark.parametrize("freq", ["D", "MS", "QS", "AS"]) -@pytest.mark.parametrize( - ("year", "bp", "jan_1_weekday", "jan_p", "feb_p", "mar_p"), - [ - (2020, (366, 262), True, 23, 20, 22), - (2021, (365, 261), True, 21, 20, 23), - (2022, (365, 260), False, 21, 20, 23), - ], -) -def test_duration( - year, bp, jan_1_weekday, jan_p, feb_p, mar_p, tz, mar_b_corr, freq, month -): - """Test if the correct number of base, peak and offpeak hours are calculated. - bp = tuple with number of base days and days with peak hours; jan_p, feb_p, mar_p = - number of days with peak hours in each month; mar_b_corr = correction to number of - base HOURS.""" - - if tz is None: - return # TODO: make sure the duration_base, duration_peak etc functions accept timezone-agnostic data - - if month > 1 and freq != "MS": - return - - start = pd.Timestamp(f"{year}-{month}", tz=tz) - - # Expected values. - if freq == "AS": - b = 24 * bp[0] - p = 12 * bp[1] - elif freq == "QS": - b = 24 * (31 + 28 + 31 + (bp[0] - 365)) + mar_b_corr - p = 12 * (jan_p + feb_p + mar_p) - elif freq == "MS": - if month == 1: - b = 24 * 31 - p = 12 * jan_p - elif month == 2: - b = 24 * (28 + (bp[0] - 365)) - p = 12 * feb_p - else: # month == 3: - b = 24 * 31 + mar_b_corr - p = 12 * mar_p - else: # freq == 'D' - b = 24 - p = 12 * jan_1_weekday - b = tools.unit.Q_(b, "hours") - p = tools.unit.Q_(p, "hours") - o = b - p - - # Test values. - assert b == utils.duration_base(start, freq) - assert p == utils.duration_peak(start, freq) - assert o == utils.duration_offpeak(start, freq) @pytest.mark.parametrize( @@ -183,7 +90,9 @@ def test_deliveryperiod( else: start_of_day = dt.time(hour=0) expected_left = pd.Timestamp(f"{expected_left} {starttime}", tz=tz) - ts_deliv = utils.delivery_period(ts_trade, period_type, period_start, start_of_day) + ts_deliv = tools.product.delivery_period( + ts_trade, period_type, period_start, start_of_day + ) assert ts_deliv[0] == expected_left try: add = {"m": 1, "q": 3, "s": 6, "a": 12}[period_type] diff --git a/tests/tools/visualize/test_plot.py b/tests/tools/visualize/test_plot.py index 1b15d8a..16913c7 100644 --- a/tests/tools/visualize/test_plot.py +++ b/tests/tools/visualize/test_plot.py @@ -1,20 +1,20 @@ """Test if portfolio line can be plotted.""" -import pytest +import matplotlib.pyplot as plt import pandas as pd +import pytest + import portfolyo as pf -from portfolyo.core.pfline.enums import Kind -from portfolyo.core.pfstate.pfstate import PfState -import matplotlib.pyplot as plt +from portfolyo import Kind, PfState @pytest.mark.parametrize("levels", [1, 2, 3]) @pytest.mark.parametrize("childcount", [1, 2, 3]) -@pytest.mark.parametrize("children", ["True", "False"]) +@pytest.mark.parametrize("children", [True, False]) @pytest.mark.parametrize("kind", [Kind.VOLUME, Kind.PRICE, Kind.REVENUE, Kind.COMPLETE]) @pytest.mark.parametrize("freq", ["MS", "D"]) def test_pfline_plot( - levels: int, childcount: int, children: str, kind: Kind, freq: str + levels: int, childcount: int, children: bool, kind: Kind, freq: str ): """Test if data can be plotted with plot() function.""" index = pd.date_range("2020-01-01", "2021-01-01", freq=freq, tz=None) @@ -23,11 +23,11 @@ def test_pfline_plot( @pytest.mark.parametrize("childcount", [1, 2, 3]) -@pytest.mark.parametrize("children", ["True", "False"]) +@pytest.mark.parametrize("children", [True, False]) @pytest.mark.parametrize("freq", ["MS", "D"]) def test_pfstate_plot( childcount: int, - children: str, + children: bool, freq: str, ): """Test if pfstate can be plotted with plot() function.""" @@ -45,18 +45,18 @@ def test_pfstate_plot( pfs.plot(children=children) -@pytest.mark.parametrize("children", ["True", "False"]) -def test_flatpfline_plot(children: str): +@pytest.mark.parametrize("children", [True, False]) +def test_flatpfline_plot(children: bool): """Test if plotting flatpfline with children attribute gives an error.""" pfl = pf.dev.get_flatpfline() pfl.plot(children=children) @pytest.mark.parametrize("freq", ["MS", "D"]) -@pytest.mark.parametrize("children", ["True", "False"]) +@pytest.mark.parametrize("children", [True, False]) @pytest.mark.parametrize("levels", [1, 2, 3]) @pytest.mark.parametrize("childcount", [1, 2, 3]) -def test_plot_to_ax(levels: int, childcount: int, children: str, freq: str): +def test_plot_to_ax(levels: int, childcount: int, children: bool, freq: str): """Test if frunction plot_to_ax works with every kind of pfline.""" index = pd.date_range("2020-01-01", "2021-01-01", freq=freq, tz=None) pfl_compl = pf.dev.get_pfline( @@ -71,7 +71,7 @@ def test_plot_to_ax(levels: int, childcount: int, children: str, freq: str): pfl_rev = pf.dev.get_pfline( index, nlevels=levels, childcount=childcount, kind=Kind.REVENUE ) - fig, axs = plt.subplots(2, 2) + _, axs = plt.subplots(2, 2) with pytest.raises(ValueError): _ = pfl_compl.plot_to_ax(axs[0][0], children=children, kind=Kind.COMPLETE) pfl_vol.plot_to_ax(axs[0][1], children=children, kind=Kind.VOLUME) diff --git a/tests/tools2/test_concat_error_cases.py b/tests/tools2/test_concat_error_cases.py index 4c8e8ff..e250fed 100644 --- a/tests/tools2/test_concat_error_cases.py +++ b/tests/tools2/test_concat_error_cases.py @@ -3,7 +3,6 @@ import pandas as pd import pytest - from portfolyo import dev from portfolyo.core.pfline.enums import Kind from portfolyo.core.pfstate.pfstate import PfState diff --git a/tests/tools2/test_concat_pfline.py b/tests/tools2/test_concat_pfline.py index 0a862dc..5e30722 100644 --- a/tests/tools2/test_concat_pfline.py +++ b/tests/tools2/test_concat_pfline.py @@ -2,10 +2,10 @@ import pandas as pd import pytest + from portfolyo import dev from portfolyo.tools2 import concat - TESTCASES2 = [ # whole idx, freq, where ( ("2020-01-01", "2023-04-01"), diff --git a/tests/tools2/test_concat_pfstate.py b/tests/tools2/test_concat_pfstate.py index 8f2c2de..6ca378b 100644 --- a/tests/tools2/test_concat_pfstate.py +++ b/tests/tools2/test_concat_pfstate.py @@ -2,10 +2,10 @@ import pandas as pd import pytest + from portfolyo import dev from portfolyo.tools2 import concat - TESTCASES2 = [ # whole idx, freq, where ( ("2020-01-01", "2023-04-01"), diff --git a/tests/tools2/test_indexable.py b/tests/tools2/test_indexable.py index 6ca46ab..23989e3 100644 --- a/tests/tools2/test_indexable.py +++ b/tests/tools2/test_indexable.py @@ -1,4 +1,5 @@ from typing import Union + import pandas as pd import pytest From e26ed4d7f06aea1d5e91dad47981103ca058d562 Mon Sep 17 00:00:00 2001 From: Alina Voilova Date: Mon, 13 May 2024 11:49:54 +0200 Subject: [PATCH 50/59] deleted unnecessary files --- dev_scripts/plot_state.py | 16 ---------------- dev_scripts/tree.py | 16 ---------------- 2 files changed, 32 deletions(-) delete mode 100644 dev_scripts/plot_state.py delete mode 100644 dev_scripts/tree.py diff --git a/dev_scripts/plot_state.py b/dev_scripts/plot_state.py deleted file mode 100644 index 16a6a87..0000000 --- a/dev_scripts/plot_state.py +++ /dev/null @@ -1,16 +0,0 @@ -import matplotlib.pyplot as plt -import pandas as pd - -import portfolyo as pf -from portfolyo.core.pfline.enums import Kind -from portfolyo.core.pfstate.pfstate import PfState - -index = pd.date_range( - "2022-06-01", "2024-02-01", freq="MS", tz="Europe/Berlin", inclusive="left" -) -offtakevolume = pf.dev.get_nestedpfline(index, kind=Kind.VOLUME, childcount=2) -sourced = pf.dev.get_nestedpfline(index, kind=Kind.COMPLETE, childcount=2) -unsourcedprice = pf.dev.get_nestedpfline(index, kind=Kind.PRICE, childcount=2) -pfs = PfState(-1 * offtakevolume, unsourcedprice, sourced) -pfs.plot(children=True) -plt.show() diff --git a/dev_scripts/tree.py b/dev_scripts/tree.py deleted file mode 100644 index 00a9920..0000000 --- a/dev_scripts/tree.py +++ /dev/null @@ -1,16 +0,0 @@ -import os - - -def list_files(startpath): - for root, dirs, files in os.walk(startpath): - level = root.replace(startpath, "").count(os.sep) - indent = " " * 4 * (level) - print("{}{}/".format(indent, os.path.basename(root))) - subindent = " " * 4 * (level + 1) - for f in files: - print("{}{}".format(subindent, f)) - - -list_files( - "/Users/alina.voilova/Library/CloudStorage/OneDrive-LichtBlickSE/Desktop/portfolyo/portfolyo/portfolyo" -) From 8ac55fda3d406a4d6581797f1178cfb6a0833619 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 15 May 2024 23:19:43 +0200 Subject: [PATCH 51/59] more powerful peak/offpeak functions --- portfolyo/core/pfline/flat_methods.py | 59 ++--- portfolyo/tools/peakconvert.py | 338 +++++++++++++------------- portfolyo/tools/wavg.py | 5 + 3 files changed, 199 insertions(+), 203 deletions(-) diff --git a/portfolyo/core/pfline/flat_methods.py b/portfolyo/core/pfline/flat_methods.py index fbb372f..5388906 100644 --- a/portfolyo/core/pfline/flat_methods.py +++ b/portfolyo/core/pfline/flat_methods.py @@ -5,6 +5,7 @@ import pandas as pd from ... import tools +from ...tools.peakconvert import tseries2poframe from . import classes from .enums import Kind, Structure @@ -19,43 +20,29 @@ def flatten(self: FlatPfLine) -> FlatPfLine: def po( self: PfLine, peak_fn: tools.peakfn.PeakFunction, freq: str = "MS" ) -> pd.DataFrame: - if self.index.freq not in ["15T", "H"]: - raise ValueError( - "Only PfLines with (quarter)hourly values can be turned into peak and offpeak values." - ) - if freq not in ["MS", "QS", "AS"]: - raise ValueError( - f"Value of paramater ``freq`` must be one of {'MS', 'QS', 'AS'} (got: {freq})." - ) - df_dict = {} - prods = ("peak", "offpeak") - - # Get values. - for col in ("w", "p"): - if col in self.kind.available: - vals = tools.peakconvert.tseries2bpoframe(self.df[col], peak_fn, freq)[ - prods - ] - df_dict[col] = vals - - # Add duration. - i = next(iter(df_dict.values())).index # index of any of the dataframes - b = tools.duration.index(i) # pint-series - p = tools.peakfn.peak_duration(i, peak_fn) # pint-series - df_dict["duration"] = pd.DataFrame({"peak": p, "offpeak": b - p}) - - # Turn into dataframe. - df = pd.DataFrame(df_dict).swaplevel(axis=1) # 'peak', 'offpeak' on top - - # Add additional values and sort. - for prod in prods: - if "q" in self.kind.available: - df[(prod, "q")] = df[(prod, "w")] * df[(prod, "duration")] - if "r" in self.kind.available: - df[(prod, "r")] = (df[(prod, "q")] * df[(prod, "p")]).pint.to_base_units() - # colidx = pd.MultiIndex.from_product([prods, ("duration", *self.kind.available)]) - return df.sort_index(axis=1) # [colidx] + + # Always include duration. + duration = tools.duration.index(self.df.index) + df_dict["duration"] = tseries2poframe(duration, peak_fn, freq, True) + + # Add volume. + if self.kind in [Kind.VOLUME, Kind.COMPLETE]: + df_dict["q"] = tseries2poframe(self.q, peak_fn, freq, True) + df_dict["w"] = df_dict["q"] / df_dict["duration"] + + # Add revenue. + if self.kind in [Kind.REVENUE, Kind.COMPLETE]: + df_dict["r"] = tseries2poframe(self.r, peak_fn, freq, True) + + # Add price. + if self.kind is Kind.PRICE: + df_dict["p"] = tseries2poframe(self.p, peak_fn, freq, False) + elif self.kind is Kind.COMPLETE: + df_dict["p"] = df_dict["r"] / df_dict["q"] + + # Turn into dataframe and put 'peak' and 'offpeak' on top. + return pd.DataFrame(df_dict).swaplevel(axis=1).sort_index(axis=1) def hedge_with( diff --git a/portfolyo/tools/peakconvert.py b/portfolyo/tools/peakconvert.py index dbff294..bb2b7ce 100644 --- a/portfolyo/tools/peakconvert.py +++ b/portfolyo/tools/peakconvert.py @@ -3,7 +3,6 @@ import warnings from typing import List -import numpy as np import pandas as pd from . import changefreq as tools_changefreq @@ -41,7 +40,7 @@ def group_arrays( def complete_bpoframe( - df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction + df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction, is_summable: bool = False ) -> pd.DataFrame: """Complete a dataframe so it contains arbitrage-free base, peak, and offpeak values. @@ -53,17 +52,14 @@ def complete_bpoframe( with freq in {'MS', 'QS', 'AS'}. peak_fn : PeakFunction Function that returns boolean Series indicating if timestamps in index lie in peak period. + is_summable : bool, optional (default: False) + True if data is summable, False if it is averagable. Returns ------- DataFrame Same as ``df``, with all 3 columns ('base', 'peak', 'offpeak'). - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - In: peak offpeak @@ -87,7 +83,7 @@ def complete_bpoframe( 12 rows × 3 columns """ # Guard clauses. - found = [c for c in df.columns if c in BPO] + found = [c for c in df if c in BPO] if len(found) <= 1: # too few present raise ValueError( f"At least 2 of 'base', 'peak', 'offpeak' must be in columns; found {found}." @@ -97,23 +93,34 @@ def complete_bpoframe( # Make copy of relevant columns, and fill. df = df[found].copy() - b = tools_duration.index(df.index) - p = tools_peakfn.peak_duration(df.index, peak_fn) - # Solve: peak * duration_peak + offpeak * duration_offpeak = base * duration_base - # with: duration_offpeak = duration_base - duration_peak - if "peak" not in df.columns: - # df["peak"] = (df["base"] * b - df["offpeak"] * (b - p)) / p - df["peak"] = (df["base"] - df["offpeak"]) * b / p + df["offpeak"] - elif "offpeak" not in df.columns: - df["offpeak"] = (df["base"] * b - df["peak"] * p) / (b - p) - else: # 'base' not in fr.columns - # df["base"] = (df["peak"] * p + df["offpeak"] * (b - p)) / b - df["base"] = (df["peak"] - df["offpeak"]) * p / b + df["offpeak"] + if is_summable: + # Solve: peak + offpeak = base + if "peak" not in df: + df["peak"] = df["base"] - df["offpeak"] + elif "offpeak" not in df: + df["offpeak"] = df["base"] - df["peak"] + else: # 'base' not in df + df["base"] = df["peak"] + df["offpeak"] + else: + # Solve: peak * duration_peak + offpeak * duration_offpeak = base * duration_base + # (with: duration_offpeak = duration_base - duration_peak) + b = tools_duration.index(df.index) + p = tools_peakfn.peak_duration(df.index, peak_fn) + if "peak" not in df: + # df["peak"] = (df["base"] * b - df["offpeak"] * (b - p)) / p + df["peak"] = (df["base"] - df["offpeak"]) * b / p + df["offpeak"] + elif "offpeak" not in df: + df["offpeak"] = (df["base"] * b - df["peak"] * p) / (b - p) + else: # 'base' not in df + # df["base"] = (df["peak"] * p + df["offpeak"] * (b - p)) / b + df["base"] = (df["peak"] - df["offpeak"]) * p / b + df["offpeak"] return df[BPO] # correct order -def _tseries2singlebpo(s: pd.Series, peak_fn: tools_peakfn.PeakFunction) -> pd.Series: +def _tseries2po( + s: pd.Series, peak_fn: tools_peakfn.PeakFunction, is_summable: bool +) -> pd.Series: """ Aggregate timeseries with varying (float) values to a single base, peak and offpeak (float) value. @@ -132,37 +139,37 @@ def _tseries2singlebpo(s: pd.Series, peak_fn: tools_peakfn.PeakFunction) -> pd.S Out: - base 31.401369 peak 51.363667 offpeak 20.311204 dtype: float64 """ is_peak = peak_fn(s.index) duration = tools_duration.index(s.index).pint.m # floats - if duration.nunique() == 1: # All have same duration: use normal mean (faster). + if is_summable: return pd.Series( { - "base": s.mean(), - "peak": s[is_peak].mean(), - "offpeak": s[~is_peak].mean(), + "peak": s[is_peak].sum(), + "offpeak": s[~is_peak].sum(), } ) else: return pd.Series( { - "base": tools_wavg.series(s, duration), "peak": tools_wavg.series(s[is_peak], duration[is_peak]), "offpeak": tools_wavg.series(s[~is_peak], duration[~is_peak]), } ) -def tseries2bpoframe( - s: pd.Series, peak_fn: tools_peakfn.PeakFunction, freq: str = "MS" +def tseries2poframe( + s: pd.Series, + peak_fn: tools_peakfn.PeakFunction, + freq: str = "MS", + is_summable: bool = False, ) -> pd.DataFrame: """ - Aggregate timeseries with varying values to a dataframe with base, peak and offpeak - timeseries, grouped by provided time interval. + Aggregate timeseries with varying values to a dataframe with peak and offpeak + timeseries, grouped by specified frequency. Parameters ---------- @@ -170,8 +177,10 @@ def tseries2bpoframe( Timeseries with hourly or quarterhourly frequency. peak_fn : PeakFunction Function that returns boolean Series indicating if timestamps in index lie in peak period. - freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} - Target frequency. + freq : str, optional (default: 'MS') + Target frequency; monthly-or-longer. + is_summable : bool, optional (default: False) + True if data is summable, False if it is averagable. Returns ------- @@ -179,11 +188,6 @@ def tseries2bpoframe( Dataframe with base, peak and offpeak values (as columns). Index: downsampled timestamps at provided frequency. - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - In: ts_left @@ -198,19 +202,17 @@ def tseries2bpoframe( Out: - base peak offpeak + peak offpeak ts_left - 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 - ... ... ... - 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 + 2020-01-01 00:00:00+01:00 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 33.295167 15.931557 + ... ... + 2020-11-01 00:00:00+01:00 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 57.872246 35.055449 12 rows × 3 columns """ - if freq not in ("MS", "QS", "AS"): - raise ValueError( - f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got '{freq}'." - ) + if tools_freq.up_or_down(freq, "MS") < 0: + raise ValueError(f"Parameter ``freq`` be monthly-or-longer; got '{freq}'.") # Remove partial data. s = tools_trim.frame(s, freq) @@ -220,42 +222,41 @@ def tseries2bpoframe( # Do calculations. sout = sin.resample(freq, group_keys=True).apply( - lambda s: _tseries2singlebpo(s, peak_fn) + lambda s: _tseries2po(s, peak_fn, is_summable) ) # Handle possible units. if units is not None: sout = sout.astype(f"pint[{units}]") - return sout.unstack() # base, peak, offpeak as columns + return sout.unstack() # peak, offpeak as columns -def bpoframe2tseries( - df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction, freq: str = "H" +def poframe2tseries( + df: pd.DataFrame, + peak_fn: tools_peakfn.PeakFunction, + freq: str = "H", + is_summable: bool = False, ) -> pd.Series: """ - Convert a dataframe with base, peak and/or offpeak values, to a single (quarter)hourly - timeseries. + Convert a dataframe with peak and offpeak values, to a single timeseries. Parameters ---------- df : DataFrame - Dataframe with values. Columns must include at least 2 of {'peak', 'offpeak', - 'base'}. Datetimeindex with frequency in {'MS', 'QS', 'AS'}. + Dataframe with values. Columns must include at least {'peak', 'offpeak'}. + Datetimeindex with monthly-or-longer frequency. peak_fn : PeakFunction Function that returns boolean Series indicating if timestamps in index lie in peak period. - freq : {'H' (hour, default) '15T' (quarterhour)} - Target frequency. + freq : str + Target frequency; short enough for ``peak_fn``. + is_summable : bool, optional (default: False) + True if data is summable, False if it is averagable. Returns ------- Series Timeseries with values as provided in ``df``. - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - In: peak offpeak @@ -279,105 +280,112 @@ def bpoframe2tseries( 2020-12-31 23:00:00+01:00 35.055449 Freq: H, Length: 8784, dtype: float64 """ + # Prep. if "peak" not in df or "offpeak" not in df: # ensure peak and offpeak available df = complete_bpoframe(df, peak_fn) + df = df[["peak", "offpeak"]] - # Stretch the dataframe to higher frequency (repeat parent value) - df2 = tools_changefreq.averagable(df[["peak", "offpeak"]], freq) - df2["ispeak"] = peak_fn(df2.index) + # Stretch the dataframe to higher frequency + if is_summable: + df2 = tools_changefreq.summable(df, freq) + else: + df2 = tools_changefreq.averagable(df, freq) + df2["ispeak"] = peak_fn(df2.index) # will raise error if frequency not short enough return df2["offpeak"].where(df2["ispeak"], df2["peak"]) -def tseries2tseries( - s: pd.Series, peak_fn: tools_peakfn.PeakFunction = None, freq: str = "MS" -) -> pd.Series: - """ - Transform timeseries (with possibly variable values) to one with (at certain - frequency) uniform peak and offpeak values. - - Parameters - ---------- - s : Series - Timeseries with hourly or quarterhourly frequency. - peak_fn : PeakFunction, optional (default: None) - Function that returns boolean Series indicating if timestamps in index lie in peak period. - If None, calculate uniform base values. - freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} - Target frequency within which peak and offpeak values will be uniform. - - Returns - ------- - Series - Timeseries where each peak hour within the target frequency has the same - value. Idem for offpeak hours. Index: as original series. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - ts_left - 2020-01-01 00:00:00+01:00 41.88 - 2020-01-01 01:00:00+01:00 38.60 - 2020-01-01 02:00:00+01:00 36.55 - ... - 2020-12-31 21:00:00+01:00 52.44 - 2020-12-31 22:00:00+01:00 51.86 - 2020-12-31 23:00:00+01:00 52.26 - Freq: H, Name: p, Length: 8784, dtype: float64 - - Out: - - ts_left - 2020-01-01 00:00:00+01:00 30.614701 - 2020-01-01 01:00:00+01:00 30.614701 - 2020-01-01 02:00:00+01:00 30.614701 - ... - 2020-12-31 21:00:00+01:00 35.055449 - 2020-12-31 22:00:00+01:00 35.055449 - 2020-12-31 23:00:00+01:00 35.055449 - Freq: H, Name: p, Length: 8784, dtype: float64 - """ - if s.index.freq not in ("H", "15T"): - raise ValueError( - f"Frequency of provided timeseries must be hourly or quarterhourly; got '{s.index.freq}'." - ) - - # Remove partial data. - s = tools_trim.frame(s, freq) - - # Handle possible units. - sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) - - # Return normal mean, because all rows have same duration. - grouping = group_arrays(freq, peak_fn) - sout = sin.groupby(grouping).transform(np.mean) - - # Handle possible units. - if units is not None: - sout = sout.astype(f"pint[{units}]") - return sout - - -def bpoframe2bpoframe( - df: pd.DataFrame, peak_fn: tools_peakfn.PeakFunction, freq: str = "AS" +# def tseries2tseries( +# s: pd.Series, +# peak_fn: tools_peakfn.PeakFunction, +# freq: str = "MS", +# is_summable: bool = False, +# ) -> pd.Series: +# """ +# Transform timeseries (with possibly variable values) to one with (at certain +# frequency) uniform peak and offpeak values. +# +# Parameters +# ---------- +# s : Series +# Timeseries with hourly or quarterhourly frequency. +# peak_fn : PeakFunction, optional (default: None) +# Function that returns boolean Series indicating if timestamps in index lie in peak period. +# freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} +# Target frequency within which peak and offpeak values will be uniform. +# is_summable : bool, optional (default: False) +# True if data is summable, False if it is averagable. +# +# Returns +# ------- +# Series +# Timeseries where each peak hour within the target frequency has the same +# value. Idem for offpeak hours. Index: as original series. +# +# In: +# +# ts_left +# 2020-01-01 00:00:00+01:00 41.88 +# 2020-01-01 01:00:00+01:00 38.60 +# 2020-01-01 02:00:00+01:00 36.55 +# ... +# 2020-12-31 21:00:00+01:00 52.44 +# 2020-12-31 22:00:00+01:00 51.86 +# 2020-12-31 23:00:00+01:00 52.26 +# Freq: H, Name: p, Length: 8784, dtype: float64 +# +# Out: +# +# ts_left +# 2020-01-01 00:00:00+01:00 30.614701 +# 2020-01-01 01:00:00+01:00 30.614701 +# 2020-01-01 02:00:00+01:00 30.614701 +# ... +# 2020-12-31 21:00:00+01:00 35.055449 +# 2020-12-31 22:00:00+01:00 35.055449 +# 2020-12-31 23:00:00+01:00 35.055449 +# Freq: H, Name: p, Length: 8784, dtype: float64 +# """ +# # Remove partial data. +# s = tools_trim.frame(s, freq) +# +# # Handle possible units. +# sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) +# +# # Calculate. +# # grouping will raise error if frequency not short enough +# grouping = group_arrays(sin.index, freq, peak_fn) +# fn = tools_changefreq.summable if is_summable else tools_changefreq.averagable +# sout = sin.groupby(grouping).transform( +# +# # Handle possible units. +# if units is not None: +# sout = sout.astype(f"pint[{units}]") +# return sout +# + + +def poframe2poframe( + df: pd.DataFrame, + peak_fn: tools_peakfn.PeakFunction, + freq: str = "AS", + is_summable: bool = False, ) -> pd.DataFrame: """ - Convert a dataframe with base, peak and/or offpeak values to a similar dataframe + Convert a dataframe with peak and offpeak values to a similar dataframe with a different frequency. Parameters ---------- df : DataFrame - Columns must include at least 2 of {'peak', 'offpeak', 'base'}. Datetimeindex - with frequency in {'MS', 'QS', 'AS'}. + Columns must include at least {'peak', 'offpeak'}. Datetimeindex with monthly- + or-longer frequency. peak_fn : PeakFunction Function that returns boolean Series indicating if timestamps in index lie in peak period. - freq : {'MS' (month), 'QS' (quarter), 'AS' (year, default)} - Target frequency. + freq : str, optional (default: 'AS') + Target frequency; monthly-or-longer. + is_summable : bool, optional (default: False) + True if data is summable, False if it is averagable. Returns ------- @@ -385,39 +393,35 @@ def bpoframe2bpoframe( Dataframe with base, peak and offpeak values (as columns). Index: timestamps at specified frequency. - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - In: - base peak offpeak + peak offpeak ts_left - 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 - ... ... ... - 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 + 2020-01-01 00:00:00+01:00 42.530036 30.614701 + 2020-02-01 00:00:00+01:00 33.295167 15.931557 + ... ... + 2020-11-01 00:00:00+01:00 49.110873 33.226004 + 2020-12-01 00:00:00+01:00 57.872246 35.055449 12 rows × 3 columns Out: - base peak offpeak + peak offpeak ts_left - 2020-01-01 00:00:00+01:00 30.490036 38.003536 26.312894 - 2020-04-01 00:00:00+02:00 25.900919 35.295167 20.681892 - 2020-07-01 00:00:00+02:00 32.706785 44.033511 26.371498 - 2020-10-01 00:00:00+02:00 39.455197 54.468722 31.063728 + 2020-01-01 00:00:00+01:00 38.003536 26.312894 + 2020-04-01 00:00:00+02:00 35.295167 20.681892 + 2020-07-01 00:00:00+02:00 44.033511 26.371498 + 2020-10-01 00:00:00+02:00 54.468722 31.063728 """ - if freq not in ("MS", "QS", "AS"): - raise ValueError( - f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got {freq}." - ) + if tools_freq.up_or_down(freq, "MS") < 0: + raise ValueError(f"Parameter ``freq`` be monthly-or-longer; got '{freq}'.") + if tools_freq.up_or_down(df.index.freq, freq) == 1: warnings.warn( "This conversion includes upsampling, e.g. from yearly to monthly values." " The result will be uniform at the frequency of the original frame ``df``." ) - return tseries2bpoframe(bpoframe2tseries(df, peak_fn, "H"), peak_fn, freq) + upsampled = poframe2tseries(df, peak_fn, "H", is_summable) + downsampled = tseries2poframe(upsampled, peak_fn, freq, is_summable) + return downsampled diff --git a/portfolyo/tools/wavg.py b/portfolyo/tools/wavg.py index add0d43..1769410 100644 --- a/portfolyo/tools/wavg.py +++ b/portfolyo/tools/wavg.py @@ -117,6 +117,11 @@ def series( s = s.loc[weights.index] except KeyError as e: # more weights than values raise ValueError("No values found for one or more weights.") from e + + # Unweighted average if all weights the same. + if weights.nunique() == 1: + return s.mean() + # Replace NaN with 0 in locations where it doesn't change the result. replaceable = s.isna() & (weights == 0.0) s[replaceable] = 0.0 From 27d541c65fa3433d56d15a7072c48cc457385779 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Tue, 21 May 2024 17:47:17 +0200 Subject: [PATCH 52/59] removed longer_or_shorter from frequency tools Use the up_or_down function instead --- portfolyo/core/pfline/decorators.py | 4 ++-- portfolyo/tools/freq.py | 35 +---------------------------- portfolyo/tools/intersect.py | 12 +++++----- portfolyo/tools/visualize/plot.py | 2 +- portfolyo/tools/wavg.py | 34 ++++++++++++++-------------- tests/tools/test_freq.py | 3 +-- 6 files changed, 28 insertions(+), 62 deletions(-) diff --git a/portfolyo/core/pfline/decorators.py b/portfolyo/core/pfline/decorators.py index 129b854..06e9d37 100644 --- a/portfolyo/core/pfline/decorators.py +++ b/portfolyo/core/pfline/decorators.py @@ -6,7 +6,7 @@ def assert_longest_allowed_freq(freq): def decorator(fn): def wrapped(self, *args, **kwargs): - if tools.freq.longer_or_shorter(self.index.freq, freq) == 1: + if tools.freq.up_or_down(self.index.freq, freq) == 1: raise ValueError( "The frequency of the index is too long; longest allowed:" f" {freq}; passed: {self.index.freq}." @@ -21,7 +21,7 @@ def wrapped(self, *args, **kwargs): def assert_shortest_allowed_freq(freq): def decorator(fn): def wrapped(self, *args, **kwargs): - if tools.freq.longer_or_shorter(self.index.freq, freq) == -1: + if tools.freq.up_or_down(self.index.freq, freq) == -1: raise ValueError( "The frequency of the index is too short; shortest allowed:" f" {freq}; passed: {self.index.freq}." diff --git a/portfolyo/tools/freq.py b/portfolyo/tools/freq.py index 302f367..d7f3372 100644 --- a/portfolyo/tools/freq.py +++ b/portfolyo/tools/freq.py @@ -53,6 +53,7 @@ def up_or_down( backup_common_ts = pd.Timestamp("2020-02-03 04:05:06") if common_ts is None: common_ts = standard_common_ts + ts1 = common_ts + pd.tseries.frequencies.to_offset(freq_source) ts2 = common_ts + pd.tseries.frequencies.to_offset(freq_target) if ts1 > ts2: @@ -65,40 +66,6 @@ def up_or_down( return 0 # only if both give the same answer. -def longer_or_shorter(freq: str, freq_ref: str, common_ts: pd.Timedelta = None) -> int: - """ - Compare frequency with reference frequency to see if it is longer or shorter. - - Parameters - ---------- - freq, freq_ref : frequencies to compare. - common_ts : timestamp, optional - Timestamp to use as anchor from which to compare the two. - - Returns - ------- - * 1 if frequency ``freq`` is longer than the reference frequency ``freq_ref``. - * 0 if frequencies are the same. - * -1 if frequency ``freq`` is shorter than the reference frequency ``freq_ref``. - - Notes - ----- - Arbitrarily using a time point as anchor to calculate the length of the time period - from. May have influence on the ratio (duration of a month, quarter, year etc are - influenced by this), but, for most common frequencies, not on which is longer. - - Examples - -------- - >>> freq.longer_or_shorter('D', 'MS') - -1 - >>> freq.longer_or_shorter('MS', 'D') - 1 - >>> freq.longer_or_shorter('MS', 'MS') - 0 - """ - return up_or_down(freq, freq_ref, common_ts) - - def _longestshortest(shortest: bool, *freqs: str): """Determine which frequency denotes the shortest or longest time period.""" common_ts = pd.Timestamp("2020-01-01") diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index b8fbb83..b8cfa87 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -3,9 +3,9 @@ import pandas as pd +from . import freq as tools_freq +from . import right as tools_right from . import trim as tools_trim -from .freq import longer_or_shorter, longest -from .right import stamp def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: @@ -121,7 +121,7 @@ def indices_flex( if len(distinct_sod) != 1 and ignore_start_of_day is False: raise ValueError(f"Indices must have equal start-of-day; got {distinct_sod}.") for i in range(len(idxs)): - if len(distinct_sod) != 1 and longer_or_shorter(idxs[i].freq, "D") == -1: + if len(distinct_sod) != 1 and tools_freq.up_or_down(idxs[i].freq, "D") == -1: raise ValueError( "Downsample all indices to daily-or-longer, or trim them so they have the same start-of-day, before attempting to calculate the intersection" ) @@ -135,7 +135,7 @@ def indices_flex( longest_freq = freq[0] if ignore_freq is True and len(distinct_freqs) != 1: # Find the longest frequency - longest_freq = longest(*freq) + longest_freq = tools_freq.longest(*freq) # trim datetimeindex for i in range(len(idxs)): # if idxs[i].freq is not the same as longest freq, we trim idxs[i] @@ -161,14 +161,14 @@ def indices_flex( values = sorted(values) if len(values) == 0: - return tuple([pd.DatetimeIndex([]) for _i in idxs]) + return tuple([pd.DatetimeIndex([]) for _ in idxs]) idxs_out = [] for i in range(len(idxs)): start = min(values) # end = stamp(start, longest_freq._prefix) end = max(values) - end = stamp(end, longest_freq) + end = tools_right.stamp(end, longest_freq) if ignore_start_of_day is True: start = datetime.combine(pd.to_datetime(start).date(), start_of_day[i]) diff --git a/portfolyo/tools/visualize/plot.py b/portfolyo/tools/visualize/plot.py index 5d59d78..09c27f4 100644 --- a/portfolyo/tools/visualize/plot.py +++ b/portfolyo/tools/visualize/plot.py @@ -209,7 +209,7 @@ def get_portfolyo_attr(ax, name, default_val=None): def is_categorical(s: pd.Series) -> bool: """The function checks whether frequency of panda Series falls into continous or categorical group""" - return tools_freq.longer_or_shorter(s.index.freq, "D") == 1 + return tools_freq.up_or_down(s.index.freq, "D") == 1 def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series: diff --git a/portfolyo/tools/wavg.py b/portfolyo/tools/wavg.py index 1769410..492b8ab 100644 --- a/portfolyo/tools/wavg.py +++ b/portfolyo/tools/wavg.py @@ -13,35 +13,35 @@ # Developer notes: # The following behaviour is wanted in calculating the weighted average: -# weights values rule | result +# weights values rule result # sum of weights != 0 -# 1, -1, 2 10, 20, 30 normal | (10*1 + 20*-1 + 30*2 ) / (1 + -1 + 2) -# 1, -1, 2 10, NaN, 30 NaN if values include NaN | NaN -# 1, 0, 2 10, NaN, 30 ignore NaN if weight = 0 | (10*1 + 30*2) / (1 + 2) +# 1, -1, 2 10, 20, 30 "normal" (10*1 + 20*-1 + 30*2 ) / (1 + -1 + 2) +# 1, -1, 2 10, NaN, 30 NaN if values include NaN NaN +# 1, 0, 2 10, NaN, 30 ignore NaN if weight = 0 (10*1 + 30*2) / (1 + 2) # --> Remove all values for which weight == 0. # --> If remaining values conain NaN --> result is NaN. # --> Otherwise, calculate the result normally. # sum of weights == 0 but not all 0 -# 1, 1, -2 10, 20, 30 Inf if values distinct | Inf -# 1, 1, -2 10, 10, 10 value if values identical | 10 -# 1, -1, 0 10, 10, 30 ignore value if weight = 0 | 10 -# 1, 1, -2 10, 10, NaN NaN if values include NaN | NaN (done) -# 1, -1, 0 10, 10, NaN ignore NaN if weight = 0 | 10 -# 1, -1, 0 NaN, NaN, NaN NaN if values are all NaN | NaN +# 1, 1, -2 10, 20, 30 NaN if values distinct NaN +# 1, 1, -2 10, 10, 10 value if values identical 10 +# 1, -1, 0 10, 10, 30 ignore value if weight = 0 10 +# 1, 1, -2 10, 10, NaN NaN if values include NaN NaN +# 1, -1, 0 10, 10, NaN ignore NaN if weight = 0 10 +# 1, -1, 0 NaN, NaN, NaN NaN if values are all NaN NaN # --> Remove all values for which weight == 0. # --> If remaining values contain NaN --> result is NaN # --> Otherwise, if remaining values are identical --> result is that value # --> Otherwise, result is Inf. # all weights are 0 -# 0, 0, 0 10, 20, 30 Inf if values distinct | Inf -# 0, 0, 0 10, 10, 10 value if values identical | 10 -# 0, 0, 0 10, 10, NaN NaN if values include NaN | NaN +# 0, 0, 0 10, 20, 30 NaN if values distinct NaN +# 0, 0, 0 10, 10, 10 Value if values identical 10 +# 0, 0, 0 10, 10, NaN NaN if values include NaN NaN # --> If values contain NaN --> result is NaN # --> Otherwise, if values are identical --> result is that value -# --> Otherwise, result is Inf. +# --> Otherwise, result is NaN. RESULT_IF_WEIGHTSUM0_VALUESNOTUNIFORM = np.nan @@ -118,8 +118,8 @@ def series( except KeyError as e: # more weights than values raise ValueError("No values found for one or more weights.") from e - # Unweighted average if all weights the same. - if weights.nunique() == 1: + # Unweighted average if all weights the same but not all 0. + if weights.nunique() == 1 and not np.isclose(weights.iloc[0], 0): return s.mean() # Replace NaN with 0 in locations where it doesn't change the result. @@ -404,7 +404,7 @@ def rowvalue_uniformity(df: pd.DataFrame) -> pd.Series: # or uniform NaN, this value/NaN is found in buffer. uniform = pd.Series(True, df.index) buffer = pd.Series(np.nan, df.index) # define to ensure exists even if df empty - for i, (c, s) in enumerate(df.items()): + for i, (_, s) in enumerate(df.items()): if i == 0: # define here to ensure ``values`` has pint dtype if df does too to_type = float if pd.api.types.is_integer_dtype(s.dtype) else s.dtype diff --git a/tests/tools/test_freq.py b/tests/tools/test_freq.py index a6224e2..1cd0737 100644 --- a/tests/tools/test_freq.py +++ b/tests/tools/test_freq.py @@ -19,12 +19,11 @@ def test_longestshortestfreq(count): @pytest.mark.parametrize("freq1", freqs_small_to_large) @pytest.mark.parametrize("freq2", freqs_small_to_large) -def test_frequpordown_freqlongerorshorter(freq1, freq2): +def test_frequpordown(freq1, freq2): i1 = freqs_small_to_large.index(freq1) i2 = freqs_small_to_large.index(freq2) outcome = np.sign(i1 - i2) assert tools.freq.up_or_down(freq1, freq2) == outcome - assert tools.freq.longer_or_shorter(freq1, freq2) == outcome @pytest.mark.parametrize("tz", [None, "Europe/Berlin", "Asia/Kolkata"]) From 5a0fb5a8c282175d50d525cd1f8eda11db0ce362 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 22 May 2024 10:20:52 +0200 Subject: [PATCH 53/59] tests for peakfn and peakconvert --- portfolyo/tools/peakconvert.py | 6 +- portfolyo/tools/peakfn.py | 49 +-- portfolyo/tools/prices/convert.py.bak | 435 ------------------------- tests/tools/prices/test_convert.py.bak | 83 +---- tests/tools/test_peakconvert.py | 119 +++++++ tests/tools/test_peakfn.py | 93 +++++- 6 files changed, 217 insertions(+), 568 deletions(-) delete mode 100644 portfolyo/tools/prices/convert.py.bak create mode 100644 tests/tools/test_peakconvert.py diff --git a/portfolyo/tools/peakconvert.py b/portfolyo/tools/peakconvert.py index bb2b7ce..77f0616 100644 --- a/portfolyo/tools/peakconvert.py +++ b/portfolyo/tools/peakconvert.py @@ -12,7 +12,7 @@ from . import trim as tools_trim from . import wavg as tools_wavg -BPO = ("base", "peak", "offpeak") +BPO = ["base", "peak", "offpeak"] def group_arrays( @@ -104,8 +104,8 @@ def complete_bpoframe( else: # Solve: peak * duration_peak + offpeak * duration_offpeak = base * duration_base # (with: duration_offpeak = duration_base - duration_peak) - b = tools_duration.index(df.index) - p = tools_peakfn.peak_duration(df.index, peak_fn) + b = tools_duration.index(df.index).pint.m # as float + p = tools_peakfn.peak_duration(df.index, peak_fn).pint.m # as float if "peak" not in df: # df["peak"] = (df["base"] * b - df["offpeak"] * (b - p)) / p df["peak"] = (df["base"] - df["offpeak"]) * b / p + df["offpeak"] diff --git a/portfolyo/tools/peakfn.py b/portfolyo/tools/peakfn.py index 888e7c9..7e933d7 100644 --- a/portfolyo/tools/peakfn.py +++ b/portfolyo/tools/peakfn.py @@ -121,23 +121,6 @@ def peak_fn(i: pd.DatetimeIndex) -> pd.Series: return peak_fn -def base_duration(i: pd.DatetimeIndex) -> pd.Series: - """ - Duration of base periods in each element of a datetimeindex. - - Parameters - ---------- - i : pd.DatetimeIndex - Index for which to calculate the duration of the base product (= total duration) - - Returns - ------- - Series - with ``i`` as index, and duration of base hours during each timeperiod in ``i``. - """ - return tools_duration.index(i) - - def peak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series: """ Duration of peak periods in each element of a datetimeindex. @@ -145,7 +128,7 @@ def peak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series: Parameters ---------- i : pd.DatetimeIndex - Index for which to calculate the durations. + Index for which to calculate the durations. May be in any frequency. peak_fn : PeakFunction Function that returns boolean Series indicating if timestamps in index lie in peak period. @@ -157,7 +140,8 @@ def peak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series: Notes ----- ``peak_fn`` might only work on indices with daily-or-shorter, hourly-or-shorter, or - quarterhourly-or-shorter frequency. ``i`` is resampled to account for this. + quarterhourly-or-shorter frequency. ``i`` is resampled to account for this; the returned + Series has the original index. """ eval_i = i # index to evaluate if peak or offpeak for eval_freq in ("D", "H", "15T"): @@ -199,30 +183,3 @@ def offpeak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series: quarterhourly-or-shorter frequency. ``i`` is resampled to account for this. """ return tools_duration.index(i) - peak_duration(i, peak_fn) - - -# def bpo_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.DataFrame: -# """ -# Duration of base, peak, and offpeak periods in each element of a datetimeindex. -# -# Parameters -# ---------- -# i : pd.DatetimeIndex -# Index for which to calculate the durations. -# peak_fn : PeakFunction -# Function that returns boolean Series indicating if timestamps in index lie in peak period. -# -# Returns -# ------- -# DataFrame -# with ``i`` as index, and columns 'base', 'peak', 'offpeak', with resp. durations -# in each timeperiod in ``i``. -# -# Notes -# ----- -# ``peak_fn`` might only work on indices with daily-or-shorter, hourly-or-shorter, or -# quarterhourly-or-shorter frequency. ``i`` is resampled to account for this. -# """ -# b = tools_duration.index(i) # pint-series -# p = peak_duration(i, peak_fn) # pint-series -# return pd.DataFrame({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") diff --git a/portfolyo/tools/prices/convert.py.bak b/portfolyo/tools/prices/convert.py.bak deleted file mode 100644 index 1f05af2..0000000 --- a/portfolyo/tools/prices/convert.py.bak +++ /dev/null @@ -1,435 +0,0 @@ -""" -Convert volume [MW] and price [Eur/MWh] timeseries using base, peak, offpeak times. - -. Conversions without loss of information: -.. Base and peak values <--> Peak and offpeak values -.. Peak and offpeak values in dataframe with yearly/quarterly/monthly index <--> - peak and offpeak values in series with hourly (or shorter) index - -. Conversions with information loss: -.. Hourly varying values --> Peak and offpeak values. -""" - -import datetime as dt -import warnings -from typing import Union - -import numpy as np -import pandas as pd - -from .. import changefreq as tools_changefreq -from .. import freq as tools_freq -from .. import trim as tools_trim -from .. import unit as tools_unit -from . import utils - -Stamp = Union[dt.datetime, pd.Timestamp] -Value = Union[float, int, tools_unit.Q_] - -BPO = ("base", "peak", "offpeak") - - -def group_function(freq: str, po: bool = False): - """Function to group all rows that belong to same 'product'.""" - if freq == "MS": - if po: - return lambda ts: (ts.year, ts.month, utils.is_peak_hour(ts)) - else: - return lambda ts: (ts.year, ts.month) - elif freq == "QS": - if po: - return lambda ts: (ts.year, ts.quarter, utils.is_peak_hour(ts)) - else: - return lambda ts: (ts.year, ts.quarter) - elif freq == "AS": - if po: - return lambda ts: (ts.year, utils.is_peak_hour(ts)) - else: - return lambda ts: (ts.year,) - - raise ValueError( - f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got '{freq}'." - ) - - -def complete_bpoframe(partial_bpoframe: pd.DataFrame, prefix: str = "") -> pd.DataFrame: - """ - Add missing information to bpoframe (Dataframe with base, peak, offpeak values). - - Parameters - ---------- - partial_bpoframe : DataFrame - Dataframe with at least 2 columns with names in {'base', 'peak', 'offpeak'}. - Datetimeindex with frequency in {'MS', 'QS', 'AS'}. - prefix : str, optional (default: '') - If specified, add this to the column names to search for in the provided dataframe - (and to the column names in the returned dataframes). - - Returns - ------- - DataFrame - If exactly one of {'base', 'peak', 'offpeak'} is missing, calculate value - of missing column from other two columns and return complete dataframe. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - peak offpeak - ts_left - 2020-01-01 00:00:00+01:00 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 33.295167 15.931557 - ... ... - 2020-11-01 00:00:00+01:00 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 57.872246 35.055449 - 12 rows × 2 columns - - Out: - - base peak offpeak - ts_left - 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 - ... ... ... - 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 - 12 rows × 3 columns - """ - col2bpo = {f"{prefix}{bpo}": bpo for bpo in BPO} - series = {col2bpo[c]: s for c, s in partial_bpoframe.iteritems() if c in col2bpo} - - if len(series) > 2: # i.e., 3 - return partial_bpoframe - if len(series) < 2: - raise ValueError( - f"At least 2 of {', '.join(col2bpo.keys())} must be present as columns." - ) - df = partial_bpoframe.copy() - durations = utils.duration_bpo(df.index) - b, p, o = durations["base"], durations["peak"], durations["offpeak"] - if "offpeak" not in series: - df[f"{prefix}offpeak"] = (series["base"] * b - series["peak"] * p) / o - elif "peak" not in series: - df[f"{prefix}peak"] = (series["base"] * b - series["offpeak"] * o) / p - else: - df[f"{prefix}base"] = (series["peak"] * p + series["offpeak"] * o) / b - - return df[col2bpo.keys()] # correct order - - -def tseries2singlebpo(s: pd.Series, prefix: str = "") -> pd.Series: - """ - Aggregate timeseries with varying values to a single base, peak and offpeak value. - - Parameters - ---------- - s : Series - Timeseries with hourly or quarterhourly frequency. - prefix : str, optional (default: '') - If specified, add this to the index of the returned Series. - - Returns - ------- - Series - Index: base, peak, offpeak. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - ts_left - 2020-01-01 00:00:00+01:00 41.88 - 2020-01-01 01:00:00+01:00 38.60 - 2020-01-01 02:00:00+01:00 36.55 - ... - 2020-12-31 21:00:00+01:00 52.44 - 2020-12-31 22:00:00+01:00 51.86 - 2020-12-31 23:00:00+01:00 52.26 - Freq: H, Name: p, Length: 8784, dtype: float64 - - Out: - - base 31.401369 - peak 51.363667 - offpeak 20.311204 - dtype: float64 - """ - # Handle possible units. - sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) - - # Do calculations. Use normal mean, because all rows have same duration. - is_peak = utils.is_peak_hour(sin.index) - sout = pd.Series( - { - f"{prefix}base": sin.mean(), - f"{prefix}peak": sin[is_peak].mean(), - f"{prefix}offpeak": sin[~is_peak].mean(), - } - ) - - # Handle possible units. - if units is not None: - sout = sout.astype(f"pint[{units}]") - return sout - - -def tseries2bpoframe(s: pd.Series, freq: str = "MS", prefix: str = "") -> pd.DataFrame: - """ - Aggregate timeseries with varying values to a dataframe with base, peak and offpeak - timeseries, grouped by provided time interval. - - Parameters - ---------- - s : Series - Timeseries with hourly or quarterhourly frequency. - freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} - Target frequency. - prefix : str, optional (default: '') - If specified, add this to the column names of the returned dataframe. - - Returns - ------- - DataFrame - Dataframe with base, peak and offpeak values (as columns). Index: downsampled - timestamps at provided frequency. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - ts_left - 2020-01-01 00:00:00+01:00 41.88 - 2020-01-01 01:00:00+01:00 38.60 - 2020-01-01 02:00:00+01:00 36.55 - ... - 2020-12-31 21:00:00+01:00 52.44 - 2020-12-31 22:00:00+01:00 51.86 - 2020-12-31 23:00:00+01:00 52.26 - Freq: H, Name: p, Length: 8784, dtype: float64 - - Out: - - base peak offpeak - ts_left - 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 - ... ... ... - 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 - 12 rows × 3 columns - """ - if freq not in ("MS", "QS", "AS"): - raise ValueError( - f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got '{freq}'." - ) - - # Remove partial data - s = tools_trim.frame(s, freq) - - # Handle possible units. - sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) - - # Do calculations. - sout = sin.resample(freq, group_keys=True).apply( - lambda s: tseries2singlebpo(s, prefix) - ) - - # Handle possible units. - if units is not None: - sout = sout.astype(f"pint[{units}]") - return sout.unstack() - - -def bpoframe2tseries( - bpoframe: pd.DataFrame, freq: str = "H", prefix: str = "" -) -> pd.Series: - """ - Convert a dataframe with base, peak and/or offpeak values, to a single (quarter)hourly - timeseries. - - Parameters - ---------- - bpoframe : DataFrame - Dataframe with values. Columns must include at least 2 of {'peak', 'offpeak', - 'base'}. Datetimeindex with frequency in {'MS', 'QS', 'AS'}. - freq : {'H' (hour, default) '15T' (quarterhour)} - Target frequency. - prefix : str, optional (default: '') - If specified, add this to the column names to search for in the provided dataframe. - - Returns - ------- - Series - Timeseries with values as provided in `bpoframe`. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - peak offpeak - ts_left - 2020-01-01 00:00:00+01:00 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 33.295167 15.931557 - ... ... - 2020-11-01 00:00:00+01:00 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 57.872246 35.055449 - 12 rows × 2 columns - - Out: - - ts_left - 2020-01-01 00:00:00+01:00 30.614701 - 2020-01-01 01:00:00+01:00 30.614701 - 2020-01-01 02:00:00+01:00 30.614701 - ... - 2020-12-31 21:00:00+01:00 35.055449 - 2020-12-31 22:00:00+01:00 35.055449 - 2020-12-31 23:00:00+01:00 35.055449 - Freq: H, Length: 8784, dtype: float64 - """ - if freq not in ("H", "15T"): - raise ValueError(f"Parameter ``freq`` must be 'H' or '15T'; got '{freq}'.") - - df = bpoframe.rename({f"{prefix}{bpo}": bpo for bpo in BPO}, axis=1) # remove prefx - df = complete_bpoframe(df) # make sure we have peak and offpeak columns - df = tools_changefreq.averagable(df[["peak", "offpeak"]], freq) - df["ispeak"] = utils.is_peak_hour(df.index) - - return df["offpeak"].where(df["ispeak"], df["peak"]) - - -def tseries2tseries(s: pd.Series, freq: str = "MS") -> pd.Series: - """ - Transform timeseries (with possibly variable values) to one with (at certain - frequency) uniform peak and offpeak values. - - Parameters - ---------- - s : Series - Timeseries with hourly or quarterhourly frequency. - freq : {'MS' (month, default) 'QS' (quarter), 'AS' (year)} - Target frequency within which peak and offpeak values will be uniform. - - Returns - ------- - Series - Timeseries where each peak hour within the target frequency has the same - value. Idem for offpeak hours. Index: as original series. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - ts_left - 2020-01-01 00:00:00+01:00 41.88 - 2020-01-01 01:00:00+01:00 38.60 - 2020-01-01 02:00:00+01:00 36.55 - ... - 2020-12-31 21:00:00+01:00 52.44 - 2020-12-31 22:00:00+01:00 51.86 - 2020-12-31 23:00:00+01:00 52.26 - Freq: H, Name: p, Length: 8784, dtype: float64 - - Out: - - ts_left - 2020-01-01 00:00:00+01:00 30.614701 - 2020-01-01 01:00:00+01:00 30.614701 - 2020-01-01 02:00:00+01:00 30.614701 - ... - 2020-12-31 21:00:00+01:00 35.055449 - 2020-12-31 22:00:00+01:00 35.055449 - 2020-12-31 23:00:00+01:00 35.055449 - Freq: H, Name: p, Length: 8784, dtype: float64 - """ - if s.index.freq not in ("H", "15T"): - raise ValueError( - f"Frequency of provided timeseries must be hourly or quarterhourly; got '{s.index.freq}'." - ) - - # Handle possible units. - sin, units = (s.pint.magnitude, s.pint.units) if hasattr(s, "pint") else (s, None) - - # Return normal mean, because all rows have same duration. - sout = sin.groupby(group_function(freq, True)).transform(np.mean) - - # Handle possible units. - if units is not None: - sout = sout.astype(f"pint[{units}]") - return sout - - -def bpoframe2bpoframe( - bpoframe: pd.DataFrame, freq: str = "AS", prefix: str = "" -) -> pd.DataFrame: - """ - Convert a dataframe with base, peak and/or offpeak values to a similar dataframe - with a different frequency. - - Parameters - ---------- - bpoframe : DataFrame - Columns must include at least 2 of {'peak', 'offpeak', 'base'}. Datetimeindex - with frequency in {'MS', 'QS', 'AS'}. - freq : {'MS' (month), 'QS' (quarter), 'AS' (year, default)} - Target frequency. - prefix : str, optional (default: '') - If specified, add this to the column names to search for in the provided dataframe - (and to the column names in the returned dataframes). - - Returns - ------- - DataFrame - Dataframe with base, peak and offpeak values (as columns). Index: timestamps at - provided frequency. - - Notes - ----- - Can only be used for values that are 'averagable' over a time period, like power [MW] - and price [Eur/MWh]. Not for e.g. energy [MWh], revenue [Eur], and duration [h]. - - In: - - base peak offpeak - ts_left - 2020-01-01 00:00:00+01:00 35.034906 42.530036 30.614701 - 2020-02-01 00:00:00+01:00 21.919009 33.295167 15.931557 - ... ... ... - 2020-11-01 00:00:00+01:00 38.785706 49.110873 33.226004 - 2020-12-01 00:00:00+01:00 43.519745 57.872246 35.055449 - 12 rows × 3 columns - - Out: - - base peak offpeak - ts_left - 2020-01-01 00:00:00+01:00 30.490036 38.003536 26.312894 - 2020-04-01 00:00:00+02:00 25.900919 35.295167 20.681892 - 2020-07-01 00:00:00+02:00 32.706785 44.033511 26.371498 - 2020-10-01 00:00:00+02:00 39.455197 54.468722 31.063728 - """ - if freq not in ("MS", "QS", "AS"): - raise ValueError( - f"Parameter ``freq`` must be one of 'MS', 'QS', 'AS'; got {freq}." - ) - if tools_freq.up_or_down(bpoframe.index.freq, freq) == 1: - warnings.warn( - "This conversion includes upsampling, e.g. from yearly to monthly values." - ) - - return tseries2bpoframe(bpoframe2tseries(bpoframe, "H", prefix), freq, prefix) diff --git a/tests/tools/prices/test_convert.py.bak b/tests/tools/prices/test_convert.py.bak index 4e5557e..77ad906 100644 --- a/tests/tools/prices/test_convert.py.bak +++ b/tests/tools/prices/test_convert.py.bak @@ -1,88 +1,13 @@ import functools -from portfolyo.prices import convert -from portfolyo.tools import nits -from portfolyo import testing from pathlib import Path + import numpy as np import pandas as pd import pytest - -@pytest.mark.parametrize("tz", [None, "Europe/Berlin"]) -@pytest.mark.parametrize("withunit", [True, False]) -@pytest.mark.parametrize( - ("b", "p", "o", "o_EuropeBerlin", "ts_left", "freq"), - [ - (100, 100, 100, None, "2020-01-01", "MS"), # 31 days, 23 working days - (100, 200, 41.02564103, None, "2020-01-01", "MS"), - (100, 300, -17.94871795, None, "2020-01-01", "MS"), - (100, 100, 100, None, "2020-01-01", "QS"), # 91 days, 65 working days - (100, 200, 44.44444444, 44.40484676, "2020-01-01", "QS"), - (100, 300, -11.11111111, -11.19030649, "2020-01-01", "QS"), - (100, 100, 100, None, "2020-01-01", "D"), # weekday - (100, 200, 0, None, "2020-01-01", "D"), # weekday - (100, 300, -100, None, "2020-01-01", "D"), # weekday - (100, np.nan, 100, None, "2020-01-04", "D"), # weekend only - ], -) -def test_pbaseppeakpoffpeak_explicit( - b: float, - p: float, - o: float, - ts_left: str, - freq: str, - withunit: bool, - tz: str, - o_EuropeBerlin: float, -): - """Test if base, peak and offpeak values can be calculated from single values.""" - # Handle timezone. - ts_left = pd.Timestamp(ts_left, tz=tz) - if tz is not None and o_EuropeBerlin is not None: - o = o_EuropeBerlin - - # Handle units. - if withunit: # add a (random) unit to see if conversion still works. - b, p, o = nits.Q_(b, "MW"), nits.Q_(p, "MW"), nits.Q_(o, "MW") - - # Do testing. - assert np.isclose(convert.peak(b, o, ts_left, freq), p, equal_nan=True) - if np.isnan(p): - p = 0 if not withunit else nits.Q_(0, "MW") - assert np.isclose(convert.offpeak(b, p, ts_left, freq), o) - assert np.isclose(convert.base(p, o, ts_left, freq), b) - - -@pytest.mark.parametrize("withunits", [True, False]) -@pytest.mark.parametrize("testcol", ["base", "peak", "offpeak"]) -@pytest.mark.parametrize( - "bpoframe", - [ - pd.DataFrame( - { - "peak": [100.0, 100, 100, 100], - "base": [80.0, 80, 80, 80], - "offpeak": [68.2051282, 69.4736842, 68.9770355, 68.421053], - }, - pd.date_range("2020", periods=4, freq="MS", tz="Europe/Berlin"), - ), - pd.DataFrame( - { - "peak": [100.0, 100, 100, 100], - "base": [80.0, 80, 80, 80], - "offpeak": [68.8510638, 68.8699360, 68.9361702, 68.9361702], - }, - pd.date_range("2020", periods=4, freq="AS", tz="Europe/Berlin"), - ), - ], -) -def test_completebpoframe_explicit(bpoframe, testcol: str, withunits: bool): - """Test if missing column can be reconstructed.""" - if withunits: - bpoframe = bpoframe.astype("pint[Eur/MWh]") - df = bpoframe.drop(columns=testcol) - result = convert.complete_bpoframe(df) - testing.assert_frame_equal(bpoframe, result) +from portfolyo import testing +from portfolyo.prices import convert +from portfolyo.tools import nits @functools.lru_cache() diff --git a/tests/tools/test_peakconvert.py b/tests/tools/test_peakconvert.py new file mode 100644 index 0000000..0b7eff9 --- /dev/null +++ b/tests/tools/test_peakconvert.py @@ -0,0 +1,119 @@ +import datetime as dt + +import pandas as pd +import pytest + +from portfolyo import tools + +f_germanpower = tools.peakfn.factory(dt.time(hour=8), dt.time(hour=20)) + + +@pytest.mark.parametrize("withunits", ["units", "nounits"]) +@pytest.mark.parametrize("testcol", ["base", "peak", "offpeak"]) +@pytest.mark.parametrize( + "bpoframe", + [ + pd.DataFrame( + { + "peak": [100.0, 100, 100, 100], + "base": [80.0, 80, 80, 80], + "offpeak": [68.2051282, 69.4736842, 68.9770355, 68.421053], + }, + pd.date_range("2020", periods=4, freq="MS", tz="Europe/Berlin"), + ), + pd.DataFrame( + { + "peak": [100.0, 100, 100, 100], + "base": [80.0, 80, 80, 80], + "offpeak": [68.8510638, 68.8699360, 68.9361702, 68.9361702], + }, + pd.date_range("2020", periods=4, freq="AS", tz="Europe/Berlin"), + ), + ], +) +def test_completebpoframe_averagable(bpoframe, testcol: str, withunits: str): + """Test if missing column can be reconstructed.""" + if withunits == "units": + bpoframe = bpoframe.astype("pint[Eur/MWh]") + df = bpoframe.drop(columns=testcol) + result = tools.peakconvert.complete_bpoframe(df, f_germanpower, is_summable=False) + tools.testing.assert_frame_equal(result, bpoframe) + + +@pytest.mark.parametrize("withunits", ["units", "nounits"]) +@pytest.mark.parametrize("testcol", ["base", "peak", "offpeak"]) +@pytest.mark.parametrize( + "bpoframe", + [ + pd.DataFrame( + { + "peak": [100.0, 100, 100, 100], + "base": [280.0, 180, 80, 380], + "offpeak": [180, 80, -20, 280], + }, + pd.date_range("2020", periods=4, freq="MS", tz="Europe/Berlin"), + ), + pd.DataFrame( + { + "peak": [100.0, 100, 100, 100], + "base": [280.0, 180, 80, 380], + "offpeak": [180, 80, -20, 280], + }, + pd.date_range("2020", periods=4, freq="AS", tz="Europe/Berlin"), + ), + ], +) +def test_completebpoframe_summable(bpoframe, testcol: str, withunits: str): + """Test if missing column can be reconstructed.""" + if withunits == "units": + bpoframe = bpoframe.astype("pint[Eur/MWh]") + df = bpoframe.drop(columns=testcol) + result = tools.peakconvert.complete_bpoframe(df, f_germanpower, is_summable=True) + tools.testing.assert_frame_equal(result, bpoframe) + + +@pytest.mark.parametrize("tz", [None, "Europe/Berlin"]) +@pytest.mark.parametrize("withunits", ["units", "nounits"]) +@pytest.mark.parametrize("testcol", ["base", "peak", "offpeak"]) +@pytest.mark.parametrize( + ("b", "p", "o", "o_EuropeBerlin", "ts_left", "freq"), + [ + (100, 100, 100, None, "2020-01-01", "MS"), # 31 days, 23 working days + (100, 200, 41.02564103, None, "2020-01-01", "MS"), + (100, 300, -17.94871795, None, "2020-01-01", "MS"), + (100, 100, 100, None, "2020-01-01", "QS"), # 91 days, 65 working days + (100, 200, 44.44444444, 44.40484676, "2020-01-01", "QS"), + (100, 300, -11.11111111, -11.19030649, "2020-01-01", "QS"), + (100, 100, 100, None, "2020-01-01", "D"), # weekday + (100, 200, 0, None, "2020-01-01", "D"), # weekday + (100, 300, -100, None, "2020-01-01", "D"), # weekday + ], +) +def test_moreconversions_averagable( + b: float, + p: float, + o: float, + ts_left: str, + freq: str, + withunits: str, + tz: str, + o_EuropeBerlin: float, + testcol: str, +): + """Test if base, peak and offpeak values can be calculated from single values.""" + # Handle timezone. + i = pd.date_range(ts_left, freq=freq, tz=tz, periods=1) + if tz is not None and o_EuropeBerlin is not None: + o = o_EuropeBerlin + + expected = pd.DataFrame({"peak": [p], "base": [b], "offpeak": [o]}, i).astype(float) + + # Handle units. + if withunits == "units": + expected = expected.astype("pint[MW]") + + df = expected.drop(columns=testcol) + + # Do testing. + result = tools.peakconvert.complete_bpoframe(df, f_germanpower, is_summable=False) + tools.testing.assert_frame_equal(result, expected) diff --git a/tests/tools/test_peakfn.py b/tests/tools/test_peakfn.py index 7f97aa2..49a19fd 100644 --- a/tests/tools/test_peakfn.py +++ b/tests/tools/test_peakfn.py @@ -193,7 +193,7 @@ def do_test( (2022, (365, 260), False, 21, 20, 23), ], ) -def test_duration( +def test_peakduration_longfreqs( year, bp, jan_1_weekday, jan_p, feb_p, mar_p, tz, mar_b_corr, freq, month ): """Test if the correct number of base, peak and offpeak hours are calculated. @@ -201,11 +201,8 @@ def test_duration( number of days with peak hours in each month; mar_b_corr = correction to number of base HOURS.""" - if tz is None: - return # TODO: make sure the duration_base, duration_peak etc functions accept timezone-agnostic data - if month > 1 and freq != "MS": - return + pytest.skip("Feb and Mar are only checked on month-level here.") start = pd.Timestamp(f"{year}-{month}", tz=tz) i = pd.date_range(start, freq=freq, periods=1) @@ -242,3 +239,89 @@ def test_duration( tools.testing.assert_series_equal(expected_b, result_b) tools.testing.assert_series_equal(expected_p, result_p) tools.testing.assert_series_equal(expected_o, result_o) + + +@pytest.mark.parametrize( + "i,duration,peakduration", + [ + # Quarters + ( + pd.date_range("2020", freq="QS", periods=2, tz=None), + [(31 + 29 + 31) * 24, (30 + 31 + 30) * 24], + [(23 + 20 + 22) * 12, (22 + 21 + 22) * 12], + ), + ( + pd.date_range("2020", freq="QS", periods=2, tz="Europe/Berlin"), + [(31 + 29 + 31) * 24 - 1, (30 + 31 + 30) * 24], + [(23 + 20 + 22) * 12, (22 + 21 + 22) * 12], + ), + # Months + ( + pd.date_range("2020", freq="MS", periods=3, tz=None), + [31 * 24, 29 * 24, 31 * 24], + [23 * 12, 20 * 12, 22 * 12], + ), + ( + pd.date_range("2020", freq="MS", periods=3, tz="Europe/Berlin"), + [31 * 24, 29 * 24, 31 * 24 - 1], + [23 * 12, 20 * 12, 22 * 12], + ), + # Days + ( + pd.date_range("2020", freq="D", periods=7, tz=None), + [24] * 7, + [12, 12, 12, 0, 0, 12, 12], + ), + # . End-of-March: DST (if observed in tz) + ( + pd.date_range("2020-03-25", freq="D", periods=7, tz=None), + [24, 24, 24, 24, 24, 24, 24], + [12, 12, 12, 0, 0, 12, 12], + ), + ( + pd.date_range("2020-03-25", freq="D", periods=7, tz="Europe/Berlin"), + [24, 24, 24, 24, 23, 24, 24], + [12, 12, 12, 0, 0, 12, 12], + ), + # Hours + ( + pd.date_range("2020", freq="H", periods=48, tz=None), + [1] * 48, + [*[0] * 8, *[1] * 12, *[0] * 12, *[1] * 12, *[0] * 4], + ), + # . End-of-March: DST (if observed in tz) + ( + pd.date_range("2020-03-29", freq="H", periods=48, tz=None), + [1] * 48, + [*[0] * 32, *[1] * 12, *[0] * 4], + ), + ( + pd.date_range("2020-03-29", freq="H", periods=47, tz="Europe/Berlin"), + [1] * 47, + [*[0] * 31, *[1] * 12, *[0] * 4], + ), + # Quarterhours + ( + pd.date_range("2020", freq="15T", periods=192, tz=None), + [0.25] * 192, + [*[0] * 32, *[0.25] * 48, *[0] * 48, *[0.25] * 48, *[0] * 16], + ), + ], +) +@pytest.mark.parametrize("what", ["base", "peak", "offpeak"]) +def test_peakduration_allfreqs( + i: pd.DatetimeIndex, duration: Iterable, peakduration: Iterable, what: str +): + """Test if peak duration is correctly calculated for all frequencies.""" + if what == "duration": + values = duration + result = tools.duration.index(i) + elif what == "peak": + values = peakduration + result = tools.peakfn.peak_duration(i, f_germanpower) + else: # 'offpeak' + values = (b - p for b, p in zip(duration, peakduration)) + result = tools.peakfn.offpeak_duration(i, f_germanpower) + + expected = pd.Series(values, i, dtype=float).astype("pint[h]").rename("duration") + tools.testing.assert_series_equal(result, expected) From 04a123b367c77bf7b96e178c094566fc799f6f90 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 22 May 2024 12:23:01 +0200 Subject: [PATCH 54/59] removed nonexisting import --- portfolyo/__init__.py | 1 + portfolyo/tools/__init__.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/portfolyo/__init__.py b/portfolyo/__init__.py index 93c6b78..8fe3f38 100644 --- a/portfolyo/__init__.py +++ b/portfolyo/__init__.py @@ -16,6 +16,7 @@ from .tools.freq import FREQUENCIES from .tools.hedge import hedge from .tools.peakfn import PeakFunction +from .tools.peakfn import factory as create_peakfn from .tools.product import germanpower_peakfn, is_peak_hour from .tools.standardize import frame as standardize from .tools.tzone import force_agnostic, force_aware diff --git a/portfolyo/tools/__init__.py b/portfolyo/tools/__init__.py index fa49fa8..694d064 100644 --- a/portfolyo/tools/__init__.py +++ b/portfolyo/tools/__init__.py @@ -15,7 +15,6 @@ leftandright, peakconvert, peakfn, - prices, product, right, righttoleft, From 98b12efe7b517d74dae622dd3a331961efebfc16 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 22 May 2024 17:21:57 +0200 Subject: [PATCH 55/59] fixed test --- tests/tools/test_peakfn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tools/test_peakfn.py b/tests/tools/test_peakfn.py index 49a19fd..df8a9e4 100644 --- a/tests/tools/test_peakfn.py +++ b/tests/tools/test_peakfn.py @@ -231,7 +231,7 @@ def test_peakduration_longfreqs( expected_p = pd.Series([float(p)], i, dtype="pint[h]", name="duration") expected_o = expected_b - expected_p - result_b = tools.peakfn.base_duration(i) + result_b = tools.duration.index(i) result_p = tools.peakfn.peak_duration(i, f_germanpower) result_o = tools.peakfn.offpeak_duration(i, f_germanpower) From 152016e26c348ed38ff1b8562a390b8f7331c6fb Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Wed, 22 May 2024 19:09:04 +0200 Subject: [PATCH 56/59] removed all Union and replaced with | --- portfolyo/core/pfline/arithmatic.py | 12 +- portfolyo/core/pfline/children.py | 6 +- portfolyo/core/pfline/interop.py | 22 ++-- portfolyo/core/pfstate/arithmatic.py | 6 +- portfolyo/dev/develop.py | 4 +- portfolyo/tools/changeyear.py | 11 +- portfolyo/tools/frame.py | 8 +- portfolyo/tools/freq.py | 12 +- portfolyo/tools/intersect.py | 7 +- portfolyo/tools/isboundary.py | 54 +++++++-- portfolyo/tools/product.py | 110 ------------------- portfolyo/tools/standardize.py | 13 +-- portfolyo/tools/startofday.py | 7 +- portfolyo/tools/tzone.py | 31 ++---- portfolyo/tools/unit.py | 53 +++++++-- portfolyo/tools/visualize/categories.py | 4 +- portfolyo/tools/wavg.py | 62 +++++++---- portfolyo/tools2/intersect.py | 11 +- portfolyo/tools2/types.py | 10 ++ tests/core/pfline/test_pfline_init.py | 4 +- tests/tools/test_changefreq_fromexcel.py.bak | 4 +- tests/tools/test_freq.py | 4 +- tests/tools/test_intersect.py | 10 +- tests/tools/test_intersect_flex.py | 6 +- tests/tools/test_isboundary.py | 10 +- tests/tools/test_wavg.py | 4 +- tests/tools2/test_indexable.py | 4 +- 27 files changed, 222 insertions(+), 267 deletions(-) create mode 100644 portfolyo/tools2/types.py diff --git a/portfolyo/core/pfline/arithmatic.py b/portfolyo/core/pfline/arithmatic.py index 9a845a2..7acea4f 100644 --- a/portfolyo/core/pfline/arithmatic.py +++ b/portfolyo/core/pfline/arithmatic.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Any import numpy as np import pandas as pd @@ -185,7 +185,7 @@ def __rmul__(self: PfLine, other: Any) -> PfLine: @Prep.standardize_other # other converted to None, a PfLine, or dimless Series @Prep.raiseerror_if_otherNone # other is now a PfLine or dimless Series... @Prep.assert_objects_indexcompatibility # ... with a compatible index - def __truediv__(self: PfLine, other: Any) -> Union[PfLine, pd.Series]: + def __truediv__(self: PfLine, other: Any) -> PfLine | pd.Series: if isinstance(other, pd.Series): return Multiply.pfline_and_series(self, 1 / other) else: @@ -195,7 +195,7 @@ def __truediv__(self: PfLine, other: Any) -> Union[PfLine, pd.Series]: @Prep.raiseerror_if_otherNone # other is now a PfLine or dimless Series @Prep.raiseerror_if_otherdimlessseries # other is now a PfLine... @Prep.assert_objects_indexcompatibility # ... with a compatible index - def __rtruediv__(self: PfLine, other: Any) -> Union[PfLine, pd.Series]: + def __rtruediv__(self: PfLine, other: Any) -> PfLine | pd.Series: return Divide.two_pflines(other, self) # NB order! @Prep.standardize_other # other converted to None, a PfLine, or dimless Series @@ -285,12 +285,10 @@ def nestedpfline_and_series(pfl: NestedPfLine, s: pd.Series) -> NestedPfLine: class Divide: @Prep.ensure_pflines_flat # pfl1 and pfl2 are now both flat - def two_pflines(pfl1: PfLine, pfl2: PfLine) -> Union[pd.Series, PfLine]: + def two_pflines(pfl1: PfLine, pfl2: PfLine) -> pd.Series | PfLine: return Divide.two_flatpflines(pfl1, pfl2) - def two_flatpflines( - pfl1: FlatPfLine, pfl2: FlatPfLine - ) -> Union[pd.Series, FlatPfLine]: + def two_flatpflines(pfl1: FlatPfLine, pfl2: FlatPfLine) -> pd.Series | FlatPfLine: if pfl1.kind is pfl2.kind: if pfl1.kind is Kind.COMPLETE: raise NotImplementedError( diff --git a/portfolyo/core/pfline/children.py b/portfolyo/core/pfline/children.py index 824dfc5..c118f34 100644 --- a/portfolyo/core/pfline/children.py +++ b/portfolyo/core/pfline/children.py @@ -1,7 +1,7 @@ from __future__ import annotations import warnings -from typing import TYPE_CHECKING, Any, Mapping, Union +from typing import TYPE_CHECKING, Any, Mapping from ... import tools from . import create @@ -11,9 +11,7 @@ class ChildFunctionality(Mapping): - def set_child( - self: NestedPfLine, name: str, child: Union[PfLine, Any] - ) -> NestedPfLine: + def set_child(self: NestedPfLine, name: str, child: PfLine | Any) -> NestedPfLine: """Set/add/update child; returns new pfline instance without changing current instance.""" if name in ["w", "q", "p", "r"]: raise ValueError("Name cannot be one of 'w', 'q', 'p', 'r'.") diff --git a/portfolyo/core/pfline/interop.py b/portfolyo/core/pfline/interop.py index f59e2ae..22bfd41 100644 --- a/portfolyo/core/pfline/interop.py +++ b/portfolyo/core/pfline/interop.py @@ -4,7 +4,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Dict, Iterable, Mapping, Union +from typing import TYPE_CHECKING, Any, Dict, Iterable, Mapping import numpy as np import pandas as pd @@ -44,12 +44,12 @@ class InOp: inop = inop.to_df() """ - w: Union[tools.unit.Q_, pd.Series] = None - q: Union[tools.unit.Q_, pd.Series] = None - p: Union[tools.unit.Q_, pd.Series] = None - r: Union[tools.unit.Q_, pd.Series] = None - nodim: Union[tools.unit.Q_, pd.Series] = None # explicitly dimensionless - agn: Union[float, pd.Series] = None # agnostic + w: tools.unit.Q_ | pd.Series = None + q: tools.unit.Q_ | pd.Series = None + p: tools.unit.Q_ | pd.Series = None + r: tools.unit.Q_ | pd.Series = None + nodim: tools.unit.Q_ | pd.Series = None # explicitly dimensionless + agn: float | pd.Series = None # agnostic def __post_init__(self): # Add correct units and check type. @@ -219,8 +219,8 @@ def __eq__(self, other) -> bool: def _set_unit( - v: Union[float, int, tools.unit.Q_, pd.Series], attr: str -) -> Union[float, tools.unit.Q, pd.Series]: + v: float | int | tools.unit.Q_ | pd.Series, attr: str +) -> float | tools.unit.Q | pd.Series: """Set unit (if none set yet) or convert to unit.""" if v is None: return None @@ -305,7 +305,7 @@ def _unit2attr(unit) -> str: def _from_data( - data: Union[float, tools.unit.Q_, pd.Series, Dict, pd.DataFrame, Iterable, Mapping] + data: float | tools.unit.Q_ | pd.Series | Dict | pd.DataFrame | Iterable | Mapping, ) -> InOp: """Turn ``data`` into a InterOp object.""" @@ -411,7 +411,7 @@ def _equal(inop1: InOp, inop2: InOp) -> InOp: def pfline_or_nodimseries( data: Any, ref_index: pd.DatetimeIndex, agn_default: str = None -) -> Union[None, pd.Series, FlatPfLine]: +) -> None | pd.Series | FlatPfLine: """Turn ``data`` into PfLine if dimension-aware. If not, turn into Series.""" # Already a PfLine. diff --git a/portfolyo/core/pfstate/arithmatic.py b/portfolyo/core/pfstate/arithmatic.py index 2319734..dec9526 100644 --- a/portfolyo/core/pfstate/arithmatic.py +++ b/portfolyo/core/pfstate/arithmatic.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Union +from typing import TYPE_CHECKING, Any import pandas as pd @@ -36,9 +36,7 @@ def wrapper(pfs: PfState, other: Any): return wrapper - def _prep_data( - value, refindex: pd.DatetimeIndex - ) -> Union[pd.Series, PfLine, PfState]: + def _prep_data(value, refindex: pd.DatetimeIndex) -> pd.Series | PfLine | PfState: """Turn ``value`` into PfLine or PfState if possible. If not, turn into (normal or unit-aware) Series.""" # None. diff --git a/portfolyo/dev/develop.py b/portfolyo/dev/develop.py index edc7658..9a2e6b0 100644 --- a/portfolyo/dev/develop.py +++ b/portfolyo/dev/develop.py @@ -3,7 +3,7 @@ """ import datetime as dt -from typing import Callable, Dict, Tuple, Union +from typing import Callable, Dict, Tuple import numpy as np import pandas as pd @@ -68,7 +68,7 @@ def _shorten_index_if_necessary(i, start_of_day) -> pd.DatetimeIndex: def get_value( name: str = None, has_unit: bool = True, magn: float = None, *, _seed: int = None -) -> Union[float, tools.unit.Q_]: +) -> float | tools.unit.Q_: """Get a single value.""" if _seed: np.random.seed(_seed) diff --git a/portfolyo/tools/changeyear.py b/portfolyo/tools/changeyear.py index 22a9485..00f7617 100644 --- a/portfolyo/tools/changeyear.py +++ b/portfolyo/tools/changeyear.py @@ -7,7 +7,7 @@ # . Daylight-savings time will likely start and end at a different day. # . Weekdays and holidays are not at the same date. -from typing import Callable, Union +from typing import Callable import holidays import pandas as pd @@ -16,6 +16,7 @@ from . import freq as tools_freq from . import right as tools_right from . import unit as tools_unit +from .types import Series_or_DataFrame docstringliteral_notes = """ * Function is meant for data that spans full months. Using partial months may lead @@ -364,10 +365,10 @@ def map_index_to_year( @additional_notes def map_frame_to_index( - source: Union[pd.Series, pd.DataFrame], + source: Series_or_DataFrame, idx_target: pd.DatetimeIndex, holiday_country: str = None, -) -> Union[pd.Series, pd.DataFrame]: +) -> Series_or_DataFrame: """Transfer the data in a Series or DataFrame to a hypothetical other index according to certain rules (see Notes). What would the data have looked like if it had occured in a different year? @@ -406,10 +407,10 @@ def map_frame_to_index( @additional_notes def map_frame_to_year( - source: Union[pd.Series, pd.DataFrame], + source: Series_or_DataFrame, target_year: int, holiday_country: str = None, -) -> Union[pd.Series, pd.DataFrame]: +) -> Series_or_DataFrame: """Transfer the data in a Series or DataFrame to a hypothetical other year according to certain rules (see Notes). What would the data have looked like if it had occured in a different year? diff --git a/portfolyo/tools/frame.py b/portfolyo/tools/frame.py index af2ca9d..512b085 100644 --- a/portfolyo/tools/frame.py +++ b/portfolyo/tools/frame.py @@ -3,15 +3,15 @@ """ import functools -from typing import Any, Iterable, Union +from typing import Any, Iterable import numpy as np import pandas as pd +from .types import Series_or_DataFrame -def fill_gaps( - fr: Union[pd.Series, pd.DataFrame], maxgap: int = 2 -) -> Union[pd.Series, pd.DataFrame]: + +def fill_gaps(fr: Series_or_DataFrame, maxgap: int = 2) -> Series_or_DataFrame: """Fill gaps in series by linear interpolation. Parameters diff --git a/portfolyo/tools/freq.py b/portfolyo/tools/freq.py index d7f3372..d2f3e34 100644 --- a/portfolyo/tools/freq.py +++ b/portfolyo/tools/freq.py @@ -2,11 +2,11 @@ Tools for dealing with frequencies. """ -from typing import Union - import numpy as np import pandas as pd +from .types import Series_or_DataFrame + # Allowed frequencies. # Perfect containment; a short-frequency time period always entirely falls within a single high-frequency time period. # AS -> 4 QS; QS -> 3 MS; MS -> 28-31 D; D -> 23-25 H; H -> 4 15T @@ -114,7 +114,7 @@ def longest(*freqs: str) -> str: return _longestshortest(False, *freqs) -def to_offset(freq: str) -> Union[pd.Timedelta, pd.DateOffset]: +def to_offset(freq: str) -> pd.Timedelta | pd.DateOffset: """Object that can be added to a left-bound timestamp to find corresponding right-bound timestamp. Parameters @@ -237,8 +237,8 @@ def set_to_index( def set_to_frame( - fr: Union[pd.Series, pd.DataFrame], wanted: str = None, strict: bool = False -) -> Union[pd.Series, pd.DataFrame]: + fr: Series_or_DataFrame, wanted: str = None, strict: bool = False +) -> Series_or_DataFrame: """Try to read, infer, or force frequency of frame's index. Parameters @@ -251,7 +251,7 @@ def set_to_frame( Returns ------- - Union[pd.Series, pd.DataFrame] + pd.Series | pd.DataFrame Same type as ``fr``, with, if possible, a valid value for ``fr.index.freq``. """ # Handle non-datetime-indices. diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index b8cfa87..2ccf9b3 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -1,11 +1,12 @@ from datetime import datetime -from typing import List, Tuple, Union +from typing import List, Tuple import pandas as pd from . import freq as tools_freq from . import right as tools_right from . import trim as tools_trim +from .types import Series_or_DataFrame def indices(*idxs: pd.DatetimeIndex) -> pd.DatetimeIndex: @@ -190,11 +191,11 @@ def indices_flex( def frames( - *frames: Union[pd.Series, pd.DataFrame], + *frames: Series_or_DataFrame, ignore_freq: bool = False, ignore_tz: bool = False, ignore_start_of_day: bool = False, -) -> List[Union[pd.Series, pd.DataFrame]]: +) -> List[Series_or_DataFrame]: """Intersect several dataframes and/or series. Parameters diff --git a/portfolyo/tools/isboundary.py b/portfolyo/tools/isboundary.py index e6208ef..001a5e4 100644 --- a/portfolyo/tools/isboundary.py +++ b/portfolyo/tools/isboundary.py @@ -3,7 +3,7 @@ """ import datetime as dt -from typing import Union +from typing import overload import numpy as np import pandas as pd @@ -17,23 +17,59 @@ # i = pd.date_range('2020-01-01', freq='MS', periods=12) # i.is_year_start # array([False, False, False, False, False, False, False, False, False, False, False, True]) -def is_year_start(i: Union[pd.Timestamp, pd.DatetimeIndex]) -> Union[bool, np.ndarray]: +@overload +def is_year_start(i: pd.Timestamp) -> bool: + ... + + +@overload +def is_year_start(i: pd.DatetimeIndex) -> np.ndarray: + ... + + +def is_year_start(i: pd.Timestamp | pd.DatetimeIndex) -> bool | np.ndarray: return (i.day == 1) & (i.month == 1) -def is_quarter_start( - i: Union[pd.Timestamp, pd.DatetimeIndex] -) -> Union[bool, np.ndarray]: +@overload +def is_quarter_start(i: pd.Timestamp) -> bool: + ... + + +@overload +def is_quarter_start(i: pd.DatetimeIndex) -> np.ndarray: + ... + + +def is_quarter_start(i: pd.Timestamp | pd.DatetimeIndex) -> bool | np.ndarray: return (i.day == 1) & ((i.month - 1) % 3 == 0) -def is_month_start(i: Union[pd.Timestamp, pd.DatetimeIndex]) -> Union[bool, np.ndarray]: +@overload +def is_month_start(i: pd.Timestamp) -> bool: + ... + + +@overload +def is_month_start(i: pd.DatetimeIndex) -> np.ndarray: + ... + + +def is_month_start(i: pd.Timestamp | pd.DatetimeIndex) -> bool | np.ndarray: return i.day == 1 -def is_X_start( - i: Union[pd.Timestamp, pd.DatetimeIndex], freq: str -) -> Union[bool, np.ndarray]: +@overload +def is_X_start(i: pd.Timestamp) -> bool: + ... + + +@overload +def is_X_start(i: pd.DatetimeIndex) -> np.ndarray: + ... + + +def is_X_start(i: pd.Timestamp | pd.DatetimeIndex, freq: str) -> bool | np.ndarray: if freq == "MS": return is_month_start(i) elif freq == "QS": diff --git a/portfolyo/tools/product.py b/portfolyo/tools/product.py index 9faf61e..152fc54 100644 --- a/portfolyo/tools/product.py +++ b/portfolyo/tools/product.py @@ -41,116 +41,6 @@ def is_peak_hour(i: pd.DatetimeIndex) -> pd.Series: return germanpower_peakfn(i) -# def duration_base( -# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -# ) -> Union[tools_unit.Q_, pd.Series]: -# """ -# Total duration of base periods in a timestamp. -# -# Parameters -# ---------- -# ts_left : pd.Timestamp | pd.DatetimeIndex -# Timestamp or index for which to calculate the duration. -# -# See also -# -------- -# .tools.duration -# """ -# if isinstance(ts_left, pd.DatetimeIndex): -# return tools_duration.index(ts_left) -# -# # Assume it's a single timestamp. -# return tools_duration.stamp(ts_left, freq) -# -# -# def duration_peak( -# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -# ) -> Union[tools_unit.Q_, pd.Series]: -# """ -# Total duration of peak periods in a timestamp. -# -# See also -# -------- -# .tools.duration -# """ -# if freq is None: -# freq = ts_left.freq -# -# if freq not in tools_freq.FREQUENCIES: -# raise ValueError( -# f"Parameter ``freq`` must be one of {', '.join(tools_freq.FREQUENCIES)}; got {freq}." -# ) -# -# if isinstance(ts_left, pd.DatetimeIndex): -# if freq in ["15T", "H"]: -# return tools_duration.index(ts_left) * is_peak_hour(ts_left) -# elif freq == "D": -# hours = ts_left.map(lambda ts: ts.isoweekday() < 6) * 12.0 # no unit -# return pd.Series(hours, ts_left, dtype="pint[h]") # works even during dst -# else: -# # dur = ts_left.map(duration_peak) # crashes due to behaviour of .map method -# hours = (duration_peak(ts, freq) for ts in ts_left) # has unit -# return pd.Series(hours, ts_left, dtype="pint[h]") -# -# # Assume it's a single timestamp. -# if freq in ["15T", "H"]: -# return tools_duration.stamp(ts_left, freq) * is_peak_hour(ts_left) -# elif freq == "D": -# return tools_unit.Q_(0.0 if ts_left.isoweekday() >= 6 else 12.0, "h") -# else: -# ts_right = tools_right.stamp(ts_left, freq) -# days = pd.date_range(ts_left, ts_right, freq="D", inclusive="left") -# return tools_unit.Q_( -# sum(days.map(lambda day: day.isoweekday() < 6) * 12.0), "h" -# ) -# -# -# def duration_offpeak( -# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -# ) -> Union[tools_unit.Q_, pd.Series]: -# """ -# Total duration of offpeak periods in a timestamp. -# -# See also -# -------- -# .tools.duration -# """ -# return duration_base(ts_left, freq) - duration_peak(ts_left, freq) -# -# -# def duration_bpo( -# ts_left: Union[pd.Timestamp, pd.DatetimeIndex], freq: str = None -# ) -> Union[pd.Series, pd.DataFrame]: -# """ -# Duration of base, peak and offpeak periods in a timestamp. -# -# Parameters -# ---------- -# ts_left : Union[pd.Timestamp, pd.DatetimeIndex] -# Timestamp(s) for which to calculate the base, peak and offpeak durations. -# freq : {'15T' (quarter-hour), 'H' (hour), 'D' (day), 'MS' (month), 'QS' (quarter), -# 'AS' (year)}, optional -# Frequency to use in determining the durations. -# If none specified, use ``.freq`` attribute of ``ts_left``. -# -# Returns -# ------- -# Series (if ts_left is Timestamp) or DataFrame (if ts_left is DatetimeIndex). -# """ -# if freq is None and isinstance(ts_left, pd.DatetimeIndex): -# freq = ts_left.freq -# -# b = duration_base(ts_left, freq) # quantity or pint-series -# p = duration_peak(ts_left, freq) # quantity or pint-series -# -# if isinstance(ts_left, pd.DatetimeIndex): -# return pd.DataFrame({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") -# -# # Assume it's a single timestamp. -# return pd.Series({"base": b, "peak": p, "offpeak": b - p}, dtype="pint[h]") -# # - - def delivery_period( ts_trade: pd.Timestamp, period_type: str = "m", diff --git a/portfolyo/tools/standardize.py b/portfolyo/tools/standardize.py index 24925f4..054811c 100644 --- a/portfolyo/tools/standardize.py +++ b/portfolyo/tools/standardize.py @@ -2,8 +2,6 @@ Standardizing series and dataframes to use as input for PfLine. """ -from typing import Union - import pandas as pd from pytz import AmbiguousTimeError, NonExistentTimeError @@ -11,16 +9,17 @@ from . import right as tools_right from . import righttoleft as tools_righttoleft from . import tzone as tools_tzone +from .types import Series_or_DataFrame def frame( - fr: Union[pd.Series, pd.DataFrame], + fr: Series_or_DataFrame, force: str = None, bound: str = "left", *, tz: str = None, floating: bool = True, -) -> Union[pd.Series, pd.DataFrame]: +) -> Series_or_DataFrame: """Standardize a series or dataframe. Parameters @@ -53,7 +52,7 @@ def frame( Returns ------- - Union[pd.Series, pd.DataFrame] + pd.Series | pd.DataFrame Same type as ``fr``, with a left-bound DatetimeIndex, a valid frequency, and wanted timezone. @@ -151,11 +150,11 @@ def _fix_timezone(fr, force, tz, floating): ) -def _standardize_index_name(fr: Union[pd.Series, pd.DataFrame]): +def _standardize_index_name(fr: Series_or_DataFrame) -> Series_or_DataFrame: return fr.rename_axis(index="ts_left") -def assert_frame_standardized(fr: Union[pd.Series, pd.DataFrame]): +def assert_frame_standardized(fr: Series_or_DataFrame) -> None: """Assert that series or dataframe is standardized.""" assert_index_standardized(fr.index) diff --git a/portfolyo/tools/startofday.py b/portfolyo/tools/startofday.py index 2cc3415..50e6cf7 100644 --- a/portfolyo/tools/startofday.py +++ b/portfolyo/tools/startofday.py @@ -3,7 +3,6 @@ """ import datetime as dt -from typing import Union import pandas as pd @@ -11,9 +10,7 @@ from . import right as tools_right -def get( - i: pd.DatetimeIndex, returntype: str = "time" -) -> Union[dt.time, str, dt.timedelta]: +def get(i: pd.DatetimeIndex, returntype: str = "time") -> dt.time | str | dt.timedelta: """Get start-of-day of an index. Parameters @@ -27,7 +24,7 @@ def get( Returns ------- - Union[dt.time, str, dt.timedelta] + dt.time | str | dt.timedelta """ start_of_day = i[0].time() if returntype == "time": diff --git a/portfolyo/tools/tzone.py b/portfolyo/tools/tzone.py index 41d563a..6a2b381 100644 --- a/portfolyo/tools/tzone.py +++ b/portfolyo/tools/tzone.py @@ -1,11 +1,10 @@ """Tools to deal with timezones.""" -from typing import Union - import pandas as pd import pytz from . import freq as tools_freq +from .types import Series_or_DataFrame """ (hourly means: hourly or shorter) @@ -56,8 +55,8 @@ def force_aware( - fr: Union[pd.Series, pd.DataFrame], tz: str, *, floating: bool = True -) -> Union[pd.Series, pd.DataFrame]: + fr: Series_or_DataFrame, tz: str, *, floating: bool = True +) -> Series_or_DataFrame: """Convert/set series or dataframe to a specific timezone. Parameters @@ -136,9 +135,7 @@ def force_aware( return fr_out -def force_agnostic( - fr: Union[pd.Series, pd.DataFrame] -) -> Union[pd.Series, pd.DataFrame]: +def force_agnostic(fr: Series_or_DataFrame) -> Series_or_DataFrame: """Turn a frame (series or dataframe) into timezone-agnostic frame. Parameters @@ -195,9 +192,7 @@ def force_agnostic( return fr_out -def _A_to_A( - fr: Union[pd.Series, pd.DataFrame], *, tz, floating -) -> Union[pd.Series, pd.DataFrame]: +def _A_to_A(fr: Series_or_DataFrame, *, tz: str, floating: bool) -> Series_or_DataFrame: if isinstance(tz, str): # convert to make comparison (below) possible tz = pytz.timezone(tz) @@ -215,17 +210,15 @@ def _A_to_A( return _B_to_A(_A_to_B(fr), tz=tz) -def _A_to_B(fr: Union[pd.Series, pd.DataFrame]) -> Union[pd.Series, pd.DataFrame]: +def _A_to_B(fr: Series_or_DataFrame) -> Series_or_DataFrame: return _aware_to_agnostic(fr) -def _B_to_A( - fr: Union[pd.Series, pd.DataFrame], *, tz -) -> Union[pd.Series, pd.DataFrame]: +def _B_to_A(fr: Series_or_DataFrame, *, tz) -> Series_or_DataFrame: return _agnostic_to_aware(fr, tz) -def _idx_after_conversion(fr: Union[pd.Series, pd.DataFrame], tz) -> pd.DatetimeIndex: +def _idx_after_conversion(fr: Series_or_DataFrame, tz) -> pd.DatetimeIndex: fr = tools_freq.set_to_frame(fr) freq_input = fr.index.freq if not freq_input: @@ -238,9 +231,7 @@ def _idx_after_conversion(fr: Union[pd.Series, pd.DataFrame], tz) -> pd.Datetime return idx -def _agnostic_to_aware( - fr: Union[pd.Series, pd.DataFrame], tz: str -) -> Union[pd.Series, pd.DataFrame]: +def _agnostic_to_aware(fr: Series_or_DataFrame, tz: str) -> Series_or_DataFrame: """Recalculate values in tz-agnostic series or dataframe, to get a tz-aware one. (i.e., B to A).""" if tz_input := fr.index.tz: @@ -263,9 +254,7 @@ def _agnostic_to_aware( return fr.loc[mapping_onto_input_index].set_axis(idx_out) -def _aware_to_agnostic( - fr: Union[pd.Series, pd.DataFrame] -) -> Union[pd.Series, pd.DataFrame]: +def _aware_to_agnostic(fr: Series_or_DataFrame) -> Series_or_DataFrame: """Recalculate values in tz-aware series or dataframe, to get a tz-agnostic one. (i.e., A to B).""" if not fr.index.tz: diff --git a/portfolyo/tools/unit.py b/portfolyo/tools/unit.py index b6175a7..6da956a 100644 --- a/portfolyo/tools/unit.py +++ b/portfolyo/tools/unit.py @@ -3,7 +3,7 @@ """ from pathlib import Path -from typing import Tuple, Union +from typing import Tuple, overload import pandas as pd import pint @@ -53,9 +53,29 @@ def from_name(name: str) -> pint.Unit: raise ValueError(f"No standard unit found for name '{name}'.") +@overload +def defaultunit(val: int | float) -> float: + ... + + +@overload +def defaultunit(val: pint.Quantity) -> pint.Quantity: + ... + + +@overload +def defaultunit(val: pd.Series) -> pd.Series: + ... + + +@overload +def defaultunit(val: pd.DataFrame) -> pd.DataFrame: + ... + + def defaultunit( - val: Union[int, float, pint.Quantity, pd.Series, pd.DataFrame], -) -> Union[float, pint.Quantity, pd.Series, pd.DataFrame]: + val: int | float | pint.Quantity | pd.Series | pd.DataFrame, +) -> float | pint.Quantity | pd.Series | pd.DataFrame: """Convert ``val`` to base units. Also turns dimensionless values into floats. Parameters @@ -101,15 +121,26 @@ def defaultunit( raise TypeError("``val`` must be an int, float, Quantity, Series, or DataFrame.") +@overload +def split_magn_unit(val: int | float) -> Tuple[float, None]: + ... + + +@overload +def split_magn_unit(val: pint.Quantity) -> Tuple[float, None | pint.Unit]: + ... + + +@overload +def split_magn_unit( + val: pd.Series, +) -> Tuple[pd.Series, None | pint.Unit | pd.Series]: + ... + + def split_magn_unit( - val: Union[int, float, pint.Quantity, pd.Series] -) -> Union[ - Tuple[float, None], - Tuple[float, pint.Unit], - Tuple[pd.Series, None], - Tuple[pd.Series, pint.Unit], - Tuple[pd.Series, pd.Series], -]: + val: int | float | pint.Quantity | pd.Series, +) -> Tuple[float, None | pint.Unit] | Tuple[pd.Series, None | pint.Unit | pd.Series]: """Split ``val`` into magnitude and units. If ``val`` is a Series with uniform dimension, the unit is returned as a pint Unit. If not, it is returned as a Series. """ diff --git a/portfolyo/tools/visualize/categories.py b/portfolyo/tools/visualize/categories.py index 2ebff9c..0136710 100644 --- a/portfolyo/tools/visualize/categories.py +++ b/portfolyo/tools/visualize/categories.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, Iterable, Union +from typing import Any, Iterable import numpy as np import pandas as pd @@ -44,7 +44,7 @@ def _get_subset(self, attr: str, max_count: int = None) -> Iterable: def x(self, max_count: int = None) -> Iterable[int]: return self._get_subset("x", max_count) - def y(self, max_count: int = None) -> Iterable[Union[float, tools_unit.Q_]]: + def y(self, max_count: int = None) -> Iterable[float | tools_unit.Q_]: return self._get_subset("y", max_count) def ts(self, max_count: int = None) -> Iterable[pd.Timestamp]: diff --git a/portfolyo/tools/wavg.py b/portfolyo/tools/wavg.py index 492b8ab..6b01092 100644 --- a/portfolyo/tools/wavg.py +++ b/portfolyo/tools/wavg.py @@ -1,4 +1,4 @@ -from typing import Iterable, Mapping, Union +from typing import Iterable, Mapping, overload import numpy as np import pandas as pd @@ -46,31 +46,47 @@ RESULT_IF_WEIGHTSUM0_VALUESNOTUNIFORM = np.nan +@overload def general( - fr: Union[pd.Series, pd.DataFrame], - weights: Union[Iterable, pd.Series, pd.DataFrame] = None, + fr: pd.Series, weights: Iterable | Mapping | pd.Series = None, axis: int = 0 +) -> float: + ... + + +@overload +def general( + fr: pd.DataFrame, + weights: Iterable | Mapping | pd.Series | pd.DataFrame = None, + axis: int = 0, +) -> pd.Series: + ... + + +def general( + fr: pd.Series | pd.DataFrame, + weights: Iterable | Mapping | pd.Series | pd.DataFrame = None, axis: int = 0, -) -> Union[pd.Series, float]: +) -> float | tools_unit.Q_ | pd.Series: """ Weighted average of series or dataframe. Parameters ---------- - fr : Union[pd.Series, pd.DataFrame] + fr : pd.Series | pd.DataFrame The input values. - weights : Union[Iterable, pd.Series, pd.DataFrame], optional - The weights. If provided as a Series, the weights and values are aligned along - its index. If no weights are provided, the normal (unweighted) average is returned - instead. + weights : Iterable | Mapping | pd.Series | pd.DataFrame, optional + The weights. If provided as a Mapping or Series, the weights and values + are aligned along its index. If no weights are provided, the normal + (unweighted) average is returned instead. axis : int, optional Calculate each column's average over all rows (if axis==0, default) or each row's average over all columns (if axis==1). Ignored for Series. Returns ------- - Union[pd.Series, float] - The weighted average. A single float if `fr` is a Series; a Series if - `fr` is a Dataframe. + float | Q_ | pd.Series + The weighted average. A single float or single Quantitiy if ``fr`` is a Series; + a Series if ``fr`` is a Dataframe. """ if isinstance(fr, pd.DataFrame): return dataframe(fr, weights, axis) @@ -83,8 +99,8 @@ def general( def series( - s: pd.Series, weights: Union[Iterable, Mapping, pd.Series] = None -) -> Union[float, tools_unit.Q_]: + s: pd.Series, weights: Iterable | Mapping | pd.Series = None +) -> float | tools_unit.Q_: """ Weighted average of series. @@ -92,14 +108,14 @@ def series( ---------- s : pd.Series The input values. - weights : Union[Iterable, Mapping, pd.Series], optional + weights : Iterable | Mapping | pd.Series, optional The weights. If provided as a Mapping or Series, the weights and values are aligned along their indices/keys. If no weights are provided, the normal (unweighted) average is returned instead. Returns ------- - Union[float, Quantity] + float | Quantity The weighted average. Notes @@ -158,7 +174,7 @@ def series( def dataframe( df: pd.DataFrame, - weights: Union[Iterable, Mapping, pd.Series, pd.DataFrame] = None, + weights: Iterable | Mapping | pd.Series | pd.DataFrame = None, axis: int = 0, ) -> pd.Series: """ @@ -168,7 +184,7 @@ def dataframe( ---------- df : pd.DataFrame The input values. - weights : Union[Iterable, Mapping, pd.Series, pd.DataFrame], optional + weights : Iterable | Mapping | pd.Series | pd.DataFrame, optional The weights. If provided as a Series or Mapping, its index are is used for alignment (with ``df``'s index if axis==0, or its columns if axis==1). If no weights are provided, the normal (unweighted) average is returned instead. @@ -311,8 +327,8 @@ def dataframe_columnwavg_with_weightsseries( def _dataframe_columnwavg_with_weightssumnot0( df: pd.DataFrame, - weights: Union[pd.Series, pd.DataFrame], - weightssum: Union[float, tools_unit.Q_, pd.Series], + weights: pd.Series | pd.DataFrame, + weightssum: float | tools_unit.Q_ | pd.Series, ) -> Iterable[pd.Series]: # Calculate the weighted average if sum of weights != 0. weight_is0 = weights == 0.0 @@ -325,7 +341,7 @@ def _dataframe_columnwavg_with_weightssumnot0( def _dataframe_columnwavg_with_weightssum0notall0( - df: pd.DataFrame, weights: Union[pd.Series, pd.DataFrame] + df: pd.DataFrame, weights: pd.Series | pd.DataFrame ) -> Iterable[pd.Series]: # Calculate the weighted average if sum of weights == 0, but not all weights are 0. @@ -421,9 +437,7 @@ def rowvalue_uniformity(df: pd.DataFrame) -> pd.Series: return buffer -def weights_as_series( - weights: Union[Iterable, Mapping], refindex: Iterable -) -> pd.Series: +def weights_as_series(weights: Iterable | Mapping, refindex: Iterable) -> pd.Series: if isinstance(weights, pd.Series): return weights if isinstance(weights, Mapping): diff --git a/portfolyo/tools2/intersect.py b/portfolyo/tools2/intersect.py index a8b50a1..0fc6017 100644 --- a/portfolyo/tools2/intersect.py +++ b/portfolyo/tools2/intersect.py @@ -1,18 +1,15 @@ -from typing import List, Union +from typing import List -import pandas as pd - -from ..core.pfline import PfLine -from ..core.pfstate import PfState from ..tools.intersect import indices_flex +from .types import NDFrameLike def indexable( - *frames: Union[pd.Series, pd.DataFrame, PfLine, PfState], + *frames: NDFrameLike, ignore_freq: bool = False, ignore_tz: bool = False, ignore_start_of_day: bool = False, -) -> List[Union[pd.Series, pd.DataFrame, PfLine, PfState]]: +) -> List[NDFrameLike]: """Intersect several dataframes and/or series. Parameters diff --git a/portfolyo/tools2/types.py b/portfolyo/tools2/types.py new file mode 100644 index 0000000..79f3264 --- /dev/null +++ b/portfolyo/tools2/types.py @@ -0,0 +1,10 @@ +"""Help the type checker.""" + +from typing import TypeVar + +import pandas as pd + +from ..core.pfline import PfLine +from ..core.pfstate import PfState + +NDFrameLike = TypeVar("NDFrameLike", pd.Series, pd.DataFrame, PfLine, PfState) diff --git a/tests/core/pfline/test_pfline_init.py b/tests/core/pfline/test_pfline_init.py index a3b8d0d..62632d9 100644 --- a/tests/core/pfline/test_pfline_init.py +++ b/tests/core/pfline/test_pfline_init.py @@ -3,7 +3,7 @@ import random from dataclasses import dataclass from enum import Enum -from typing import Any, Callable, Iterable, Union +from typing import Any, Callable, Iterable import pandas as pd import pytest @@ -187,7 +187,7 @@ def test_init_A( columns: Iterable[str], inputtype: InputTypeA, has_unit: bool, - constructor: Union[Callable, type], + constructor: Callable | type, ): """Test if pfline can be initialized correctly from a flat testcase.""" diff --git a/tests/tools/test_changefreq_fromexcel.py.bak b/tests/tools/test_changefreq_fromexcel.py.bak index fa80891..1d7d70b 100644 --- a/tests/tools/test_changefreq_fromexcel.py.bak +++ b/tests/tools/test_changefreq_fromexcel.py.bak @@ -1,6 +1,6 @@ import functools from pathlib import Path -from typing import Tuple, Union +from typing import Tuple import pandas as pd import pytest @@ -578,7 +578,7 @@ def get_testframes( avg_or_sum: str, series_or_df: str, with_units: str, -) -> Tuple[Union[pd.DataFrame, pd.Series]]: +) -> Tuple[pd.DataFrame | pd.Series]: source_s = get_df_from_excel(source_freq, tz)[source_freq] if target_freq is None: target_s = source_s diff --git a/tests/tools/test_freq.py b/tests/tools/test_freq.py index 1cd0737..545e8ba 100644 --- a/tests/tools/test_freq.py +++ b/tests/tools/test_freq.py @@ -1,5 +1,3 @@ -from typing import Union - import numpy as np import pandas as pd import pytest @@ -147,7 +145,7 @@ def test_setfreq( num: int, wanted: str, strict: bool, - expected: Union[str, Exception], + expected: str | Exception, indexorframe: str, ): i = pd.date_range("2020", periods=num, freq=freq) diff --git a/tests/tools/test_intersect.py b/tests/tools/test_intersect.py index fed0837..4a7c6a6 100644 --- a/tests/tools/test_intersect.py +++ b/tests/tools/test_intersect.py @@ -1,4 +1,4 @@ -from typing import Iterable, List, Union +from typing import Iterable, List import pandas as pd import pytest @@ -45,7 +45,7 @@ def get_idx( def get_frames( idxs: Iterable[pd.DatetimeIndex], ref_idx: pd.DatetimeIndex = None -) -> List[Union[pd.Series, pd.DataFrame]]: +) -> List[pd.Series | pd.DataFrame]: frames = [] for i, idx in enumerate(idxs): # Get data. @@ -160,7 +160,7 @@ def test_intersect_nooverlap(indexorframe: str, tz: str, freq: str, starttime: s def do_test_intersect( indexorframe: str, idxs: Iterable[pd.DatetimeIndex], - expected_startdate: Union[str, Exception], + expected_startdate: str | Exception, expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, @@ -183,7 +183,7 @@ def do_test_intersect( def do_test_intersect_index( idxs: Iterable[pd.DatetimeIndex], - expected_startdate: Union[str, Exception], + expected_startdate: str | Exception, expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, @@ -205,7 +205,7 @@ def do_test_intersect_index( def do_test_intersect_frame( idxs: Iterable[pd.DatetimeIndex], - expected_startdate: Union[str, Exception], + expected_startdate: str | Exception, expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, diff --git a/tests/tools/test_intersect_flex.py b/tests/tools/test_intersect_flex.py index 29e1281..fab118a 100644 --- a/tests/tools/test_intersect_flex.py +++ b/tests/tools/test_intersect_flex.py @@ -1,4 +1,4 @@ -from typing import Iterable, Union +from typing import Iterable import pandas as pd import pytest @@ -211,7 +211,7 @@ def test_ignore_all( # indexorframe: str, def do_test_intersect( indexorframe: str, idxs: Iterable[pd.DatetimeIndex], - expected_startdate: Union[str, Exception], + expected_startdate: str | Exception, expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, @@ -242,7 +242,7 @@ def do_test_intersect( def do_test_intersect_index( idxs: Iterable[pd.DatetimeIndex], - expected_startdate: Union[str, Exception], + expected_startdate: str | Exception, expected_starttime: str = None, expected_tz: str = None, expected_freq: str = None, diff --git a/tests/tools/test_isboundary.py b/tests/tools/test_isboundary.py index c75dd90..ce1f505 100644 --- a/tests/tools/test_isboundary.py +++ b/tests/tools/test_isboundary.py @@ -1,5 +1,5 @@ import datetime as dt -from typing import Iterable, Union +from typing import Iterable import pandas as pd import pytest @@ -257,7 +257,7 @@ def test_isboundary_index( periods: int, tz: str, freq: str, - expected_repeat: Union[int, Iterable[int]], + expected_repeat: int | Iterable[int], ): """Test if boundary timestamps are correctly identified in index.""" ts = f"{date} {start_time}" @@ -272,7 +272,7 @@ def test_isboundary_index_dst( i_freq: str, periods: int, freq: str, - expected_repeat: Union[int, Iterable[int]], + expected_repeat: int | Iterable[int], ): """Test if boundary timestamps are correctly identified in index during dst-transition.""" do_test_index(ts, i_freq, periods, "Europe/Berlin", freq, expected_repeat, 0) @@ -288,7 +288,7 @@ def test_isboundary_index_midyear( i_freq: str, periods: int, freq: str, - expected_repeat: Union[int, Iterable[int]], + expected_repeat: int | Iterable[int], ): """Test if boundary timestamps are correctly identified in index when we don't start at beginning of year.""" ts = f"{date} {start_time}" @@ -308,7 +308,7 @@ def test_isboundary_index_leadingzero( periods: int, tz: str, freq: str, - expected_repeat: Union[int, Iterable[int]], + expected_repeat: int | Iterable[int], leading_zeros: int, ): """Test if boundary timestamps are correctly identified in index when we first have some zeros.""" diff --git a/tests/tools/test_wavg.py b/tests/tools/test_wavg.py index 2fe2e5d..120dd0f 100644 --- a/tests/tools/test_wavg.py +++ b/tests/tools/test_wavg.py @@ -1,4 +1,4 @@ -from typing import Any, Iterable, Union +from typing import Any, Iterable import numpy as np import pandas as pd @@ -57,7 +57,7 @@ def get_index(number: int, indextype: str) -> Iterable: def do_test_series( - values: Union[pd.Series, pd.DataFrame], weights: Any, expected: Any, **kwargs + values: pd.Series | pd.DataFrame, weights: Any, expected: Any, **kwargs ): if isinstance(expected, type) and issubclass(expected, Exception): with pytest.raises(expected): diff --git a/tests/tools2/test_indexable.py b/tests/tools2/test_indexable.py index 23989e3..d757e31 100644 --- a/tests/tools2/test_indexable.py +++ b/tests/tools2/test_indexable.py @@ -1,5 +1,3 @@ -from typing import Union - import pandas as pd import pytest @@ -24,7 +22,7 @@ def get_idx( def create_obj( series: pd.Series, name_obj: str -) -> Union[pd.DataFrame, pf.PfLine, pf.PfState]: +) -> pd.DataFrame | pf.PfLine | pf.PfState: if name_obj == "pfline": return pf.PfLine({"w": series}) elif name_obj == "pfstate": From aa972de9da906d5c169aa14d7ae01355b43a0218 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Thu, 23 May 2024 10:50:19 +0200 Subject: [PATCH 57/59] minor things --- portfolyo/tools/intersect.py | 5 ++--- portfolyo/tools/product.py | 33 ++++++--------------------------- portfolyo/tools2/intersect.py | 21 ++++++++++----------- portfolyo/tools2/types.py | 4 +++- 4 files changed, 21 insertions(+), 42 deletions(-) diff --git a/portfolyo/tools/intersect.py b/portfolyo/tools/intersect.py index 2ccf9b3..c953d38 100644 --- a/portfolyo/tools/intersect.py +++ b/portfolyo/tools/intersect.py @@ -214,8 +214,7 @@ def frames( Returns ------- - list of series and/or dataframes - As input, but trimmed to their intersection. + As input, but trimmed to their intersection. Notes ----- @@ -228,4 +227,4 @@ def frames( ignore_tz=ignore_tz, ignore_start_of_day=ignore_start_of_day, ) - return [fr.loc[idx] for idx, fr in zip(new_idxs, frames)] + return [fr.loc[i] for i, fr in zip(new_idxs, frames)] diff --git a/portfolyo/tools/product.py b/portfolyo/tools/product.py index 152fc54..c9fbb0e 100644 --- a/portfolyo/tools/product.py +++ b/portfolyo/tools/product.py @@ -1,7 +1,6 @@ """Utilities for calculating / manipulating price data.""" import datetime as dt -import warnings from typing import Tuple import pandas as pd @@ -14,31 +13,11 @@ def is_peak_hour(i: pd.DatetimeIndex) -> pd.Series: - """ - Calculate if a timestamp is in a peak period or not. - - Parameters - ---------- - i : pd.DatetimeIndex - Timestamps for which to calculate if it falls in a peak period. - - More precisely: if timestamp lies in one of the (left-closed) time intervals that - define the peak hour periods. - - Returns - ------- - Series - with boolean values and same index. - """ - if isinstance(i, pd.Timestamp): - raise TypeError("no longer supported") - warnings.warn( - "Calling this function with a single timestamp is deprecated and will be removed in a future version", - FutureWarning, - ) - return is_peak_hour(pd.DatetimeIndex([i], freq="15T"))[0] - - return germanpower_peakfn(i) + raise DeprecationWarning( + "``pf.is_peak_hour`` has been deprecated and will be removed in a future version." + " Use ``pf.germanpower_peakfn`` instead, or create your own peak function with" + " ``pf.create_peakfn()``." + ) def delivery_period( @@ -59,7 +38,7 @@ def delivery_period( front_count : int, optional (default: 1) 1 = next/coming (full) period, 2 = period after that, etc. start_of_day : dt.time, optional (default: midnight) - Start of day for delivery periods with a longer-than-daily frequency. + Start of day for delivery periods with a daily-or-longer frequency. Returns ------- diff --git a/portfolyo/tools2/intersect.py b/portfolyo/tools2/intersect.py index 0fc6017..41d2278 100644 --- a/portfolyo/tools2/intersect.py +++ b/portfolyo/tools2/intersect.py @@ -1,21 +1,21 @@ from typing import List -from ..tools.intersect import indices_flex -from .types import NDFrameLike +from ..tools import intersect as tools_intersect +from .types import Indexable def indexable( - *frames: NDFrameLike, + *objs: Indexable, ignore_freq: bool = False, ignore_tz: bool = False, ignore_start_of_day: bool = False, -) -> List[NDFrameLike]: +) -> List[Indexable]: """Intersect several dataframes and/or series. Parameters ---------- - *frames : pd.Series and/or pd.DataFrame and/or PfLines and/or PfStates - The frames to intersect. + *objs : pd.Series and/or pd.DataFrame and/or PfLines and/or PfStates + The indexable objects to intersect. ignore_freq: bool, optional (default: False) If True, do the intersection even if the frequencies do not match; drop the time periods that do not (fully) exist in either of the frames. @@ -28,18 +28,17 @@ def indexable( Returns ------- - list of series and/or dataframes - As input, but trimmed to their intersection. + As input, but trimmed to their intersection. Notes ----- The indices must have equal frequency, timezone, start-of-day. Otherwise, an error is raised. If there is no overlap, empty frames are returned. """ - new_idxs = indices_flex( - *[fr.index for fr in frames], + new_idxs = tools_intersect.indices_flex( + *[o.index for o in objs], ignore_freq=ignore_freq, ignore_tz=ignore_tz, ignore_start_of_day=ignore_start_of_day, ) - return [fr.loc[idx] for idx, fr in zip(new_idxs, frames)] + return [o.loc[i] for i, o in zip(new_idxs, objs)] diff --git a/portfolyo/tools2/types.py b/portfolyo/tools2/types.py index 79f3264..8805c4d 100644 --- a/portfolyo/tools2/types.py +++ b/portfolyo/tools2/types.py @@ -7,4 +7,6 @@ from ..core.pfline import PfLine from ..core.pfstate import PfState -NDFrameLike = TypeVar("NDFrameLike", pd.Series, pd.DataFrame, PfLine, PfState) +Indexable = TypeVar( + "Series_DataFrame_PfLine_PfState", pd.Series, pd.DataFrame, PfLine, PfState +) From 5f2974bd1f5216b2ba5ed6d00d52a1f7c0e154d0 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Fri, 24 May 2024 18:07:10 +0200 Subject: [PATCH 58/59] fixed po-method --- dev_scripts/sphinx_autorun.sh | 0 docs/core/pfline.rst | 6 +- docs/savefig/fig_hedge.png | Bin 32477 -> 31045 bytes docs/savefig/fig_offtake.png | Bin 64272 -> 111624 bytes docs/savefig/fig_plot_pfl.png | Bin 28115 -> 39293 bytes docs/savefig/fig_plot_pfs.png | Bin 43127 -> 37893 bytes portfolyo/core/pfline/classes.py | 10 +- portfolyo/core/pfline/flat_methods.py | 16 +- portfolyo/core/pfstate/pfstate.py | 42 ++++- portfolyo/tools/hedge.py | 96 ++++-------- portfolyo/tools/peakconvert.py | 11 +- tests/tools/prices/test_hedge.py.bak | 86 ----------- tests/tools/test_hedge.py | 146 ++++++++++++++++++ tests/tools/{prices => }/test_hedge_data.xlsx | Bin 14 files changed, 241 insertions(+), 172 deletions(-) mode change 100644 => 100755 dev_scripts/sphinx_autorun.sh delete mode 100644 tests/tools/prices/test_hedge.py.bak create mode 100644 tests/tools/test_hedge.py rename tests/tools/{prices => }/test_hedge_data.xlsx (100%) diff --git a/dev_scripts/sphinx_autorun.sh b/dev_scripts/sphinx_autorun.sh old mode 100644 new mode 100755 diff --git a/docs/core/pfline.rst b/docs/core/pfline.rst index e4ccb54..3cb34a9 100644 --- a/docs/core/pfline.rst +++ b/docs/core/pfline.rst @@ -758,7 +758,7 @@ Using the ``.hedge_with()`` method, the volume timeseries in a portfolio line is Peak and offpeak ---------------- -For portfolio lines with (quarter)hourly data, the ``.po()`` method splits the values in peak and offpeak. We can again specify if we want monthly, quarterly, or yearly values. +For markets that have a concept of "peak" and "offpeak" periods, the ``.po()`` method splits the values in peak and offpeak. We need to specifiy a ``PeakFunction`` to determine which periods are peak - we can create one with ``portfolyo.create_peakfn()``, or we use the one for the German power market which is provided under ``portfolyo.germanpower_peakfn``. We can again specify if we want monthly, quarterly, or yearly values. .. exec_code:: @@ -768,9 +768,9 @@ For portfolio lines with (quarter)hourly data, the ``.po()`` method splits the v offtake = pf.PfLine(pf.dev.w_offtake(index)) # mock offtake volumes # --- hide: stop --- # continuation of previous code example - offtake.po() + offtake.po(pf.germanpower_peakfn) # --- hide: start --- - print(repr(offtake.po())) + print(repr(offtake.po(pf.germanpower_peakfn))) NB: be cautious in using the output of this method. The values in the "sub-dataframes" do not apply to the entire time period, so the usual relations (e.g. energy = power * duration) do not hold if the duration of the entire time period is used. For convenience, the relevant duration (of only the peak or only the offpeak hours) is included in the dataframe. diff --git a/docs/savefig/fig_hedge.png b/docs/savefig/fig_hedge.png index 13bb2086fccf5cbcc68506e910d9af5301a32bf2..0d1ca1344e8de68ce7960ff98ae028f46d8a8917 100644 GIT binary patch literal 31045 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

+M}njjlJo#_ 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 diff --git a/docs/savefig/fig_offtake.png b/docs/savefig/fig_offtake.png index 160a93ed5bd2dd6ea2059bd96c3eac95956d924c..6b0152054fa947739aa87dd6d2ab674c925d4f14 100644 GIT binary patch literal 111624 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

  • -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

    GF{tQz{R{Giwup4h-IDl6pkaK3`%+WY z#>dU1r_|YAE5v(jk-jucXuIGfs|85qllh8@wUAQeRu9_jOQ9%053Lk|pE~?wy0BYf z8G=m)4{~XJ_uA*h$#x2FNF48z-|^7RbyTg0i&%&nE&KAvNAfH8rA`Y(I=Jx!_wy4~ zd%~~)baGmiAep81gEAQ94;51!Mlr447Xo9ktxVIs02(~T^Q!y(8JMJ>#oYU36>zUf zI#rSWmpXeKJ8j@1+Vetnz)xDAPSFCiSd|K`VO#+z2GarTEi1`HH|6TaRbf=5F7d)W ziiC;M7r4Ho-Bygn)K}G=U2%D=A44}Gh-MuuN3lD8x+`f($#9Utd>$pm*QwO6VP9NF z&6y%Q!!riOLQ85*u7J={Y$sr#ViiiW;W0CA&VY`ZiD9y_H6^KU^*rTAqKmSn=zRaD z#<)!NUcToE&vyH2D&-h+6${nTUhH9=h?z+xYTt+VTZ?u4(HW~#{W3khcaSIWEQp4K zW!lGum8d)&#Rfou%x+~Y=^72p-~vtO?Q;a;*B=%ar2qho;!sJn{i@5UQ*Hv_x53vf zhzg2m>oNRCAb_Yv43uazdJF85>}LeZWYX%Y{^U%!HvXx%05>>;5gX`Xdpl}JbphP1 zRkjr_RKxvi&vKvqRw;OAwJ>ff3>u&LXFKW9Ds#p;urEG~iyG)HN9? zvPpbIo{-Vak_fMW(QCiyrc^-CXN#)<8@Lx{D8;OUS4Xwd^uv59(%9Ewa5FEXvKM>^WXF?Yl%&gfZLO zzErO(iS9pDWt~0^0U`zuO-Rc)@9$#Mpem>C;DiKi>_IWApK1&J9dyzk@@j57Ljaf7 zKmNBRLi^xQ6=XP4Ooja}fonw9R9zSODB~v8=OP0aYmOdxKqvHec<|H z5l*?jq&3HV;>cpy%d+8{!GJe41q40IKUaL`MwZ^eNTl`0Lo_R_xH&fq z@h#jFOF;QDCU`fI-^cLVdY409m(_$c*x2Q|x7)NmPYx`h%}{@2hE|e!;>ky9ZaVFW z6z-`aH;P9y``9h<0N9T5)HY77=l_Gv@@d|~(B*qsr=~(km-dn;lC883VWv@ z%uCLCHvYUh-AnQg#@?m&t+73-A2-pHN>P-DtrsTpiP z=WG%_4J0MVXrRH2CSQc7xRRr2H4^P?->F&6H8~1LXi8qwKdc=OJ@12MQ_9aYVoP?I z#1xR)58GDa>u0cPkKGqU0FMH+;KiGzB7_NdU+H1(7MB*y8 zhN^7zxHl@5LBA*4n6^GUPHLN-Gh@4vnW^-~U2r`%j8yN?WS5OE067&Q7#>#Kz)2AT z5KPQh)y!Xplihr!+j*OiFrxp!fs(cg!}l(qGhsQ-v_4(veOo=Y^Aw9`sX?>t%dp#x zn14Px4tYOGdmS&^T?*9aWAEfwVU-3{7R z;t<#vv6PhK)`dX95YZn^umiX zwSkkm+ubr-qzMPV+vV03s^W+ z{vNx4JKp7sy&~@Ob8Ror7dxzTC!dJfB&VRJine(t0Cx&c5F26hmpJGWmw?{Hig{3t ze_5;NAXLiN&+HVgiEdDh<{_$~sxRiq3TDP133QFW}q|<4o`h2D-ivC`X=yqWYi&zbc?ge0X|xA% z46!$x3Y}q{i?tP?h-;=hpZadEg@PFVi6K~-ml!fys2Zb$_@m|}X8DY$2q;abf+A0H0a`>8y7sg{p0B(DD?m4|GVmgIJ4EuXP2diLN2T(+*n4G!MSj2+mT zE7z@0*_yfZ*qaF2QnKB@TVbd8-d~Vjx}Nvw zksE@ZbiB(nk(ttGoK&~w?dG0?Kica4I$N!GSE|EkxQs*Dq1K)iT9NGEtB>svQLYrX z=yjoB=2OoRM>rYT+nf1JK_hb0B-PiCYuM}PUSQyeJYmHGarl%$W%uFNo$nMS;mnM( zP?Q_;plhmpnEz!&U0Q{9fNceoU!O4yCD3HUTNJu)L)WvqIwUrz0)}qO({%&pIj^l8 z|FxH)r!S9@1fdiH0@us)85z(2`_yFRMt{+3fM&MAg88tk*&g3-Db6Xc{1E0B3^PssD*GKEj_5 zT@ddwKGy_s7&y_hETwts}Zgz1%6r}KSmJ)ezn_NWO!=jr8$p9tbk`I zP__Zqy2ElCbd6xqGW>Ve0_}B(`WU<@&Y$n6`G_^_kQq6=`vCTSA zMx##+epFUj(#9st7hRD)7yORR@Y&dh23M)au6hBgco`L|ltqDdCj6X|vitCE?9kHM z`dlK{A@?mtQc}{@?-HpZ zb8zdxKuSz}YR7?vBS91JqL3#xh|p&OhZm+nw#gqSbR4dWjcnPnkXbdgg%mpud$9|5 zzGnFP65OmQ`n0FBYwiLQKVCb)(zoU!UN^CTnmIP=)23_r0WE7&X`L@vQeeJFatJX6 zWjEq?CI2N|F`X42RO2{$^jbKgmc7T?r!g`*I(k>+M&(+4K(S)zjg=DkuENo&G|+&U zEtOAQ!8-$j*Lqv0 zPen$t6sbgrsekw=*^;F`FGx7fv6W!BH?XC_;9vw88zn@){N3($9dsr#S7po+9+fM2 zlW-7GFkWY;7Jio;rnp(bV?XI;R2tTpTX|f%CkqTur>gl0@!cw>G~o7}t+n~Fndve< zHKjA_cRKoVeS4xH65-Ljk=pIDw6qj35o@j+(3Vu`ACs=~J)dl-H5xvn_8^$1LR#m~ zW4}nS7i0^i7-YrUId?Hu_Ly!jh8X^?iPyfh;9;Yu41~j#P{j>SoE`Rp$YfO3SpK^eN#A0p0>VPVa>|ep z=)vz6M1zHS$?OZEe+K{e!EwS^>H{`<@VJQGy|N|%ivxn?XyLEv$A~7Td1_Le>K`04o{_Sx^O>U0#!Kut8-gDZS3uq_jpf#7~UwVJT*%@ za;me}tjCa6;IJB4`w%4&P88hI~`474$7TsfE9a z2pBC&>mtG~UY9{|AYuto=e6gA%x0vd=T+t!*blv~XNPZhRk)wv9_)@2VauVuDY{if z*;d{1np=u+u;kEdlxSf+TC!0(!hE@C96&I=`-WZ`5paD~H`MMjY_>N`h-!RXYj=J_ z=51%u)?W)LtrTmlQvTX~O&uR)Fii*AZuu5q@u3Kww6XVQM&eTSGLw}dy9gQb?9$vU zIec244KR`@8~N(Vpr23zl(5a+Wlnb0IQV=6EYf+W-8ATI0>GN4*zmm-t(y>L z`k}>J>(N@F%KmH4`A~`HuZ9HKG0FiJ3134KIrOj;X=5Okc6}QFF)A~Q_F{^Sei3y% zugZ=2=6?D88?3EKk&dS78YjLqdEOj=0OX^<>#A|v-`R;IF8dSsBy~p30DFGk#nS0< zdZP-;gJX0f#W8(3??PyJEx{S&8s4(|=0n3)`^lD7^KHQO{cA8EG0wUkxy8F^)~K5D za!ikoo0hsz9~1hp@IHD!h(GzmOzkS?GGr;P{DSIJ)c86_$JyF^onz*=D@l_^{8#62 zV>64>Hly=a?5e$>zwLc%&73!AX3riqY5{*8aLe%)pYUZ+j+`jFo7Dzu2}U&yev%^d%|B4@RQRRw%nmi_cW-7CD)KvH?q-i}PIZXZ5oSO&9%#MFS^SH2u&S{c?F&qql2E zEfi0`^<{7sT+<+}!P3}*^>wxxw`vhQr7G}1UA4YO=``6svcfjaFkNgBhy=JY>ny-cR=ad6z;xv-I->M1=!H4nW`vD@SA=)jkJ z;pG{E@lbS#tBz2)INU8Wjh0&3y~l$kNvG*ij(^;%X)U?&?~SKv+rHR01mBYd?>CkG0;=bDf9M3&rnqmv zT8Rr=*9xBHFEHm+LES1Vdwx$gXoF>5a#0-{Vi0W%pfN?H$Mqwt>kc5t*SG_d*WSA6 zqgM06#4-CSG@E4zD{hBp7jXkqfP1o-t)m05-R_u9JUmZN#cNx<_W%8FrC65&U-gbn z#}5tIaF!?^aJzx%ZltkwSsa%8bGW_%S`z$Qh7x$(tcm!M#xLBifk{u*lpnyj z#H34Y0Y|y7zlRhb-^bF|-(5Y<=7Uk_6Mt=1S9(JXeYwN$92BR0s^=o_Z3fjI7CHP8 z0i$r^ppCndk&R%E&|+Ku;=R+PQOfdv?$Ri$E_0s;w}md`1o+ItbpEwfI+Hl@JH}?; zw(RVT9v+Obd_b1cWjAQV*LMgr3P~ECq9Pn-y8!0Rg z)d0TC_B;jDHt(b3H+ru9*W5gaj^}nL@qT>fXNj|SRAind)>NV)(qm%=O2+Ns6Ldfl zbLXGMc}i_7ivMMBzwF*eZ!CeqAdQ6<-YMwjSa#>5a~zBd%5dF)&%4fWQcrQ8zHOXf z7gEp)0^DxtINU!#^77?L*YD->x@#`}{h9aX+n@9D>h}5b6;J9XC9j^R?m+_VDHZ2? zix%J!>)$ec?x>Zz>ay?1tF?u;3`8|TEEf7|pMe&TnLHyvi)1Q{9-71dvmLhI-XWMLx}Ew5J_=pl4M+8P;aN=z)tVN4#-M0uIE`CY0*cK$UswYt{%y zu?VS9DaT*jLc}T6@_O3QjcsSmdiIYEm%)|Z91a_j^ZJ!yrap14-+I<;#Ie5#XH9$U zemfL8Kbh@)Jr_3iLXbK;r+fI)-1H=~%+sQx(r3ZEjGWxgYkwE=hN)}8;dgC2$<6;JR3hKVmt{kjo$R58I7Ss@ zZ7tEyi!U753uQ~gLs~U|ry=HlTb&unUNL4xSo|4I68=<%*dM%pE79aH4qDw`LnUrD zorX89dH2?3e6%w%Spj)k24YXePyl`&GHqqoOaBeT6t@o@nv9r3x33CSD76xUL&ZZ# zwV!74Z99)YciJ9vhvvk6aarh$aq7Fs{KL_*OIFiRjLIedx#MfmD?z;2Qo+Vnip?tB zc2g}5oE7bylyV=v4KdT!4!81;u=+P;XTkc-hX~q*IvO_J2Xnvu2H3jZ1w?;LwYjCR zGLD2!Vl#@$y|YxO|2{n ztQ}Xmt7pw;mDEakbu6`+`rZ`KLA4De&Xe`8*l=iC@%q`?Q07WO?Q3Pl6X)EF+zN4< zYwrS8rjGJ{d@$8(3I*@B?)&EMEvyOF=0tu7?bOU5y_! zp=%_wt^PdbCtuROH~(1{)K6{>-~i0@5{Zchd9~5m#=urJ%#vnSv@Mug^Oy>czO<~7pThs3e z^-9{lFZ7V~L|T5QR00G3@@E!^_X>rM2L}M1t8Nk3SJ}`u)<7xm0+>ZUiRlv=vNBjU zcrIPZ3ml|LLXx{RWBChP=R*JLCaH{ZawpqL!x0_tNKvI}CE|jVFlstf-l~^eu!-ka zene>*aLkMfy-o|2<)!HTN3-0Wl}PucwV$z=`cAw8g#mlm)?kmZ)JzaF9D`4epI zXGJ`3*>|$iIJtwvv!8PPo)vi9@P6E;2go*x##?=7o~qE6xk!PX7Sxr%Uhld1pD=#B z3+V5Y0-qO>d}2LuYBZ8=08e;a1Zj6j8f>h*{+X`4zFKh`eORf2b*Wmm;abjgxS>Dg zTp>}b2G&EgTucp$1+HYdiqw5TI{t7PFrn?zDh;=;QdWg+a+X(Z@RYM8n5be;cqRm} zj7^?3SxbxgV>cHm#sT|U0V;*<+eg*HWyt^xr}E>I$VsP9O5z@FCjzkzFjc3$6L*qB zGJf8gK#|`#=0~W|+l7^?ACGQLOHm8%t(DV#CxzK|0FxyU@E3=tdhaqd=vP^y9DVla z>fBsu=3XY5IIm972QR@aVDksz_}gJEmqkfmGBb#&#jOMDF1ER=(zC$JEURl;fnC?t zGNCpZ5>)Bu5^)48caxB`O1&s1#saKnHv6vHIjUP_9^HY75YzB zH&01O*{2nNbA3+;Y1sBaw@7LDmy|&ef3Ddz)*biM51@ejvn5gL- z8!321QFf+$DlEs`;t)FYYQ5M%!Dp^z6YN1&@@^yg1cyP4)o@49I7O(N3fL)dD0T$@ zzsP&*sHncUZ*%|&X+Z($4oT?-Ndal3Q=~z1=#&-#k&;Ffkd|&nKtw=FV(9Mf8sgpa z`#sNE_r34)+`HaC?|o7-E5KOSVqpCsQ@*uZJcelgRMx^_ApjWlAL>L|emFAu zWgWi?a@*6Pn|9$_dBVu$5COKD?c_cb@4|W67zNwcr_#D;DU9lK?b#nD@sZ=ePg(yy zmn2c`m7xxf#ZM`Lreo0^>|m%e@j5lX&X!CtLY^U2dd3@s|3u>FOFW+jvDO9+sO_Pn zc-*k)n%S6G_qZFSoV&q$e%HWx-YP#EY_N0=syV|OR@y&`cCvgL1u8n2Y4=c1sTI&KbAYm<7fX7IEA?izW$9F~W+#K(!M736dR}C;b^!o?M0E!}_g6n7 zu`s{b?B1)Su^n2G^gfceO({0aZ!~voCv>NIFI4D&C|ZUsNo}zv=B1*cm1MHxw3glO zig5AHWjtW4rR5l$yC!QvS0^@JYe!#IT{PcNiVBN`hYQAfC}ki=A4%YxkO)T4_Y6Vc z9klh_w8u@991osVv$we!9k&g2?{jl}FV_i(e5+4fBm|{!@^xm-cKSU%0!b47Tq)4; zi)jvd(3^VeSI8$4#jD5C*{u-v)mlG9F9Y4sh-v|%6ub!8a0MW3Eq~x9+5p2TJ=P(<;#sLf9rz;USwfGWKPqFB7+W!4-+483 zdL%DdL}x{I`M!DA)F-zrsI|qHdTU+lzB)Qf*+)ShuaYi6dGC z6o?-P;D9?Te0stGP7-JXjQ6D;#5di3gooKG$%X_Q>N)QLR$XP@XZ^7--lFlrM@|fw z*lLPmEEBUnufx}`*4*v z_vsF*7pr-U10QpLP5eDB@_LpXNc%JUbnOez_`9JL*pY_r3-~r7o+fzQnCk`UR~p=5 z6GNYW*Osyjd5S^vUZSQ)G)E59?Cv`&Y#T@p#v%;$_1r(C-5;x>KCsk4%`|MBwv2M5uLcclj%qycPSKzOQV=2A_AW&yg6eVq=1lJ+`&eU@|1zT;p&s!NW|h zsaoW(A9$b$SgM>^AIJV!BJv};jfAa2zEJ_n*z{%16_+fX+;r%YRa26aI)r!#ip$Zo zUvy|^*#Fh8i?aKfc&fX^!%5w^?Kwc+U0kfZT0hKja_4U4T5YOs^Lpo-lanb*UKbp@ z`BG$se!2c3k-A!JZ3{p-&Qz z;>TL4#S%zC?^m_rrF;LD0Ch~w&cvLzqe0HF?ZitSTQO|FMS^IY|Me_0XGiZwJ5K0K zd!dq2#I81%QuzYjNRypT?InTU#i>}-G)_NY$eg5gpj5Ud+p4bor+`RUR47!VK*C`c z^%BxLH&^ba{bCXckWdqJtPyqe_6++y!^rQ(T1>uX(ALQ*2Fgkme1%@%RVJ( zN}HRdVYJi<{9zC2${#FZVd=IH#JG6pyH5IdjABiIjnHY>Ez2QMg1qjfYf`AX@(f>9 z+hB1+f=M#%c;AcFg-DjT+Ges9P2hk;tdJM;-6+YjX>i@S$8~!#l^p-in}Jh5c&~w{ z3Ca}cTMHL^n$yc|!|!GRiz}?pA~iHY{zc(b&IPmG8lf^=Xr9+8{ZmP0owF-}*LamN zivxMQeERJ{@%@l$=zAiORJg&6!Tzz9-g6M7~bl+NAWZ*3NAoo*I`98X^petYofB?!=|TP z`8Ah?n|g||OFn#HM` zjU#co=ze4mMa%g^StB+6)SmMeZ`u!MU^@eU)&rzo8-G3Y5QcHfS2)`5#s{k55`-^A zG@$2PfGXZ(N|}GKF!6mGv$jVLHxyc$kN7#tS|cb0VH*`XmBtE5Y!}hzQc#Ed@D_h} z!=?C{6#|47qc_DE+gJl&gZ(phE2L7B|Mjd^-FEi2Zp6FvzF#s%tEoid4;jh|fuSl%>*BCc zdzUN1#)r*DjeSDX%eYg}MVj8(#@HEjw=)GZL)+MdReq#`5mu{woL+L7=?OV#{i)=QQfq;iMMRWbq z73MrpH9hB$+4~q;=86kpk;N$wwPcg)&o4^>E;kz;lpnd)>9b9ZSxe=2#%(#YYK7!e ziQ-?pABFz0k|G!0j5ZZQM=uFa%bf0KVWLhWi_q#F3$1A#HGi@YNcILWSv(Tq!F5!H z`68-Y34>WbvOCHKzVD_m-DbY)PQQ9j#^**BzgkHBnuFLkdC(AL;lMwD9gp)^hR9;e zc&}-?4x%kW_RaFsg0IQrjkkjgoj!KUoYq=AjwM^9GEe&l=3FuLz8 zmCEw$8(K?9CF)Q=H#%g7PdvEBs)qA{iA0bdxE1QLOX;)g_21?CZP+nE+Zubn;p(a> zaNonWeawTSv(94t@qzHmH6hXrRc7OO4L&N&0;f*+l7ftoRzyfQvx3VqI%#b)tK7;1 z$2^v!Pr(I%E`BvGtM(XUt^S9WSXM7f{`Ss+w4|c6L`c06YTl+wuG7PO9TSPiZ+wqa zfN0fbx{1nTshm;B!)c zD$w9&yZ0B$STlpAt{!hGX@Wp-e(Y6 zz6rXuZ4y^OJh<%mB+e42%wW#3QL#R|arg9fu4EHWC<7P#&cyR>g77^v3t8VMX2=i9lD?xfD&_|Gk_}h(mWmCVE1jQ+1`{Gp( zTWVJZctVJ5wLxZ2dUQa`G)%Tt}JKD!foxfv&>4e^SaVsCTPnX+A zG`RHCg!igQy@jhLKK??_DX@5&QI0r&)#zw~r-`1E(x-_XKUSFzg#7T@o!6}c z@+28oPGUrO%f`ZCK=diNS@e}NLTO2S1JBtT&Ghh{-owB;4xD|TLBE4yy;f`pkGS~z z!GJw??@bjm!wDP2*)E02i{eCP##fCmM&N_9_V@#1rblwv(b3*D<;$YVwKX;!DxfD0 zPhOfieTa=tNig91WN3#Uw5lt;9a4s>QWBjSg_9$kmM=Oow|AB=`#NXkf#lyzFD}@3 z)Q@1@k>WfSzsYc1EtTjzK2w%wH_-Obl9-`fmz_|hweWPM7^vKd#yZ$KU0u2-iMK0~g6 zRL$nfc7`ZWPZ4ZwZOQ2A=`F4YA?kxdwXlPZSb|VHd3Xc_!nezt@%_#k29H#CQ};Pv zxy*gjl_0Z|X&R`R>j7R<9M*;-8cFUPYKyF|xS8ro3Wd0B44#uKsHEhoaN{|9x)UhT znHQ08_N;$qS^?0jx0+c_iFtdW-6thx!WV@@%g2qPZ9s%9%?MlpRRID;LNKTS)6%&l;7*Y=K6}N zCuXLKYD`l?CDvu+3ol7bLvKWj=9Vh+_cm6q`(sqvZ(Arz*P+W43^rLnxp5xt^Rd{Or=&xcZXex+8K zw1*0owTkR)$vJJS5rn9RB&iv77#JH|pMp+>zVEkT4y=qu-0kiM?E4AdT^}D_!C}-8 z9$wzJZEcd*n>n{^rng6_%ScF*+Ha>4kDF9e?8VPkA)Shm(UA<5WC5-!&5SGl`suG?uALNKX+(A*5uECPoll=9|1QN8YDE$QB~b9Xz#TO3f(VvHg* zhWJCirj?{C`S={`7Rjn&KTnlV_=j*aT1@bC)*j0GHEeXD9KSYSG-+(xpMC5z;pHG# zPK?z|*zdvfF=+IsgtEs!vFK>?!yfJps7qLxURDSVsNXgf-$>^F0saP>3`Xujl^*jk zFCj@3plKW7r~(Z5|E{2D#_vF~HOZ05km7MXUt zd0csoyR;TioNq@`z9k2VSB(Qkk_z>v0Vk1!s8>f`aW_JWsDCwCBx^6_tc+tmNMKFzNJC9?Mhr8TMFLYD68fvx(l7m19lWKbk%Rj7~c{1A^`b~ zv$M7P{n>lTqC0y>V>4!nM1Y#ou@4V{mO7iomOE^09kr*9FIJl{4!YmF4y2NN*-Y6q z7e10edo9_zc4LVX{*8BLHbZa-4uAQrvz#2tN)_@UxgBsS4lZlb*XK2{JEO6_mNzQ9 zZHx#28VpX3y1Rg(IV<%qJW|t*Ek6Itxf2BRlR!t%B9`O)aA=l<#0LI_g-(xwMf+SAt=bJKfrd|B6#oP5PuXqcVx?v+d`Q$3PjkFSffy_ zQ^bdSt?-T{SY{z^pMTd`^6)2d!)l6=u9a=7R?2Hf7_heF;pbnuYFKpX)t1;uvHB9~ zmgx7`8($ht5Jf%nF?f7UquT(*v5^EmJPFHzrG%Q%+chZ)0i3VEsi%*^%*Yw?D9BAmU($k^u5SqO6rU- z3mx_JrWq3AcpGz}O-YBJZfFmE(9lkx8Y$?|BmT@~mc>kQJON&8ThW!+J>T!MqJh`K zrq@fP6;o$Yx7~Nag#Q>?;!F=@OT@63H*}o3QYkw97EOJ_*2Tmzu7&-5_u8k}R4DKJ zo$fc;mlv=pN|yNs;C)nyA2Sh$*I8%6gyX*BPjw_}-0ynS?ooDLob+~A_)=7-_8cDe z!|5qP?AWX+*&eT=WGzgC_bDT-gCtYk@6dyv3vP=Z2mPv{)o4~rX>1e%Q~;-! z9#rGyr1|$ardO`IoInAZ{1ugP^8EC zUF|I-rJ(Iy=LJq;FU4NjI=li;4xa=Xbb~dsQxRNjbTa0jk5X6H^I+$*gnGsp!z;Q+ z?d{K6RymywYIpU5PWAq=QRVjOQE?ej6b21OE zu*L`Kw3wObOcJi{b=K8l8`lzHs&rYf!#$JM+s&$M$;=PlJqYpQ1X2eg6Gwzr)G2@F zb2`nzU@4Rz^A;+(W9$xT!s0^Oa2@%aB%YnAR#=^u3ZnKL@flzPFKki#vf=AjUT$^h zt#Ow#r;Jg2j?Lw#D>ONjeO}B54k_by?m_Pal=fi$g!)*h>-!-sn;08+y9^(MOfiS2 zrxs~HYhc~n+?3R{p4C=#ncc3ME%lk*@>*M4yIiiOE<2bZ$j|m>r~g(B{mM}L$&*u_ z{W$p>=(1p}srJ1U`|c!b_4qU7djY@e=g&~19$StjQLNlv zAiZ$xpm4bKjgl2;PMIb(AI9NlQ1BC)U_CVGo4(k9*~qyQsx3Cc<#qf^JYV zWfgPrX~Hj;b5OKoOoKSVq9@q@FqV+iWMYq=Xqf!aIHl7#gVrGps~|Dk@bdF4@JqIu zE=`2~4g1m4<+H*;+V`|H^dUshN4;`Y7 zo2an2uVXNfVrNUXwtU+e~{d zN$R%m9y0GwoMb1HC5*m)pgD0qgSl-6!#8#bq|=9+UVZc=O^u2&j3Tg)?Hhf1m#ED2 zo+CSx+P&7fZXkjXB|%-X4!zvHzI9zTfe?62scea!C0st<$Y}Wd94iFrr4!V+m{hc(_B`jQ)~Qr1MypOB5&&dr$l`^&osih~mNwg0`mF z+1VMzPJ8Gp(vRnbi-Oam-mlXp_voL5y7vghaWPpZo~j-X%LVq-^i$5*$&@;fr=c1X zkV**)t@@hf^@pMOX6Z0uum6FJZdSVtWQLPdqhAO9rYH|@S-kQjjTgKR8ztvOnOx)^Uu|MNHr)^B{a=8p0IaU?0ut4$X`e)*G~t|a??t*>Lk2dh zFT-4$@Lf-nKh)2mUf$l#d}JC2mbt2lL@aOJT_BQgC0@7Ng<5CDOIOXOmmyVQ2o z9BA|99XQr=Iu{QMj0mUtX4V>cJ1u%kzQ=}N8t{F6(nze@=bu=AyzfZh@pRJ?4RB`; zGqc;$5t~}{Hpjk9ZZXJfq`u!{!#7(EtoMOsL<@k*QD&P4FnRLunIPA;3ygC?%VoP< z@75jH?!Bf!b`3vdwv1rKmDAhff!)q;I1FPzdk_Mt(QCs!N(Rf5m8CP1cTx6Rhpx|E z8IrU2tUr0O;@SbB)*UJdZJ|8KnClqX(Xi!T+R7NDafhf zeyC_5(b+P>{C3hzW@iG$2U#vId4I2)j)Euffk0N-Lt;&Vb_oVFCm@XB19A#;Q9-|0 ziUUCJSY+)IHU68wt&u4?{Jry-&$jE)qoETh=dwc0UKA z_zs^XwoiAb%Y>w+kjvgwS-;gj+JX6zy*zN7E;nmad`rjoTuh<#_7u~ufD}Y;W6*+M zv`LvS9Q*!T4_R(S=n&Kv45;04qudw7184-DSMkoBw`*R64Tv)^W~08bk$n>4`q*Qh zAvLu3%A=k`J)?BFrM9iOc=TJ!n|sA7wWiq?xQ}O~TNvTK`&I^! z?o8bN`erh@8hIXRulC!iAV?Fw&#@|UPKCJOQ---OnD?|9V}kG-035p&(dOZIulUOS zQ_3oBglO+&Mk|@Ws@f_Cqb|xe&1}Tny@-~c9`Xa|QJ86&ibKHI3~|18XpWHvhppji z_jos1M*)H-+M&}y%(qja(xnP*dR(H3tARdusoBa_`d}GxI`g7vZI+??9Gi=I0RbdmaItCuNMix z!mSD3ihp;aeit@UsJ_g7cf{?wHzQ)~IcarK0=r^2_S>y3d&2ckB!X<%!;7m!n?=^K zy*xr6YP1t3Njg_2J@w`o6bKnmRsqDr-v4SOhszP?9_sVLk&95N3$&KYe&=6zxAS)t zAT{IsAcVjlf;_mdZ;PfUGR>f$*@}FKk;SMqm5Wi~%Yzf1VQNiP%B8($ot>QxOYhjf z+YDxR+yTzC>!8FrEg{x|IyhO^&HU7*!Mp3h;pyoZzx~$wS$SsgWmBUb?cHk%7hl8d zronhkSU*hs6&ev4>3Y~jn(8R!xkL7*?Q*T-DnSOT<)VxG*YFobp}Jsj!{p?kgfcF8 z9`vNZF!a3^_LnbTkY@Xb$ZG?;-G;>>T`nUn$gnU%k@$$-ZqS_1y2YC}<*NBi;JD!5 zuwJC}h)+vPd&Zm?GQZy~b-OI}%HAG3=kkxuhkk3E>6pu#K(Yu;`1}VgX(otH1|D7U{qErtE6#1~3kJ#M__c%kziP|w8A8wa~? zZxEFM2v6YNbvmZk=?cv5z?F5~E~`(uw;W-STTO!9=O%Q;a!V<>)dNd-{O>&Z=M3Sn9uudFi`(edvu*w_8)s1M%G3aYE+3pn1gm zEJd>%umC{M`(#*gcs9%VrI`B~uIJ7~NQQIUW3!trJs{vkx%NvZ}NF*LM4ZEShrxFbV#=2#~U`(|gC0FDY z78cHSA;%yX3mCvH71IP*?t);0HqEoz?FtyR*DMr{0aiQzybNO{{?7^AYQpRv99%}a z#=mJj)oodNRPn<`3SqF~CIb0kBYFJT*k?7lYN)6F4(o(j9VY)#fGBPJ7nepBzSSr!q~lEV4~VaeK80K5uLaMkVWpn0|6w_ z6GTs7njxm(-~G<_UQQ?WFn;V|Tw7m97LxixmwzgT+$b+{xWHgE72aL!*ivF~p~#Sq zi&e8*D-c}(s3*ul*2Qjisf^sNwVQa&j{W*e^v^Lgt6lJ$x&f%4)44fP2*kQx3jp2% z5b;M9uJ)iS^}G9nk_e95CGK0)fPet+eh1U#t4~_k&)E$1?Y;Op=Or2ML26*)S$o1mtXbH4b8$)JL0=G>kX z9=7fW5ab|c)(?<16G9utdT+gtt8s-${P+(aluGPB3kmDkT89TK-I3XNY3HdWm0%on z!%18UJl%p3|2kM#&8U+A_+eVj4+qU01P6GMhP(qhfn4su!_MDt=WDO2$+K-E4yhlOJ9%gvs?q zx706Sn-0z|-uUnb3vkJseOxspg6enan>)aatDdr-pt>% z&dUFLZSydYKf%2DdKkqv{oIeLbE#m>YIV! z*@dz&mWkn?gXbymNbmEsn-hw8?S;*Ql%wfZKOwh9%DiD)1h&Gzg#>Sr@Ekv}=d~{S zIs{vaB4Tli4Ee05o7VZ-rH7%Rch=?VG^>oHg+UxYgTb}!lJ#HBhgc}Wpigm@ti^`0 zLB&jnm2_{ZPs$4lZ4^anG70l;P(&fuXJhcC0-T&_u)0JRBBxI=UORF@W?mp1jT$8N zbQ-&~qescnf9Jqy%9aWMr)^?lva!GK1%3aoUQOaA085zMG2?h0E<3__g=l^dZ=)Z% z{qw(AW5^@lZ*iCO`p@OS3BEg6waCJuloGxV>u20>APYmEWg9@`5p9061#jG!1>w2J zG*;9293?k2YFY39n?yPB936ZXNsmu^dvC7Coo`6~39q;~T=qU_$2>&ZNFc2uX7}>` zDYOqX(I!IYLL?8P)fWtZ>Nd2&Z6hWlHxK?ncRZ} zC!vCgkDgMk-BqVK21wkHYtH|5ep;$MZnPP!LrzQIF|(!=lu_vJeSNsgrQH1r`RV_4 zBE}hHdHJ6uBkF%ERkg1)!G<;8Ty>x$uABpnh5!D1{$S(|c1`8$ELjo!KM8EYn=dRf z4iF2llS@L$xxF{6BX6IIqgZ_kcd9C+Xj3_pd0uDNwD{VcCz2)CvGBXvokHlHn|7eL7%uS7png(m&M|@ z@$e(eyY#i+c^Ul6{%M7yY_zEQ*5|?xA}%ej{pKm&$ewe;YmuLHT@T=iU{S7fzEg+Y zzhfG70H2J}!mf0lxi3a;cJr2S;xu7CwC)Q`0v*)IycA0>LZ66MvN8v;xrtmtALerez&`78-Ueg66cU7LOIJ$d|^Agj0`{;6=p zpW9`PIFpHj-3`Tk2eY=-$e#{kSCz{*u+X1W=Nou0e(m4h9jO;pNt-TaN0!m)IOQX#luWD?x1MPu?OE#(8-;l$bqc;`mkuC3P8=BUr`(kNtrkF9?;ojAg!! zro|_}v-fmUhK|F^Wj!uS_AKL68IE_NKkklS)1!GnItpd)6$=Tksb$HYT}bzMCiDH1 z@(U%ycP)&o&HSk{-AHxIZrV^aTl3@w`;j(S#a*GVw|gD-hPLqbE5qdFlPcZHF0;Mp zPGSbke4jl_^9-NQd({O`zx%lUY`T>lHoG9Op}WYZj&)JtPxm^=EKqD4ByoIO<^f(x z>#(I)C$MFqDS)w!Lyv1;(8F`H^=98?r_Rp+#HprD=#Cux_f-IA)R!6gev{?=nqCqN z5qw}h_wVHVzxDiVBQ5%Hi4SS!(AddLCt2?`1#OC+w7gHNpZ)&D_2+&Iftt9%1T#OL zL`C5JrgFZiWNLzX6U?ZAC#{Pw56rG-1XD`gR|aqyPKUHhQnZr-S|`rN z;nGshHWVtzDST8IW21(N%yNWBfmx-lFh}?&WHx^$%|d_Vm}#015&u-$i_LH6&z1r` zO=p^}EyZ4qf%QYRAq@V&O|klCe*)00PF%F=Xqi4t?di!-^f0nbzW`P+Q+ z->y?Sx%f54dRlqwRzk8;cP-b0g4;v2`Ar{NXE%H%`#(%y9ZmaCHP!3rP5FooA6I42 zo%oAYSMA!v3?}Z2p~3kd-@^>Qh+@)0TLEamG6UwGikw=Ml->rtj&!JiT8=xH-YqE-D%y z0&6;UMTwp8WTv5{b`@FE8p3 z5Rk^d_@(d0gXUR({bnrPY|P_CZBqg6oRNu?h z-X}y-E?Y_!o?FZjue&QCWL4?(v+ZW&Z>}!Z&eeuruG7B5#zk4)yE!koDqI>1mb`loh6-l~h_?hGhF;0DZC?APJG0G1EgW22OY2g1B9cc5 z@sQsHAyRkOV-ixpu#0+aZEYb1g{Y5A?0Xc20<}>9fO;ZISN2w`S6ZSf2w!8iOam_dQj%w%Wlr+1=tlhIY5%Kp`NdN zrl(AIn;2=XMv{d_Hw4|a+VFenK%x3>dx)(V?aoImcbjOSZZ1#M_{NmaCPLRVk*J9a zTgoO|JSw|{+u){td^9cT^2RD$R44j%V2~;>Ewx(N*7!QYgb;4we3_baHzX zyAgOOfH$h))CJY|r@E{=1v}O2W-r=mWA&ymjwgOwKMr5QzddOhc>kraau*(CH8yW( zWHYuk^c0WQ27DtNLWj*jFUO2`({lR~VYEoLBo)xWw+KPFeR+u;`Q}86ZD;UeiLPSN1Jg zlbs2FKORa#E2=Qf>;IG~zck09C-ClfHkYGcr_+H+L*b&Yo61PaoTV3}P5RbB)TPIC zWgsr4RhJimU(qJi^|#e=T3Q_6X|Ozh*-dxax9p}Z@9O_08c`YmzA)PjA;<*)coib&1MkQabL+gOHEln?jX*?5-69bBp&dSb_fK$U*75PD>{(Y&ZEzCP>R zzHxU&zoS#2QTM8G(A6?uecSM>t?g}@J7B((H~XB! zX&M;ZgydC~IAUz(!_Q{CMf}%yr5!id_nc<)Ppb+B{!mMCSv z55?XzqkjoH9E2zjGC>&Q)jA%hv6gif;xFczA@ZSc6$!8pT-@JR@Grs#zYVumlNy@o zea`mW+c1Di;=#gdjU(a4xK@+Tfh}UBO!8>ol&DeLKvVM#6Jkn!{rIg{D@xm}*wa(> zc@&5v_#SxrO($mjGu8f-(a-J|jGl8-QwnibH#f6{)4E#@-EpS20TM30s677UC&8w^ z&U+iOTxrfa!u#l?v@DOR;#U)`J%Q_QCGbRm*7;|ho+Qm>OkVV!!p`pyK^9zLPw!g& zQhLYH%9J zf8n*GQ4JpbCfAhug##!MUpIpju7F=$LF0d~0M6cdpBb<>L~j zNqCNZYve3#KW`x{f|Gz8Cq^|v{OJmUX`yyggoMZ;!e!IJ@AR4%<6j<n24kizB|)Aje@v^+^7xfdQi z#He-4MVk=bvU2$w@4d|H{*S&&WkuBZwrQDxuE6AT?6j5MTH@#ex*K+F*1u`j(4}Sh_ ziAA!%c3-~kIBYxaLUsT2yw)2_TLVr;hq$~BXX?L>&SQoIJm$Rx+&YQBGq}F~n1)x@ zxl-)MiEj7g>)%Uz23o!8T$`4?o3fe+X;#*x_5U~Et)yUhriG69q$>5t+Y8gRc2kf{keZH_6cKPq+T zqUVkzyI|GV=~isd`$CpEZrZd;&N%B~yBs$=NqacvtNJPx?8!8}dlOc1PGyv02Y)k; zdWKVotPE1n4Aw6Ct)~Zy-8kTShln~S^vYuV)Ga+Y&VJE>WZyr}n~|aeCyhfRN7pK= zgcSRF6GDJncCCnk$C@O!7pNTBIBn8IYbb@?^2G zi}>_Q`ZTNVw5YIQ1QIY;iqh%*@JDgUtu%&Rby-K}1tyns95d(g6>JcV;+b-i>TFfL;Ov87@8eA&*6c%$?QMFCueKd-dAh0$LUD ztjPH>*Xk!G6)N`67Yvhh)9q2a&j*~hyHffupwR$B!*L_$E@Y-6nCnSF2lDPc>@ow^ zj&y;T@fcCP_?z0cQuNjN-}SAI6c`vhJUki~=WvkdmX4VBoOWv1t(!J9K=y6HYs#E* zNzLeO;)~STat@qcv`Id(_F{qF82#hVRntXD0upAP%_1Vr?M$1-$y>en5kd{f6{=i+ zH?_wU5wALx!R0e->GB%Y$2N+D-osW-tS@bPs3p)K8fSn1>I^7%MhK9;z0I86W!3H0 zD7f#y7G?bAp<%fSOTyd49+`53)C^stvF9}f`0h4}QyTO~yet`^t;ntDZKecapjn3U zs88l=Y)|33s%OtPNOwbqYR(=NcTOY-XUe%*g_b{q9r&xMmWDpUm9?r0&ym-IOl6yt z%1+fFcO0}$&B3;m5L$#UVZ&1RbBXT+5cBTDvB2aMEEqvA4_ykmkUzIKS5^1%2;YwP zM-*Q?wQ<&KqwW2^yYrT;@75#`$dfE|vRpkY7Txi?@tku?hzi_l0CJJ5AfIGMf7IpN zsbr(;lzJ0@1QaZTH{Vi4(;emSON*2!rd^sI81HxwI@cHJWOb3H$^8Rp%t4Q1zVF6X zyg_0YYYX=o_k94M0dRnb?9{o@2%-nI)R7G%DSx3i$%Hb}V$R*grXFq;>&f+y-%?+P zufS4P^%e#<8D9J7!3CC)m=MWaO#@FxO`=S+U}E(SrIa^?TI0sw7=Wt8sCw* z+|@3Xt$$+T+=6e1#4W(6axx5X_I{LPN1~vbY{{baTio5_lxIpBG7Ix(sM!sm(0rjj z4M3MpGD^j@$>m4qm2WLx6J!VTmUReD!ejQ#8t-px&qclRO&Jo{xfpa-+^R(58Hm-L z8O+R-Kbx3*sr|d=*fSTA>Wq3)Hd~aNRZo259KcB=6+k$C{i^H64ebjLh62jB4#D|3 zoZ-_Y2f^GVx&HQlHrRrkyDhsK^4c$Yd&J!zrWM8~wV6+E_@U{k4xeRW8Zgk=ZnYPh zT>L2}b>HWyj^B-I#v0eC$DZtpb_ye~d!yIYy5Ncp&g0tkM`rIcsJm2>>F*xH2$*fOg0 zO>06YEp6D_tm6h9&6SXUIAekQLxUEM-XqGUC&z@zcDjX&Hjl!{t4Egrk6fGU~D|hbTo$c_QZB8F2gT0l;YpE0p z>7?otn!;BHZI`RtN^iFNSxlz|DZ%#gw=N#n@#`R(pIXx8 z`;(hj=QYQJ?AOi4@d(|jOgsZDlu5HdRR@-2u4}(b--jmbD)dFhmuwXOl)azOq3HCV zUWcYws-bmdq;5tunQ~RL@>{}S7l{cO;ueMVgG$-=MFLgNXF-qt1Aw&2i|WZH6H!-aagw-lJ!kVS0eH7@_m%}lhcK^kD8CxRyeNpS_nf*xSh0% zL?d}$Fw#uuRZT^Th{Tjrl)p9Q_YLo@CM8Mmxq9B?>F!HyB4mQLXd|o1`D?*@Qtp!) zM>`T`I;>{GbMir*Hakec<0cs9#dl=^vx-d0`iMibS9{PZj!K<2w6_YUz43MiXQA2K z%8+<_C~L|02MhXNY`+0G{T1a=XP1h*eZ&>w0GI_RN~f0eEK{0K0U+GVU7Y z-ezjL-Uvc$FP40Ko@C1a^2q*~_2`cvAZ_rzGMjL;P8U2&u4&03sjzfQmOYE3S_7`d zu3cZXgZD&fy*QAjux_X6?39(`T=!Rsi6=7DH^v;qFqp@s_-t_WHl_G%4Pm4d@Rcc( zFr;p&mCh^y&_}QVz|hrq7rg|1@EqeteD`h@;-ew^w17yxK-R?mDawqwAAdaxW{RFc zf~#W4!``i}zL|yY0?b1YOxP>;)%>lLc;~Gy1-@Gi_D(HV75a7djoRsm8eNKi|3=oC}InavM8ex@*>2-|XRQuC5kY z|7OCZAx(yYYMH>%(;*y!677eFVYJ{^Q4vytSPfY>HKQ;hks@S%Om`0}?7cLrO3Ccl zT8kKkwKdE7fXU&xqL9>;NE zWN%K`LZJ;TDC|fe)Dq$ECod9Nqsc4J%5a1&$W7ZlB^os+v**AcU*%BouZ=tPX}@ZL z5J??`ud2|VTF=$KrxH)7!n4J@w6v;G?OI%4zxprKs#I z96s2a?j^A-bKjjRg$cs#_*6A%31Y2g6?Qi4yx&Y{ZVhckAl7ED9J;TPqgsxv703l1 zhA>;xxax0hq6?O#Lvhm!o>5bV^NN&lTk4Z^6z7}ImhaG%@*Z|Px)Ip+d?s+p{4S^Y zUU#~cCk;D}>Ikg~RWLa(S1AuFLHE|GdDzs=W9CzW&5Fl`kY6WRS3gUSy_!nb~{5U*t>}m#o5062q)a$bD+?%Hl>6tFOuatl3mx z)_W)~8lJxCDq+QZuY6dq-8+wv``oBNe`VUJDzN(juTd?cU-~)z8qMkZQ1x4fKN(NX zPC9C>OuCkfS&I8pvo7DYiSuL737q2fwjQzpUnG<^xw*Je+eJ-$(2OlM!wY~DmFrnA(#Mk);<6r-X>oBZtrxE&Z zc}3;)w`}j+9W*cUtJdqQ{DCQDP75*K&Q?A+ayC=pD0SfuOWVJpJo+v7>u61V=6?|N z)?ra~-}~@LOM@Uih_uq(ARr+Ojf8Y}N~a**?a+-NjdbS-LrM%C(jX1e@H;%8?|Z#} z=rvsD%syw%S$plZ)_vb=V|BC_<=4bt$B^$7vK1W)RpW?pNah}O@*d$9^yAdPHiWL(1#O0;+(#7ps& z29x`IgWbttl@W^55j&4^Go8iGYVd#>0N2tT^_ zy7rC=_H%v$CItx8(4D~>Ba+$9uX@#tSX-!fR^l{!>o{~p6h9+@;K4~C!PPc3Ar)vW z54N>+bMQZ=s)z_kI%{7b7}FnZVe?)U_}Uua2z;js&P|5%nU~@9>7D=nHyTQ;%Vm4w z1HpHDFL=k3cy!+Ra@=y;7XA6V2kLdbevud?Fhf4pz%?2&SL9deIoXy|E`A$_o=An5 zH)}i0{jpQmeIs&XYdmK{Ug7(4xILVb;^S`cNXiFz@FlJHF&*&a%pouQ{W}lzeLCtY z^7ZqhjQz8P+(>49W%aXgk+NK?5aqC#E#>8~Rd#>N-Jl${^B*MKM}>g7*I4L`JXG`Z zkCMseBUA(r(XbR=b_a~OV-udfg00 zeUrLff#_~FCN2j1iP(~#+|f&~h(K%fvYvOJ)ZnGDyyOyBMHXci6Nvosco|&#m_?t{ zfmdlB1%L3sp!piFX0lk>=CQ%cIniZK(Y7kAd$G-1@44$wnU-{E&kq8LH2#%Zl~qo2 zUyq(>rAgBOyRbrxDB5mFUtc7K9kwrkK+BCQUymIP>#|0SX9O6aVRMb85sAwJ+a&eK z*adjx--Z@+x3wFQuzS1e?U7CBvqitIHT8kA1#zRAIp4DAWAl;+bBUR6*vIgV=P4WY z?s@#Yet!^=4Wh?}5|o>A&2l2NU}fg5@du}a#jl~4OR5JPk!dz`(-I8c%idZ36Gd#(U9W;VS{;7OEwj&kJIdU) zmD37(Ty9-m=l^}gpeaOCLC*TW0~n>xrX(28vKcV>vs0HF@m$D5GY18cZ2s=-V#=uJY;<&I?)NMB5l0sK_bX?Pb*N3gikpwyQ+yg( zjs5!Y<@(jF`HTsp&%36H*lD}1u+lQo8`v78I2r@eE4jdpEp8%Z&hyX@x zSL^ZxTieavkJPcYhnxK-K!{!q5N~}qXsH3YWI$1GC3`Wu&!vGWof@Ly0z^3J9Pb+~ z^4UQb3uL5^>r^oU0)^&@48wVHIXjzZPaIpV9X82HPnu?m_TKED1wjm6xs(IDyW~>; z^O6_zcKMnUP!N=SidkP`fB%4a!u31GOB_wUZ$iYv z-V7(NQ``ozC~W93>G8{yRK5n1?`RUo!A_uKzGx)u22*L)>7mMgd+JuUw!OfP1raNc z_bV`DJdwce?!LIPr&7nBdQQ)h$4X4j-3FtTwRJb6__chCt}fGLGX0jYW1-WQb<)*) zd(G%VF=tjt>TcN8`vcABVzHB`7!hFYjee!UnSPTWt-MX zoc}qkrwF**pq>1wzVq}upO89bkrR{#ySX6o`$=(BkjUL}?-SF`>3H?s--X619${ef zW3%NKEhJxzNt@gq-~BxIc<_rPF0+WKdVV8&&>o+($uj$sJtpi4NyeUXeLhO3L2+r30z3 zlI~N(JT;s>78%imc}zx!-apK~{dMv4r6#~H*6V4C$C z?VLpFa9%Rx%W7DJab60nHvN4r@2+u<0rdbbk?;>szklV>i{hUfTh65WVf!Tz(V3c> z?(FPTv)J0(_a7fSz1x5OG;x7BHpOU@OA=umxQR1jzTnS89@4v3&EhIRiJw%kzxBxw zBh|cXrpwhu@AMEER1JRQ@i;ai8nw=?dK zbyU=`b;Xufe^2NekiQp`@{Ul-@}7=&v_aFjMQjZ#fBzG0XDM-9&>q!28$Wckm_svK zL^V&kHWy3Xx*DPp#haGgw@4+en;t2Lg~{K=ZJw5l>GInTb=Z|%Qo@4Xnu60)Y8`4> zlH4m4jrN9NLdS45};p-eU}| ze`RrU5O;lN z3~sa&9;cP$DDvR*>GsqQFG}@7sa9HlEkAq^_{PbpHCo$(QpD^_Fl_&)U8~-mKR;d7 zi~O!H$_qK+3V{s32~??@Nl551=BsDTqptQG>f!;+PwP~qmx6F~w974;o-wdFUv<+^ym9p^jdUbidD2RcB8R@-*<}_}8E7P@&Y}@o@SIrhd+X?KG@x3wB8ywyzLa;$@mR-k0AqkP-#COw**C zNnbWmKkp?)@i8RO%4$QhCEXbJE{uVGgNSfb&?}k&6-} znh9aQ^;Q^Aanp;tw_W$lUx4yoIH0IsZz}sc-eiV9rz8!nNq*OLwfyr(hWiR&XQ>9G z!*q~_4YGB7yD{z*j?L9vn=*fgL?Tu3F`hyy<(W!{mMq}T$D|5G7*7?5>DPVgXwH1< zzO|6azkO6yw;LH*j^rIbn;t2a!9!91`ys)N`=WgplDh4?l9AdnXH}Mg19eM+z`3V0 z1jaC}JD;h+lJL0!Z?pPH=_4ONl|V1zaY7m!i)R$kNMNTcby?-U$W_ugJvSGToehT9 zo}4(hfAX=kWE_COxMv&}n`%}&IR(iop~5@BEBYcql&6B7nEZ{z%|-}&21=^RO&B4S zNMz;wTwQ(OSLI0)ijEq7O!$op?@L4@0p>t1T^cM{)$e*(5v47jv|fNxsZdLLuJ&M% zWMyg+UDEkj-B{WrvBPdBrQrDQa(+pi%zL@SAgkf<_eADQi9vD#4s-6M&@+yDahv&v zzQh{Yf_(F4I_7aAV&Fb>U7CqFPT$~%zfRQyKPU6DU6!#~A*ciAL?B`%)d|mrmB*yJ zoG4!#n^F|O*m`PuNS*oIL}&-sOXX{``AE59%>}@D*ijFoaFZ;Gx6=Wo6l}$OvDKq1w!ksV{EHIaACbsswuw#iW9-rZ=ZnzXZhA+i6$t#QcQ4 z=kOR~OL$BJSm1!eJ!#VOT*B^)EX$Z1s%07)r$fzi!XA%PR#|c9A)TItNvVEMMA{vC z#lRSJg9n-WEQ0)n^pCo6U(k%{AajbKV`{Af7w7XY5>x;5ghh#g1utA$df|*E{+F;T z*i4v@`NZ=N>H9>OT%ws(ZBX^@tcE1r8}rNzHSCnBL*DnY4n0oRG-6^o*0BcrY{aB3BqrXR z_-;OB{3i+F0*3VYd3rI8`$Hr+39R6PqGPy9gf`N3crS%mLgh9XZ zzIWI==%jUI+FJ*?uyR_2u`nAYuB*LgH-t0YZk?%>2at}sy;aCG{r5qKUsH23;EsN@ ze&!rI>3;DUXichwWp~;vn<)>YZ#UPxj1i>5JL1CfbHnHT1XqK;k`0&P-%qu9E`3|ds^JdcyP*0 zMx^F6w1{+2X@96B)z}8oKbp-w=-GN4f(Wk(MBP*$Z)?lA-t+HhChnE z^myM7UOj72X{uVu>)aC3wV#yJf~dbJ+A8H2O)8Qx*~F-D5NNDG7-GF`{i3xpEJvH& zTHa}q^WfhlF)cl?Y`c10Zk6Ug+9%bCe=VQv110&pD)Vp04Abs#I@c4 zhKP2Y^QG$F-C*0W`pZ-<;_9VXhQS6n385b*=g3qw6=g{El=q2Z67en0RF{5(jS9s4 zLlh(UM7?+5GKf4P=t6~mO|P)y-92wFqkmlC5Y&E2gTz7y{$9lKA^Rf8nQU9q+~o~z zd+{v7)I4!Zi}8Bm7YgcC)OJAhJ1>MBi?}xp~8SAlt^pYuXZCs`C)h=3Bj(0BnBd_URd@a=&30{`*X& zZ87KKY>nh!8e=ti36#yM>GDAC&gb5p_MI+x05@l}rDCUhoj#_*z$*1<4#+&Wx9THM z`Bw1O(rOV}oO8BLd7O{`JREe9XEs5IWXi|EEsqaZja5bVU7pNwN~yHcTyf)6=SX)j z;X_#IAWfU#@3=?Tzx2c5oPTW$gG8wmYFho6$+KL2vUl&U&r&bpY3#7e&d2-mU0@r( zmw>KrG24x?2<92{_Davylo%*9M_Y#?b<{0+dt`0&3!o^N>S@p6ocx*IL)8caN;NmO zp~hYHJin>%K$2RFpg@9JLyja^GtImoktr)@%HRhOK# zojAp%EBkh1BI1p#MgXO)R^Xbzanw9v zd-%|7@aK-x#bi>cp=N(#$xiQ@mhSkLcR1%dJLf#BOK zU2Ppum$`dBrFW&KTe56#cuoHK_F@$0G>M45;icFD>qJjJV@*BC7N#joep<;o#jjZ0 z8$C>A7YJGGt!m3(2;jB~rJBBYRXSDJHn^a+LDVKCX>Bf^a-f^{Fcy za)Hx-A(f!@%ppQv6Gs>NGn+zPffS6h2B?iNLM9a_ap!+=Df4lvy5fDX%npi+zy9iQ zIT}=6CcwuRn1;r_*8c@eNx6#*tDaq&&_5UleqKB(B#BPWFE|3RMSVO-@V);`>wI@5 zT-4kKEj=?mad=AZ!xqhmZBEW-=G)AFApE>JoYP3E5wQ|cP#V%I zdhiYP{d`EbwI9_UYq7q|@=bnTfF4x+hBKaH!EAUXJ3TJbtmJ*P;6aFa6u_8Gd_Qob zCrSjo+bIe5uAGNMS<;xV<7+3zmbZky7Tc_|6AdT^Uz93=2PIeGvQjM-aNxBMMhW=0 z5Y4mqnPZzTxs)uou4pQ68V6Q9ePcWJsY+^NQ;N)bBd_K!#W>IR1k&-ptg@bN@3enE zf5mB@?K(-`H+F7Tn80>ne&5E$S)c3U=LGSu?vTDV7G*m=V2y_{aQ}X)-L>GH+@;j^ z%gU9il3XH1O9xrG`8dN9r<>dc$@Ny6Gs(A~-ku1)xcS|8%ghMj!{}aP-GID5oYNF1 zF4DLWQIAA zn}dGXP6p#MP`VuQ*`^t}%4m&u^TT|zHO|Ht0+0r-{QcAXXz_#W{Nr8o`_Ui)Ovy~r zp0yfV&*DoKu;7J|kSNaV^m2^;!BUg+Nu*8Kr?idkiN$>wL!Nc|rVUpOq3h>3)VVuHg z#ohV6Ju(5GOBk@E#4hLA>4_NqL4t*_o@XL%n?(K#0na)QMZ-!~&bBpUtHq$Lot#_E z8xRk^jRzV4;d(==c|Xnrd8C2*r!4vQYvY7mY&V6c5b_k8e|UTc9g_0$jAkR+e070K z?x+a#H5vU?H9L5A+~O)@DRtX z{@uVBRg7I7p2A=oQS2IYetMNu2UDJztTX$egvvZDWZg`uu{b~Qh27CWxiagT5fyA! zGN$2Jc*6a&#Ek<~21%FK&g>)=V=T zyIP9f(@iR*7kwIamd~i5wA*DhO$R$!788iLo_dMa38BWyx;B!J?#NZtH7rRmhBNnq zn4FF#qt=PyY$=GdgMQkC1WDCK_WDaup{vGtl#S zM7xC#`}4R_@sqm|&HZTc%>O+0cI`#xG;VO=H~+X6Me#+l*bvj{-+dbNEEiV421Vv~ zy$hZV-n2y|n3*~U7KjW-a1MM}6<&x&EJY1RydhPg`jE<5Sp;C50wv_8O*DUh*gmMYubksNJJ5Rqb_x%u1(LYib{q0m;m4%xG z|Lw^T?>gj7jy7$l3-7YL)vc;Mz$C>YP>V7a{0-LR3kyTm`u zllJXy&TETeuB{e_9}n~Gw%qxS+2u0Q7ch+hJ>eG~Lu9e2o!_ZWkH493VJC*zY~;C0 znG9f8PLPI$vEe7!ugg9}Kujz=4V`^G@4izqX)@+hV$21-7`bm4U^n;p zsbrHuTx{f~=6u84#MKX>l+5yc<<>@OXBt5O%y9FT#SqEMvpjNQih6)X8=UsJTp#zu z#4%PGU(Fvd0DNFE|DS91G}<2#5SfY7LStX=Y&+#<`FC|8yiWx-e25|V{~{Ud?_b2Q zMBpZd+b)0i^>F1?k24<5u14pit}g4sj?aA_+UD01UY9y^2IPmZjmgcYD^AXD7L+z~ zbFO$xZbtv-qo{FGgcXu%F#NqXc{;8JxUUdNRRwdq17V26@9x@tG8-4Y%`d*c0Rp-q z6!j9xv5rL7b`dUIUh*IRbLM@xIYUqe|5K5lcCNZFtnyJx*)MZN*GQHDXa8i^G@I`{ z#-lh0u-2!$-+H?3aE&U(nj|znbJS_W3~1hzA?K+~g`yR%DUP+C6mO#!b7{9*UWF#02*GXj{UBonGI}&GyWgHkd?6_e^fEyf zo;M$8pJuOLfgv~Q)%9kQr`s{+C?qbw_n`Mv%g43#49C9o;s%>A8O($`R(2Lc6KfSA zzVb3Pi3@nUqtE=UeK?h{dXd#$($S?uL)&G?0UAoSZ^MU)DaJ9#%r1+lV>@m_8lE}N z;^3lHda7#+122A=9*5hI2y4c{jg`o@w@FsyhMa~+H)x8|7bk1PT=_VD4K;r9T6aAW_ity&q%=%%B$yVroV>ZQK>kf}GS z1b_F`)6JfU%l}i9BHZF?06y&sf0*~Y>-lxNV=KGb?q(QLP{w{TIiLqON_1P&@Go$r z3{GNuxlJVexyQ5DV$1l6ZsORP*P}X}_G@1@hTo3sNYRVQ;BScQ{Scs=P-VSEYL&=_Ui z5_w^@zA%l=+~B9u#Gltwazy1Y{Xa~$K%?s^L*W?~bfc_n*84wdcUR5j3yJ8mdCX;E z0rx@1hWs7AwNvH`)p=^=%sCiiJlUi)>KQFXLr;)hRiFo;7 zA5Owj>ht7MJr0{n=4qZRQL~p_AMglA3tx7=n37o+E(6K+`e(Wa-jNAPaSyUX{R}vX z8ICC>Qj})gZNQmDU<}L$? zGQ4rS#@@bNTr;vv*fW;xO+QrtRs(8Mn`^fHvX|Gdol1LuY1))98xEgdSDNF+TCD)q za$Spz0lh}DFr#Y{(8j|eayDUY7hCV>D9q3kX+_8t1cRaHeQRxax^I-gT>{e332J5+ z2ks^MeCyNG5Bjr!qal&j6Xqv>Zsxr##5kE-&89x*YR`YF0<1$L$>Nn%8Rv*tw+Oal zY?!7nL6j0bZ zkUK+xi_1GZ7!-6W@e0U0eBvpVbx-BJP|9y|t90!naeD8KCO$w3|Z#MY^avMhh)zIG_2 zB5Rd&FIi=b2NLYrEN+>81qFL9*Oo{UOjAP=^S)(U*3n+zb~QV@g}g2k-&L=fQynPj z^7yStIHz4~4wuAv-v#v#{4Z(Kpr~hvn)-9PdZ2(<%Ug2n4QN}BJ07gy4>Bedak+83 zTdV5SO6=t1;rSXDaJN2NZ%g9PdGGGKExa;;$P#o#qrO{3f9g5)pDGjB1oOiwzkCpv z1vb)m`I*CS>EB2JcSKfYrFbFJX6F5GXo`4Lq$zo+E^Usb?=bvCo#Y&`B^Ec_WIWxR=z&W;`ECs`5E!0sN_9@lx@?oa{G>~=uFQAX&+p(R z{%|pam%QP4hj_d(Ts!eRp3He5GQ8>`ISzO{dh7>U?tGGdP2l_2l)4uHQ~x^(wA$zc zI&e8lzrH?dNa(RjttP1by|V- z2}E88PNN5EbUWBQc&0-B;yPjT~q37fq}rUx5k2P6Xxj z&9BMc+sxzUW!kKXI7QJ}|5_Avp&IpUUqY1Gri(O1J4&}?LN#~*b^Lrc^C`%b`~dK? z-nW?U3i;mteRqz=NW)xoDEp+;ZKcs_#76)*I{v{mxoI?aX=Bj z+7`h^DePXp;jAI~chNjr?1W|G5b~wEL(gZBM66T~pUzKcrA$JauAD5)70%#&*l3S#HWMg%!io0_g zLaD~*2i1x$WN__<3QpaD2HwdA!DVu+G(8vxN5jaxBL(Q&hR~>meyP*oww)jwca9p- zq>xzi=xo~X?B9RPDXEZ!28(5PuFj^P>%Hl5cyJ55g)5(#yN|4}Y*rs|v55kUsa>3( zO^%vZg29X$DMNx~>4Ek?dVBGMA=f?6bhvKh!HF?hpfOiN#c8p<)+;~6>Qp^+_g>L`6^5K$Z$ zsSY{9BOOpf6NGz3a8l*`JYz{~W!vwhP+U;)x@{Y}XwB1`{n=T{KGq;!+A=tgfTZ#c z8F?FwG&`i9jc@sgUU<~`v8O1|xJ}OHAng@fd+iB#j<-PHIEG9?;9fnxm21&AreY=d ziLw7P@s_)YEh9j_el@7r;D1flg!!;IG{;faAY5F8H@6_yqzmCH9!62Bd(S(ivE=jBFom19Jk=V5a1BWA^0@K zDnTsJq%Y$S5%y#<+3M&sB@pc-Ctp0~@#*Go!k1^WwK)wuYq>a2ggw()UFD(5iB|`q z;DX~Wu9$FNs+Zc|>RB3Y0;5(S{4-)!lf|qX(8%=?T@^eZJtK*w;7$e`h%=k~` zO0MlZ#6HiSvikiL1gd&|rYIFmA*SvF;hS zz7z;3UT50be$hyla|W|aOC9G}`~tX0d_8nc;RybJri@0wpaY>p42)9i`v z5NGpD3P`$~%gHc{Lr(1KPG}IPVXVr@xOwE##KR(y8$H}YS3le3 zSS7Ffz!e=>afQEtaYd;z6GjV z`JwjUL3_`l;8RsbX)OTyZsamiwi#$Gw+uo@c}E~%KL&zz59F#Gb+t!A6Cg)?eSh4O zkhy=P&);Y%rko`dvI$T7L=J2rVBbR0QFSm{6Ubf~&| z0~#*EHQzAg0Z=~jh6^-K^nOK&i6~fzIMnRMhx-dte)0L5lgR=$sh{wKmC1slUacJk zNLn@Y4KqgAy3y~M6iisn@$C`@Nwbg7-2^;w>OJCVezHq z2C>Adql@l}Lri1&g%U|bU!|P8k_~vMZY6ZR*org&s2d}m$(Ayj?O(kf|HwAfhy!yl zd08*Jq`1dOf0GKQ)69+A=&!l}WiWaK*Q?0dB0Ho&!s?aBZ_R7~Tc9-JC}ye#pnLG8 zvScKDuhE<2p^a6c)P)Y^LPhMCb4dF%pcsJhs%_J=+6Vk`))D7NMVjdIdJS*>$P>Vh z`Wk;RVl!{*#7rCBP%v0a9i{tNymT4r74UluvPpcz|b;u$*~d01&ns=q_zTxOcu zZ2>^~VO)&TB~fr^I6G{~G?CvOm^-@60PB zpCbQ8q63NLs3;{*ZUShaxn*z6<^)ukYs-}F3z^8xbVBm2Zn$(l=0Sh|7<4Nu-d#|w z-{8`$v-_mZ)ySIBQ1Q#Urf|lZqoHEnQMld^5E#_xXxT)Lbj(&H5#w-d=cSTmEQwi{ ziVWA=>!8}Y`f8t@s7^=QQv{5quas@h{xBcw)v$}`OzX&*@iQSEXeckDtNl3HXgZg6 z&gGzw4dF+J92*)~Kc&iu7C3kY)z5yy=RJE#D!5e`U?lwyCFj zxZdEcvW&#UPKWd%y*=M5rm_y4GynN4OZBRQ(fZQO-A(nnQh4cA;Bc)W+wNxk9+2E0C+x;QKx-sKJb^GezGkZS&J9iVQQZ69Fg&#k>*ql%_rz|VTItgHO( ze3NfQVN*?RY3h;@?uaI6-)z9IdFyK5ar#ki>1QUR8SxuiQEIC)3&9eNH{w9i9GyDy ze3t4``{DL*;ix}u*;yP&ZXy9Zal7q)!LgGn=+)|fE%`Qwh(&;|x}L!HT~3epm+Pa# zN7AqGyR*7 zc^mx7hm8^^EA72ysUpcghC6OS3eZTF+y3=qJURp{^ZeO-2;r|11tQ#92>?|`5eY&L z`03B@?|r?I**HBu9(V*~J){&Ay-%3$6K(XWk5TLkUcgoF@wM+&W56x{QSa(z2(YPV+QuU0m>u2~hSZh9G{O4^Tj1AT<`zMR?U@5ImRuNTo?O|^-)?v87*<9KPvJGcAWzj1}9+^zR5SrY|AWrZnDH$q(tq zItvIud$iW>=J+1a!Au~-fCSNZ5{n5`Q$hl8LEe&RWJPp9H;ZF-dqPDxQN<2|IONBP zP)}E_{=}HH8$nwFOBEI0y`bm7&HKGZp!N|cXe2JZawd@Pg9oS8v{(GVBpBg`;@AwB zQmt`$AAdawRmj<%^K1Za|EIn7h^1mGLGj!G8XWKXYEW9sW1;nPF}ox^DH@`>+MBc5 zI_8XMV0Zjz*g7A@+=bypw|21C?9$ZQh*TE``$5gRoYB=H;@sA}wsftc6lk_XDC&vS z;n7xPRx^zyQ+@5NM6o#OyT-LXWo@JJ9yc50Fk*K+_9^m2^c4$tM_NeAfT>l;qPgKO z(h|<1w+kBxLt*}M>5a``5QtX=`lV+t#ot&YrusAIA4~RUa$7XK ziU(A&O4>XF@Kp(w=)CTPCfX-|F7B<1}fqcc{rcTCvZadJ;AN17H6Bbn%-Y zYi_l>;Ia4NE=ojqJ!>6hi--L?r{n84(&{;sZ@GP1njB{%b{+~e!vV7T!Az?YAhoFR zr|&z{DkD<$8<$?!`OJF|RQNJR2Qk4T-H=Q$d0w@vpO7?m^CRyr&VOWOHG!qxvWRzi$Vwa&6+f3Nyo1`bJ$Ga(r)9o^qOyGi`xS-E2HuQSh@ys+bL z(ne0JDn&HayGXwFK(BH)c_IQ6c<{ev!$#BD#(0FWpj=`p{4osjD%SqCPoqt7k`vZS z#AVLog;|e3m)AT#;6`8DdNFAnjyd9{$1<}$m}3>2Oi(ak1-9nvZt8h$kXssFOTezj zyIdF(Xp@c0;J$~ncsmp@Q3URf%Rv~HjLF-Bq5Ocf?W+U%@PN|Y2I{@rjnzPOuP1wU zI|?FpSkOhDFvk4DuQto+3K|^`?3iE2x#lDh(OdcUlOR2TRYJ?lBfHKHC{C< zcuoEaHYE-(^nZ^B9&0wh`I;NrLmXKw7Gfw6@7nI!ymGn(0d@*{qT&SbFKZs)%RN8N zsvv^{HBFk9M=N4ru`6H6s2K*#`Ti9v{{E%;^1E#TKy0GIaO$zf5Llg0p*Vl`z8sO| zxfRalv_WTZh%l@(SkI^1ci*k5*DlY00^<`C!t@jhPFe<=w3*|^*TtHdOp|VGD@(gQ z?ORsg8tjEsCp&nXnRYmhGC1;pK>M5qQCeuL^EU0@m9Vj4@6?H`Oy)i1iUoH!6P{!6 zXuc{%Y6%8*g!{_EQF$<63X1NcI78t+ugg{G!7RAMLi|OaHCwLXk$@--V%cHCblB`L zepq!J1<{|WXt&Is{)%&jF{r<8F@mad;Vl7p>&sThMRRXiFS)YdjtD@=5FZj+?|<)V z51EcAP^tlY$SC8sOn#&kW9qkeA+%}#c|G(a=a=KhX3EZ z^%-8fNr5R@tpc+{B$Mb+vX|lj*5<5)G4fuYa(0-@{xX;BNAYAMQb2_Gs!R^Q3istX z^f(HAb+)NxIAI#k>oZ}V79P#eOFm+9(AOLvoQ}(mil+l7dmum@_pBBPl8AMqcphWA zn&y_m&+%mU8kB$(FH@gN`*ipA&8deR()wp@l4_PN%a`&4#@J=VUb`w@!EcP>nIVa% z#ib}GlI*Y1l_l{7eyN!hs=69LIdN&L3c{39`8il0&)KeJ5-XFhYU;wl!dN=1xjSAv z)eyJ<`komUH-zSqF@;_ITg#!M3?*+~2N zfKziwz@^Z}v;BVA)|TP)QE1JJ?KNwMVL2(_j^l5DtdTBsdsVlgY2KKHsV7m1XT@36 z!n^XFCa=Iu70Uk5o$*n#Ke|bn@-xs+Icz4Uc`S&k>R%Pnkk}ozf4E%$D4Otzo%JjP zX?w3oMF;muK|Ja0*b1JEyGH@#hQ1Doa~F*|QSIsUVm0s$=}upVjqVZ?sx+NX7V)JklG?3eG7Hp;}=(}tu* z*O3+`&_>n*eOCTOe+I}9V~|z?uLF+2o->swBJr{&hQWdGO~E1W|3h^r7T9@Nvwum= z93ihvU^aAPZ8uzy?KX|_9V-Z3478C)5;gdxd&dGUvXtT+Td0&g)Oh@6v@!QOZaE6* z_KgfU|AyVB83qCVawL!(axbc~@r%1_$EXMAs?vca!^-ylS|x28y)M;ILj9q2OYc($ zbuNg#23riZKMDEc@sd-ep>?Z)b_<5DOTeEJHZ!HSiTzXj)QubRG^BByelOPDb!Tdd zncb2no?E4(d6|hE@olc%S#JfMHI3iN9)&yxAAKFS7q5?Vz5l>5_@!QrBpQ?8>LlPL zwTjCzGjDq9U0F8=k9-ircIS(7CDf?60*u)Hg9wqf+e$3#d=jN%)66FD9HA zV~c=8ucU)trp;sZL!UwEYKzy#c?sU=E|nzgmzqq8H^kyet*}JT6B~1+QgtAmA}1Y% z%8=*6&|N3!1dl?L(%+;c69Nm4{_4CgSL%uV2pRl0#n<2Ui-sTOFqWcNmgJvFXgl~V zs{_#}!X0OMs&;Nb#m3$1*W3mT;Pzsh4AiT%S{>ITbDGktu9+SSVJ_*bmIX zW=m!62`+~yW4hkI9Mgwhteh{l37bMM4`zI0sJVwodOw}v7mLJ9O9*c0W^l6!0sN>1 zSg@yhR@{d5#%u(Y@Q==hWY)=?w94d1Br{Qkiw(KQ*m1f7#&2ALt*(D1a|iz1p#D0C z!Ff1q^q{yBNm%Yh@va@5!Kt%ffo@`pM3wER09b!O)n*64 zMnW%8rta?Zr=5(KKB<#0d!T17Adm;Cx$J`Rd_62>getqSRhH1b9`*ya zg!^L6*q`687sIGXmDkjd0G!sXrMk7>Cc#6RLi`jxz7luGJkZt_ZDk@oK}oxXwDN%B z&F@@p@uuLVgifd-ady9(k@stkwKz@!vX%ui1~j*tJ;od$`RiRctKQ z5KIKaunsxZqtD-zLI)uDA9c4)+{<;03*VaDJ%=P?9tPpo9}l1+{>q*)9)@tG50iv` zscw6_ZbAz3bXY18SK|PhPZgyh&uE}$Wz6iv85izVGYoni{eEvCj(NE}45QxS4&BZh zsi&9M_DOjp6L=MKsn|xqD10RMcTjEfv;P#(~>|`a}`I;l6S9% zeJ>ZA2d{w2IPF=}hl${3AC|#_7b@$oL5`!J&DQeKgi5inVLdfA)(>Ch7K?uHz{-Zv zT5K1*zlLH_=!?={)vdgAqhC0b^_uyKgtskp%XYk5cG3^`_-W4KdaxWlyEcjHC^gBW z7;wuNk1mV#pvdXpa-Fk5Bx{I0C!8LwLdrrlv~9UJ;AnxpD9jk2QgO@=tz-kSP^J+0$cy)9Xl}(htr8a$b(#Yk?2*=Ad|pcPyXa4= z6c%fYj;y1h)laMP?*m?urp`WOKx8zuBdr=UL1am?X&kvIF7jibS>G|b#dt4dwZkC; z$U8{|5R5)BqVXRV@3=*`*5_@o34eL($w)=KZDSk`GHcQPl`-&Qjii2|n1(OWJemLn z{@(Dc-@0P_iv`K|DcW~Ek@Q9a>uuZfrqT7%UUDvZ!aHB5UTvq=J2?ze_6t&t)mg1H zkbn6Wq=Q2u7S{|cVz;EyLd)F+rZC;%uU3WopF37s$;wBTet!;H_%d@~%Sjc!1!*0> zS_xoO>5{uGhoSn*Z_zSdF!^CZD%;5f42z8Rh%MW{(R^kfYEqD`T~EIw6ZN@@{rIaO zWj{gv=r?T1SO6D@$lf|JP$hazq&O7EOR6Gg#gq5d^YmJKe`KM^w(M@!mngpy&OW08 z=zyytW~g8w*q=Osx4io7wxJ9IdK;khy(-s93{m}bRqRs ztL1KdpyR@OU-9Y zHYN{;fZzC|TwF&U85G8Cr2o-27Prc(4mur=t@f242#3d}0NPF-*;>7g^H8&gaUPr+ zQ_IuhD6qiC2cx}YhQauoFyPO&8;hrc5)hTx&;?ZGTt#3i_3Kz}*!H3pB~{`k3ld7c zi8}<6@31v(o`63F3LeIlMbD#0P2-69D&yiKgIJPrQoxhQE`gRv9A)PV-Q(nyI&cXx?&N_Q$9A|+kY-O}CdNK1F0 zHGbcYYoGlOoa;KjI65%n8*8n1J$F4RRK30OoNF}Ge`<<2ym6&&{p_s!g?F%NPW{O? zjdTonaXd^lUz@9E&8XQ}-?k*(fFa9OT*%t4cDxfR9Z%5Jktz~O1cCY@F?+t_*hEKb_=61R%GB-XmeB^pe zSY}~Ab$a|odzhoT*Nuk*R9BJMB(7w94i7dpd|ZE;q)UR>1w1+Iz5@_1p*hx{nP1Kl zDUaw|`I~KueQLjQx2dO!TQrH4Y@vJthR99q`{Q>2zpD|2g;sVxi}YX?PzF6}&$<2H z8)$vdUgv6^l$9@x)${4aZ~14ClBx&o1;)ma-|tv`AyX;$kwOskej>jevlk9xr$P37 zZS@$}pZ+XV;DkT^%=d(yxWL>ALSr3{eoR8Ip;e?N>)0~^StG8}RDo~QE-rzt+1vn} z-3Vrzo8Vi6!_J)_$CyC4$7@dod8{Chl*Wl}!knBuJKwbsCxyd};S!slH}TKN{Zi07Lsfp{s+7=AzopJXvivK&?ci6F|s zfzh*>cVS$c@K&%o-nWh(JDSVwAW6~jZ~GlslyIaJoo|%qA4AZ_3D*m>o-^1OO1l89 zdBFSccBA3tg~enA@^=V_z&$a684KtHSJwq%3^*;}|K9LP|=B(38+{3RWR! z>BSAbnu|F?Q)Nsv@&Xv8oFZgqg9gT)e*G?sty4kwyR47nW1y?zG|`B^Y^>$e1x3hX z+^7WMTDR5;z1ZPL>;0m~6(bxh>bdJr{x0$iZm3P&AQscGHhXEwn@Ehzrx! zD8r`RlP7H;&bKKK0{Ip2{HhB-(vV}UlEShs(V(WOuHcJ+mB+PQFemq`xOc?73kQGZ zakxD*Zgn^p>WMQG@M)()^W4J)esdfL8%78iZMaf#H|^tyMWv%m0GhUB6nA*4N^k7g z=+b~!^+iD9pWTPTu2fhZMlTGZ{Ul)O#*e@I9wP8to%4RR0Z-VSR7#$p%lSuJm6c*Q zdh1fL<-@z-gcHmUzv}w+5<6W-xp7HRlXa&1m2mp$Z!hw6js-09Gx8nR1*AN=1$E!2 z5AvQrO?920I?3Ne^~ND@p70$~b&qmRo(A1T|^HBgL8xio}Xl z`=dTD`S^KKkk;HG+wiyOUA51Cea2L}l_vuI&K^n|c@t+Jb}{3$dg!Ow1md`eEWOzD zjyv0dvv9m${mNB9P~L&BKlp|EGDfdxgJGVUL3wEkG_3KIN=m3(@1@Y%d)dX`avOA0 zxl1X>k54tTQXR*cET^nF)*To%k(N`kO@O$)8;GJ#&dz>;25JxC(;VE!)t3A7dz_m2 z2s2KMppKVE*>H^t5l_99OxUzjU#P|5H72=oy;X9PndkjH#+!oOS;*F!UodXuc0WnF z==@dAN=gxJcmp?7^5znl1F-id7tL&#t&opqzXu3FKVp3AZdmeNf|+I}N+_(8dzxu3 zJqWBxkFCY-r=ib#ZK2g*b+@sa`v`^Jy7qo?^Lo1`Gilw#>BWAtohxlc()@_{1Wb+|Zz!a91@8#RLe~CDQ1Q z<6}BH)I$rPY~YC4WO1d4M!}J1EZunh^C<)oEviSqm$<9V;8|T7Y6d3uppMv$jpuws z1QoCBmh#^i1Lp(d;tt4T2eMqHa<1AHnQQmd;Q+H|xXDefhL}L&frysyoQ;o3XY$pPe1u#VC!Uz#|pjNm0%?e0)YpGvzXOw`8`t$zpJoniJbYr(!rRV zsU#R9X2{4F?Q(Ag>0b;R*dPFv!S08dZf+Wq>(%pyhthjt<4JWa|EfIXekTktsYfwR zuZYln(H+z&V`e0bB8Y8$UB(Ae4x(yX+hF$bf?%wWrf_R(yQSy!sk><-K@^GD;^Koi z)OQ#-HtIi6e-5NWFDi3)q4a~IX3Yb}(yfQl*YPR8a ze}Vn6p`O(400=vDN>4AOl8X{dOQ-Yiu|>wMfH$y!)A21s&U3|H{f^c*iv) zz|Ic;D~@UAcjAT%2p{*mT0HruEEwf^!k7q><(0usK%BaHL>Of)ee3?x=ejPHEJd+O#9q0Ee%K zpRO}yhv=3#u>6^?Z}e?uQ11JTA^jpdRyhK)TV|3l#(h6B+23d#4l9)tN*nG=s7}Kw zWmLqS@eIMnKRZ5zbkY6%@GEiP1V=O$Uy$>!Z~&$TT7=O_fBNW%9v4T$isk2`KPg+dmwR|}0kiAxaImmc(OO-+KvW$cLc#qhV$PA^HrZ`M|^*_%KF z@QEomO4onEY?@1@&L0)$wv+uxd0P!F4p@Wv}C>6bB+u1cN3NW=Q0=}}^& z8vnQ^>I{u-#3>9{zUPxEwS+uoJO&R54vvTZZUn^I9NQ){yiVh)L61u{blxsqitgJ*y}d>+Y2c#Kltf@Q3f*{QT-ifVS~LinQwR zMMXtt8k||Wdy0osBBP=}ck{ORtapl`53PTiCTuyrZ)V( zAuz#&rnIS!5NGJaPHOm$%jzCrLBvO+x9hcV920_UcxLFkzc{1()aXt;>-1P(TWYEA z7xhL`^Y**rRwXqgrXQ+wtn!vh-LLxH)p_uV;L1`RMQyy9sp4B{*lEXo0nCY*l!*!^tm{m8*8$y-5@Qz`Y?XXv$ACypm@3%Xt5@6+=+ z%zwiIDuhn4;7{mkQJ5MZu0t(~$>VR{y=Se!5LbRt&X#OXBRF5qgr;6jrOV(cJZ{kI z?7=nuHQ^mABG;u^$dfmuTa$1l175>S3a?N_yy8?iZ;^52AVHW)n}95fDOOx{hPi!m zzq&*n`y>w}_#Ag*xmSEsxV=NLzLl~&u&j*&Kk6&046{FHTGb{J=$hDH)s27laf)%4;yLq59O zL1woVh(9=Vp-?T+8con{_8^sshqj&V&fA}CDmHzvOb(=#jMTe6+nvNn02O4K9XZUXjQrOh(f%WI z?U|X${h>wBD+|KK*Kqz$N}IqP?Q#0vr+Ds1=FIQ*Uy;%l2p?7^Jl5IsBZFE+zv9C4 z6<|*nUPT1-9l-5HsYw0Uxs^vuJD*Q~9YF4 z1Ir^We9;xqqCF#Q?ZbxtW>P|Ht@avDDf3U!EOf!+Z;mwmh|sv0snnntV%*Ps6*r-E zWyy4x7{cZvzX2w(!d&1QcOC8UAUq)nHDny*zdz67guunu@$q|TL!lAb@qyo7gW>a z8vy;((&W%;-~j=PLsB~n%{t!25(cC@GSUL`N^f6oeb7~hG5MSHVV3mbmK38bX`ZW- z!JdL(zmw^;p^i=Ro}=7Ru?HUzPMa2>t}|0u&6SVRYxb(-cIqx)-a6JDv);_B9_PlO z24==zriu{Z{KJglVVdiSc@OfY#XE+Na|XE`?Zvz5tXfUjAtx93K7~aZ#9)FkV{+NB zcD>~JJatFKNPD=3yQ9hUIdF0Lv$LTXf2jYu8!3E>NVey0t5}{$9--wPW}L>Skkj^% zm#6rXz~}pK!B)@a*M7C^3$AE#u-Igy_cyGlRT2JL^8&?}kIK&%8hQsQ3hnOa`;Q)l zF_1R#&PZf{16cUp5`P`oTEi_`zmVaa65zC&5f-nol;F_ha7NivC7^~k%JNk1?EOBSH3gE z2e?rr5Sg1~N)MZ(sqfdiujG!Y7|A8J9BA_Fa#7_jIxp4l2TxF0b{sXywq9vawI>H9 z8+;U0WhlIdEsu@Jtka~>2Z3CitubweV9kd)3J={!3_6s=%-AVc(tOIHhNWu~$FNasOdCcXQ+8NpxQ zo`x6$@F+AaQ})Cyg%Nk~RE>&a(tUxjzsenxq+5e$kw=3Cy|0(uEG*N6_$k)EC#Xo` zJg4m#bl4%>w7LcIA7fOPftaK1$3~~a2u5QeI^kLHcRs57>wSNA0tkc^iV3XB)#jcp z-e?T>!-gR(nMB8`vWcLVID*gVHPks{7PT~87|ZmQh6TFi@3M;FBL<=ZCKEGG~{Bs8|m zvE@Fuq6gd}GYjB`^^5IO^7!ss1TnmU;IokvH)8>2ZCSg9=BALC0MkSrM?HhlP~FW? z36m5F`6z7On!6pb0Hb?tKr2DC?x<{a&-s-nwn`}r6V!$G&wZms{>_!7UsY>ihe-+pih`w6XN60BM~fqwi5hDIP~YS?WS|2Ovq{N%2FI@9%W`>W!;`z!HF1 z;kj<%c9jwDDgDK?Za z%KAW&YUttgsE8}C3u$G{P->YO`6fZX9-(%{kGL^UQp2b3p7ZNTN5F3Z&%*YY+%tB%F5gwBU_TO{)a)>$8 zkuroP$vOZ@H6&~CEag{M;aWstWSJbc9)+)C(mYBvjf0N$()*3BuqNZEVx5_^^9nfx z^WF{_`XSNCWF0zTGCDZw18DkZy|F5qkA@d1!1pG9_O`KcwaflfP8j;og?E~ng$cJVx4WW;00`QSr0%G2 z`abS*j;JLNEDc&7ty4n|(yWbbze?g#pzSzp$mNL}8b@T2fQXwVV@lWKXnhhu-S*AB znl`W(!=++jwci!kZmZ$;vmN|X7Xu_U=rTlr2xfN00+N6gwFU~`9+aUSR57yWK1P5a zgEI%uK>hb>bGnr9@IkIs`9$HxELG<)(Ws9x6YjXUj%Vdhg|}3>&r7HnnJJ=?r#4VJ zlvJH#DZk*rxrzyjK;zZ9s(d*3D1o;!*W3*M+tjYF!+5eqkm5Ah$Dvy$sPbcpY@`0W z9(Qpr+`8LYtE=v^ZflHZc%zG`N>+7zx3u=YJ`DdfEwws>%A#?i^eDpIB zjK7s&z<5LMcJ|1u;@x`icGO2lJdNzKHbmM|DrN^xqs*_&dvH9i{NuTDE>iAVlJFyv zAW?5hw{>w=c}a=nfM9#zT&-?o%Zq5VgM3eGD=B<4Of2U|hOVBFljq0_p_6Efq+%NW zp?1ooEX<`i5%$HJs-oNTrQBycVbvM&oPft)bS;=t%Lm#&dJ($2RSp%)OR@d4v%|9+ zj5q+!UMW?y6Jx-awq7-onlDaUiv!gJBqU~5+PAENe9x2rYq$af5i1rDlg{OyHm~{=d{kk@eb3ArOPoIDz}ZWFg0)NC&k$cQp%H1hDTume#&y*_B3Y z@88TGz5V?7>|}fRu0jYG*ic)`l0=bv36!GIB-)%EeQYg<)O7p%TqEDovIQqxL%0qd z;w^2Emlw_X_p3R15sf{_0H3*X(;VBaXtOpTYRrJ1?>us$88+AE{KF`FoD+L&65;!* z)HmmddF3(Q?IeMh4_sYjy;-39h|`I;A{xb>w$(Mm%VA!p!FzviO12qRPg|Xh_-k{% z7Tg8yDC2-C2xUO-`ZP}HM*@WT_tJ^7bhHN1Ln19+s@r*VLlRdG^%{Ozj4 z`NxdT#A73FGeT$hl>Q5r|6gI#f8Pdw{Kq7O|7J89od5aXKf;OocWr_H@Ey`7&VT#I zzXKosxe3TW!|Lys|N991`*l*-pziqRP~e~c{~!7HBL6>m#a0R_A^DBv<$6`35J(x+ zFP?~nfwAMQa`D{i1pPmxA(()35vW34SXz-`+?qW~kd`cXl{P>Ow+V7(e zJe*3qZ?}ooRu{l#igHcgIt#|({5i-$^pXd>9Ai={#A0%dY)BD`FE~zX^V+Qdt*-6; znQgh(?N#_ayea5r#%!gjLid#&FBT-Y2L`;%%|5`7wX&XK+g;OgYu&%R1JbPlax{0Ai1JrTN|9p2tYLq&zV zD0Z+22GTq}y8va2S5Nvrcz%l%_u&_|XUGCozkWB$%He>_^1uy=X3S-Ju3h|5q`$Qlr zj4!g~cD|)6&3Op~K-D5a?6$_}f7H|%ZjI%T&WDRVarqU(cra+|MF8@yyVnO(><@p5 z1An=2EBq5YOD;&ax3?D{f*m=k$8WMw)etx{U5q z$Pd?q|6SFd0T7e{oTm#cg69BOy+Hv)7ah$T;3BUU{;AV+%l2vgI zA#Co8D-P7_5O#etFr1wu;fjT+^|xfZfMF-;$_s{FRYc@4d^}>WEyG_}J_<-P17}2> zX@(~eIgd>zU~!@SEvLn{uVd+4nsgwoa2yLH_q}jg4Il_W2QXaYfb-yZBR9OMYGbQz~rjbEZS0?EHTZ zMQwibVt^7%jkkA$;N?c7CvGMa)h(&baCM#QFHDA<|>y1+Ty-5EncvQ;(JJ| zgMt@QL4n#>1lAeM+S$8+jAlxpL4d9+^Y4T7f0@T1(HH<{vf$#QCg-mH?v1x)0CmCx zHXnv{oiwZiE*GBW9u}&g%=Nt>URWO(*D%!OK|WZ#U+&NN(+cR$&aRj!$6KyPOM&YZ z-Rk`Vu2LpJM|NO+u_UL=fU6bA`&!^Hx|=Te{3k1-q*z#3k123WKiZm-pw=w8J-^$^ zxO;$xL($q5Mtle;TBIAurfd^N%&0#!V*Ph|H+WAhr|4acqcFT`w zO;`*J3=l{}L@<MaX zFZu7>sEQorEOxqj85c_OKekCl&ik%g2~i^PzevrOozDHL=Uonoqh7_(Lt6W=r}Zau zLAr?@c13@OgQQOD#lfSG#S2*K_%!ICAyh5Th7%ndD(JF#C_>*}^3=&yDpb_y(JlRf&%ODQ)j= zN0?tDR%rB%L%Sz{JeIMSjnGDNEIlkKoc z?Y&2LMZf8i4_)^g(y1Fgj{TOK7ofs%8?(J<)Q-w~TC8_+u zn2b8zzon=pO0)+O@1p)$+T?h6)vQmgP^(}vo1_X zkj)>nN4NXrVg>pnjk;oyDJswuFOe+Yij_+&6zFoZkOX?m9S0-J7mHUI7b2!=(bhF{tsqbAQHuW@4KDYuV%z-b2!vIEVMrKIUmKT9&#QH{W1fPr`tD{h ztnB0IS>rrEI9HN7CxneiA>G&uiu$8Ax1<@eg=L zg`KtkOL5*Yr;+ua%Rz(+WH-r^RR)!JFIA&Y^W^h@~JfEV|{J|0beybHM=V{Iw@i<_&ljtQ6zSLS4qO{@cXdNj#m&5 z787ezIhD8(V7sRl+P1_2Z_^Qgc;<(T;ak}bnu?4J@Zt#F^K#0GJGk?7sv*mPcvF-9 zh!qq`i7PNZUVDF#__VWMi>u=;6F~cS=;mVsWD1IYsOBOc;h?O%ZQ*ZIQ}fU_>jb-R z~SETf|6`P zA5mh}ESgaQv6JcU#m^sAt;KXO!YeEIX+@`t20Xu<{axM`+}R_~4{aWePP zT#xzsuM@lu(T6BKX?Bh`*D>uX#D@3b<^3rL)${)x3=KKHlHdF-m2o$>Yb_=@z1>OP zFux7ybeTA6F5MsrbQ>Pp5lAk+ocfAAOhUWr{9^h2m^C0Ho6`+zU5+M;7GXPS1fQ8X?aEXR~>1;CezWex`7I) zo*P4Lxv}EZ*3WkmXl~GbmUI^s$jV1o4v@tWOVTr;CY-F%uwv(GLjE!zfr15MK)4i0 zRJ81BDV=u>ro*PObPS!Wskw!F5f*w%5AED2XlB-Kz>xNM-Rra%`9AGwl zA>%<_O1rG^733Wq7-T3R#t{$uC9NeqTRxoWEe+?GC1WUZ);k25bhEjf$}VzIAO~UE z*wR9LddI9Oe+rf9ywtHHJUs{Ve5*9*dg#&V?1#{va7+v*Vu#QQUw1R$>zzywn~+CUxZ-59hmy?S_#Q7nF-+vB(FMC$ zogs*g@w zWEu>P%J?cm<(P+wWP>Rs8Usxvk7Y<8kVU9s%!8K`BFX&wp7 zvrnf}!iQWw<;1HDT17(pX>I4#)=x-R6)fJD{c0^;h=|8spqa`EoeYh?!2$#aayQbb#suKoZRk*D-@i@@BHg*-nK_cK~On~ zvY2h0K=jHoXlvH|ooi;&VJbFqO;1!{_gU)v2!NQ7e}jo=6G9RArP8bjLX<+zua5xUJf!3aRlAQ>C!@gAL43Oa-fI zg{(9Wn}G1foz4#{L8qk~G?W};5+a_u54OGE*!i`x>Q$_YoX|1x4eKcd1cjox zv^U01XD;K<*A}LJe?J{6pzA(p$hcFQDu-Bn>6y-M!I6ys3%t=95ho`-vlgq>dOq(w zErse3l^Ad0?4q{vBYzY8D9v!J3Hb!mK>gE(UpS^u$)e7pNPqY5yRF+jinqn;Fj%HM z_tnQ=3z4vclkwZQTqCCWd3k8mS0h0q)6)s%dt*5=@SaaV@^X5=u-A!O1i#xZAX_a2 zzHgr?(?@E)nk@a5lb|Ew?JW#hX;{8x7P{S1FdR-7gx~hVY46+Vi#A*@2xN0-rvsCv z(dX~T0TsFsc>5Rl5*DwE4r&#fp8n0FS)@yXnAG*L-4-<&73)!5ONT!?P?L~`r9S`C zQJ27sr(cELGl$jl;92AvZYG|+eS`E18r2>zjxImB_N^YlpQ9k!6}}Iu6ay*bFI^5E z1D!|E-~Lqsgc$muUIW=>Ww#55u%2?$VXE6(5PdZ|IT--Y00Tb+VxHQ)`kj;02Iu|m z)>epwq$Ir9hUzquEG{m_pGrmzMJa|4Vke8FyBVVYIA6;551N7Y7})Hv;m}_X1#nXxn^+YxFcy#&oH5^4Rv* z&*#E^792LdPh?zfXZH>6ZJUFRdvsDg59rr9BPt(0|4<+Ve;Q0A%$}CgslzokSRHzk z15n$`l(OB$ia>lJT^27dUXa4VLg#-;M&YO9_=HFwszeoA7-0hQlWAd+Ip6Vv5q(lJG>j=cIbvu3bSLp}`34myggKXj(Q~R!yCK*gVPstk_VpGGvW2#;9 zN6BZ_9JJ(`ptNWaK17;X{hj%YLO_QxIi)FBk`x^g4Ps_ymsK}wX5^o{a8;knz>;c% z+o;2c3|d$9YK|ecwrwm;jPr22t{l42pi=<*-tbPJ)c%JDc*r<5HAsVlI)55hol@O6 z*w&QYH00O~%ugEHGO?TTXOac&ekXn_eh+$b8HJ3)4lePpvx9SI$QI4myM)--qhpqK zonGPb)@q4#dqpxFC&2J8pWA)2_qf>$Kfyu6m4mIEz8szS%{6w#e$3CiIyPOZR!N1V z8vY4)d^}#JfTDivNY7*-xVWwtNr#m=);@T9=cZS{t{yp<4TOf#(mF*kmRp;CnBQ6( zkPRpAaoCOD8F4?P>vZ|`L?=tmE3eu*2hjq3aFFslh76)SBQoLoBu)0|6&91v8bQNAh|kcF ze0Wrp=2R4r88$UhrlqApe9Ft&ZuySi*PKsWS!KNF{%uriviJ4+)&?0-5#Ts%%%JI% zSi8NfTmVh?ljv-*nq58C(EO){kIVH~3rbVcaXKE3@T1jIh~UQb4flA`(+=8O0k-BazFaCQbrxoKsew^ z64i6sLXJUy_Eay@ngJt%%b?}MVPmtru~uR-$hvw2zS4m0siCmaWnn>xK(N1T4&_#eO~XfmOCD*Cx*w8I$U95Sy^~=Hnl52ThbgSRW-{vJ z=AuLxCP(@aU=l6>0=MuM^gH8>8Sx)-7(|KTUy>`>@GB3M=m_{Z^6!;pe-VT2SNKw= zoHvuBW!$s*i18UBU&G>97eJmYv-{EB=KA~)vE#p+e zp#K8iztofd4T-|P?(x2nq!4r?Tm}h1C&s|x(NUmW2!X&;p;kMB;P4U>Brq_L6=az1 z&evpBRuX7yYx8{8RrC$gZSj*{%1zwlNmYb6qI7_(;DNZoStb#-}Q_i6%=gEM;q_-GFRD* zj-9?G#P*3%QLe~SjVou$RT~>mo__kqL?iG8*qAH6XR6?fG+LYEg7t1N~&x z*D>Lxc`sp+R{rAH%k;PYwhMz{?-y=b?gScd9% z0esPfs)md!>4P~kl-m=;F&2n8uHIuRy|vthblk36#T%7jV(8S%rVcY?PS8p#yBn5tF$;I>n&R{t@-`OZ@Jnhb}6*9Wv) zT>*xgmvA-&0*PnV4o$IbCe65B*s$AM;1f9PByhRf%ClegJXf~%?gy1hNv@$^LIFwd zO*iIHsL+uf53g!5tAg%SosnGR=Ld0Fw^x=9u==-yyWL-XE8btI;m54JZ!?FNDUZgr zx}LO!%AY5YQP>-BI`qj@7GEzZpH#cEP_&T`-+ujSzH1@9G3E$Zp8weS;DhWW^1DOo z`-cjGr-Wcf!|bu|zT5#f9{pKJB1v+CyNrUoFVH+-$_-4gJ`sH=_pKf`xe ze<_<*B;1vjn}mDczr9!Cc)sVYYRi=}fZshfMXCR$@ZF!b+z|r@lFHU%5&AKw4rh+) z>6ZfiMThOvSgX7R54lTfN_`R-p+!1U)7ux60n4-NyjdONcK4TBiu!A)h6NJG9LHZ+ z1=+G&oND`)jfYm>Xp{7M#`JET8FUQIf5?518{v;j$2=Fzc5QP6FGXl_B(xV~R&HE( zqSoLP4JbM!<0o1{C)i?Vdxai*3OJ|>--}o8XliO6{-li>5Sn>8US&W4Fsghf66Dq| z4rppeKo(B+oB(+Cj`Xo^Gx||7`$+XO+ z%E~)v2dkOQKC?b29cBM4&&u;z;|%y&z_m@ijRa8vG$G~c-a6x)1F|@43Ti$YUQ2G( zD%J};{R%4H>pm8-owauw@xS=qF+){{DGQv?Ns~2*4d+k0Id&ZC%HVr0ymwe|$i;6X z!ql2E(A~5tt#u;!&dtd=EW(0oLX&^-ILGA&Cwak&&xhlXO9Q#k(c3JX@t))@Mp8*%AS$J|$~i!lLtIb??1j zC|}Ay?I2UW0VUa^>jsD2F4kqPYUUCr^eS4{rabG>(8l55;V)n@TD&;;l4`CV?>DS_ z)9RhWO6|V%etxYI?Vzvp&KtmBQTZ`InVX$E`q_r#P!9yis7`q${& zUf5F=QKg`}WaH<~fiTRV4pqKW3moYS(nR5_Ek{c8fsAIW&PAvXbO#b zvG(EccOmb|4a~t!4DLEkdJdR)c1aF`4p7Keei$B!SJHF)VT6=azOdlNEgNx`Ko>d7 zF3i9>;an0L6a5ZnMGe=b?Ll5cblq;LaznPqYO>0lyI0bQhLf z&k9<@80iDpLH%I;%Bs3Y`BjG~Bzzda^FtJF3VjZFWTgu??v8(&WrDogk}jV+9?R{KBG$PslcSm=Jw;+? zCNY)deGUu`!oNM%B1s{mZautJ$hsdp#1IGPdJIa@Uf;>Fa;#Ubs0p-PbslH0Kz=?S zM_k7xK@!$EBP!9jo;C8YEY9ov7{#_O7vyq$?DWku?sy~qx*yJ@aX*&}jSzK->p7n3*w9G_6OhoXn&O*{0vUvHR@Jx&MZw*3CjbgGbnXpV@#L zp`l?S04G+Nd7TP^$_oKs-P-LOGOAfras9yBzv#?^c4WQU}8tZ=10B;m!rDMR3=#X$iZl!M zWv*nUbN%rXjV?|?RhtFO$JVW7&+a938a-e|Le7^13vMdmxNGS<9+|&f+K#-Mog8rG z$RlLDkN+_LJTiCv@+8DQmG6ck@Oo%*y4z|U?#rJW3;1ZzjNT7x*TQ0PZ)fHHlpD;u|Wpb%{N92zA&%E}t`Rhax! zz9Q({k{}@%C#zKUrLXY*QmwZ}-8z;;6q;;C!d>MAz+7z<&moW1hY&4w)VueDux}Co zF;`aJSX}&NC7AUj^XdHBY&TBkEQ`-uJw&i^dl=bxqg1cQhN)zTwAo~rZDff0@ZAnv z(UMd(L~mJ0DKcnou?v<*N87`SPRjFHtwdIi;WB{f4w!3JJt0hF+MZn!A&aOW>{(6l zigj!Ny(uXY2l!v9y$At~+m5z+gjCaOJtJm*Tt|MpU&0i=M+I0kELQ7t;iGaWhZ(@G zyIQRJm5uLyOP3R>i|k)^@E$DS!r|kI3y9A3sk7bbLZ+_}zug)q;HpxciM>Nv_}uDJ0yuZEG~#w7R#Q z`@`-NH~E(I@|$;&ZhU~Y=s6dTfX@H`Qd8yO+>wpLkk+s&bCXyoc>}~1T z0%h`+TS2`K%C>Jm9bK26U~2B3e4@(^OlrW4(rWP8Q$D>f;-ty;f@)W4Q|Aj)A5+3k zHU=F=Ij{MD(@x|2`J&_og8Cx9M{_%%&NNKRH>?OLVVC^!xQeE1r`XvLuoqYfWexQt zQBSC_+oor@HJz|R_^u| zjCod>;$;IXp|CbW&I#ft)V-fsQ9PL z`pXOvX8fP;7RI_7iFmcrW90_(3Z8WbG85m{x!E)}2zt4YYrLrzln!47N!k2x-T|Qe z=wM{<3aW4@iKv8W!vqolOA63;KzJlDeofBNH^}BO%!jJ8G-GS=p~xvc#F2kuG`9a|)=*b>QQh7^;Sksm@MOYkS^&F~#5e4^k8-n(e){!A=1@HS1IxyORv`fKlF zLBLDmB_}01Upns|NzbokO^5Qg4Agkg9RC$rXTK4^9=zH)@NGbPM~0KY)^nvr=06ql zWh*F^lu^ypocC&bm@R3|^|WnE98MZ@*XoHnJpEr#uc2cj89 z+pKbyd0)(scfXLIfmQ$bQ?7aNyudvfRF9RDjVga$aWG}R;dHu=EIj3G;Zt?ja|c`K z?$BcA$YhHJgY;*F(t=(^+ipBbBbwXhvqtH*9Fn^hE0Z zv0QcioWnNP{Mu@((d&#-$FA_37K7XLZ`GbhE8aw0%2d6CU`gtROFv0{kzzxdU4+!dm{80r$5p_dN0$LJ>h! zZs@zayS1lNnxH2^iB3}}9Qjo%Hwd_^TVEGbo$jG>$5If!<-EJhxF@ZE!W=TLDKx-_ z+tmBa6ygK_c)1!@l<*xdJZrY)x}l{5$d1ab=c_~a-1FDmaz`UqK8g|&WM!?p4Mj{u z4((N4ok(mU)kP!Hm+tj^do5)U-Y4|5!G+VT0Z4AwiO~+LS^? zE!L2K9+U*_8g;M`MlDJ0JaTL(w}34rlX+?=%gl>=&(5WZbA6WVyETK5-t^kKu%6ifoMsmHKFCkxJa`G2i~FN5MX!2!Z)k9&l`@7@uJ9_ zhmW0zIkz;*>nK*E+3kjZ$+MMzNX{Lu*m07@;Nf6<54IvXCt(swhST5Yzei~Kfd)3K zJtVcUoAguetE}BY9Fm14)o;$j(dDC7XDnM3#f22zL|0vG&D9Yjy9F z&71957@QdMM_C106i~SmK0Up8k|fA=X=r8gA+cNJyU)rAQ~Ld^@Nml0KX2%H1w&(? z96Z?yN%Y;cT#72>nnYWre&dGp0PHk$U*b%V-|y*^VnI~u;B_r4dp*+LCM_FzGWnYq zy@35ZkwKz_=r$>-S064E+L1(hw_zt9^Fip@FFV&Vw_|L+8ZNeluoz3?lk?RTIvtPg zhghfSFXYPpZv0HQmfZKdh?@^kY8R&ptpN=%Q*Ib^=Vf4k*aBv?T?ckZTqmH29-|`) z-5o~3a#L*Dsc%QAS35%pAozfjV`5@r_m^*! z()f8l<&TEmzR2ISfrY&8wPGbvhSSjJ@?3-Z!+{fKn4s#Oa5jU+9OiLbsGh4pr)Va9i*>-})1)9K| z543hV{pE16#AEDM#dg1tR+LQ)iOLZjXzOkS(qftvcVNB+|c)OY($o z&Hv_`P~RU?!{bO^L*sczc`3R-bLUTgV|qdsp)r*+6=qez5Sh3MdUHNBT^pxvRxImf<3I4@Y%5 zE41}HmRe+0L>GQmE@%ogAdBS->*I+|)r0KKxpj3L?I5v~~6i6$> zjvl~xWk?N9tc~(ha(AKHO^-~Y8l!`wOxr4o?p_K?SbFO9CkL723vl*mOD%HlwLBCctvbM z4>W>gH99y>%l)9ci>QepDtn8i(Nmk=yc6$1$9|Y)+3k|tD#}u|R-K^Eya1Lg z&h}Pb&-HVSvw_+l`%*#U`TvKfvw(`~4Y&TFAl(Q^mvl-EE#0AXOLuo8Aq~8Ix@nt>Mz|k! zKIl>j7eN-~nZcS$TIY_1|41@))^s+7SUc2Oj1#O7;4b> zZQu7P9ixTh%3`B0{?ZLc!raHdbWT_M>MtF->67|^J$XYhKslO#y$1bf+KVOO3o6O+ zMgeTM)PWKvf-?xhGq>(-D=)X97^hEo8_sWeRn!1B$aRPs3ox1j9i0_PY_m#KwT?i{ zc~w6S3Mab0?uue*&r^)+#E$^5S?uG)4Ot`FJJE9|irC0W+pU>zTCcVZs&Rw5dp6dY zmr}OKggUzZ1Q-A159<~;=kn}OlJ`z!!Y)`c>)&*+?H^U!)Z*r89T6U`2T&SQJ-bfT z3-#|}|JMCrP5mA|aa7ZP*+b( zvAp-HTc+ZaBIEl1N|Yd%Wh0dHsm=VNir8u6FC6=q55qrb(}!IOh@;I}EMn^+XrH(F zvL`G8>`|34cK5O|$O@k5{wy~lk?J$;e5W2DRwVO@l}{?KY^#QhWe~ zwii3^jQ;BDZjQI$T|Fby6ZFD@DYwTr*nb0}H-fJGEs-fD3vy2wuI~d7GY-s63J`_6 zAehF{4bzIbYdYhTH*9`EG1Gwf6iu{ihJ_M(3U~-$ zFS2>pzlSbeDI1uVfkW2o2&V0FjmlnNzz^UthNEe1Ey>|jcJpy?aFDjJpaVD*`U!(j z=%3Y`e|Ic(Lqm>Z%c3{`O(sElWAeSQpDkgpl--l^tlgM~N-P1de+#F$IJ!p#fPN$t zQV?NZZP((>HDRL+Ty6t+4L>iNIVnFcaF)UZeTp68E2;Z#1$d%FEjqamc-o?1lBUAA z0UQn~6DelW6=Duy{)!Xj7O8b^m=R5jh*B!zMoo|-I4hbhUGvi)oF@8VfVq?R9U{W{ z^(W*6pi6`?bc{Vq7ex5Q4FCgnO!;$Er;Hp);T7PEukwz%!{9oRqJR8Y$MzXK+S;q6Sp~WVhB`tk8TWc-qOom zx4w%a+UCTI)Qwdx6L11sGUk4z&r&ry@Ur56Wzqftrs(&Na-zk4a0}pi*qB>EiI*P96AIneMM6d_RD+Fj%8yG?YKu}tb`eH8JCUZ5&E*&KXuTTzI#X?<_w#PDJ^xJy)ciY zXKb8ML=65Dxs!J{KcOIvMZhPMfQEkkvc#n{aJD1ifaP5zI3aOSdad?I zEvHCcB;{kihpP25IVde7t9zO_!ho}>6E?Bo=(Ur?HXuXlqmEEq+#4Q}pK=k+#NsZ$ zlEpK;urZe-t_ro5C;KKgFr%n$#sWxuOxh!f`M*M1rh7mjtuhP4QSb~Honm?%vo$K)^4i&mGM4h znqN^-u&#`;%#L}7@a;@1dgJKpNBYRJe`B^@$(?#rI1dGB*HCAYr25Mt;7rj{R`_zJ zC_d^cF8%)Y;tVn&KH?-lknQd}Ecr?8SEPB{KW_u=;Y>fBfqL|d=d`KJ8$&itD=5_d zU!5H_c7a>Voff0>_PGk=ZypMdcG%%L4Mf?w)*yXYy|FdD2(4(+yfQQ6>F#5S`jc^y ze)R19kD&68WW~?^JzGCv@Bo#wk$1$ zY#&thZF7eGD2v>_)evLE2)M}qyJD$c4c&vJ9jM>zlcrxuLw52SV(C_S8(4a#=ed^z z6(;I@z0w#b_9hQ}TZ+hiv^C;y_kNg7nA6< zf^UOGZeN4`E0tfIZ7<=d7dh|+Ep_`#TKE+RkO>*=JMYYWk6m*6fb`C3Kd$onUP6a>C}l2&G6}r@oCh@H935+4=;evjgFj?k zye4Jw3b;P_q_gO@)h$xujS7~v@kC+w>I$SDRJ$ZI#Z@Dd(BXAFdH1uU;j^*%?_hk2 z#(&JT0t`A9d~~}Cyl(;b{^??MmuhNPABj@IhG2GkplRm##$aXFzf?X&-TC6^ zdr=i%l)?TjC*Qjf!$Dve*NX!XXbvcxTtC0`0@Bjb03lHj6uWi$&*5Zj>+jEl$A6mY zYg3#;H$a1!cIfZ;Un-jKj^PxqP^elrseaUWQXICDwZ-etx#){_88o8=p)iRk>%DcH zG1JtxXa63Rm1z1QacEg{;?i&WBrd1yS{dpoVMMlP&?9o>`+!YIs0W zxPuAt^$_OJVlhTvmxWMt9D25tiLNGVq$K@!Hdy{01-{}v)XGxV>h^}G?KOrbpV(LJ zF<196)FoCg-kgUOOsqI*?x~blrDRVHUtqt1_07emU6~cT!0-m=q$6YSeTEm}6X)*9 zLfAOk>h;(g8^#{(4|DICelz9gr*m*}m)-ge50;X@+ZBC?JdQS_KnjGv%yIjb?iAsn zjdtsQG6Ba8#hZdTJS5$ehRvkF!gr!s)~~f~Yqlp+F+=nwJM%9Ih^{{Hmkd$<)wU^W zuN^;iAX;j3+?VOC5+vfl7Y$+mHn#Io`~W2y?Gmq*{u})bVE~k{$K2ybMLSO2>RJ10 z$-JdOEfL+CCtRRAQsaG!Qj+Fu9_;tUw{y1HGXwp#l)CRfOX94<&=f+qJgrf~e|lbrA21qMua`Oka@k$JgR!ij`3# zU@TgT4FkWA1wmOtZdlI?rOa{~{Dd>sM%?&57(#J@6PX88*zZx0cO{0p>)fpvt!4Tj zhor+hjqB~GlZ@2q#^}G8N6p5nby^xi7)&xk#2IQ43}tp6;>V5)z38NObhFwij|cHN zft5h2uZ!ybFVUf0tHuXLBpPmVk{eLEALzjGzgcyN2g8#Co z=@czjh?R7yRx8AMPm7L}z<5KNjfZxyu1~!xK0!s?)l!r3`h3F?gj)JmW%RZkchCAL z%F`*B{S9!9vOS9x7V_YvOZO`1PWIvY4iv2}*wmf;^~C}o*kdQ$RS%74<6>aDYSb$y z*dlgEP?@D{Kd~6YyrBziR7oDX0QRG<4NOP;z&H1~SKGALUiG1@-BO8#mS4keB#o8` zIo%o3nwF3JH!|cd;{Ku2&x=>1qDzG{F5-{>fJ4TJYfqAFB4 z7_@yhzlVQHfRk42AsKVpb-z8RbRVo+`l>U&UF+eM(5J`gGaY>OrF6eM#LzUrCpwpu zRQJn^`Vr|d++Mc4u<5GK{4?d(^zHAU75Q%wp%*R|7zC|Itu?z^Nu;EL*$UOvi^F22 z8BNUkQB}uL_DQ)~_3iwrK+rJqE z?;50%SJBRBLc~K8-S@YxOX?l@{@8s}2}Tz)Y39w8l1PQdfUij8@UnWV@T^=iE@Ce5 z)y>WHKJ^@@vuJv>QXNl`4Fq)|;{LHsGbqv5wX`%>ETj6qmd z+O5UECDV9q(SGkm9D3MfRXJNV)!|LIXxh&UvGsgdi^fb}!bp#q$mAHWz+kLJ!j$?; z&g0)k57M>6kf5g2QpAGg#K@Awgt)Su<9$wR640B37_hCN_Vmk;r&KH_U7gg;)Z$nf zwBmO_asKGYarh?3Sb1% zdLSNkX6!wGy9&W;lH6>vkKM2_?-CDZ*N+~H@1*>i%NqI0AGUF0w|=+U3h{km7K=W- zhJTdB4H<6nZ#EsEWw7_o)9$pVi#>X%+gL--;twCLO#Ry~=xt?f7@GHNg3#8L71GaT z2n(@LK2D8|`BwER@O=1jP=}3Hhkw>=oBE>~OnC0$&8)4LYE@LSi*4iR$!GWY{6;G) z;i%VboGtTNR@e?R#ZlcCg7?bD6J=evQJDMh`}65=FsSg0*d?jB(Fe21uw|J?SqTn~ z7Ld+7^>A8ajw3zGi0fJ{Iys)CW#fMevT;pCuhd~5ad6&iv)4wQl-hrfg&j~h-X2DH zJ*_H)$7;cBjC)x@nriV(jKEC zD9#aydHs@XA9g}LoWt??c7B?*^IMb?F(JuHbF+FRAFpXMr;Er$MugV09GxuW^2N)7 zea-`q>!)xpIG=DtR!Nm^^3Suscq9QUouAGNVMi^T+GYP&I(wa;@5SUY|9OR#rQz>^ zHe)BoCM?&gg`Am_9f6Xxh)&$~54^|Wv-1-rZBA%FDuXaJv!2Ho1PLV>~irQ;HG#hys)N~4!) z#G~v{-c{#}U_E;VW|O?FmO7<>V$a$!Njtp?v`i!gDyt43Gi9QZiQQo|8e2CW-lg4&{)!gi;$d?dDr@Ub!9Cg$3G0IR!?hCzwkQwvXPeIY3*B?b~rLm)OGkT*rN@y9{|I8si+POZaxetgQ-X+J40oE!;IZn4`detpCsF*ipg?&ZNtW6#M-Ow3wp1 zM!^3Gv(x%o^4v}!UXU0rWknE2fsYc#SvqXjG!?7Qqs5HB=Xr|em z1uvSGH5=>pZc3|yXK$Vl2G`{|6!W@Si&>8LV}B52w=p3uOEBte=p6~zTk7oI@1N(z ztJH7`d_)pxp4E^w+7&5_>!(P3ciy6TQkm_9TRk+F&n54}H|aDXmB??=JeenGi6lxt z^n#IgJfozB;ps30QztgD-jC-$WV9Rx#Q?8flv$^lq|%g40~{-Drl>l!h-f|nR9TMa zr}EzdU>8b1@`szH&8T|1_jrHHm91PDTR)PN9q6L!qpAK0a2C<9UslYk4iCaH68rJW zSvt&HjAHRnDMWnJ;U^pJpq8sHJIqcm?{0z~=>E>>xu6^P-{0l^acjw=m-cz~>_ z@AfvwN2xRNx)+sgJ;SC-)Wd`KrQEu_8R=Vm+?5vT1+wfAuM2ZufTb=)(cLeL5qi3( z96$sZBKxZJ+km<1kKK;x$UzixD6h%SD_VDUTU77p6=nO5N#Z%{55H{5Dx=-Jt)bZo zatj*tZl{fQIljyT-f4Oxg3x=P>(auF4d(LS*%k-2==Jjwgyz5-8Q^Q*wIf0uBKAL7 za-}RVWi~E6+zZWfe}DhNVJ5;eFTe#)yQ)rSi`hiBn%`j=^MCQFPT$?9;;Xqx5 zBj?$SSCk@kk$;8cv1uGVTGa8_>Hb%;g*71kRM$!2i5h2Cd9P0DK zz4sm>=BvC3g71?_I#xuwQ_h5vA= z3G-!L^#miH0n87z)=uE(0Bre-)jNoSf+)uLVrQ(jy$fh%QIf?4!{l`-jlGR!oV7MH z)9D?p>KUpl5@So~zR7;fMHCe|f*&PV8#T>~`iO-(e7dj&Y`1u6t+ppi8ny0(G*smj zVL4i<`%hE9bHZ@2;p5Sxls;G2Lh6Ddz(nkC-`*^= zEH3Jxp`)9%A76Q6qlB8yRcbJmm6ZVsEqo5_lfFKBn@}mMs-|Wbz{f5vWtg6x-enY+ za9O|WUFy?fZoljr=#}N+*I>dd=XM&~sF8<3!<3A!iuKddi4w=pNDAvC+Hvkq1?jSz zv^)pex12=z9UwFl7kb`gpf4M^Fg_(d2cEdaZ}++)SPG4h}#z;Hp<4cin_ z9jO%LNrw6fL(TII`h9Qfp9furuk2*4wtN#3Awz;)&7LFUxW?X5p<(LfRd_jul~olf zmypqk?5F{%aHv?#L3od#VbHU7Dao0Z45VrvhK!6o088EB$Vr^QMcInU#!R}`-4{w; z{QPK_9}x6zZL___(GTkvdz{n$MOp<$I)v6h{%_)H*ypvGP2e%f8~-gclWF*qhCu{S zJ@W7*uZCvH`N4=|5u2MI^?xyqhT68kZ9^FRnVRO;Nu`_R3`3ll_R^oUA>(NIyw-24}+Uc)(G7&J^)cMJ;TM93elg)nq zRLF{h8c*JxJBKB$?$!2~*LCmJkDQY+c=Q7QG;WZAdG*k3Z=5xo?yYRwhlqqinOC0S0wxVqY}rPbpaDk8{_3TEx5%{l>+^XoHZx`W2DGBnmEVu&Tz0xwfm z?Inh^_d_#man(8*rmwFXymwX?@j<%)brO?QiMUr3RnN*USC~f}fhg0x4FQX}7P99& z)}So6Bygx9VT<3a*VsO1SnI3NzjbyOqquW7GJ>l#BuGZ!$(p5LxczOwTC$tW;@;Uh zppFWs_D8gpGKA%b!H*A2?V#)tN<1@@JlPWH0gBOI;j3UU^PLTMolqxklrzgpcO1@H zIaXlC&pPsw)UYq@;jE4YfIwSo4x>U?pOL2^8JGlP?_~M_00Kd@6wZi13;{w43bzV%!N?Ot;U2Cp$~IB&;e7FCNjkcV17kWI@|Z;YRp4^uP-;Kp2Yp#2236cu_kEuam|PV0vmN&wOlqk2Oo-YJdmJH z!2D~|983~QfmCaO7#%wnSb=d6|1*sDT9~b6Ff-%)Ym*lCB^~rkK_>wB!8vUY0ED8I zT$y?Kd@JBdnqxK_ys=#!`|0xMi~rY%niZ2&jil} zMhy-7?fgCa>q{6;E$qR96HAFNKZ^Jioh;MdHXJv9YC?N zXF`d>6R$pg%&I?~TWVr(sLUF4WGJf*`>TO1`#UyhHZN}GWpI(x&h=6Y^JDPFL(`T6i1vO6Il+Dp@L1>|yo z$tOknhIQuXz=M0;5zG$w^|nWFIq(bq&=(gMs~8$$iej$R00+dW zr{HgSK~@Sf-ng4hE#_EHy+8^i%OkBgEd|hlzIHopKY~PoQ@^p(5T79zku(>P#kpKz z%tX=K3r#ulIJya_@u(N25GE)*VjC;z!u$e6Q4|B+hFyqq5%ryR54AY=o8ClC%pij< z$pT1inmXS>WEA){m!=t%$u-NwMK!{xAoM=M=?39+IU+fq>4q8=b`mqfBsX#(Y2R=7 zqX#w#g_o$4RadWv+^>~l`;JQEfqMyKS?2Zx-`q6^EjgqMxzwxf$)&2(^oj9($F#6Q zcE8D4y*EOjmRd)^POwBv{PkgkP5Og6CA2tATJJlI^zxz5SFGm;vxG+H_k9(!$6cb# z(F^F-5I=-(<+Epfb2l|v40V~hrpt{f^oNeVq{-d|9CV4mmE`rgKY0wpoVvn>ueR6Q z?uAJhq?y9+Bh=Vw;0!+oCF6Bsaw5x47-$9V z4aG~OC+$Fz8eyJMmsvb*0@`7tTDZAvM2ejk3&KhFRrtI(`L$lm9T=()>I!-G2+8;3 zymBYK&Aoa^pr;ayksL#;zb2}W_P7V^cM9n+jv@#{qvEEAwTohwmHe4Deieq~q`cAO+n=AE zaS%a&w9urz$Bp~SiX!K(CRbKs5XpV9dcFW4oK?V`+GxMRsK3_cQJo}=g|vRU(RT|J zQYbkvh*960!<9AySZ;tY=nH_VtI?^{>hR_c3{h;|RZ$xC0TRaVwJs2@3?)Gb0y3jN%^$e(35)wvrG8+{NmHZ6nSLN@xQks0Xu?npAId~0F{s!c-8U3fM-C#3F2Mzy=WiNXRO(m#HD^hV3ys`T6{kT4_Q3?`O{iORx!LkU$!oCu#t6v zdlogo+ES9rhxS{d$#f$~U~1t@9(V>mn4-T3%jHa~zPo6M{Ey=#r?<&c&IUe!I8tLi+wh z??oF!v`$a{J)aPgk`BBu(bk@?n{I(o6Tv9}gUb`JE52~pw$7mBP;}nqK%h481*i}4 zheQAc!}>p$--{O(sPo9X0S)a8;Lm*?4gkcY7xtok%QpUh`lr6fN+?rRv+?RS>suXu zEw;yqYZ9>APxep_>;`2c~boXmphui~VA87ZZIl(pVU{D1Kjl z@rfizi`~*D@Vz`t1n>hSK6SY6eSYyHYA6Pr4G?T?MzLvh_(MrO)?)>ZRoZu)TTYX! zeGy*9ZPYT_lor%44OA8K%OL#|;lii9fH4U+^{Jf4mC z3j!Ufys}2^`?kD>TaVrF0cji9OAF|?tPSi^Zv;v{3()M#2S@#AQmhY5lTlEXJY%a>Gyz^iZ#(9s(wfo z$GiuZOFl^t>*4Hl6U)3GaI?EDdza_HNc9?MD@MKXkZjm*82VFK$4K3Hu(94d&&NU| zS7yYiN{v7-d$!43{yjGIb`uXiBeg32$?lpIos-fUvP(&rHk3s#|5&FQE+v+Zi;o(e zvb>(&hrk@pk7`A(Pyfh?JL$x%)9U_sCxHcj`>w^5H+inmC0A_8b3Fk@8#)Lp;y2^5aWKql{&2j-(KaGk zQG@WO-88myoc8UR8t+bfw0ZEAImR!7&T*0ebo9y*f>s$xQLY5EC47`S6s?5Kt?7-_ z8rv(cP}ad9j)7Yi88?kz-V7LT%r{(<`|Lef!il^ARV>;{OO=q*yUPQ-0>mC&ZAg)@ zwuo;mjv#&se|}9)ZsI@|Nq{#YidH9Nz?#VwJ2HU+7r(yP$VjcrhA4%3aTg2^`OO?@ zR%0el#Ic2HY;3J@Klf)Alq*8>B(#N^U)OPoz$~UzM#LHwKVO&3Jr?zWSx#Fr+0~X~ zz1s}Z<8RBR-y+Gh@hWNXvBqheAgaXny){wlujeXL62&6#krS;3JJI1ngoCZVdV@Q3 z%ki^OB_l9bfMTrmYxiH~hDnhj!AL}>?>QuRnyi36&9*6JG0>QDp`wZzs6~>(ql?;% zx~C5CGka-yyhnzf{j@Ro2I-j!WtIEWy;xH6!SNmo=;5>k7ICo2YuKlhI-rXAemYt` zMWN+vh>>^Nxi#qX3VnrI-tcFBw&BOk2!Xt&-9S(3KPEaaZDt-bRRQ%;t6&Qc8UlmC zFz-LD3QLI{mW(`{4W51O#W(~B8SHgaCO?0cv3;?^XDfJ3hpG=Bq+)hvcL#J=G^sXJ z3`jMTi4KpU#&u0Ry@!|0t|W$qu{Y7(ixJmXhjUMDQ_==QS>amsTpx-tyxl2;W{@l6 z?ku&EGdO4Oca-+PIJ9dl7e+NFGP7M*V@h(+8B|l+k67M-xIlr16D29jEf*XSU-+6y z=sI*&@|bdU!@12C(xbW1#2F-MX#^p3`KGhB z%yHtAbKob=Kf4v3tmq(x0x=Qp11B>fXmt^9e1AqDDUx)I-Qp%)H;;<9B!Q1d>4-oU zattd?}^UTKx(elxZZ&Jgdj@G0C< zz#!QIcmjiOYCGq|x>+Y{*GS}Qir-r(lghMJnJN|bPv5qTM(iNnwijYck47axL~qo1 zjc>S{SbzD256IeW;bi#&qhkUC+&8uY@u@X3_0JwhT|f9H&K!ew)Hdz#i17j+gT>>% zbNgQ3E}!6+>^HULOYsA+gO8HxLdAoLRP8l221$p4r(~TqYD!DFYe{8=BL7@g z+_&$$HqsO0w|_02zs_$=`v1cU!Ff;p;{rd5vU&;L2+#TNhk$v4rP1l16-t?@KYgYR zD*!=Af1}KEHPTbC)lwXvfyKCn+&H~g7eb3re;{faTteI8Igviyvt-=2UB&E*y%Q6x ztyjOuX`^Z;mik&+ir%o+_@ezp+tPFOm9iUdd!qQour%7&U;J{@;;Ik(UMs0uS>GcC zL{3fyG>1EEkUB)J>DnnVtL}h-mGsYpyT`D}G3fbvfM?*MyF|2-H3b<@`p^A(Ag;I`{E@ERrBZ34D zTrXeVeWVd)^0gC3Ok zrV;KHgf{YlW2r4dFABY^CR3xn_q6flp^w=~yeN6>LX{(buZ4BkNHv6JG}nKt=2LL@ zc}irnoq3`m8u+4AKTarfa0~x@@W7UuVM)Y)1)Z1A7HV1Zq;!FA!^J`-5Y~$g?3cbw z->QCFPa>~Dn|-a4HFGF)FGi7zv(WubnTC==U_KnRZt9*O2U!eN$cPWwZXO~V)hv+* zTq8ZdQs-IzK6lj28_je&r;5G@H(^0|?6338{O1ZIa6n2BZ- z4qgP^h1)z-bO%VU>I#=;Y_GC9#L^h1=P)|$Yvj?4;{ES)pt1i1X2WSji2q{B`z`R4 z*wW*VU#JqSMr)X+P-VQx-heBd5YhQKaSLs)MYma1Ps%@U$NMQ>)zuOsBbx1x>kuMi zLoe{vW{56)v)KU2?mVHI0_ju9t`)VmRTHdsyAlw@{(5z2LyVw@Yo39} zd7Mz#Ckvl1JgeuM0!_G>=qvtD>`LTMsLwaNBE9{)+Q6g!Tfo}2$n zqA_oVgcBOR*ipxT$SkSwIr5K72|&yU5wCs}KDnvWva4A_bzm|W&p`U?D8xh-x3OLF zPvp?&nfG?ep|jiuyVn?4M%gN)T&>MK9L_xD&KcRBf+-D8wmdr0q4|DygJJ}tnUWtc zao|y*PN!<`J6p6W*@7rgl#Mzplj&b1H}{iOmM2nx9zMd-w4NZ(3J1y(^ul==9Or(l zQ1z^#q45gz45T#HpC3-3fYC7wP#s<>rkC#!zDS<{fnMNd|Epe&XA1!6k+6V|^75!v z09ZTJr<>%H_EboEDJ7s+3>I1K>1`(ihh+#=m1?rxtU#3yY;06uIKt6snEZRZj7%yi zzk@745AmVUtMZvxK-7WwM;|`lE4IH1xNP`0*5ZBSiakH2!>pkO;A*XHDN63f6=Hwo z!vTiUAC0q#XC6S^x#Iroie==F$EF+TBY2lH)TDOrjB=W%XyVfXR!qp*rrhUfp}H`JJ5x_cu#x&-g(U>$thM@Vy)C<2gc6=)^p~Cg+bL;wD~j z)J@CIsH`2ApKX_$v0pGUFR~#u7E<@g&DM*mcH9CZdx;9B8v66ucRjfaUeB8#_-{V; zUf@r2yO~}s4gGOxo!a?8qQhzwYS~nRpK9=6l>WNak}D`(_NZ2Ku7UQ#B;;wF8)oxt zZ~K$C?z?c)10Kpf7KU}0BNJX?!M;Gv^FqH;AvX8E7T2p>50Z~x)#u&5GpS;UVy#~& zQQ%!}uuVLEb|3o%o{DPAr-gZ$2ajayQDhMwO=x#=P8A>_n8Sfe;yTN0@+$KgOO4ca zEngMA(mgSE+x>N~vv)%I4;|hJzhbsy{Z&c`J-5uq2~MDUd;5IT6&DxqxK*=s z1a{lU1ILQ{`1t57YB7I%LF5Ap+hmJkCJ!Y}#QN@^0HEUJ6MZ)}Ub197W zTRa2rdk(>yHrKk0jXEg$cJgm~28@PHIciHZp*_ob>O zDh3AsF*H55lQn-&PlvP}x1tgl`f{`zu!-ei5fLSb70g&ms;j>Rm{EY0sI0uaXvH1$ zv%Fj!;F|+1dTZ-TspP7QaC?KZwNoK8Bhq+HgXl28Q77dD))a}OIsXsVn(E;ay5W7T-9 zx$PYWLLt|g79LNgBqK4@X&p>Kf+llCEu8qd(^#8D5K)P_NwNh)({?^$F89GMAEVOu zLr1Smqes<13*XyMQK6~Bv@;BetJaFuhB>MenN5~W4F->#TebWUt;)}Wo|%632zueN zR%Hj7Q%h6U@m0!bxhb(rsnwdynOYVWu_uzS47)P7S6`}F_y9*F+yv_9wGF-^|Ktks zgJsVRF8~-f(B5$W6MHbsNByB(E6i3zjc9}#t>~7YeNBpDGi_2;x#!P>$~2{3#dPlmx>&h}ufLNN%rw ze-Q@-4?K?oNl4U*QO%a0T?%N~UgC_oW7hGhq4MLw8cb{l7PCq9DM`Yq?yOgQZ+F!9 z7QF82bXl^Da}$SCC+9L2HNJSR|80jt490VoQ!B)EYYjHD&b6?ijowQm0R=p({q=$q z(-Ffy-M!O!;MlEC+c%g?_MEEXKYvyX8`&`=@@q2X!X}ptDh)Z@iiLTSa}Dimb?|mD zQKy78v`Ke%^o`*gd~_-lmgN29Y;21~x+IOp<^Prl@(c*uZ`?(jBpziRwtcsgcUPhe zR|9qgGZ|_#6=jUUs+7VNBWA&4=3l3*#F-Ljg-|KGqZ?$H}K?=5?kkj)oHuld(VR^ChXI( z_0xk1*=;8F&ui#UX=bU_krX6uP6{GM_yQ3GSrzA<;*mrZ2!YvbGx8W$CQyc z4OeRJ(wioMKRNC`_b!MQ+jgqQPJQNeL9o1eVI_;rmg&JL0}_ljh3tSET?dI1h~KV= z8@#)ZF>|g!hsfP%vKc*7>RPqS3{iBB{9&WO(W@+st6GRjU4CzbbGFHpJ+6xW5f2y7 z({-A;&myTtzX^U)a?zXv&tbrx)t*1q_O`p4dK(A7CQsBrz9(Cw5EJ9!XAxEFhbvu= z%{vj=Q2}_-Kbd%#u@!s^ucE*MRUT`VSBEqo`8y-aMQGbzplt;=`Z`2Y|^MPgZU@ z8n|hHd0830?#jbjjY}+n6ekm#4`b<*0qrJ3*QI67edZn%c3r1?1 z4r6wq4D7-;hal7K9fVv!=mh>E`S?ji^&McI0k7FDrykurK^}3@@!#{zs-AQGy+gvs zrOb)rajn^r6N$=&4xly`Guzg*Mz-LQBPnJgb<#|^iQKXIzgSb;JSEcUt!0dfofm~L zC!LKmn$DR1f5<_A_Acmrx-N=_iMa&~!ATkS`%6vU^RRj&JjAfPKT{5n9UayI$Q+;W zH6#vBhM=);gB=(lVhl;!J4{JYrbP$BLK&OM6p41E`DRJ;P1{g~<0+b#V#UMR z_)Q%rCkT|wmXxw8K>B?qJ>a+n?u+v=2=+ zz>8mttJ9!)7%U_Zf9>beCC{cyGdk-8a)Nh_84C{Z!WbKABqYid?J}$r>dV{JBL^OF z1-It3PM6)~Rxr$CKkS2vHa$jN<~IXAkRz|nQ_9liuV1_kk>NKd1>r!j`w2O_SNg`BAu!FO5Dk7mg@rIf9qllIEOz|Vj9{brq-+H9`??yK)=UN=gLvO8~0 zOs2x2#$|RB!v97Uuvk41+Bt_OFxXv~FMv%31!UgYgR7By&WZ?|4afZIqQ*FlfN?}) zU7p6u?rF8pD?(&Za@(snlewQ(=0o?+@=Qf85#KHuq}Bbr^nQJ+#CZbe0MfAd;0Gp= z_wf&);F{yzezHjMnp04``_dqZjd5>w@hvGwd0gmgckgAN_Kpzcf##@ys;@tAg3Qi% z1-exqEC#!GtbQCHEWTykVj1E;`*1>dQcqqJ?#JgfkqC{=FQ!~kevU)w|B`>bPr<A0x%V%^iAw?+pleLqoC> z1)sEF?(hKe835&OoS9z#V8)3<4TqvS{A2K^K^8j)NQaK_TmN{$Tf@E;Zj@S6Wi5lDO$`< ziXgf+{1^$->!vURKcZwh%)DYFTihxl!%(7!VwYuv(VHjK`#U`c~VSXZ{Cwz~ITZt_$lXbttmGpzZk1T@ z!X4G@CN9>#68svB#7mm7$3FNg1nr7-;{!I0%!9?ByA;NBEB#~G9q-Xe{GI}ey0XpQ zBHiOg8A2?XKiNZUQS2}&_}sT%0qU*V@qJ1%kqPJ7nJ}L)bCE}Dx!GRglL+77wx434 zBtIMdwFQK{c-BiW#S7R2I(BOiZviDzf2-s4&Cd%s6I2d9*LPv}KEHpf#aYrY`gGCH zPzqGbO^~IE_;3{qhV`r8>#z<&u;G&*kYCXyXKvw`WceZ1SI$>VUY}d2m%DJ-368%U zxdM;E{#cT%Z!(-vd)?PY65Y0M)wW;A?(0?h3V#|Lg22u2$1fUe3ys7odaam~WpaeN zo3EvRqK!KrmfCy#JI^l2Eeor=qbi=g9&MxH*EAG=qT?DgzrTRu?X*ky51Vk_J!@K# z^8ofZV5p>Cio3ZtTD%N=p!^kakk<0|4RJC)K#Xj(U7!-UiTigOH(zHFcewngK>E+Z z0`mV!vzo0y+D=%jQlkQBLfFh!e4Vi#==6IiJn*?W9{7e%+)eD5uaPu5RM(k~9Macv zRlhXbBI>btkH4L5Pkn1qVj3XbD;kY{wR!vXUt$Oa_N-4ep}2Qm1pC#>@7B+pmDq7R z7f#`Ws}{DqTvCY2<;B@Va$Rxem&Q!G6+(COm)jA?$--N>}g<>9MR8SJwG^ zS=P@i+AVxXj5ha14SbVTC6kbSLDCy$z&@u&oAtW;{z!9}M4iaUwnp>1sn5#xMjSvn zO+y4O%M)v3xh;0G!ZC9Ah70N2X&1%%oJcZKD)9dSy<_Mn4Juc9I1u&gh){E(yAJOv;T@o-+t9P#SLQ(mF1jXS=DaRGT3Yc22mh3yhA@pTqJRkiKA z2SgvOS(~zF6r))?gl}+k(L&ud(#b)(nvSL2I=lT&wk(UJLk;&=bRa56czT~ zYdy8@`?`KtBUU1(oP~lbNG%@r{$RIv?5=_%NBU+9`Ce_H0e=GD;Q{Tf!!KN`A!CXN zB67$l6~`fbljUk@MG5I3(8W*`uyae2>N9GP$5D_o#DSi7v~``zfj86EZ=~q)fus(- zFJygn7-+sdOl=-ezdapa!x_&CBh`@X5sZPUQ;IV69eS{@l6|jny)T(s4r? zMqvfiq$hAXKIc;~TQ;m^9N1;31N+awd`ox#8FY+c5quFaS@6cjMgzbG+4o?pGj2Iy z``3*`;R!fVI(2$3uxtyC?oL+2Mife?0R$5j-5UGXN{B3~taCf^Qkt{EgtAsQAIYx3eeDbEUG z)D;xIE%GH0uCVTtlHwBF;bf?@Z)>_x+shG0<2MflF)itLKdxpZt8#$#OKulg@|)5+ zTeneB=Ub=ljug;y+WzXgjB7HUmC4uwC~0V9c>a z`xB0_FHKbd>$6lLIOZEz6jkoGxRX8t5B_n>Nf^$c>aQRSF+a28;W-euIkbO7lw5_9n(q?Q;p zgLy;=wA3XneKdbmVzBZH2G4E3Jralkrnm9(8E&_c!%UCv&a>uhb_w_>T@*E1k}V$! zD*5`)@&<9rvX`MeQEO( zwb8}9^Q>ICwy8bjBg8Oa`?3_=U+j0MV#aBUEzwY(sUCKJ+NY8|8Kkd)S8}j{P+&H> zMr@tqX>edynhMuJ1A%I-V_LbN9f5;cvd?$*d(rfz))+DNk{t0(*Y{W>1&$?JiDfrF z0wi5~={5y=4i;OKG@A-pI zE1uNT6qRRSjC}#lQl1I{Tn6A#1WE?PY}8j{$enPd!(>(!Z8cUho<@JY)E3{GJ(Y=u zLeAIR)~a?7(XPfemtYu{+>=_pH z#kX7RE`Cc&nnDi^6#bT>{Cs+?gW)mlEt*WZ{s~SAn!Nf6g>B(up{3TcQAWKV!8g^* zT3~vHm0^3VWSURj@bh4$;Ea;58i>O~vN^X2DYc(}k?y=&Hvb$plX*W{^Ld#0RZzeQ zq{VvpqV%8ww?I3~zJs~WohI@yu)1z8$e!9%O&(%~z!xf>fa`(7j-~l2De;vwI>#Zw~B++k;?_aXX zV^u60oR;a!u^-}FSo1(_YGUc6n)!@pRi{Ipk)>AHMa95Pm##eKJ@$RE`eUXc)*F3K zfi{}83bP0M#7A+jkU68@G%fQfT&N=y)_Tl^#@;U~n;SiUnY|}>p%K95bh!*V^S2H( zdhuw^rBQKN|cvP9PV5(?9Ysje@HG9?9-;&`eO@E_noYpSq zI$LLuMTGy}DUpW0j-2JGUgaK=7E^8AOIg3j@7-^_C!imk>zFpIi_V&K9W~{5NkJ3~ zig~H_4!0{`lX04ZhHX1{rbKb!`X(tTia3LgV4<^4} zZ;&Nsv+v|%ba!@*yew*CiL|ty$zimH;}Wi+SLxjb2YN!hx|id75PJOtV0|9R!VN�@jb#9Vkjf~VoqasL3e?Vak8DwLjUvrq@} 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%0A#930H0!tU;zH}Bq=%M!soDfxYM zyz-MLPbybV)XrUtQUamtD~p_ov-5RY{>=$w7NY$N^8r=bg6QbzHAGa|X20Ff<=2Vy zHF!x&6O`Iz!9LGI(;~a?mReg|^FZD2XVSUw@Pj8Fp2>_}oM^o&VG>GXZ+kn>NucPO zqs46V#wQnQ^G)dp>c|4C?3iCzorcN)bsd2$1a-fQuD%@RfhjPRAzv(MTXLhRY=-Kf zap1s#E#ujZN#h}3bJHocN|Te5>QG*dQ5s~|HR|i=s28^0j_&aG*}R5r`YvQ&bPlD0 zNcAD?SKz6%dg{@@C1t8-$8B%Mx9tFU^8wmt9vg!lotEhsLyO(PifF7huzB zSUwuqI9N5Fzcp2V-`Bl>NIW23xv^x6?KkOqkOoFDk3fMHVTys(7H~K|VgXkk5hz<; z;&u4=?{r*US%4RG1zSto$llvx2j>0?pLEFrW7Pu5eXY?Z#0Mq>0#6(izA^{~_p#c0;OIOE+UZoQJ$slA`0Ir7 zXSmTs=$`OqIP94|Zv?cZp%_*3e*5M+-=C(IOkEes=E5v9*U=k@9kRAEMxe(lK0>E* zSEXF7np07o5_UQzG7`u;)%8x#KaBi&5RF%+{s{>B`oC(Q^i1&ik^j?S>vLc~2ll_t c>XcQ(rY~+f#`e_XFz`F{{ZaP{*MLiZ0i~9ed;kCd literal 64272 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 AnE(I) diff --git a/docs/savefig/fig_plot_pfl.png b/docs/savefig/fig_plot_pfl.png index a379a06915be63f3357045891534e4c5f8b95d9e..c870aceb94c7261ebdca201b3948d24a8115a5ca 100644 GIT binary patch literal 39293 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 R@(8;0eBKrh`MRA6{{j!`_yhm| diff --git a/docs/savefig/fig_plot_pfs.png b/docs/savefig/fig_plot_pfs.png index 8ac43f358a1efca6344000a1507cac83569e32e5..a3022e32039d272e0fbc98730a8a8dd55e6a8fdd 100644 GIT binary patch literal 37893 zcmeFa2UL}5wk^8VR=W&XrD7ITKoJmBP(hMeH!3JmvZ#RM43f1Blo8nqNDx#IBr7>% zi2+4|ARt*JgMbnx-?_F{pX$@y=iGDdeRqua?sJT)qGYr8|9}7Ytu@!2b1g0(k>5Xe z*0Na)24gPsz#c^gV_F-7G4OPlQ?B4&Skfv|kW(yjLlQLH8nJZ zZ)ZG;XjT>WyRzIot=Y%B{%vpemg?GP#czdD=5Lv+sP)SQi5%H6NAvwhHtpnS>>NJx z<>x}XmhBb8;(dOdqBaFf1N4?$!i6vxJA$lVcTQn{$(Uu!{;$xvsVmuE%)Yl{CVlaA zDt|HiC6E91lC%GdFZsB3PHtZ3YI^t7{YUQQ8a;pUB0?cpCQ>Q<#;?Er+W+CCr_r}B z4cpIrIUeTfK0ct9WLl|M7Nw?E8g|$_C@6OI?o0eaLWi~(zb`J2(M)n0FwPnutWMc- zDP+H=z{ZV7xZS?#$=_AIG4dsM9_NxJkMP$m14kHR?m6Rw0V9K5QQPf09ytwkL~5qQ z>Nt08>8ef19zg@px)>kAOcl-9jxhuCT_q7&P-j>n|52|j3;Lgw=8$(`DpyBOU+ zjSlrxC5jk`IzAf!KyoUob9NH6Jd_D zg?REZV>FT!)2y4jCzy=XbsMx&kG#0LxS}S_rnzM>C%kFj^<@#vTWkF#Y{E{QJlSV? zfx-A_{%NIclk=ucn<9@rd4M(aj)>WDZmLsX!M5g(j>t5dRyo$xY15KiNA0^lJlTEj z+&PZ?_+?v+LvO5uwO>!%mXgBm;Ia$@l? z`FVJ9^+rEDIjIt*xj z+-{Gs?Bm!X#=u+d9?k!9vbMqV?C64vVk8WP#SQ)u4*rh~obY!5jEK)`A;>C** z@^`l{+jQbWVW7mxWW%KAqa&VmTCUgPjy>7s<>eK5G~`nDXtyM@L`~QA;b2#_pqQAl zU1xdOZ@=)^4t`coi2E!RRum`^($;o*@18wv_dU2uo?l*Iafc_)xF+?lx1LGAeQd%NGJ+jWL{3##FR_RZqpP#qoYvitT$&#W#} zT|ss{k?tnhOmn<9UxdSzmZGEh{(1c6!e4&5|NHrwo$n)*wn?jf)G2*=}y7c(?1zx5?j?bWpXle2f#fmN|kaDTebd-J8cVYxZm<4~~`n zjh?dpDGAkGS8&4cb!lG0@gZLSDz@Jv{KS^i#XF+Z;>va1#~;>ZISV3~40Kjh zIQL|=7OPoX$M3tgi6Hh{S5;D}&jw9%r`S~2g>88ic%BcXod@|hZ&utIup!^| z3a4NgUTT8S#0sUAHZF^d)JTd{jn#@+uM~D?!P7f;mRw&Up@<{X+t;UreUxO~Eaxqx zu84=BaUV9hpJ`sV+ z;(O<4L0NnUjlX>SeY@4C3!#FO+Yl@(iex9FD|FqpZ>>}CsWq=a_;Y{NI3;lJ`5AL5 z%q3aW>mdG=Vha^W6^AkxNcX)JZOIljEL6^M8(+9=S)@^EScF=fPSs<*^Ylm#`U=+$ zJ~?^f1Z{!qOE&G&)6=WUbWCvSZ(GgH&7C#cow01=@v~bI2C`j8<=)httTIpOe6d*f zJ)IlcsWB;aC53k-libEf0&YBX>}wh6h>EkF7<06##4zdhFX*B$<2Z4n4778(&53_vCVFz3b558tiWT^z4)tGyBgU?h9+DKRW*VuTDd? z4qI&7j+oVFYv0{&m)`i5QFt6dh@!%=g z>|`enfx_J7Ti*vt*w{{v51BOOd3C&xxW(o2WoJR4gwpT7|GrGtEz`cIZUa;9@L`qK z!n?S}wF6z%YS`WBJ=vrEpRS51hPH0>N#)T+e80mRama7;w%RzC;oho5qg#lAA;rZ< z9335*tX;cz^Sut#QjJjDtDo=V&6}2y5w+*?{1zEH7C3cVtUm2YOVx5Ti^7o`!TTnf zRd1CZc(26qDp1NXp3WCemNfDhD>gGk#;AlB2tnc2+QXZNVvgMZHQl!TL0tBT+}vei zd14dT+L5>tjTG~{h+iAp-w58jeED)qlO58gfNpjs(i_s30Fw{_m;0C%Evr(ve3sn~ zi>KIW&Az&-$oYIs!=fOS`fS%Sq=2k1&t|hi*X+IW2%)el!O*iiqeli2@Bp&7Mz%}Z z@MIrSEbVmv?RJr2hXV#ZUriIg+8X36kB|13br&_gGfzzrlZZ_U>WV@+su`5Jo%WNK-$Dv2a_hLp|Qso0nOgVo`xW(_iP@)9$sO%ZqpX>nm=j(XJFbZWYaV1|WGoWVF)gfKCU*LsL4m)~vkO0sd^|tT+(hc(L0|hb zUS{nj4_l013#ddMU{O9tNHzvS+dOA?lxmD3qRRU$X9uQQi^|r3!!|8%-`NyNho5+H z#Rz-fxGFIMsoA*O2H_y)*pp9}P9iX0<8o?SjmTISsJT+YdQXN!Px;ukB+RShk$3|G*G6-$3$!|r$f_KlST(YBf~xhF*F>AV?8hLo)YiYvw%3pIL;af z;94svBJ99(FnOlxtHepZ#DDZym|9m zz819&n#qTrJbB{O5fQ#(R`+fXj&@{w0!AgJr3JwrTuujcbaYxamv&Z~Zrx&0r$tXv zL&HB*FfLy8(UG02SFcV#^Yww-Nc%eJ;ig+HX>w{oD|mQ#Y?{2wA3xsM=YUws+`J&s zR{!CzyfzY_v53mpL&Kw^0j=$yK0Vma?W$bwJ~_V9bEf4Y9G*zRsfUB4)Xl0Ay?lLr zWrmv;(3)IbEaJoa;?*m`4I2&vx7wtdA#c68y}r+rt5I!TD9g6JgbxTw?fSAU*2k{D zPc%|8`|x;Yc6N59)1gVA41pu}&Qh8lJc>o`bK>5n7^@{w_ULGC!`(r^66M4GVqO^; z&ar`$NmmwaFkaNkYU=D1Y=0>s%*VGk!@f%qNmPHyrKO(M&2J(UAIfce+k93u!;SCc zks~*A1Dk-TZt*@04aH6=i+tE#8ZIaxAcu6Xs;J1CF^?-6aP&ZW?=JOIr$W^O$@rw_9NP+#(dQd=nECBpHNCRRrlx$3JRhuRh4WOh28RI7v_I}s#SGVFzaL5Sx;*7Imo1{cUMEa%|1j9U0&WZ3ir)ArNcRKeOq1ea*Ir_ z_9dvID&~6DKiE5)3XOV~zUz1Z;ge&nvXpv41z(qLoMWTtxItG}S2V5evPtl&*xvsB z%!Ua>vk`zVWmF16)k=zr=1$HZbrcg%AKhY7{#IzmPWfb^^L5p=>75~HRLNpRq4@@`vGnV zhcz@b!dm+~C$rN>zI1F^A9l#^0e+wp*|HQ5s0sTSxU92aTfMU1W_?=(g5@$Tb8{`f z9XMoP)S!X;N_p$Z+8lE;v!m(tErFvCE`&~UCaCGJYu#d0vIiGcZW!zuhTPMRQbMKi z<#mi*O3p8(K$exj71VMTRRe!&mA{_7ozT!r!z0+^35_vCrcwXHnw+g z(1#bf>%cF+{NiWsknr3d`B+d~{8+H-pr4kO7F7on0ZP1^n-TI*hWMHL-nnz8bn)8Q zoG!m19ER~D{+@Y`>H#k=t54@MpQaMro(^{sVf2ya_Xz3%leu>Sq1*OOkzeO~iw}SN(00@nrNX)sQ#} zRL-l3bl9udTkCkO+4~;lhwEUaq0_epk0kd=H;kRV4e2=D3dT=U3n`P@^I_ zd8r5XAee;9-+j~n{9|Wl)UVTL8$bW;myzMt;3Uh2T};InS2&v+8$*b$;OEa9`#LmK zfjwy9c(HHM2934=i)^9|A`z$V+$!01aTb-wBcBtBR?P21@aP8`@xN8m2^8hG*e+vG z%4Qb|Qx0yK=+T~>`Ub6vSna5JGT)x+^>Wl)b#ZlVZfOY{s(06oh=}m3nzwR0@4R{Q zyhU_%kS(ko9FXlgR}2m}cyJSPw_%=ccy^Hzw#P(#-yMX*$C1hr4}dTwO(%gV%8+Fd zNpum&Wl^aSkbHT4d4UX`Uwl&2Xvco*t!7oBfRK*>!CNH1R!UFOb++T~II8hv9P^*l zTtOzGjfeCm@%+>8Gr8XbBZz7rU6$9gX3ZM93Zxc8>Dv4>qp`rpmucDeWEizQPn+kdF))i8=!F}n_B5H3+zaKMb)j$CTm!3Qlu zv5P>sRP;9ItEAf+d2F+Yx0$FI4KJEfiKBU6c5+M!r=H{MH^4tJi#n+mJBi;MioJRW zjDj_Kcj2c6{osQLBnqg&iCyEAMuX(3Xm_=9Th-K&O_a0z!RJ+R+wfxXSobp zt3)a@0fkGW)e~^~-WDlo$6)~gFfM~7iN&f%X{A|rRHwwDSY55AriK*MfhvH=8u=h8 z$6Wp0YFo^zlr6Fbe9Gf=fUuf8Rdi*DOB5qd4{<^=_kwfl1$%KVOdo9+%mB1=UPAK#Rco^-LVZ8^kM}J$u$v zI*i+~>6fw?O|@K)c@;n~F`M<@oTlOosQR!kOQ#G;dGFr6>p>G`GQw<|`|2wtCOe4* zp#1{ELpj^U(G~HaMbg}%qvK-8$WTvQOF@7jcGT=eLdCJ#8SfJei&jX?IL?XEpbYWl zeaQZK18whiV-aql1V+|HIF>?E{Cr8|w*EsD8&nU88N6L`SJqu;a-}HYN!YZUGT}T3pqqH= z_57^fH-cBLT%o!l>CD#?#C8=)4+XyQ77WJ~cj9nXfVNc5aLoQW|2_Fk@AhbjrdvZb}&HAB^%h$ago-_3k3?0^Ce_yUBd3bQ( z*=&(Es(%2q`p1XrO}cB+5SMeoJYM`90{-(%!^Oo57cC0IIcW!3SB{g^)Y=-3r9b`o z!xMV4<{3p;KoC||C^Z8X32QwVy#k53r3M~AnX&O3zseiZemG!$*i5c-Mx z>!AAqFB1;xHPW)-ng2G6AS(SRDq_R=iy4(1_BE1IygZ*z8C8@k-jPF1*C+PSHDI|% zL^J5-xFO7`Apq35jhab+`*>b`kRU#xes0%(FV*N{pw*lXfWQ&WiS3gAHacp8`0S4w zlXmp`_sS}O)`&kU0b9+wQ{A5~6(jaYHKt^2xNnQ|pefh@x$f?6B7F#htP48xtR@9) zcJIJI85WS(9!^2kLjbk!OyaT(Vmq)xHwcIF9rQU3{Et}Z57Os760znDKJZG|X{v_~ zT_dVzKA&7$dw8&Fu#79O{^X{W3l@ZckTt^Tp!yq^To$V>*%u{j5r)_xfXqqTfYQMI z4U%BJKpO%oc48fUfO1i27|VzDC?f)Fai4HO>Bx_BHGS5?BT2?(iAYR+)v^pjt0eJ2 zY3F3sIGq?Q-|H7I_99-XQPF#Uw?}oi=-RdW=R&=GB)&}LR1O<;(~k{Im_RU*1U zM3=?s=4ihB*s-_XM@apIo9Wlc&w-Nz-Axi7RcCPugrWj7Lh*r1*-+HODn^b^thpgC~oO0Ix894V-md&;8KMK4~s@CcX>$33;-$(&qJ zWVa~K39ebQYr)z>mfvJLX=$;Chzi9PAG+KI^8ov7!xR67rJ@B!Gzs3+_LL2;y~F3S#CmRSPM3u#IOPhXDP z<;yv_+x+)~q@6qVEsoSpwY*Qo1Q-^gLWp_9xjmh{fB*hY$OG(X;n>VMms>^)m9r18 zcIKI*wHfSFCWEXc$^6r(4)XZ%E$`0=*Tz!sC4^SG3;X$NpsuPZ9lSc&Gf+ex|^ zX$i1M)X!fu@VQc{-gW5i@ZE3_SOgx+!WFm=-`%c)Ty!2!a}86D$vlb^CkBp$DE88? z#2A2Trkh|TVx8#Kx-MTY-dG{=0A#clPOTy$ARiO!sI+h2r8=k14X%(wi0uTS$RAL! zHg_X&|HOG3xU<*ul&_}FypI}gZf+EB)B|}j8ziEeM9ln0x~jnrod9$ zszI8n#As|G*dkD@5F`~rs9>IS|IOXH;3!IoWrl1Mfumwz<(A|M7Odroae4H5d^C}N zqyl_uY)sI;w{C4vez}`!)29Pq$Rm9JYHO+Ir4)h7KDt2%5DzX%P zE8dJ?D8U&Bz=f>{t*u=y{e0C=Sqrqs>sGK6O#|^H|eb{@Z+0%k`!7Q~5 z{2a)&sZjg*Hp81mH&^0Le`yTdDW4njbA63N+{+K~(?`IH5S>e`InF$b5G|0Kr5zx0!4=9z{}u3s;^TnbqIGOcLoi9_=FOA9S^A8-B?FdDe}r30%-Nd2BC zm$XK{uSf+hqzqffCL<>&hhv5K$Hx|^pwbrB*4OJ&NmhmM$ZB6QF)_i46;jC=k?4!c zuNxm5GymWl99)0c({4QeTfmd*>n@{dSE4p={w$|Z6g)3*?AIl&!k+>}^9=JiP6Uqr zW>vTbF91EJ0-LqBu;{g-0^9s&PQ$mR?)tm8(~k5FskL7B4nT z1^_#a zzm|eN0>$&Vq#mJ&?|A5|qlk0qedo^Ui35r#JmkCu9wN_l)#vDBMFT|#Tx9%jX-uP^YLJeyIY~sJ^EBb!0>SBNlX@M8k8C#K-u74RA$YYqikv#ovZeg zy?{5hw>EYxGpn&19+uo%Tcf3%c}DN9jB7*Cm}y?^j%zl)qR)MM<`lBG*>*f}Y_q1s zz=k&7F(>KX6vcE zpQq25VKCATw4J7K=FFL}LDUte9IyS8EISC{J`z6$#pEdX@g#tDk3p0)5u~8v??7M^ zQ?cS2J5hYpIq`a`G)hV^lBJN*RwmEG=0M>RGn@e22YNeT`Uv8xU3ZOySxxFYy&M2n zeaAo?7^t7}f@-nv1>-UwkPw8Lj1>yV6NyT2*1UNYBv6C2r5a9Gn7pxNg31B-V; zgHWSN#I{|LIA-I@_=mj2)?c}HO&Nt$@{M_PJx`N_hB)A~s3t)^Mk}p1Y}BkWelJP> z;OgI+&E!~7jA9} zAknT<6$k&V-Y8%&*uFYZb-rb$%YtWp>*GN$kI7 zGecr-$}Sh1`mAM*F6#H(0h*mYKY6v;%mIJSs8!>!10`?qjnU2jp2;|>Su7UHI)~E1 zsQfAmyV1|$b{)I2-R#P%tCb9k!uWY|gDP^Z3qMj{SJU6!(ixvtd zM51(%kQxB3GPV|~-^fI$w7XF?y?w86`t&0RD`5-P$+xkI{TDA@tVeOcS~!3H1F&Il zHqJp|yY$k1oG1TRb8$kov;rNY34ys!42NS&#=8pJXROYU?knr)yLD|&MoDR3>$G)( zA_aHoBGW#Y3LJT=;wxg97xW@!S&f;E^8nm6O|uL$=CyM6E{#9Gq*dlbplF^^`AKgH z|FRat`8HyPw|W*0a!cADLXnx5m|1I(5V7<841XEdbd;%KsIX0n@9m`epY-lSrPRB17Ed4$ zN2wdi)Lr5DnPHiKvkenNa~ZIWf+5WywMh^Z6HPX`56b zh)-g?ND;^OQU;+RGdX6%Wa%w|^5hF%I?1458BqK#B;0aTqI^tvc-Z|kuz>QgZ-wGQ|XhNH>li_+@L3v7t2&F3(YDh|l$zq3`N4V0gHeChPx&|CY#18<_8bKb1jC*~gzdZ!C zR1~NfB0hPIU>G5jBCHy*(C(T|kFc*xzR0@gp6&)qwOB2`h%V4V+Z}sD1>gv4Hgo8z zdI*}iuLmh90=g(9DYY=yAqdC){kABR{i;z2MxZ);jcN@^jaVdHL{l*rEE&yDepHqT zY)j_ZYP~dv;$Y|QwB^ZUFF}IDDJuuWje*qNesQr*F_Iq-+e@VklaxpGw{PFtP@?#a z$Q?SQ48pJ(w77ZSz<`ReaU|>3Er9qlrP=0XK`VuYx2C0jh|kLLPEAi2AL|s-GA$pT zd^|q+$6Bmme4Dxl@Bm}Sl+K91D8Y(%>F8ntxmbLq>Ibh|oLyDE=9*rV6CGw4ShXsvv1 zYOJI5g+tLS+wVywkF(I8yHK!6^wi8vg|5%V4R4l4zcRKFi+Wqc+j6>atuAL9M090H zySRk4%t)=Yc(=)MhYh;fS^yTQQc_ZzIoYLQ|J$)(=MY!E2zYy-EFQ78whkLa?O4}8 zScjx36RZ?2+|;RNn3W}MH)whV#hIgY;0l{z>wP-&eg`aRYH4}UZ=1mHXCj|GV9FBoUf_bBjIS94g(9J-(NjmDSwS6Neyws-v?besKB9DD2cq z8SaeQo3-ZGXAa7Gd+Dh;IZe2HJoUodYmeY~&(vQo=^Z?k|OrlyJ~biwfTo?K&y4ToHTO7@zYn{zC-yNX&9 znmZ^s%EowsIwUdc(>YZY1Ft~Tyo0wcL242EjHIyQX7%Gtk~U6w29;7j*sxA$%Ug3G zTo?wI;cSqX7X~v0fKEmHv)T29zio45CmtzWBO!@!v;ajP1tot3k&2fI#*L(!2O%LO z~6>+egoGbIH-Q;n?G+ z_oY{_-bqv@P%P;8NEm3#?~j95P=iT`&J6qo>mkI>EL=g`!BQmt)VUyk|46X;M#!@q z)e9CZ7$`X?vL4JZi4}1CiaGV4b{%f^Wrae89>)&>EPh*WN!sEi zbXjLht^ZVAy8B%02Jg`fVH=mpWFgVrL&4mBOF`x+89@8nj*=(^d`XUtb}M0>%tuI~ zBpi{{L9Sdv$SC*-`zD*$M#AJmbQZENvZOZ=!9-P)N(-o<0wv3?t4f7MvLqRb$wme@ zinYu}x;93*0g__eqEytD^og%7;`XPvBpJ<${} z@JetIu^`+1V03|a^X^N_$mp;VO)7*hdUynw!S_Q~TlpQbc0K-HW7f>ACdvrF!5==U zq52W{%!#6AmcV7Ia&N~JD%YI{KflBG;!qMm0TEZyr3kK*nOaj@TVRIuC+P+zj<;Mpf9hI06rD1ys@x&7s9(}Wh=Tz=w6TwTH#5$i;ttb%a6TK|qpYYmu`Us34kWUq8vl6+`-0s*cYti5K z4s|mtGc%Ky8M5y>+r10=o>+JeS8z0^1j6DbwBfmNJadL$LPA2x`S)L^TR1seSoD|% z|2==Zcj?l>OfLBwX)Y2xaURD(saxCF9Cb>soxhk{%5`KHu6MsguImRmg}f%wnmGUt zg+HIP)+n^RG`dSQdh`B-sec`I3DJI4&(s`={M-%*33Y zoWVf+s6}g+&HL;QCOx*le{A^a>npWuE~}2zPhT@9_wn=8!1l>ujeml2X4$NM?eu+7 zpA=SIGksj$MammF3ZNvm!AN0yx(7~sXo)KZC&ASujQJ-aJ?0e@6f`_Ahg)sdtXV9i zY}Ca4s6B~;=jcN4VTFP|Mp^A=hRY<<{*O(cr#5|rd=f;|zP+;vbh;|;68pB`VH??m zNtZ=VYll`#x*L&PTQ00@97_UaMgXEV%s%eUqVsBKG~ z$p@LHbM@Fsb8}&w>&NoJ*&mgI=Q!_dm8@QQQGw z$2~H+1t4Ks=WJRV-aN-JRpitQ0pQmH!mp~f>xPANH&}gdyi)&vn&|!LbN6n^XZvyM z2~%^=y(*cR&E3yTW-x9lb*oMcCR8h*9hgHA=A@4)#?R8DsRQh4xf>?pUueAZ?a$%{^~Mgm27@x(LLQ%e&;;} zE4t=0EEnI*nIb;Bcj;Ldq5ZRMLrTW2C2YmlW&DLvGyQKrlF`W5Ev)HqCue!{Bws}{ zcb@&&g=?&AR>6~r6xp%jyIdTMo4bE}{Mm%m#;LV-uX_(wYfU7q&v#}1#yGz6$6GyB zudzDk=J--lViO1BsrJ5!86So63>krY3w3zeX@@b!lcsnNL?%l(ymem%mp%sE?Y~j)*U$DDm2U8g4YZf;N5=*kmCIwb zJ1s~5fkO|H+-}IoGm*e$KAnYo>U$p7 z{x`r1pbxxjWbsD?6f>(5a|Iiq0U^7RYvsxqo7O_3<~QC>&E9Hcv!t-ZLKE3uI~bC{ zkg!_?L3wdWJGFg!aaCf`Oh(?}G+gc~k()&f@vD;V>YJpsV@+heJ3Bl>Pwdr?TfrY9 zcki?JG~T#pDYdmfI0>Pv9biQS0Qv+~qmSI*brG5`A2Hvs?;nMUBN4DsB~C{h1wYzx zxMg*yo$WhK9&>1XgHGnLqeqW|{rBZ1s}3vz0Ft$~O?kf%-TOny=0r!pw{K^%U?xCI zS2;XU%?%Cr0XAM6Bp7{otTzH$ZU9!pDAXz`u5}E{ie}4+8E2(-%S`*o+nu^Y!P9AP ze6_wLYgP5R-PRJ82ZRMH^0x5p-B($%SzzWH9lkGbHuI=eXbw6g-RXwE3=W2sRrcU9 zfZSk=+|`o&hxnbNVS11i9v)7R4phS-w$w2Iy{-d}8tb-B7~F6zIfSW@`{Y0=+no*; zHN4>%jdyrskicY_ZVezeKW+!@r^CDCTP+xQDDD}BYYb)XG=5qWvdeKP=bQXGenr+P z$%$~&nH;a}Ki;cpdFwl;z4vyCd1V=l{tmgxe@E#DihIQjc8;=|9_PSd%1a*lZJ#?~ zL2T*bKJ)S1p{@#%{F#h{`M;0NWjJ1Onep_erZI2P&6`hEyB`tGS$WfJa!Tb5E?+He z{kXA@D;@5#SZhFwdziuGBX{s%zUpWau+^z#-HbTf=BaiPj?v4l{w$QgXwWrmIFV2| z`6?+&H2P=#ZQBH|t!WkSbp3XtX6Hn5+K1jQ*9)V&x_Mrvc`ngy-bJnh?^cH{PW=N@XzOi>G8_r9j$NUgq?@_`ZDx% zVY1jJT|SWi$)e?b#O&dbl`t?U+?5V^aBa?LjKxg_t?WQA@bs0YYC2g83Mutp0{+?^ zRvIqS1n7BNw8o>S|0juceM6NAzP43CvOPSc)&CGt9ayE-PBL=x30zTc-$iegy>%x< z{oUQB1WEUq<2_1>Ur)q)RHRyey?%w$y6e+&AR+2B1V{DOA(B+`1cSo~(!#=pHL_?s zfGVc~=}mNiNEjd|L3~4~_#ee|`9SgeXjdyT&2ef-2d+W~j@l)?Jc9((U(`Axk~3zV zT=dF(+o=@I#&hEe`lmjirCF9+T>XhA?>o84QI0*i8-+Fr8;-bV`_MBv$kAevYu+>} zUROGFG2_CL)@uZSx*;T^GKz52yYj#qW%s zm3(DpPT-PoUaBBTX9Fk#smg8{23JDuTx_m{`jNnuaKe+hRMg-RxDs`@7yi7`qn{Jt zv16&9g{`G>>`F3qT$tCUFB7-C2bX&o?32_*REh=RW0J!Sr)&$fdFlY92q-6aCCH`s z^$JN{gi{Am_h~!K*91?oT;wppk?zi{96$J`?s2xQgf@10Q*VBp_3(&fTI|S|H;N$w z=i=2Ogm}c-Zg5azF$x!?7ddYAEuGNH}o=72-8z+(#?rhviGAar{vMHjUlw4}8rsn2{@L8Tl#~X-UZ#2?!E??gH zh0~I8+{j@Qt~-{ld%lD-=g?I1&5^3A`^w%Zb}oY3Lo4T-hOlNzeslGPbg9O>)g9d+ zWD62w(DK%j@j)H_!)!`xF%#O_+MGy4ZEbBr)vhisVki@r*U8|+QP>|%zA>HQX#&2N13y+|->66)Q?Fx-h8AVja%PTTh~ z=gk|gMQfa!XX-0Q@^kXvTyPRETl43arBuWThJ5j!9a70LE?j-T-XhbY^reH-p8;6m zr$XOU_u=cO5|}Tp)>`Y%U&A;y^T(yJpR?0lkLLN4rQY=>mtJ#mtqn2tljK^$Smp2o zvA}TnYP!=)o37jMvag%wbo(Bx@w5)ut|XwiXKBNhQ}gECk{fA$EDTPu`cl;mNpD;5 zm2P7-bqMf0^56VxH!bNA+y_$!lzxofH7yM>;sy3@I&@10F zqdDHj*L3DQCg1oei=X`kJ*G06R{dC~oAa8r&IP&b6PE2};;x95h|Zz-%2T6#7qlj&tV*>BVE%Cr zPnm3h`S!QKB{LZxg?WBJ!NO;J7#qO;^T%k1zx*-%VU=d^&bUv_F`nF!cdJhx6>hY)=qFJjO-k z-eRF+N2bqSBsLiYj0IQe*(uX_nXtiacj|vcJrR)a^C!?|84bH6IIe@N8FQB0gH#B0 z(45GQtrm6BDCZ-nv+S>bJ>ue$S?50KI(_C$6S!Nz(q+@5-F;N zZSZ6~HENFH>#iVz8!{Wso}lJV)(=4ld84*>5X1>vMu6WsuSOO5btN=(w5ItIyd;GT zAI;H49ooD`B!;OcgaIM)0@#w-o915pp70miSv7*aWs+?b)MqQ_BNTzU1Q5%=MF!U43KFB|%6p#;mD4o% z{J*nmY@fY2z-~e|*7fVFSx4<{5}xr}-$Ofx`+ z^d*Nn)fx^?y7c|kd`I-OA!pAVgi? zZSAK0Hd}||cTB=VZrj_$WVcUOV+%*XQsKY&B3ek|-6n<&L8l5RopUqW)ZNgaHzCXf z`HAP9r)(Pj@S$Juxf~T|`@rpX4avH9ySAE@m~{nf;<41!Xx$Dn_tjhCD7}JNGWKYS zL(Qw^{G}2bS%G>UKOXi$X%2iAmfAGw)R(Rm~q(# zr&apCKH{=xXGx3%y~$A;i0(WuvXk6Sw@&ySt`ZU8ag z7OvjxxF^1@Z+V{wd1&fu-$s?I2UsmfKYR?#Ri~9k>sZ3JvIy|<@~)Hrh4#9oCvm7Smx*fM zJIsQM+Tc)i@R?6PQS%!F3^I@ppiA4hF4K`i*V{e@$gmwP0IC4W z1lr&$qtOlqqwoSy)S%vBzNOX70oF?txAJ+sKZbB(UI6dQM&V|Y0ddl zT>(?KnVM85#~=y^#JIuF0vL7INPSENy#W3YD&|^n!>;BjGs3U=icQpgH0W)f??CUs z2%P)>dn5m29`0t(tbP&*;90f(cKOPc&DB`&DC{6?!95@|%Fz;FUR6(AFKiI&F)9VZ zz6yYSr4NKEnBfGZq_oK01crBodB8syOaccmD|OX4@efb5I|`rPiP?+;-2u_(R_jYWNHh*xC1B_EV4}?ituAomu4?rx)j~i!3(*# z%*|(`qZlMLImiB_VpZb}|Cw(jsO*{)8`Gy_O-;5`` zX&=ljCTpy_1g1x2zG-Z+Z{>L+hnW0AeBCEO^>r^*ug2ZB*;F`tk~diWVpP=C+?+he z@2vrL84?8oMP{slp!z$qP4McCvXcg98~TsmVIRXBcN7*uaxK_rXv06Dj2ifFMi5vl zj)!IAf8P#v4h=!K*tc(=j~Pq(--IX4SLt4qf*qcIhEs4Ld9cV#Re&E&kS?!Wk8Q|i z*_{Yn@YOqd@yV#?YH!k(v|e;)6-B>fC+m;>-!pQfy^ViaP&IF-RL&;%JlIx-Y6~PZ zvIUCysP~S;T@AgSpg*_Uv|NKv-~0CMreeg~+eYh0%G_{i_>x>nOcpF5-hqKaaPYzK z2=lU_w6wOlx!SYackVpG@dHB8B=ZQy&(PY2%WJ20IRpyp7N*9G+gvR$z_5U;C8b>$ zSQY2N!-U7=*~%e3?{9MDSFPlqtHsM-i&>=GK6ujf;ja^v04?q8yi!ua3xf_H-FHbk z&ZF@*?#2e*pVmMF@7Araor)~pa$BSK!_~p&h7ar=*z)_P&6raROXqrpBEh(yCox!x z@*s5<{R=K6ESuaT3m1kWI|5A}WG&?87TLCKn@X&fdWm;YC}j75#iUyO$!G$PA~f~a zE)`P9eBiO)4i10ly7YOlI-|65gY~+s5howLB|b})oJQ^{9Ei3SW(|CQL<>$vz4*6B zv=*M#xXF3F)4umuq}I}1{qpC#5{=U^tlhEo!o`cP;fST)QiQwyGBsT?JUd}j*muqY zQwNCiSSfC~gW3dta2`UVFlx1mq0x>kD>PpO4wm<5*K>4odQ)1e^k4O~6lh=lE(VgD2hFwu zPbmHM`2u2b*yK38?GXrcy}iAPz-|4{7bqNHAUmZ0&;GGnQdz-hMd^raIX8X`I zb~LrzJ{-BjH#mTq(H(byz;*|QIP#ELjS9C3IE^lE|kH5IZvva=Y{01c2J-mbGEj>b3G$g*81jBr+5 z-A-9dTtTzk7G!nm<%L$FrmTD$Haf#@8)SCaJ5>NNTRg+V4Sm>x3fx+%umjR8!I#S| zPNOY|oM}kyWZ|LRji^&fX62O5QXUDNpQ&0y7xBwP!Ij)GO)D2lO7&TB*5Wb)&6GwnSW{NbV%(&VaxmaJ|kzu0i%e} zc@lq^g}#T|ES7a{wSn&+rL+iBIJvr7Hs!;_q&SL4eVt}2n~XlMV|>~FJUTxsD}#{I zB=tQwr?Z3ezfU<9v-@%B#_t~N_1~<2W$M(ayv%=L{*+QWhthU6({EM>X(Ucg0vL;w zzm-YGN=mSSfq@ZOaDrCKc>Fg~y<}&n_o~+KofR*;TEwEHQOY{Hot(Id=DqHW0GmVr zzJF*LEHDtg+82fN_y`f)pd$oGfQ+a#f<+~gmxQ<-I;WOg`jgQ_=^u?Iu50=D z^fdfpe6<$hql$S5jZ+EaIqXnfi`7@J?UXW%|Uw60A+)J{( ztRewsnYVXJN_$*(o$$8tieB6p_*>kmyGt}TWGfcF5EmJ{Q{#~}ri>lD!aHn_WW$avUZk#{Nx3~0j~oLqE$2+}MV8p%PC zR)l>KjBszDx$fGGD8ztmwc&sVP-&0e=!b(Y0;QWKY>f6kUF4j>GfHq3V*ivm@BcaH z%Kv7r_#e9Z{}1xkBP$OaK1|~-IJvlDF^q@yila0yE$I%KW@O;JA{vVTp5rtE9je(> znjL|4kHRDfM`^L|FWh}@VjeZ&|MM<~A2ff;b-wP&VssMS22%}OV55m_2vSD4vTIOk z#Zr2wRkEK}_Pg_=H5?hz7cFdT!W2mbysj#SY?xR6=wqwi9(%QGaIk1Y@}w+BK!Jgu znqy5(w+pZ8<+y)Nr=gm#`nFiY^Ly(6n@vkQ{AV^TFr;!$?#Aw_cY%5628#wUZH)Zd zk_>k!jARFNT?f1|V<%f`1-ltyRnC()SLYAkKx;R$&5C60@eIUo$4x&LZXecze0Ufw zgh0A21#E95IsMTQp6kWVbiF*Y`rRL)tb$ii30!yD1{4!JckZ;dS{+R*akhFl-|)PD zd6t!Q=FO#--JECTl`46Y#d?5K(k?qW>bE+=mP)IxYnbHYL*x<9t!f+ArScm!o~X9W}RT5_L5I;iK=& ziR;=N$IC80eR+myo-UV`uMTgPvexKc6RhuvNd}D6#RLHnI_y5EVj7{;vg)x}9?so}75m z>vT+>50nqhSjbJLMl(DuWq_!@fAZ7(#a?Cz;7%B~#R+E~KqgIYB2x&jwz>i4YwxFc z1{)qtzQy1Sk?a>egJ3{O-vyaSeXtmw6lk=x7=$&|CHx?zXfh#i=&k)BNy)FcoDUJ( zKit<^V5aLf{E*Do=##X;pmcwl%L>klC>ru6VQ!2Odzv?T326ulbqaNt%Kz%(Gn!{8 z;o)*g6U!z8U+Ajf+GW$X$2UXApkY0T+#w*ij3&m0NhX0zUf}9B_H{qa*P$T*xSLp< zmQF}EMY%^?sUxclbD$rf@7DwjKM>YYh#7Xnz4|u6$P47rAt+4~yYLuW8-9xsMCUCE zcXI9&n2|a_RE@_tK4}1>cSzu7i!Hcb^x$b=vOtRrjpU&8lTzn&wOLL6tc$(F%_3_K zn#UlYA(>|+ao)w=1OtnGa5WJaTS`q=G#m!-x&uuM==vHhaHUpx*vZM$N`pagu>%-( z*WBk-C?n>C~BU0Y68ZL73fk*0OrIT(2Zu)tH z%7L+>lb+HB!XcE8F#j$b&*`lm$#5nZ3WOPXH2A6?>_8{R0FA&bUEqpI8?jHH?m*o? zY|g=*cEQCbAvZOMX*eJ8W*?QudqPJw$kHKBvC9yBQj z4bd*<>t=gO58lC#QJ4gv%Y5*i^w1MZL=y>0b3+fXv@?nw2@z&5(d zeh`*CXyD%~pYPg~5P%^`=fSq!#TY0ch@4Qt;1nxZP=Ac#qlOZMU{&}LXs{aw18TRJ z0jY})v>pnc`I?Cjrilf)$!PVGW1(Ti_~m3I&9}?RNKg0A(Y-FBwzxn8ahy+k*t8Dk zcmVLru*wkQI7xrP)_+K|Qt>$bvXfut<~GJ&Tm0i9yE%H7<{3H6l-MxjRb&p$*7EW3 z-=}5`lxw!sW3;al8pa0dCnwZEvzCEVptXAL05wb+EiZ0vC_+hsuIUOCTK6%V#&E>t7BBh!<8mg_Ns0vO z5rETX{({AZJ7n@Dn-T)|%S@Bl(1S>{X!vsre{sVq#2tv0Wmv~J^kTGQ_&3P-A3OvEIOHtWY3rHT5~8U*Bhx?5EL%|i0$q3@j> z#8oL4A_@vcQY(^@qz6Boq!q-#6zY~g)J4@4PJ%ZWZv27)oQJtA-tKCgJf9RicTX34 zSYMkrAbhL|u3d7lrs3n0S6rpDMKYn9&S*#dg#lPkXrMK`WYh!&qaSEr$bTiko|xL+ z@BHbUb&4(IU^EpM(*St*(8()^5bJPEhURdcM&tl%mk3J@6aK(e^Y)v%A~307qx-}a z%9UV(CblR)F+IIQLuzn$k_v;UxEJC`n>N=5>-ob%7G6cxT*II1_Q~gK(k7M3*c4zT z61{+u8RO}vW8a%}{}bo#U6i`Gfh+h$17O^#GXvDH91DH&@3Gn!FI}R!$0LK)7Aws& z(B?@MJ{d$I;$RMZywpn!IV1R~CA*k0w6%9B!*G}Uv~KBzZA0R@8y9kNK1AO>4&EV5 zFMEe2A3)wmpZC9NU%~#-Ahw-+O=$8v22bTtAacxhW_p~2j>f-s?OGA}c~7M;!0YFC zv-GUX`lBT!Yq%wV!X2L3eIzcT{#p2)4crlk;ZVHN z$cI#+<9rw$9W-ow#f?oM-H0&w$ImMKcU-}rIz3OB$3f)=qrt}%$^Q002jkQZxdur( z6poF9lu!kkNE0w6*D)BA+{1IuimncyGPD-H14ge8MmMv42WBbNNi>dO>`N}SpkadE z%E6)UWj!wwiP`4#C=$y6wm$WQ`|v^%lp~e!*~QuHaNq04NUiXK%XNYEGD{2meh2Y8 zn2j|E6$ns~P9%(v99=)$kG2`;=H=hMT?4)QiNm2AG0}@W|MUwcdft4P@==4_n->CS z)GX&O)}t9))IxzOorX)$q=NabNX%%IXnWj+DRfj6QC7nA^aCuKHjGIRfUr6aW@8LX z&Oh##!zXn&ixL$99!lO2GuT~|V7kxdx*;EO9E_xT3cgHg_@$vu!_ObPjXRNsf$7)3 z@va9`?kl3J3QIptWdHKzONOlhqkGFASF6cieE;u@*%RjT&=8FVdNO;i9Uyudg(0gS z?yd+tKMKn9PFTc%l$97xuj4kX-`7JEb*Yt*W>vYnPyYRfIP(|xSfOY6J=zawlID*} z(?Ijz#^}%lEKIX3NAX1z7qbM~%?8Z#r||%YAtXHUM!H!x(u5h3O$`Nr}X9>;o!u$-0MR9s!TqAB~E+8;NxzTD^f&n@No& zKpi&Q6s9rAl0HjfZt6CI=e75DrwC#2I1okfU_s3Q=hJ)FPrbQU}=?@12A$7_D~hr{2Sw-~=o_ z6b3#$YTnBC>8^VkRIszr%3vOGG{h$HDA=ZotiD3Y5v24)4D+lsO_o}5-{uZxj$y{B zb<8C88k(Y;H71{C9Y>?z$WYE?41x>|R71umm_om!0Jaz-WMSZ?f=)dRDAt51p%NnXHMJr$g#v;+LPa*PT*za?+kFj>nigq$& z;hKngrFBOi0UcppBOGY5c7p$551N25jF~rLqcl+iywU^Gr_m=*zZd~R@N8n35V|SB z(V!Zd7ymz6`|^0M^X~1h7S&X`r&6M5-;_0}tc@rUC6uf!$dY{tSz6sqBuXMFku_w= zzLmxnm3>dfPDr*8e%F!a*ZsVn`}ymce`ad=Q`Jggpj3q`jtYL6WOyA zO2(tm>LE1)1Aj^kkXTU(Lb{aDCM(R(zhkA_S%!T@F`c*v7%D0jXaggu{LVTlurrOJ zt*DM$Q--YrL}d6~E$z_fWrYMIM3o6Y*MH|fMbbCu-Q3nE{GEO`MW*22y>YaY6}5D-{fctMhe#0Xk{RY znDkn9m2V?OTAbJX?XrZdNl9eEQU;kftpds-fNDX{Ot8*0;okQ#J1x}|DKA(X@Gj;Q zJxO65dR^s#QuAm%wDn*bg)%?&RPBW;~S{+ zpFjz=V_J4Br3bR%#{oCseebC0u|XV^C4g^Q+g)0kTr6s#M@(@O?~rB`y@Ej+Bt*s@ z`locc@YPTxsx*4E6_B+x_JG=~6p6=T3W5ZcNza#xHp+B~%@>m~>_@^j@FM5{D}n}9 zQbecFDzS%|2?ZvSVZjHfqP;;$G)f&c5V!^Evc7+ngVfJa5;X$CsuFufntE)c#SE?B zLFhyiaS;auf8K8FTd|RPOZ(1eKGW3&h&rUQhBP+@5s0{Gs6SM&z%hwh06!(9;1DM> zr!a(GIbN(PV%-p!2-LAG^_CqazZG0D1~S!%)VMqp6SRJc!6an>_kdvN{~F+#P~A>l zNF>)}&I25h0^u%<)=gkA1^ge4#3@CFe(96_v*Wj-&VNa54XQ#RX#s|Ud9^L#66U4- z0vvkxlD!DzImkr=X%b@Kb`m;DyiH=L5YD18MpUYlniHq4gR*XHj>wjlb4S4SCILq5 zP^__SL`ny<%^uvvRsfl}{!Uy?6-_t-27&;`w4)3n0=dxOj^wc(urVgA%0#WO-h-4O zyL1Hp82~hha)Ody2%Yxnntob*Lyk8i80i395sCvnXaovG8HlQo1T>+!DEJ~tRSpXj zn(2XHiefBO7G;bIGBy%Jp`lYsT{!JpJnR14;PRa2fv_OUk)m2damsy-h$@$ybmM=bn+6-a{(ppS+jxgm2fWk?3Yz~L}zoj^)~ffrKQf=FG4hBr=3UfEJSdLg7` z6d_Pyge4l+JVkmWrhfJei_H=N#w|>SUhM}>lmn^PZfA^Vx}pB#K-AAAce5N&ZpYyq zLUZ$NJw7|t_2$f(!zN=f@gYzK$`a<-IL*kGWN>J>Xk$;9Hb)5~J<($4iLRZQ?d*4HpsJi=Cp!Fna9n;=(wKS9;?#TP}`B zH~g_VGA2`C1bM=3`laVu8MXDpSP~o%mCOaMu{ej%4ba9aM6=y^UFb04a)NN&$VdpFf`uxr8Cxjnj)bMXUeq z=4MsBW!<`0^!I2koMp?!!2&AQ>S2dAUwt=#1%7+0`4%-}$icQzvLoZk=zj0 zo8dp9=YTG9KP>uIp=RYrN(kDp|F#j$WV2Uc2qq!sx|G$wOoZ^k6|vMRk}H1_X*9;X7UoGT#>wMBR|H=ip92*bqW? z(aN_a6{%SX^g0R7yK(xQ)Az>n>1wUF!N_C-j@q`m2tSQ1I~N_4)6Y-6EZl=;^Y3hI z=dl9wnru*w@*@LrL;GbFEiF*H-B17)pML!N2AOkvqr3C+aj@hpwLMviz>a)SXdo1O zkfuK?bW8(C6NG)`Dvp#t8r&qa%(~I{gk9yUlLecv94AraZpG@5sV2-KT;s9N*O3i#YXa8)6d z6!bZ3k|0tEcytJ;iO8U%<04em;;y>GH7Zcpb5&VLCjn5o1X`dI(e61zDAnOz!{qwx zB@Yh|sUyK$Fbc=?F)+CbmnTJzYjX*I()xt%z4g0MUlSn})-;cG>rqK+hL3NBw$k)a4L_VAOPl&|yc3YfBBx+_|5h;fXa`a{Z*&Gyc7m=* zKsA{d08jwwPZ5zs@IAJw6qXWnGL|%Mp7mX-O8b*A%-%34)Yb?I@y8ptq3rd7n#)cK z_=F1p2}1m$lfkk#0q%zA4erxegwgsVWV1$WM37+WE5Aj*UxV|3R9|vz&i4^NY_>-=#8z45?c zHX2|sLd|KoQ(=oW8YRcDiHjHht=V16E!rLolAeC;een03C%Uz3ddXY_oixzXSe6Z7 z^&@TxngEMYqC0I6kKCe@T|?L!7y*?ynA>o5SX;^9~qhwBJ0|KZnC=fnfM zxBs_YOBl9|Ktpfs-o}c(O+(XmEw7K`$wEnHFy%Fay zhS~JNsYhkMX)u->kzA;hBB-DA{UQJE8?ARKEm~_^CQ?7WMjV;bE(26(CRJ3qYsqG4 zfsc^0>1>2P)&?ZT2{AXqW%LKLB*Q_F(Cxyr_eQHZxu|q ze|WEWZ8LQuqlk|gX;k@8>4rmroY&TH<{?#^rs%-_gN!rj+(0P&VaJkj?Q3nFY$-~X z7PRfZlsr*ifUF$JL%UgjG6i0ox#UPg^G~FfNga;%ekijW5SyQO2O}9s#UG@}2LwDM z5iAC9W~k=Fv!Za| zic(j#|kyQc)cBPHYN8YK468Udq%h1SG?O^ z5aUXuGeXwG1SaEy%J3wuL1m*>A9D68I1GiM8BRC@g;6NhhU1SIpC|rIlC_D8AX@8G zpOll9Ki~(vm2_gB<6FrOgL;ixjzcN~4FfLC140H{h}XufkMMZu;>%;SCCG~zh$|Uol9L~(^fco^^#|r_pQ0R$ zxY++Uj+zYQr6de4Te`tR^eGV=(08FTPbEZt6;(EP!G)D+pD2n`kA*aC;jIZEM=)!_ zhBN~6ou|ed=_vyf3C4GHVsWZq+fzRlsyjP1Q>W3WQFnF}LKy_cVg!u#VvYC;vltr7 zBkY+|%svdz4v9GdAs|U|SQCW<4rQroNb!dI1Ifykk)<&DEeO(6rFg$Y^7U;@EQ9(t zjk*y`{hu~1d@ThX(O=9?!0Jk zPd+&$obG!b=XDq=BT^`Db0P^?Aj0HnLU)OAI;wVw8Z4`XU}Fs>3G$t$WR7x2YQ96_ z?(@#P4^V}I(cDQYc~M^?_OBy|2l3w``9q$>u@np4pA8wB0%W^^>H|{gi>OPMRB-~} z+B8&z?iJFYUD^vWwGb_-svi*9&w-I8^uYFN`1h$2s~CQ6G=@MdCS(Kzt)lISF+({o za`ixhLw&s}w1|kgPjQV>J(!tUsJAokxrGDmJaRa~70I0zpHhHGisZEd{*9}7Y-&(o zjE;>Ng3d%X6*##=0CaY|tkM!(SWV~}oLC8=Cz>j%f^C~O=N35%F9WQGvX*=EW*IcJ z$WCSucn(=`fT5;pf!-fIZITm0u%f4Pe9|2l0K}L{X$0Y&8eRau9%1Im>MegdIzqJn z$*P9d2oSxR!nakV?l~&j516?Chc@*>@v7lf#e<$8JzfAVM3yBXCGTy=Wk9T@Cu`b$ zGCSjMLvvAJlB69BJnb$B@zj4pgN9Isqy~NHtCH~w?Pr=|#kZDY@eah7!V2sOMM;9A zLB=HqHteBkw@m|j8@PPLb_L{zL}ex8YkZ)ucB8`vf))PnrYx5K-IQhE`g`R2WE(>i zGlVjdDy^2i*ad(7O|s2=2B9{FK4+>7E<9-#cy#TY|GJx@D!DU~(hlg!QX!yvHBY?LqQ!DOq8R(oOlVUTcI#}1?8+|F!gSA= zy9L1{?GLTeW3eaYo6IhjPkMWM(?Hy*_W5&G&z<$|LDzsf9~;|H=+4!7{>~njFCQo! z*9y>_s!aTNBX4_Ik=5!g`lcIxuCyub5WCHu2Ac(R#m>#V9HV(wd7kXKCz5T_ah4e& zaT;q{;!K6%DFpJMOt8jcE{X9o@9vWN3XpMZES7Qo8w z=04j3)sG$f+jc>~R_^8!)@=htJ02ble!4o#-Aw%pr`Ry3n2rA82PPrD3F3E)P6egJ z;$P}PzH#DrPX^WG)-p|mL`GLGJm?ga7W42?e=Id$h}wa>C|KIc3sj|Iri!v z=fg_vn?im!1quWsnFob-X0eSrG=900$Yop-qp(`#LcyH5JQst<0z=e!yB{=;zOx-H z5`2Fiscb56zD=?f6&3K7{SY>RLdLwL?4!hC0beBn-;d75$FF?ySKh8GeH5F4|_Cp#N1qZGx%lI@Ui-$BIWJg1CHrlrVDHS@W`-zHeB5!q?78a_j+RRy0N;% z1GAm&g3q#+8ttk(DfGm4_z~yO&|qQYM%ma&!L$255_=eDQHMk0cmN1y5^;{m7zvwU zW@eV*6f!k2QQgJ9=4>nDj-!eGX2!ScqO)}t;ud41C8EC0vek+-Lt2R%RDsA&PfNni z#8&5z0L~Bc^J6Er4`rLQ|B#~N_*IGa=U~LWDlVGCknq%J7@w|ine>?&@B0(eZ#KzV z!pe%JFIxlovvU6K6?3?EXk!AJ`WV=BDjy+)8!%ocN8`5}zP0#6mQRB^LMR9(CB)_GYH??-dj zUX9@@u5T0gBrviI+~b(CSDIk2e!Dqyi|LY*M^s)KMnqINmYFE)HyUJotcYGI!eZ3J zA)=yvDw^ZKjFKbQXSH7{TR@fk+vP(HMB;r(s2QSx9hWV=}Pn+zebA~3D&tu$JC&*Nd7&HB9 zF0Ky@9qB94Ipec^;VmIS4pFwQnNtt(^Z&lZWx`&tGnF)3%N|Ru`mC zR;gZlY4&x?M%lh$8;@&4Nh8L0l}an;-uk|CIb)He-mDjM?U=KfD;IaPb0}=Cu=)Dn zl%h>oPYeGVr!4hXc*5(%V^%YG4*dARwI|espKyr{Wcr=$G3>Qhys*WCJ7BfyS-X=Z zW{-Lw?K|P#dV22aygmV@?D^+5Gt}>34e3;X*{ZKzUSTWK^tTdjw98cgV+5X)x7*v1 zv|S877T*QgD`u7k*1xLCv2c^9N6*y)_Z^7}Q@tZRi^)Z9{V&hYd2&LcvRe~$!`P9* zpqvZ8?YXU|EVBy_@_e#_r`G}}pZSd3wZHsAYNY2Mw@n`*ii?L0oNYsgt!)h(!xb_nCS_UYT=hG)s%gV+#-~{` zPsPF)OJ<<2w`%fu*5a0TnPr6w=j_rw^Ri7zLJUsX7zqn$U7+F#?FKC78;*RcG zo37?%5muHhXKB$V+^i^Ea?1K9;}g5UGMAnCf{er$+fx$jostgcv3}EJX0*)t=kE{VM=Hv|HCB$5)(LkG0sIckj&wlwoqj61Aax|S~%%GDNqTDko~p zNU#6hmWP=k+9s_x%Y|!tDHuvFVf8Nbv}zgLwq~zm*X$9?)$MVwM}c&cOp8)@c~}oI zw{evO@w2X6NiZA=1Rvttp&O)UPZ#CXF`J+)FFUc_&$7H6#4@3t!LFuaZ2*`W*ybM zGDO!>{_|SWOz#$@IG>&PBxe6P!#KJGr%+5}Sfw>089B%Jj~9Ra zV)pfERmXVieCJ%Rx>?spjC@dI1GU2p1*@~keQHSqIT-^Gh;bCsiLt~n^ zy>Ycv-}tr-v-35`3$|t+5$OBhhbM#OFVXns^%=*I%wvzkO_kSsmrwR8^mH0ljWk}8 z)^yY#{LD2u`oIIaYEdXz-D_>Y>$w#$JbBEk;GS2(povvT{h{}=&y;e@cZvFsUU_rR zXz$}~|M3htkwy!8A09oG#j*6}xp&%EJ8?}Nu_8vlvrGLSzPArr`s zy5zLSlw|VeGO{lE`ZDeuX<6l>q1WT$r0y6LP@AQmwYMQE@LF0-=zQj@)1s%b4=4?4 z4{%TbEUdC|sris7a%f-jZL~`LEjXj*fZ;NU`B3Z zseys}!4_nA8Tz6@h3fmlzJyYR^B zyZ*gTWLJkRqR6tDl%{2t(c{0J!iDE|a{Sr-*Xlu72f4!9^j%$aMwAO}& zMErZj5#MGhX@(BZ%qfskgp|nYl4SG1!cCfEi~rbYu+{fN@4F3S%EftcYU~U)*MCkm z`^96ABpQMPUQHgW%N&n<>``l@cm8Ok)|6VJ+-yekogbI_;=0Og`@`Y466t^&TC&8k z#ff3|?AKiFZEHT2!1=3YP7HZlX_g2R zF;Q;x)u;R_se)?(wMpvIcFh}Q`wzU1DP?5u`FS8BK@!i1lL=)Wm$~q8U+k%jex{+^ zdGG4_B8+{Q8M(h+&Oy^L|6gCU&cbf3tJ7poNuD$R6>Vs#fB1&=!0QOj;nwH=^B5MI zi30J$S@{E&42Carw#{DQCn9$HSrsDs(-z5=;=suqiZV3-n{WG$9p&iGk*{^u+gUEa z%!WI{yh*+8AnG) znmHPRjTYR34Twrac5s+F5c~nll;%Es<6Z(9$1^Bi6$4HDQl|IP9Gys)e+=W;V1gO=`#qE2dg z({;7Nsdj7s!Qqj@lzsBy2fb(@#qq9e)!9>2sGWN^^q^9^AcJ%K^bR|{KXv%{x)hT= zI2}AV)3^}^J2T%Tj0;yT`52V<@ogJ>F#=fl^GC(&B}NMr2lF?0oX2R!hPscK(}%%? zB(cZ}-@cvTo_;5HEWZhLv#Fdo(T&atJLuLmD{lRzeDY*iT$}(G_w?jh%X;QPej1m? zm`r(TsX$y*N{SjtI~lW>YJa1+R|76jPCCKePYJK?xPd`SlJoL}rfB#&tUzYz+V_KB$@`DJ>#P-9F vgpV=%hjk^h&VOA@KY_G=psW8cAM(XH$miTTlb5m*bg8n^3J0S9(7EzI2>ysB literal 43127 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 Axc~qF diff --git a/portfolyo/core/pfline/classes.py b/portfolyo/core/pfline/classes.py index 2506fca..7e0b2bc 100644 --- a/portfolyo/core/pfline/classes.py +++ b/portfolyo/core/pfline/classes.py @@ -184,11 +184,17 @@ def hedge_with( how : str, optional (Default: 'val') Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. peak_fn : PeakFunction, optional (default: None) - Function that returns boolean Series indicating if timestamps in index lie in peak period. + To hedge with peak and offpeak products: function that returns boolean + Series indicating if timestamps in index lie in peak period. If None, hedge with base products. freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} Frequency of hedging products. E.g. 'QS' to hedge with quarter products. + See also + -------- + portfolyo.create_peakfn + portfolyo.germanpower_peakfn + Returns ------- PfLine @@ -198,7 +204,7 @@ def hedge_with( Notes ----- - - If the PfLine contains prices, these are ignored. + If the PfLine contains prices, these are ignored. """ ... diff --git a/portfolyo/core/pfline/flat_methods.py b/portfolyo/core/pfline/flat_methods.py index 5388906..ed8a117 100644 --- a/portfolyo/core/pfline/flat_methods.py +++ b/portfolyo/core/pfline/flat_methods.py @@ -7,7 +7,7 @@ from ... import tools from ...tools.peakconvert import tseries2poframe from . import classes -from .enums import Kind, Structure +from .enums import Kind if TYPE_CHECKING: from .classes import FlatPfLine, PfLine, PricePfLine @@ -41,13 +41,13 @@ def po( elif self.kind is Kind.COMPLETE: df_dict["p"] = df_dict["r"] / df_dict["q"] - # Turn into dataframe and put 'peak' and 'offpeak' on top. - return pd.DataFrame(df_dict).swaplevel(axis=1).sort_index(axis=1) + # Turn into dataframe. + return pd.DataFrame({k: df.stack() for k, df in df_dict.items()}) def hedge_with( self: PfLine, - p: PricePfLine, + prices: PricePfLine, how: str = "val", peak_fn: tools.peakfn.PeakFunction = None, freq: str = "MS", @@ -61,9 +61,11 @@ def hedge_with( "Can only hedge a PfLine with daily or (quarter)hourly information." ) - wout, pout = tools.hedge.hedge(self.w, p.p, how, peak_fn, freq) - constructor = classes.constructor(Structure.FLAT, Kind.COMPLETE) - return constructor({"w": wout, "p": pout}) + wout, pout = tools.hedge.hedge(self.w, prices.p, how, peak_fn, freq) + df = pd.DataFrame({"w": wout, "p": pout}) + df["q"] = df["w"] * tools.duration.index(df.index) + df["r"] = df["p"] * df["q"] + return classes.FlatCompletePfLine(df) def __eq__(self: FlatPfLine, other: Any) -> bool: diff --git a/portfolyo/core/pfstate/pfstate.py b/portfolyo/core/pfstate/pfstate.py index aa36b20..0a0407a 100644 --- a/portfolyo/core/pfstate/pfstate.py +++ b/portfolyo/core/pfstate/pfstate.py @@ -224,26 +224,56 @@ def asfreq(self, freq: str = "MS") -> PfState: # from ABC return PfState(offtakevolume, unsourcedprice, sourced) def hedge_of_unsourced( - self: PfState, how: str = "val", freq: str = "MS", po: bool = None + self: PfState, + how: str = "val", + peak_fn: tools.peakfn.PeakFunction = None, + freq: str = "MS", ) -> PfLine: """Hedge the unsourced volume, at unsourced prices in the portfolio. + Parameters + ---------- + how : str, optional (Default: 'val') + Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. + peak_fn : PeakFunction, optional (default: None) + To hedge with peak and offpeak products: function that returns boolean + Series indicating if timestamps in index lie in peak period. + If None, hedge with base products. + freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} + Frequency of hedging products. E.g. 'QS' to hedge with quarter products. + See also -------- - PfLine.hedge + PfLine.hedge_with + portfolyo.create_peakfn + portfolyo.germanpower_peakfn Returns ------- PfLine Hedge (volumes and prices) of unsourced volume. """ - return self.unsourced.volume.hedge_with(self.unsourcedprice, how, freq, po) + return self.unsourced.volume.hedge_with(self.unsourcedprice, how, peak_fn, freq) def source_unsourced( - self: PfState, how: str = "val", freq: str = "MS", po: bool = None + self: PfState, + how: str = "val", + peak_fn: tools.peakfn.PeakFunction = None, + freq: str = "MS", ) -> PfState: """Simulate PfState if unsourced volume is hedged and sourced at market prices. + Parameters + ---------- + how : str, optional (Default: 'val') + Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. + peak_fn : PeakFunction, optional (default: None) + To hedge with peak and offpeak products: function that returns boolean + Series indicating if timestamps in index lie in peak period. + If None, hedge with base products. + freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} + Frequency of hedging products. E.g. 'QS' to hedge with quarter products. + See also -------- .hedge_of_unsourced() @@ -251,9 +281,9 @@ def source_unsourced( Returns ------- PfState - which is fully hedged at time scales of `freq` or longer. + which is fully hedged at time scales of ``freq`` or longer. """ - tosource = self.hedge_of_unsourced(how, freq, po) + tosource = self.hedge_of_unsourced(how, peak_fn, freq) return self.__class__( self.offtakevolume, self.unsourcedprice, self.sourced + tosource ) diff --git a/portfolyo/tools/hedge.py b/portfolyo/tools/hedge.py index 372c351..b728bbc 100644 --- a/portfolyo/tools/hedge.py +++ b/portfolyo/tools/hedge.py @@ -12,64 +12,23 @@ from . import wavg as tools_wavg -def _hedge( - df: pd.DataFrame, - how: str, - peak_fn: tools_peakfn.PeakFunction = None, - freq: str = "MS", -) -> pd.Series: - """ - Hedge a power timeseries, for given price timeseries. - - Parameters - ---------- - df : pd.DataFrame - with 'w' [MW] and 'p' [Eur/MWh] columns. - how : str. One of {'vol', 'val'} - Hedge-constraint. 'vol' for volumetric hedge, 'val' for value hedge. - peak_fn : PeakFunction, optional (default: None) - Function that returns boolean Series indicating if timestamps in index lie in peak period. - If None, hedge with base products. - freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} - Frequency of hedging products. E.g. 'QS' to hedge with quarter products. - - Returns - ------- - pd.Series - With float values or quantities. - If peak_fn is None, Series with index with 2 values (['w', 'p']; power and - price in entire period). - If peak_fn is not None, Series with multiindex (['peak', 'offpeak'] x ['w', 'p']; - power and price, split between peak and offpeak intervals in the period). - """ - df = df.copy() - - # Use magnitude of duration only, so that, if w and p are float series, their - # return series are also floats (instead of dimensionless Quantities). - df["duration"] = tools_duration.frame(df).pint.m - +def one_hedge(df: pd.DataFrame, how: str) -> pd.Series: + """Hedge over all timestamps in dataframe. Dataframe must have columns + 'w', 'p', 'duration'. Returns Series with index 'w', 'p', with hedge values. + for the entire period.""" # Prepare weights. - if how == "vol": # volume hedge - # solve for w_hedge: sum(w * duration) == w_hedge * sum(duration) - # so: w_hedge = sum(w * duration) / sum(duration) - df["weights"] = df["duration"] - elif how == "val": # value hedge + if how == "val": # value hedge # solve for w_hedge: sum(w * duration * p) == w_hedge * sum(duration * p) # so: w_hedge = sum(w * duration * p) / sum(duration * p) - df["weights"] = df["p"] * df["duration"] - else: - raise ValueError(f"Parameter `how` must be 'val' or 'vol'; got {how}.") - - # Grouping. - grouping = tools_peakconvert.group_arrays(df.index, freq, peak_fn) - - # Do hedge. - def do_hedge(sub_df): - p_hedge = tools_wavg.series(sub_df["p"], sub_df["duration"]) - w_hedge = tools_wavg.series(sub_df["w"], sub_df["weights"]) - return pd.Series({"w": w_hedge, "p": p_hedge}) + weights = df["p"] * df["duration"] + else: # how == "vol": # volume hedge + # solve for w_hedge: sum(w * duration) == w_hedge * sum(duration) + # so: w_hedge = sum(w * duration) / sum(duration) + weights = df["duration"] - return df.groupby(grouping).transform(do_hedge) + p_hedge = tools_wavg.series(df["p"], df["duration"]) + w_hedge = tools_wavg.series(df["w"], weights) + return pd.Series({"w": w_hedge, "p": p_hedge}) def hedge( @@ -85,7 +44,7 @@ def hedge( Parameters ---------- w : Series - Power timeseries with hourly or quarterhourly frequency. + Power timeseries with spot market frequency. p: Series Price timeseries with same frequency. how : str, optional (Default: 'val') @@ -93,7 +52,7 @@ def hedge( peak_fn : PeakFunction, optional (default: None) Function that returns boolean Series indicating if timestamps in index lie in peak period. If None, hedge with base products. - freq : {'D' (days), 'MS' (months, default), 'QS' (quarters), 'AS' (years)} + freq : {'D' (days), 'MS' (months), 'QS' (quarters), 'AS' (years)}, optional (default: 'MS') Frequency of hedging products. E.g. 'QS' to hedge with quarter products. Returns @@ -120,6 +79,8 @@ def hedge( "Split into peak and offpeak only possible when (a) hedging with monthly (or " "longer) products, and (b) if timeseries have hourly (or shorter) values." ) + if how not in ["vol", "val"]: + raise ValueError(f"Parameter `how` must be 'val' or 'vol'; got {how}.") # Handle possible units. win, wunits = (w.pint.magnitude, w.pint.units) if hasattr(w, "pint") else (w, None) @@ -128,15 +89,26 @@ def hedge( # Only keep full periods of overlapping timestamps. win, pin = tools_intersect.frames(win, pin) - df = tools_trim.frame(pd.DataFrame({"w": win, "p": pin}), freq) - if len(df) == 0: - return df["w"], df["p"] # No full periods; don't do hedge; return empty series + dfin = tools_trim.frame(pd.DataFrame({"w": win, "p": pin}), freq) + if len(dfin) == 0: + return ( + dfin["w"], + dfin["p"], + ) # No full periods; don't do hedge; return empty series # Do actual hedge. - df2 = _hedge(df, how, freq, peak_fn) + # . helper values + dfin["duration"] = tools_duration.index(dfin.index) + grouping = tools_peakconvert.group_index(dfin.index, peak_fn, freq) + # . calculation + vals = dfin.groupby(grouping).apply(lambda subdf: one_hedge(subdf, how)) + vals.index = pd.MultiIndex.from_tuples(vals.index) + # . broadcast to original timeseries + dfout = vals.loc[grouping, :].set_axis(dfin.index) + wout, pout = dfout["w"], dfout["p"] # Handle possible units. if wunits or punits: - df2 = df2.astype({"w": f"pint[{wunits}]", "p": f"pint[{punits}]"}) + wout, pout = wout.astype(f"pint[{wunits}]"), pout.astype(f"pint[{punits}]") - return df2["w"], df2["p"] + return wout, pout diff --git a/portfolyo/tools/peakconvert.py b/portfolyo/tools/peakconvert.py index 77f0616..7729f64 100644 --- a/portfolyo/tools/peakconvert.py +++ b/portfolyo/tools/peakconvert.py @@ -1,7 +1,6 @@ """Module to convert between timeseries and base/peak/offpeak-values.""" import warnings -from typing import List import pandas as pd @@ -15,10 +14,10 @@ BPO = ["base", "peak", "offpeak"] -def group_arrays( - i: pd.DatetimeIndex, freq: str, peak_fn: tools_peakfn.PeakFunction = None -) -> List: - """Function to group all rows that belong to same delivery period.""" +def group_index( + i: pd.DatetimeIndex, peak_fn: tools_peakfn.PeakFunction, freq: str +) -> pd.MultiIndex: + """Multiindex, that is the same for all rows that belong to same delivery period.""" # Grouping due to delivery period. groups = [i.year] if freq == "MS": @@ -36,7 +35,7 @@ def group_arrays( if peak_fn is not None: groups.append(peak_fn(i)) - return groups + return pd.MultiIndex.from_arrays(groups) def complete_bpoframe( diff --git a/tests/tools/prices/test_hedge.py.bak b/tests/tools/prices/test_hedge.py.bak deleted file mode 100644 index 1a080b7..0000000 --- a/tests/tools/prices/test_hedge.py.bak +++ /dev/null @@ -1,86 +0,0 @@ -from portfolyo import dev -from portfolyo.prices import hedge -from portfolyo.prices import utils as putils -from portfolyo import testing -from portfolyo.tools import stamps -from pathlib import Path -import numpy as np -import pandas as pd -import pytest - - -@pytest.mark.parametrize("po", [True, False]) -@pytest.mark.parametrize( - ("values", "start", "result_base", "result_po"), - [ - ([1, 2, 3], "2020-01-01", 2, (np.nan, 2)), - (range(12), "2020-01-01", 5.5, (9.5, 3.5)), - ([*[10] * (23 + 8), *[15] * 5], "2020-03-29", 10.69444, (15, 10)), - ([*[10] * (25 + 8), *[15] * 5], "2020-10-25", 10.65789, (15, 10)), - ], -) -def test_basic_volhedge(values, start, result_base, result_po, po): - """Test if basic volume hedge with single values is calculated correctly.""" - index = pd.date_range(start, freq="H", periods=len(values), tz="Europe/Berlin") - df = pd.DataFrame({"w": values, "p": 100.0}, index) - result = hedge._hedge(df, how="vol", po=po) - if not po: - # Result for base hedge - expected_result = pd.Series({"w": result_base, "p": 100.0}) - else: - # Result for peak/offpeak hedge - values = {} - if not np.isnan(result_po[0]): - values[("peak", "w")] = result_po[0] - values[("peak", "p")] = 100.0 - if not np.isnan(result_po[1]): - values[("offpeak", "w")] = result_po[1] - values[("offpeak", "p")] = 100.0 - - expected_result = pd.Series(values) - testing.assert_series_equal(result.sort_index(), expected_result.sort_index()) - - -@pytest.mark.parametrize("withunit", [True, False]) -@pytest.mark.parametrize("how", ["vol", "val"]) -@pytest.mark.parametrize("po", [True, False]) -@pytest.mark.parametrize("aggfreq", ["MS", "QS", "AS"]) -@pytest.mark.parametrize("freq", ["H", "D"]) -@pytest.mark.parametrize("tz", [None, "Europe/Berlin"]) -def test_hedge_fromexcel(tz, freq, aggfreq, po, how, withunit): - """Test if hedge results are correctly calculated, by comparing against previously calculated results.""" - if freq == "D" and po: - return # Only decompose in peak and offpeak if hourly values - - if tz is None: - return # TODO: allow hedging with dataframes without timezone information, and remove this block so that they are also checked - - path = Path(__file__).parent / "test_hedge_data.xlsx" - sheetname = f'{freq}_{"None" if tz is None else tz.replace("/", "")}' - - # Input data. - df_in = pd.read_excel(path, sheetname, header=6, index_col=0, usecols="A,B:C") - if tz: - df_in = df_in.tz_localize(tz, ambiguous="infer") - df_in.index.freq = pd.infer_freq(df_in.index) - w_in, p_in = df_in.w, df_in.p - if withunit: - w_in = w_in.astype("pint[MW]") - p_in = p_in.astype("pint[Eur/MWh]") - - # Expected output data. - df_out = pd.read_excel(path, f"{sheetname}_out", header=[3, 4, 5, 6], index_col=0) - if tz: - df_out = df_out.tz_localize(tz, ambiguous="infer") - df_out.index.freq = pd.infer_freq(df_out.index) - w_expected = df_out[aggfreq][po][how]["w"] - p_expected = df_out[aggfreq][po].iloc[:, 0] # price is first column - if withunit: - w_expected = w_expected.astype("pint[MW]") - p_expected = p_expected.astype("pint[Eur/MWh]") - - # Test output data. - w_test, p_test = hedge.hedge(w_in, p_in, how, aggfreq, po) - - testing.assert_series_equal(p_test, p_expected, check_names=False) - testing.assert_series_equal(w_test, w_expected, check_names=False) diff --git a/tests/tools/test_hedge.py b/tests/tools/test_hedge.py new file mode 100644 index 0000000..b96a689 --- /dev/null +++ b/tests/tools/test_hedge.py @@ -0,0 +1,146 @@ +from pathlib import Path + +import numpy as np +import pandas as pd +import pytest + +from portfolyo import testing, tools + + +@pytest.mark.parametrize("how", ["vol", "val"]) +@pytest.mark.parametrize( + "w_vals,start,w_expected", + [ + ([1, 2, 3], "2020-01-01", 2), + (range(12), "2020-01-01", 5.5), + ([*[10] * (23 + 8), *[15] * 5], "2020-03-29", 10.69444), + ([*[10] * (25 + 8), *[15] * 5], "2020-10-25", 10.65789), + ], +) +def test_onehedge_uniformpricesandduration(w_vals, start, w_expected, how): + """Test hedge with uniform prices and durations.""" + i = pd.date_range(start, freq="H", periods=len(w_vals), tz="Europe/Berlin") + df = pd.DataFrame({"w": w_vals, "p": 100.0}, i) + df["duration"] = tools.duration.index(i) + + result = tools.hedge.one_hedge(df, how=how) + expected = pd.Series({"w": w_expected, "p": 100.0}) + testing.assert_series_equal(result, expected) + + +@pytest.mark.parametrize("how", ["vol", "val"]) +@pytest.mark.parametrize( + "w_vals,start,w_expected,tz", + [ + ([1, 2], "2020-01-01", 1.483333333, None), # 29 days in Feb + ([1, 2], "2021-01-01", 1.474576271, None), # 28 days in Feb + (range(12), "2020-01-01", 5.51366120, None), # no DST + (range(12), "2020-01-01", 5.514458106, "Europe/Berlin"), # DST + ], +) +def test_onehedge_uniformprices(w_vals, start, w_expected, how, tz): + """Test hedge with uniform prices but distinct durations.""" + i = pd.date_range(start, freq="MS", periods=len(w_vals), tz=tz) + df = pd.DataFrame({"w": w_vals, "p": 100.0}, i) + df["duration"] = tools.duration.index(i) + + result = tools.hedge.one_hedge(df, how=how) + expected = pd.Series({"w": w_expected, "p": 100.0}) + testing.assert_series_equal(result, expected) + + +@pytest.mark.parametrize("how", ["vol", "val"]) +@pytest.mark.parmetrize( + "w_vals,p_vals,start,p_expected,w_expected_vol,w_expected_val,tz", + [ + ( + [1, 2], + [100, 200], + "2020-01-01", + 148.333333333, + 1.4833333, + None, + ), # 29 days in Feb + ( + [1, 2], + [100, 200], + "2021-01-01", + 147.4576271, + 1.474576271, + None, + ), # 28 days in Feb + ( + range(12), + np.arange(12) * 100, + "2020-01-01", + 551.366120, + 5.51366120, + 7.673934589, + None, + ), # no DST + ( + range(12), + np.arange(12) * 100, + "2020-01-01", + 551.4458106, + 5.514458106, + 7.674415244, + "Europe/Berlin", + ), # DST + ], +) +def test_onehedge_val( + w_vals, p_vals, start, w_expected_val, w_expected_vol, p_expected, how, tz +): + """Test value hedge.""" + i = pd.date_range(start, freq="MS", periods=len(w_vals), tz=tz) + df = pd.DataFrame({"w": w_vals, "p": p_vals}, i) + df["duration"] = tools.duration.index(i) + + result = tools.hedge.one_hedge(df, how=how) + w_expected = w_expected_val if how == "val" else w_expected_vol + expected = pd.Series({"w": w_expected, "p": p_expected}) + testing.assert_series_equal(result, expected) + + +@pytest.mark.parametrize("withunits", ["units", "nounits"]) +@pytest.mark.parametrize("how", ["vol", "val"]) +@pytest.mark.parametrize("bpo", ["b", "po"]) +@pytest.mark.parametrize("aggfreq", ["MS", "QS", "AS"]) +@pytest.mark.parametrize("freq", ["H", "D"]) +@pytest.mark.parametrize("tz", [None, "Europe/Berlin"]) +def test_hedge_fromexcel(tz, freq, aggfreq, bpo, how, withunits): + """Test if hedge results are correctly calculated, by comparing against previously calculated results.""" + if freq == "D" and bpo == "po": + pytest.skip("Don't decompose in peak and offpeak if daily values") + + path = Path(__file__).parent / "test_hedge_data.xlsx" + sheetname = f'{freq}_{"None" if tz is None else tz.replace("/", "")}' + peak_fn = tools.product.germanpower_peakfn if bpo == "po" else None + + # Input data. + dfin = pd.read_excel(path, sheetname, header=6, index_col=0, usecols="A,B:C") + if tz: + dfin = dfin.tz_localize(tz, ambiguous="infer") + dfin.index.freq = pd.infer_freq(dfin.index) + win, pin = dfin.w, dfin.p + if withunits == "units": + win = win.astype("pint[MW]") + pin = pin.astype("pint[Eur/MWh]") + + # Expected output data. + dfout = pd.read_excel(path, f"{sheetname}_out", header=[3, 4, 5, 6], index_col=0) + if tz: + dfout = dfout.tz_localize(tz, ambiguous="infer") + dfout.index.freq = pd.infer_freq(dfout.index) + w_expected = dfout[aggfreq][bpo == "po"][how]["w"] + p_expected = dfout[aggfreq][bpo == "po"].iloc[:, 0] # price is first column + if withunits == "units": + w_expected = w_expected.astype("pint[MW]") + p_expected = p_expected.astype("pint[Eur/MWh]") + + # Test output data. + w_result, p_result = tools.hedge.hedge(win, pin, how, peak_fn, aggfreq) + + testing.assert_series_equal(p_result, p_expected, check_names=False) + testing.assert_series_equal(w_result, w_expected, check_names=False) diff --git a/tests/tools/prices/test_hedge_data.xlsx b/tests/tools/test_hedge_data.xlsx similarity index 100% rename from tests/tools/prices/test_hedge_data.xlsx rename to tests/tools/test_hedge_data.xlsx From c91f12b8dcdd90a6036615d1cacd9c18362dfc62 Mon Sep 17 00:00:00 2001 From: rwijtvliet Date: Fri, 24 May 2024 18:50:12 +0200 Subject: [PATCH 59/59] fixed typo --- tests/tools/test_hedge.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/tools/test_hedge.py b/tests/tools/test_hedge.py index b96a689..38b9dba 100644 --- a/tests/tools/test_hedge.py +++ b/tests/tools/test_hedge.py @@ -50,7 +50,7 @@ def test_onehedge_uniformprices(w_vals, start, w_expected, how, tz): @pytest.mark.parametrize("how", ["vol", "val"]) -@pytest.mark.parmetrize( +@pytest.mark.parametrize( "w_vals,p_vals,start,p_expected,w_expected_vol,w_expected_val,tz", [ ( @@ -59,6 +59,7 @@ def test_onehedge_uniformprices(w_vals, start, w_expected, how, tz): "2020-01-01", 148.333333333, 1.4833333, + 1.651685393, None, ), # 29 days in Feb ( @@ -67,10 +68,11 @@ def test_onehedge_uniformprices(w_vals, start, w_expected, how, tz): "2021-01-01", 147.4576271, 1.474576271, + 1.643678161, None, ), # 28 days in Feb ( - range(12), + np.arange(12), np.arange(12) * 100, "2020-01-01", 551.366120, @@ -79,7 +81,7 @@ def test_onehedge_uniformprices(w_vals, start, w_expected, how, tz): None, ), # no DST ( - range(12), + np.arange(12), np.arange(12) * 100, "2020-01-01", 551.4458106, @@ -89,7 +91,7 @@ def test_onehedge_uniformprices(w_vals, start, w_expected, how, tz): ), # DST ], ) -def test_onehedge_val( +def test_onehedge( w_vals, p_vals, start, w_expected_val, w_expected_vol, p_expected, how, tz ): """Test value hedge."""