From a704e27c7cfe8c51cf47423bc2cece4a68cafbed Mon Sep 17 00:00:00 2001 From: Ben RdO Date: Wed, 1 Sep 2021 13:36:59 -0700 Subject: [PATCH 01/21] docs: update README to signal package availability on PyPi (#536) --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 456975973..c328eb8ea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ - ![logo](https://raw.githubusercontent.com/Breakthrough-Energy/docs/master/source/_static/img/BE_Sciences_RGB_Horizontal_Color.svg) +[![PyPI](https://img.shields.io/pypi/v/powersimdata?color=purple)](https://pypi.org/project/powersimdata/) [![codecov](https://codecov.io/gh/Breakthrough-Energy/PowerSimData/branch/develop/graph/badge.svg?token=5A20TCV5XL)](https://codecov.io/gh/Breakthrough-Energy/PowerSimData) [![made-with-python](https://img.shields.io/badge/Made%20with-Python-1f425f.svg)](https://www.python.org/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black) @@ -32,7 +32,8 @@ A detailed tutorial can be found on our [docs]. ## Where to get it -For now, only the source code is available. Clone or Fork the code here on GitHub. +* Clone or Fork the source code on [GitHub](https://github.com/Breakthrough-Energy/PowerSimData) +* Get latest release from PyPi: `pip install powersimdata` ## Dependencies From ab21118359fadbb6c4150c50c17e7a34b26a329b Mon Sep 17 00:00:00 2001 From: jon-hagg <66005238+jon-hagg@users.noreply.github.com> Date: Wed, 1 Sep 2021 13:54:21 -0700 Subject: [PATCH 02/21] ci: combine workflow triggers (#537) --- .github/workflows/docker-build.yml | 26 -------------------------- .github/workflows/docs-trigger.yml | 14 -------------- .github/workflows/external.yml | 25 +++++++++++++++++++++++++ 3 files changed, 25 insertions(+), 40 deletions(-) delete mode 100644 .github/workflows/docker-build.yml delete mode 100644 .github/workflows/docs-trigger.yml create mode 100644 .github/workflows/external.yml diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml deleted file mode 100644 index 214410027..000000000 --- a/.github/workflows/docker-build.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Publish docker image - -on: - workflow_dispatch: - push: - branches: - - 'develop' - -jobs: - push_to_registry: - name: Push Docker image to GitHub Packages - runs-on: ubuntu-latest - steps: - - name: Login to GitHub Container Registry - uses: docker/login-action@v1 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.CR_PAT }} - - - name: Build and push - uses: docker/build-push-action@v2 - with: - push: true - tags: | - ghcr.io/breakthrough-energy/powersimdata:latest diff --git a/.github/workflows/docs-trigger.yml b/.github/workflows/docs-trigger.yml deleted file mode 100644 index 5c626d9bf..000000000 --- a/.github/workflows/docs-trigger.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: Update docs - -on: - push: - branches: - - develop - -jobs: - dispatch: - runs-on: ubuntu-latest - steps: - - uses: Breakthrough-Energy/actions/publish-docs@main - with: - token: ${{ secrets.CI_TOKEN_CLONE_REPO }} diff --git a/.github/workflows/external.yml b/.github/workflows/external.yml new file mode 100644 index 000000000..77481b463 --- /dev/null +++ b/.github/workflows/external.yml @@ -0,0 +1,25 @@ +name: Trigger external workflows + +on: + push: + branches: + - develop + +jobs: + run-workflows: + runs-on: ubuntu-latest + steps: + - name: Build and publish docs website + uses: Breakthrough-Energy/actions/workflow-trigger@main + with: + repo: docs + branch: master + workflow_id: 2386877 + token: ${{ secrets.CI_TOKEN_CLONE_REPO }} + + - name: Build and publish docker image + uses: Breakthrough-Energy/actions/workflow-trigger@main + with: + repo: plug + workflow_id: 12413223 + token: ${{ secrets.CI_TOKEN_CLONE_REPO }} From 56d34905b8e2ea921cd498940c60189a62168638 Mon Sep 17 00:00:00 2001 From: danielolsen Date: Tue, 14 Sep 2021 11:43:24 -0700 Subject: [PATCH 03/21] fix: access column values instead of DataFrame method (#544) --- powersimdata/design/investment/investment_costs.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/powersimdata/design/investment/investment_costs.py b/powersimdata/design/investment/investment_costs.py index cdceaabdc..b4e811f95 100644 --- a/powersimdata/design/investment/investment_costs.py +++ b/powersimdata/design/investment/investment_costs.py @@ -74,7 +74,7 @@ def calculate_ac_inv_costs( base_grid.branch, grid_differences.branch ) grid_differences.branch = grid_differences.branch.assign( - rateA=capacity_difference.diff + rateA=capacity_difference["diff"].to_numpy() ) grid_differences.branch = grid_differences.branch.query("rateA != 0.0") if exclude_branches is not None: @@ -297,7 +297,7 @@ def calculate_dc_inv_costs(scenario, sum_results=True, base_grid=None): base_grid.dcline, grid_differences.dcline ) grid_differences.dcline = grid_differences.dcline.assign( - Pmax=capacity_difference.diff + Pmax=capacity_difference["diff"].to_numpy() ) grid_differences.dcline = grid_differences.dcline.query("Pmax != 0.0") @@ -391,7 +391,7 @@ def calculate_gen_inv_costs( base_grid.plant, grid_differences.plant ) grid_differences.plant = grid_differences.plant.assign( - Pmax=capacity_difference.diff + Pmax=capacity_difference["diff"].to_numpy() ) grid_differences.plant = grid_differences.plant.query("Pmax >= 0.01") # Find change in storage capacity From c3e7d8cd0fbf35b11053f9c6cfcb95eebf369d8f Mon Sep 17 00:00:00 2001 From: jon-hagg <66005238+jon-hagg@users.noreply.github.com> Date: Wed, 15 Sep 2021 17:05:33 -0700 Subject: [PATCH 04/21] feat: list available profiles directly (#548) --- powersimdata/data_access/profile_helper.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/powersimdata/data_access/profile_helper.py b/powersimdata/data_access/profile_helper.py index d077f3c9f..20be22147 100644 --- a/powersimdata/data_access/profile_helper.py +++ b/powersimdata/data_access/profile_helper.py @@ -1,6 +1,6 @@ -import json import os +import fs import requests from tqdm.auto import tqdm @@ -87,10 +87,7 @@ def get_profile_version_local(grid_model, kind): :param str kind: *'demand'*, *'hydro'*, *'solar'* or *'wind'*. :return: (*list*) -- available profile version. """ - - version_file = os.path.join(server_setup.LOCAL_DIR, "version.json") - if not os.path.exists(version_file): - return [] - with open(version_file) as f: - version = json.load(f) - return ProfileHelper.parse_version(grid_model, kind, version) + profile_dir = fs.path.join(server_setup.LOCAL_DIR, "raw", grid_model) + lfs = fs.open_fs(profile_dir) + matching = [f for f in lfs.listdir(".") if kind in f] + return [f.lstrip(f"{kind}_").rstrip(".csv") for f in matching] From 889b1559d254828181a76bc8937582ded2eee70e Mon Sep 17 00:00:00 2001 From: Daniel Olsen Date: Tue, 14 Sep 2021 15:56:45 -0700 Subject: [PATCH 05/21] fix: add a step to detect and remove duplicated buses --- .../design/investment/create_mapping_files.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/powersimdata/design/investment/create_mapping_files.py b/powersimdata/design/investment/create_mapping_files.py index 7335e0e87..5d1dc6fbd 100644 --- a/powersimdata/design/investment/create_mapping_files.py +++ b/powersimdata/design/investment/create_mapping_files.py @@ -4,6 +4,7 @@ from powersimdata.design.investment import const from powersimdata.input.grid import Grid +from powersimdata.utility.distance import haversine from powersimdata.utility.helpers import _check_import @@ -67,6 +68,29 @@ def _find_nearest(series, polygons, search_dist): points_in_regions = gpd.sjoin(left_df=left_df, right_df=right_df, op="intersects") points_in_regions["dist"] = 0 + # Since polygons may overlap, there can be duplicated buses that we want to filter + duplicated = points_in_regions.loc[points_in_regions.index.duplicated(keep=False)] + to_drop = set() + for bus in set(duplicated["bus_id"]): + entries = duplicated.query("bus_id == @bus") + coords = entries["geometry"].iloc[0].coords[0] # First duped entry, only point + regions = set(entries["name_abbr"]) # noqa: F841 + candidates = points_in_regions.query( + "index not in @duplicated.index and name_abbr in @regions" + ) + neighbor = candidates.apply( + lambda x: haversine((x.geometry.x, x.geometry.y), coords), axis=1 + ).idxmin() + closest_region = candidates.loc[neighbor, "name_abbr"] # noqa: F841 + # There may be more than two overlapping geometries, capture all but the closest + drop_regions = set(entries.query("name_abbr != @closest_region")["name_abbr"]) + # Since indices are duplicated, we need to drop via two-column tuples + to_drop |= {(bus, d) for d in drop_regions} + + points_in_regions = points_in_regions.loc[ + ~points_in_regions.set_index(["bus_id", "name_abbr"]).index.isin(to_drop) + ] + # Find closest Polygons, for points that don't fall within any missing_indices = set(left_df.index) - set(points_in_regions.index) points_not_in_regions = left_df.loc[missing_indices] From 1a627f9c954108cffa7d6a6a9235358206da2c09 Mon Sep 17 00:00:00 2001 From: Daniel Olsen Date: Tue, 14 Sep 2021 16:06:13 -0700 Subject: [PATCH 06/21] fix: change makedirs to create directories, not files --- powersimdata/design/investment/create_mapping_files.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/powersimdata/design/investment/create_mapping_files.py b/powersimdata/design/investment/create_mapping_files.py index 5d1dc6fbd..5a698a2bb 100644 --- a/powersimdata/design/investment/create_mapping_files.py +++ b/powersimdata/design/investment/create_mapping_files.py @@ -208,7 +208,7 @@ def write_bus_neem_map(base_grid): raise TypeError("base_grid must be a Grid instance") df_pts_bus = bus_to_neem_reg(base_grid.bus) df_pts_bus.sort_index(inplace=True) - os.makedirs(const.bus_neem_regions_path, exist_ok=True) + os.makedirs(os.path.dirname(const.bus_neem_regions_path), exist_ok=True) df_pts_bus.to_csv(const.bus_neem_regions_path) @@ -222,7 +222,7 @@ def write_bus_reeds_map(base_grid): raise TypeError("base_grid must be a Grid instance") df_pts_bus = bus_to_reeds_reg(base_grid.bus) df_pts_bus.sort_index(inplace=True) - os.makedirs(const.bus_reeds_regions_path, exist_ok=True) + os.makedirs(os.path.dirname(const.bus_reeds_regions_path), exist_ok=True) df_pts_bus.to_csv(const.bus_reeds_regions_path) From 1b585004cb34d6c3cb9e8070f9b2b3d2a8513558 Mon Sep 17 00:00:00 2001 From: Daniel Olsen Date: Tue, 14 Sep 2021 16:06:39 -0700 Subject: [PATCH 07/21] chore: update data to remove duplicated bus-to-NEEM mapping --- powersimdata/design/investment/data/buses_NEEMregion.csv | 9 --------- 1 file changed, 9 deletions(-) diff --git a/powersimdata/design/investment/data/buses_NEEMregion.csv b/powersimdata/design/investment/data/buses_NEEMregion.csv index d174ba8ab..52b8a95ff 100644 --- a/powersimdata/design/investment/data/buses_NEEMregion.csv +++ b/powersimdata/design/investment/data/buses_NEEMregion.csv @@ -12358,7 +12358,6 @@ bus_id,name_abbr,dist,lat,lon 12357,PJM E,0.0,40.0887,-75.6346 12358,PJM E,0.0,40.0887,-75.6346 12359,PJM ROM,0.0,39.9515,-75.826 -12359,PJM E,0.0,39.9515,-75.826 12360,PJM E,0.0,39.8624,-75.8187 12361,PJM E,0.0,39.9648,-75.7912 12362,PJM E,0.0,39.9648,-75.7912 @@ -12458,10 +12457,8 @@ bus_id,name_abbr,dist,lat,lon 12456,PJM E,0.0,39.8364,-75.8027 12457,PJM E,0.0,39.8364,-75.8027 12458,PJM E,0.0,39.8364,-75.8027 -12459,PJM E,0.0,39.9024,-75.8392 12459,PJM ROM,0.0,39.9024,-75.8392 12460,PJM ROM,0.0,39.9024,-75.8392 -12460,PJM E,0.0,39.9024,-75.8392 12461,PJM ROM,0.0,41.1524,-77.3123 12462,PJM ROM,0.0,41.1524,-77.3123 12463,PJM ROM,0.0,41.2429,-77.2389 @@ -36057,7 +36054,6 @@ bus_id,name_abbr,dist,lat,lon 36053,PJM ROR,0.0,39.3891,-83.3393 36054,PJM ROR,0.0,39.2689,-83.432 36055,NonRTO Midwest,0.0,39.6566,-83.5378 -36055,PJM ROR,0.0,39.6566,-83.5378 36056,PJM ROR,0.0,39.7052,-83.3107 36057,PJM ROR,0.0,39.6489,-83.3377 36058,NonRTO Midwest,0.003978078694527869,39.479,-83.5037 @@ -42496,7 +42492,6 @@ bus_id,name_abbr,dist,lat,lon 42491,MISO IN,0.0,38.0288,-87.5769 42492,MISO IN,0.0,38.0288,-87.5769 42493,MISO IN,0.0,38.0811,-87.553 -42494,NonRTO Midwest,0.0,37.9335,-87.5617 42494,MISO IN,0.0,37.9335,-87.5617 42495,MISO IN,0.0,38.0137,-87.5274 42496,NonRTO Midwest,0.0,37.9065,-87.5288 @@ -43089,7 +43084,6 @@ bus_id,name_abbr,dist,lat,lon 43083,PJM ROR,0.0,42.2138,-88.7904 43084,PJM ROR,0.0,42.3539,-88.6689 43085,MISO WUMS,0.0,42.4947,-88.6446 -43085,PJM ROR,0.0,42.4947,-88.6446 43086,PJM ROR,0.0,42.4093,-88.6218 43087,PJM ROR,0.0,42.4093,-88.6218 43088,PJM ROR,0.0,42.3461,-88.9741 @@ -47993,9 +47987,7 @@ bus_id,name_abbr,dist,lat,lon 47986,MISO WUMS,0.0,42.598,-89.1008 47987,MISO WUMS,0.0,42.598,-89.1008 47988,MISO WUMS,0.0,42.5008,-89.1299 -47988,PJM ROR,0.0,42.5008,-89.1299 47989,MISO WUMS,0.0,42.5008,-89.1299 -47989,PJM ROR,0.0,42.5008,-89.1299 47990,MISO WUMS,0.0,42.5598,-88.7798 47991,PJM ROR,0.0,42.4831,-88.8725 47992,PJM ROR,0.0,42.4831,-88.8725 @@ -48141,7 +48133,6 @@ bus_id,name_abbr,dist,lat,lon 48132,MISO WUMS,0.0,42.6161,-88.3851 48133,MISO WUMS,0.0,42.6161,-88.3851 48134,MISO WUMS,0.0,42.496,-88.5134 -48134,PJM ROR,0.0,42.496,-88.5134 48135,MISO W,0.0,45.9493,-91.938 48136,MISO WUMS,0.0,43.2861,-88.2452 48137,MISO WUMS,0.0,43.2861,-88.2452 From 629a035fba1c4cd59fba57efb03a76a7cef121a6 Mon Sep 17 00:00:00 2001 From: Jon Hagg Date: Fri, 24 Sep 2021 14:42:10 -0700 Subject: [PATCH 08/21] ci: exclude db tests from ci --- .github/workflows/coverage.yml | 8 +------- .github/workflows/test.yml | 8 +------- tox.ini | 3 +-- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index ffef67463..516bc3d5d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -18,14 +18,8 @@ jobs: with: python-version: 3.9 - - name: Start postgres container - run: | - docker-compose -f stack.yml up -d - while ! nc -z localhost 5432; do sleep 1; done; - working-directory: powersimdata/data_access - - run: python -m pip install --upgrade pip tox - - run: tox -e pytest-ci -- --cov-report=xml + - run: tox -e pytest-local -- --cov-report=xml - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf58af51e..19bff140e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,11 +20,5 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Start postgres container - run: | - docker-compose -f stack.yml up -d - while ! nc -z localhost 5432; do sleep 1; done; - working-directory: powersimdata/data_access - - run: python -m pip install --upgrade pip tox - - run: tox -e pytest-ci + - run: tox -e pytest-local diff --git a/tox.ini b/tox.ini index 5ed2d21d9..3f8679dd4 100644 --- a/tox.ini +++ b/tox.ini @@ -14,8 +14,7 @@ deps = flake8: pep8-naming commands = pytest: pipenv sync --dev - ci: pytest -m 'not ssh' {posargs} - local: pytest -m 'not integration' + local: pytest -m 'not integration' {posargs} integration: pytest format: black . format: isort . From eeb724b3b36330d3fd1506c1d6a98064eeda0d57 Mon Sep 17 00:00:00 2001 From: Jon Hagg Date: Fri, 24 Sep 2021 14:42:45 -0700 Subject: [PATCH 09/21] chore: remove psycopg2 from requried packages --- Pipfile | 1 - Pipfile.lock | 591 +++++++++++++++++++++++++-------------------------- 2 files changed, 285 insertions(+), 307 deletions(-) diff --git a/Pipfile b/Pipfile index 44779f5be..e29208c62 100644 --- a/Pipfile +++ b/Pipfile @@ -14,7 +14,6 @@ networkx = "~=2.5" numpy = "~=1.20" pandas = "~=1.2" paramiko = "==2.7.2" -psycopg2 = "~=2.8.5" scipy = "~=1.5" tqdm = "==4.29.1" requests = "~=2.25" diff --git a/Pipfile.lock b/Pipfile.lock index b031200f0..ed23d585d 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "0bf4a3f9bc8f923d6472823f6e92e22a163da1c18a1888bd416f4d232dac0740" + "sha256": "cc7beb7fb5a62576ebd376a38d1581f3ab941c6c4267a4dd17551a0a299c13c9" }, "pipfile-spec": 6, "requires": {}, @@ -43,90 +43,91 @@ }, "cffi": { "hashes": [ - "sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813", - "sha256:04c468b622ed31d408fea2346bec5bbffba2cc44226302a0de1ade9f5ea3d373", - "sha256:06d7cd1abac2ffd92e65c0609661866709b4b2d82dd15f611e602b9b188b0b69", - "sha256:06db6321b7a68b2bd6df96d08a5adadc1fa0e8f419226e25b2a5fbf6ccc7350f", - "sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06", - "sha256:0f861a89e0043afec2a51fd177a567005847973be86f709bbb044d7f42fc4e05", - "sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea", - "sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee", - "sha256:1bf1ac1984eaa7675ca8d5745a8cb87ef7abecb5592178406e55858d411eadc0", - "sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396", - "sha256:24a570cd11895b60829e941f2613a4f79df1a27344cbbb82164ef2e0116f09c7", - "sha256:24ec4ff2c5c0c8f9c6b87d5bb53555bf267e1e6f70e52e5a9740d32861d36b6f", - "sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73", - "sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315", - "sha256:293e7ea41280cb28c6fcaaa0b1aa1f533b8ce060b9e701d78511e1e6c4a1de76", - "sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1", - "sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49", - "sha256:3c3f39fa737542161d8b0d680df2ec249334cd70a8f420f71c9304bd83c3cbed", - "sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892", - "sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482", - "sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058", - "sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5", - "sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53", - "sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045", - "sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3", - "sha256:681d07b0d1e3c462dd15585ef5e33cb021321588bebd910124ef4f4fb71aef55", - "sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5", - "sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e", - "sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c", - "sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369", - "sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827", - "sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053", - "sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa", - "sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4", - "sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322", - "sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132", - "sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62", - "sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa", - "sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0", - "sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396", - "sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e", - "sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991", - "sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6", - "sha256:cc5a8e069b9ebfa22e26d0e6b97d6f9781302fe7f4f2b8776c3e1daea35f1adc", - "sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1", - "sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406", - "sha256:df5052c5d867c1ea0b311fb7c3cd28b19df469c056f7fdcfe88c7473aa63e333", - "sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d", - "sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c" - ], - "version": "==1.14.5" - }, - "chardet": { - "hashes": [ - "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.0.0" + "sha256:016ba30a6c3e93e48fd57b1a8624516aeba61f85ed1d5c31d9dd34f77fdff4f6", + "sha256:0e4d1c32812d5885956ba1489052ecd86a8cdde2f334568343e8bc646c7e2cb4", + "sha256:104516acf2608c22b5d44a58e0819da275c21e1751df69bd077a70fc8f016e18", + "sha256:1edddb00facd25f2fb0cc2f271b3a795cbbe804b36319ace01d15fb962309293", + "sha256:23feec3ff73fd47d9bf3fed96e5debb32727c67c9dcbfea67e172f8fac4500e6", + "sha256:28036db6711fcc83d154e3022270508bcfe20a4839e79b8f9f0776555512f2a4", + "sha256:2941c0ae3161b185b116eb939386c9c1dc8d4294ea0a3886c7248c50c23defe8", + "sha256:2bcca3d8cbaf4e3250f5c4916bf32e2da8ce3fd8163303ce41d9b703df38d31e", + "sha256:3d804d22084ba6cee9922cab3b0f665021be93efe40d528c6c32a73caae587eb", + "sha256:3e11347d5d19bd13359587270f2b4580fc3a6761fedb7d4a81ffac2e68c66b6c", + "sha256:415529aaf4d9b4c00b3a75fb30f82cafbb4487f96b3c7fbf424cebc978c96a32", + "sha256:42e4cb8e0705f7757816bfa6a771db1c5933f69cbab0d96a1a5a2d955237086e", + "sha256:577c7c7a5f7065ec9bf33b9ca2de96d8f579e39fff3bc94a9acd018c0db7dac1", + "sha256:66dee5853862e63d521354f7034714ad1c925e025641a4a19548e32580790a47", + "sha256:6a78361a30688afc1c79f09cee629dc5f6d627f7fbd43ab9a37b239e7609940f", + "sha256:6de0c4a6e53877696115221aefbea22eb9d31a4b2fc0756c7e4c970668376a60", + "sha256:6e1db0b63067f1a96f1b92fc8149aa20327a11d18ab3e3ad23be2d8aeb3a6bbb", + "sha256:71e842ed506fd588a427cbc127dc91d0727468f73d581fed02955256cd4bbdbb", + "sha256:720985a41a7be5ca5d17fa9196b4965c226b85f6c57e7b2f6c6debed657faa23", + "sha256:7623bbfc421d26698cc9dc4b8907ca6a149c7547d5c94ac6f55b1685e9f187b1", + "sha256:78f691b8c882d65162062bb10a69423f9d3005b3c8ec9977c60e14fe0036525f", + "sha256:8a2b1001ece83aabd818d334659a97cf3c0158501442f20fee7305c8ac3059cb", + "sha256:8c16099cb2d5a61b9ac4aa77de25a6376bb96c8f94ea96e2c69e625cd222e7ae", + "sha256:94261a9a318c6620b1e079f2ce15ff13c90305e880eaba1f9450e47ac4ea8b4a", + "sha256:9660de460a5cae80b896e560dcdbf4a4f1d055a88512207d582a361f47eb0dca", + "sha256:966df3527b71319f28fc6a723b727d5d6abc3298dff56262b20cc4236c26cb8f", + "sha256:98b299690d7a0c544bf0f211eabe426ad57751c657139aa4d3333d357c43f638", + "sha256:9c2e5e75c7c3d65131a366e0ae460542a1ace97ae93cc0f283f9efff1a97ebfa", + "sha256:afc696d8e7f3db5cbd32ae13ba53848aa6eec0a85d19ada7363443a27505c651", + "sha256:b6cf0921851b21ee5337e48a487e21a52d629453b42c85a6225776d9300c39ef", + "sha256:b8f4891d4f4772bab7d39f748ffcce39be83dac3bdf93d4e40bbd9e2ce1eb5c4", + "sha256:b96741e5ab3290aae9712e708362d4843e77d8a2418a3af3c08dda14d9691bab", + "sha256:c248be3c030cf7e0d035479b3d8d7ce4e4107959551196413897876c90c77d85", + "sha256:c4a469421402b50e48cc2ffa05229cbdd7dc0164ce2d31eae6b2ac8195ef9634", + "sha256:c5c8578e7fe6aca1dd2a1335ca977efce8bf2d38bc54568f120b912d7ab8d9c7", + "sha256:c7ed3d86d61284d5c0910c8c0988a645cf6723fa2deabe1b149112b2ebe0547e", + "sha256:ccec0368227d02c2ae5dc0881d8075bfa8fa87232f027d375a795d8a0f70c73a", + "sha256:d475cef45640f69ee779720c2fecfcef7cf2a869a0e7e7297ec7854db6cb6a04", + "sha256:d6491e6e623abb27d20f42e37011d28380792ffbba3657bc9fef464c8b5ca1cb", + "sha256:d6f8782c19a0b12b4c5d9cefe1b2ca1636591531c7f20c4ae4d7c5b4077d3af5", + "sha256:d89fcd91a1e0da07b35fbe09f0e10fff880e9ca5f76478f6bbfab10c9c9ef6f2", + "sha256:e0874c097458ce6933cdb1918f2e601e48772d10b8aff478f02d949c757aed97", + "sha256:e185aa34d2ab08e0fe1f6bd60aa6950bfcb84059e7debb8bcfb4f1818eafd6e3", + "sha256:e29accdb21f2186b80b60b07af29d752666fe7bbf057e08c54741740877909b2", + "sha256:e34d93929b4cf93e736be64c0c926af6bf90f0887de0253de233509665d36c9c", + "sha256:e42f7138056b2428cd6197351940ef36d214b8923dbb496af73ac717552cdfec", + "sha256:e4bb67bdef349768f3e662b63d3fc6a939e9e425326acebe4c0c1b48b6f38267", + "sha256:f3765dc391a99564c9b0e6030398a68d5f862e48b96e37fa66ba8101790642e8", + "sha256:f909436b96a032aed0a8529464910ae7665b5826b35801a03d9012dde3fcc9cb", + "sha256:fb2efcf7e942cf58c221adf0b39e8d55d252d2962ed7e8c511f3eec57a903f56" + ], + "version": "==1.15.0rc1" + }, + "charset-normalizer": { + "hashes": [ + "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6", + "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f" + ], + "markers": "python_version >= '3'", + "version": "==2.0.6" }, "cryptography": { "hashes": [ - "sha256:0f1212a66329c80d68aeeb39b8a16d54ef57071bf22ff4e521657b27372e327d", - "sha256:1e056c28420c072c5e3cb36e2b23ee55e260cb04eee08f702e0edfec3fb51959", - "sha256:240f5c21aef0b73f40bb9f78d2caff73186700bf1bc6b94285699aff98cc16c6", - "sha256:26965837447f9c82f1855e0bc8bc4fb910240b6e0d16a664bb722df3b5b06873", - "sha256:37340614f8a5d2fb9aeea67fd159bfe4f5f4ed535b1090ce8ec428b2f15a11f2", - "sha256:3d10de8116d25649631977cb37da6cbdd2d6fa0e0281d014a5b7d337255ca713", - "sha256:3d8427734c781ea5f1b41d6589c293089704d4759e34597dce91014ac125aad1", - "sha256:7ec5d3b029f5fa2b179325908b9cd93db28ab7b85bb6c1db56b10e0b54235177", - "sha256:8e56e16617872b0957d1c9742a3f94b43533447fd78321514abbe7db216aa250", - "sha256:de4e5f7f68220d92b7637fc99847475b59154b7a1b3868fb7385337af54ac9ca", - "sha256:eb8cc2afe8b05acbd84a43905832ec78e7b3873fb124ca190f574dca7389a87d", - "sha256:ee77aa129f481be46f8d92a1a7db57269a2f23052d5f2433b4621bb457081cc9" + "sha256:0a7dcbcd3f1913f664aca35d47c1331fce738d44ec34b7be8b9d332151b0b01e", + "sha256:1eb7bb0df6f6f583dd8e054689def236255161ebbcf62b226454ab9ec663746b", + "sha256:21ca464b3a4b8d8e86ba0ee5045e103a1fcfac3b39319727bc0fc58c09c6aff7", + "sha256:34dae04a0dce5730d8eb7894eab617d8a70d0c97da76b905de9efb7128ad7085", + "sha256:3520667fda779eb788ea00080124875be18f2d8f0848ec00733c0ec3bb8219fc", + "sha256:3c4129fc3fdc0fa8e40861b5ac0c673315b3c902bbdc05fc176764815b43dd1d", + "sha256:3fa3a7ccf96e826affdf1a0a9432be74dc73423125c8f96a909e3835a5ef194a", + "sha256:5b0fbfae7ff7febdb74b574055c7466da334a5371f253732d7e2e7525d570498", + "sha256:695104a9223a7239d155d7627ad912953b540929ef97ae0c34c7b8bf30857e89", + "sha256:8695456444f277af73a4877db9fc979849cd3ee74c198d04fc0776ebc3db52b9", + "sha256:94cc5ed4ceaefcbe5bf38c8fba6a21fc1d365bb8fb826ea1688e3370b2e24a1c", + "sha256:94fff993ee9bc1b2440d3b7243d488c6a3d9724cc2b09cdb297f6a886d040ef7", + "sha256:9965c46c674ba8cc572bc09a03f4c649292ee73e1b683adb1ce81e82e9a6a0fb", + "sha256:a00cf305f07b26c351d8d4e1af84ad7501eca8a342dedf24a7acb0e7b7406e14", + "sha256:a305600e7a6b7b855cd798e00278161b681ad6e9b7eca94c721d5f588ab212af", + "sha256:cd65b60cfe004790c795cc35f272e41a3df4631e2fb6b35aa7ac6ef2859d554e", + "sha256:d2a6e5ef66503da51d2110edf6c403dc6b494cc0082f85db12f54e9c5d4c3ec5", + "sha256:d9ec0e67a14f9d1d48dd87a2531009a9b251c02ea42851c060b25c782516ff06", + "sha256:f44d141b8c4ea5eb4dbc9b3ad992d45580c1d22bf5e24363f2fbf50c2d7ae8a7" ], "markers": "python_version >= '3.6'", - "version": "==3.4.7" - }, - "decorator": { - "hashes": [ - "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760", - "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7" - ], - "version": "==4.4.2" + "version": "==3.4.8" }, "fs": { "hashes": [ @@ -146,78 +147,82 @@ }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", + "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "markers": "python_version >= '3'", + "version": "==3.2" }, "networkx": { "hashes": [ - "sha256:0635858ed7e989f4c574c2328380b452df892ae85084144c73d8cd819f0c4e06", - "sha256:109cd585cac41297f71103c3c42ac6ef7379f29788eb54cb751be5a663bb235a" + "sha256:80b6b89c77d1dfb64a4c7854981b60aeea6360ac02c6d4e4913319e0a313abef", + "sha256:c0946ed31d71f1b732b5aaa6da5a0388a345019af232ce2f49c766e2d6795c51" ], "index": "pypi", - "version": "==2.5.1" + "version": "==2.6.3" }, "numpy": { "hashes": [ - "sha256:1a784e8ff7ea2a32e393cc53eb0003eca1597c7ca628227e34ce34eb11645a0e", - "sha256:2ba579dde0563f47021dcd652253103d6fd66165b18011dce1a0609215b2791e", - "sha256:3537b967b350ad17633b35c2f4b1a1bbd258c018910b518c30b48c8e41272717", - "sha256:3c40e6b860220ed862e8097b8f81c9af6d7405b723f4a7af24a267b46f90e461", - "sha256:598fe100b2948465cf3ed64b1a326424b5e4be2670552066e17dfaa67246011d", - "sha256:620732f42259eb2c4642761bd324462a01cdd13dd111740ce3d344992dd8492f", - "sha256:709884863def34d72b183d074d8ba5cfe042bc3ff8898f1ffad0209161caaa99", - "sha256:75579acbadbf74e3afd1153da6177f846212ea2a0cc77de53523ae02c9256513", - "sha256:7c55407f739f0bfcec67d0df49103f9333edc870061358ac8a8c9e37ea02fcd2", - "sha256:a1f2fb2da242568af0271455b89aee0f71e4e032086ee2b4c5098945d0e11cf6", - "sha256:a290989cd671cd0605e9c91a70e6df660f73ae87484218e8285c6522d29f6e38", - "sha256:ac4fd578322842dbda8d968e3962e9f22e862b6ec6e3378e7415625915e2da4d", - "sha256:ad09f55cc95ed8d80d8ab2052f78cc21cb231764de73e229140d81ff49d8145e", - "sha256:b9205711e5440954f861ceeea8f1b415d7dd15214add2e878b4d1cf2bcb1a914", - "sha256:bba474a87496d96e61461f7306fba2ebba127bed7836212c360f144d1e72ac54", - "sha256:bebab3eaf0641bba26039fb0b2c5bf9b99407924b53b1ea86e03c32c64ef5aef", - "sha256:cc367c86eb87e5b7c9592935620f22d13b090c609f1b27e49600cd033b529f54", - "sha256:ccc6c650f8700ce1e3a77668bb7c43e45c20ac06ae00d22bdf6760b38958c883", - "sha256:cf680682ad0a3bef56dae200dbcbac2d57294a73e5b0f9864955e7dd7c2c2491", - "sha256:d2910d0a075caed95de1a605df00ee03b599de5419d0b95d55342e9a33ad1fb3", - "sha256:d5caa946a9f55511e76446e170bdad1d12d6b54e17a2afe7b189112ed4412bb8", - "sha256:d89b0dc7f005090e32bb4f9bf796e1dcca6b52243caf1803fdd2b748d8561f63", - "sha256:d95d16204cd51ff1a1c8d5f9958ce90ae190be81d348b514f9be39f878b8044a", - "sha256:e4d5a86a5257843a18fb1220c5f1c199532bc5d24e849ed4b0289fb59fbd4d8f", - "sha256:e58ddb53a7b4959932f5582ac455ff90dcb05fac3f8dcc8079498d43afbbde6c", - "sha256:e80fe25cba41c124d04c662f33f6364909b985f2eb5998aaa5ae4b9587242cce", - "sha256:eda2829af498946c59d8585a9fd74da3f810866e05f8df03a86f70079c7531dd", - "sha256:fd0a359c1c17f00cb37de2969984a74320970e0ceef4808c32e00773b06649d9" + "sha256:09858463db6dd9f78b2a1a05c93f3b33d4f65975771e90d2cf7aadb7c2f66edf", + "sha256:209666ce9d4a817e8a4597cd475b71b4878a85fa4b8db41d79fdb4fdee01dde2", + "sha256:298156f4d3d46815eaf0fcf0a03f9625fc7631692bd1ad851517ab93c3168fc6", + "sha256:30fc68307c0155d2a75ad19844224be0f2c6f06572d958db4e2053f816b859ad", + "sha256:423216d8afc5923b15df86037c6053bf030d15cc9e3224206ef868c2d63dd6dc", + "sha256:426a00b68b0d21f2deb2ace3c6d677e611ad5a612d2c76494e24a562a930c254", + "sha256:466e682264b14982012887e90346d33435c984b7fead7b85e634903795c8fdb0", + "sha256:51a7b9db0a2941434cd930dacaafe0fc9da8f3d6157f9d12f761bbde93f46218", + "sha256:52a664323273c08f3b473548bf87c8145b7513afd63e4ebba8496ecd3853df13", + "sha256:550564024dc5ceee9421a86fc0fb378aa9d222d4d0f858f6669eff7410c89bef", + "sha256:5de64950137f3a50b76ce93556db392e8f1f954c2d8207f78a92d1f79aa9f737", + "sha256:640c1ccfd56724f2955c237b6ccce2e5b8607c3bc1cc51d3933b8c48d1da3723", + "sha256:7fdc7689daf3b845934d67cb221ba8d250fdca20ac0334fea32f7091b93f00d3", + "sha256:805459ad8baaf815883d0d6f86e45b3b0b67d823a8f3fa39b1ed9c45eaf5edf1", + "sha256:92a0ab128b07799dd5b9077a9af075a63467d03ebac6f8a93e6440abfea4120d", + "sha256:9f2dc79c093f6c5113718d3d90c283f11463d77daa4e83aeeac088ec6a0bda52", + "sha256:a5109345f5ce7ddb3840f5970de71c34a0ff7fceb133c9441283bb8250f532a3", + "sha256:a55e4d81c4260386f71d22294795c87609164e22b28ba0d435850fbdf82fc0c5", + "sha256:a9da45b748caad72ea4a4ed57e9cd382089f33c5ec330a804eb420a496fa760f", + "sha256:b160b9a99ecc6559d9e6d461b95c8eec21461b332f80267ad2c10394b9503496", + "sha256:b342064e647d099ca765f19672696ad50c953cac95b566af1492fd142283580f", + "sha256:b5e8590b9245803c849e09bae070a8e1ff444f45e3f0bed558dd722119eea724", + "sha256:bf75d5825ef47aa51d669b03ce635ecb84d69311e05eccea083f31c7570c9931", + "sha256:c01b59b33c7c3ba90744f2c695be571a3bd40ab2ba7f3d169ffa6db3cfba614f", + "sha256:d96a6a7d74af56feb11e9a443150216578ea07b7450f7c05df40eec90af7f4a7", + "sha256:dd0e3651d210068d13e18503d75aaa45656eef51ef0b261f891788589db2cc38", + "sha256:e167b9805de54367dcb2043519382be541117503ce99e3291cc9b41ca0a83557", + "sha256:e42029e184008a5fd3d819323345e25e2337b0ac7f5c135b7623308530209d57", + "sha256:f545c082eeb09ae678dd451a1b1dbf17babd8a0d7adea02897a76e639afca310", + "sha256:fde50062d67d805bc96f1a9ecc0d37bfc2a8f02b937d2c50824d186aa91f2419" ], "index": "pypi", - "version": "==1.21.0" + "version": "==1.21.2" }, "pandas": { "hashes": [ - "sha256:08eeff3da6a188e24db7f292b39a8ca9e073bf841fbbeadb946b3ad5c19d843e", - "sha256:1ff13eed501e07e7fb26a4ea18a846b6e5d7de549b497025601fd9ccb7c1d123", - "sha256:522bfea92f3ef6207cadc7428bda1e7605dae0383b8065030e7b5d0266717b48", - "sha256:7897326cae660eee69d501cbfa950281a193fcf407393965e1bc07448e1cc35a", - "sha256:798675317d0e4863a92a9a6bc5bd2490b5f6fef8c17b95f29e2e33f28bef9eca", - "sha256:7d3cd2c99faa94d717ca00ea489264a291ad7209453dffbf059bfb7971fd3a61", - "sha256:823737830364d0e2af8c3912a28ba971296181a07950873492ed94e12d28c405", - "sha256:872aa91e0f9ca913046ab639d4181a899f5e592030d954d28c2529b88756a736", - "sha256:88864c1e28353b958b1f30e4193818519624ad9a1776921622a6a2a016d5d807", - "sha256:92835113a67cbd34747c198d41f09f4b63f6fe11ca5643baebc7ab1e30e89e95", - "sha256:98efc2d4983d5bb47662fe2d97b2c81b91566cb08b266490918b9c7d74a5ef64", - "sha256:b10d7910ae9d7920a5ff7816d794d99acbc361f7b16a0f017d4fa83ced8cb55e", - "sha256:c554e6c9cf2d5ea1aba5979cc837b3649539ced0e18ece186f055450c86622e2", - "sha256:c746876cdd8380be0c3e70966d4566855901ac9aaa5e4b9ccaa5ca5311457d11", - "sha256:c81b8d91e9ae861eb4406b4e0f8d4dabbc105b9c479b3d1e921fba1d35b5b62a", - "sha256:e6b75091fa54a53db3927b4d1bc997c23c5ba6f87acdfe1ee5a92c38c6b2ed6a", - "sha256:ed4fc66f23fe17c93a5d439230ca2d6b5f8eac7154198d327dbe8a16d98f3f10", - "sha256:f058c786e7b0a9e7fa5e0b9f4422e0ccdd3bf3aa3053c18d77ed2a459bd9a45a", - "sha256:fe7a549d10ca534797095586883a5c17d140d606747591258869c56e14d1b457" + "sha256:272c8cb14aa9793eada6b1ebe81994616e647b5892a370c7135efb2924b701df", + "sha256:3334a5a9eeaca953b9db1b2b165dcdc5180b5011f3bec3a57a3580c9c22eae68", + "sha256:37d63e78e87eb3791da7be4100a65da0383670c2b59e493d9e73098d7a879226", + "sha256:3f5020613c1d8e304840c34aeb171377dc755521bf5e69804991030c2a48aec3", + "sha256:45649503e167d45360aa7c52f18d1591a6d5c70d2f3a26bc90a3297a30ce9a66", + "sha256:49fd2889d8116d7acef0709e4c82b8560a8b22b0f77471391d12c27596e90267", + "sha256:4def2ef2fb7fcd62f2aa51bacb817ee9029e5c8efe42fe527ba21f6a3ddf1a9f", + "sha256:53e2fb11f86f6253bb1df26e3aeab3bf2e000aaa32a953ec394571bec5dc6fd6", + "sha256:629138b7cf81a2e55aa29ce7b04c1cece20485271d1f6c469c6a0c03857db6a4", + "sha256:68408a39a54ebadb9014ee5a4fae27b2fe524317bc80adf56c9ac59e8f8ea431", + "sha256:7326b37de08d42dd3fff5b7ef7691d0fd0bf2428f4ba5a2bdc3b3247e9a52e4c", + "sha256:7557b39c8e86eb0543a17a002ac1ea0f38911c3c17095bc9350d0a65b32d801c", + "sha256:86b16b1b920c4cb27fdd65a2c20258bcd9c794be491290660722bb0ea765054d", + "sha256:a800df4e101b721e94d04c355e611863cc31887f24c0b019572e26518cbbcab6", + "sha256:a9f1b54d7efc9df05320b14a48fb18686f781aa66cc7b47bb62fabfc67a0985c", + "sha256:c399200631db9bd9335d013ec7fce4edb98651035c249d532945c78ad453f23a", + "sha256:e574c2637c9d27f322e911650b36e858c885702c5996eda8a5a60e35e6648cf2", + "sha256:e9bc59855598cb57f68fdabd4897d3ed2bc3a3b3bef7b868a0153c4cd03f3207", + "sha256:ebbed7312547a924df0cbe133ff1250eeb94cdff3c09a794dc991c5621c8c735", + "sha256:ed2f29b4da6f6ae7c68f4b3708d9d9e59fa89b2f9e87c2b64ce055cbd39f729e", + "sha256:f7d84f321674c2f0f31887ee6d5755c54ca1ea5e144d6d54b3bbf566dd9ea0cc" ], "index": "pypi", - "version": "==1.3.0" + "version": "==1.3.3" }, "paramiko": { "hashes": [ @@ -235,27 +240,6 @@ "markers": "python_version >= '3.5'", "version": "==1.6.4" }, - "psycopg2": { - "hashes": [ - "sha256:00195b5f6832dbf2876b8bf77f12bdce648224c89c880719c745b90515233301", - "sha256:068115e13c70dc5982dfc00c5d70437fe37c014c808acce119b5448361c03725", - "sha256:26e7fd115a6db75267b325de0fba089b911a4a12ebd3d0b5e7acb7028bc46821", - "sha256:2c93d4d16933fea5bbacbe1aaf8fa8c1348740b2e50b3735d1b0bf8154cbf0f3", - "sha256:56007a226b8e95aa980ada7abdea6b40b75ce62a433bd27cec7a8178d57f4051", - "sha256:56fee7f818d032f802b8eed81ef0c1232b8b42390df189cab9cfa87573fe52c5", - "sha256:6a3d9efb6f36f1fe6aa8dbb5af55e067db802502c55a9defa47c5a1dad41df84", - "sha256:a49833abfdede8985ba3f3ec641f771cca215479f41523e99dace96d5b8cce2a", - "sha256:ad2fe8a37be669082e61fb001c185ffb58867fdbb3e7a6b0b0d2ffe232353a3e", - "sha256:b8cae8b2f022efa1f011cc753adb9cbadfa5a184431d09b273fb49b4167561ad", - "sha256:d160744652e81c80627a909a0e808f3c6653a40af435744de037e3172cf277f5", - "sha256:d5062ae50b222da28253059880a871dc87e099c25cb68acf613d9d227413d6f7", - "sha256:f22ea9b67aea4f4a1718300908a2fb62b3e4276cf00bd829a97ab5894af42ea3", - "sha256:f974c96fca34ae9e4f49839ba6b78addf0346777b46c4da27a7bf54f48d3057d", - "sha256:fb23f6c71107c37fd667cb4ea363ddeb936b348bbd6449278eb92c189699f543" - ], - "index": "pypi", - "version": "==2.8.6" - }, "pycparser": { "hashes": [ "sha256:2d475327684562c3a96cc71adf7dc8c4f0565175cf86b6d7a404ff4c771f15f0", @@ -290,11 +274,11 @@ }, "python-dateutil": { "hashes": [ - "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", - "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a" + "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86", + "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.8.1" + "version": "==2.8.2" }, "pytz": { "hashes": [ @@ -305,36 +289,36 @@ }, "requests": { "hashes": [ - "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", - "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" ], "index": "pypi", - "version": "==2.25.1" + "version": "==2.26.0" }, "scipy": { "hashes": [ - "sha256:0572256c10ddd058e3d315c555538671ddb2737f27eb56189bfbc3483391403f", - "sha256:2e685fdbfa5b989af4338b29c408b9157ea6addec15d661104c437980c292be5", - "sha256:3595c8b64970c9e5a3f137fa1a9eb64da417e78fb7991d0b098b18a00b776d88", - "sha256:3e7df79b42c3015058a5554bfeab6fd4c9906c46560c9ddebb5c652840f3e182", - "sha256:4ef3d4df8af40cb6f4d4eaf7b02780109ebabeec334cda26a7899ec9d8de9176", - "sha256:53116abd5060a5b4a58489cf689bee259b779e6b7ecd4ce366e7147aa7c9626e", - "sha256:5a983d3cebc27294897951a494cebd78af2eae37facf75d9e4ad4f1f62229860", - "sha256:5eb8f054eebb351af7490bbb57465ba9662c4e16e1786655c6c7ed530eb9a74e", - "sha256:6130e22bf6ee506f7cddde7e0515296d97eb6c6c94f7ef5103c2b77aec5833a7", - "sha256:7f4b89c223bd09460b52b669e2e642cab73c28855b540e6ed029692546a86f8d", - "sha256:80df8af7039bce92fb4cd1ceb056258631b11b3c627384e2d29bb48d44c0cae7", - "sha256:821e75f5c16cd7b0ab0ffe7eb9917e5af7b48c25306b4777287de8d792a5f7f3", - "sha256:97ca4552ace1c313707058e774609af59644321e278c3a539322fab2fb09b943", - "sha256:998c5e6ea649489302de2c0bc026ed34284f531df89d2bdc8df3a0d44d165739", - "sha256:aef6e922aea6f2e6bbb539b413c85210a9ee32757535b84204ebd22723e69704", - "sha256:b77ee5e3a9507622e7f98b16122242a3903397f98d1fe3bc269d904a9025e2bc", - "sha256:bd4399d4388ca0239a4825e312b3e61b60f743dd6daf49e5870837716502a92a", - "sha256:c5d012cb82cc1dcfa72609abaabb4a4ed8113e3e8ac43464508a418c146be57d", - "sha256:e7b733d4d98e604109715e11f2ab9340eb45d53f803634ed730039070fc3bc11" + "sha256:2a0eeaab01258e0870c4022a6cd329aef3b7c6c2b606bd7cf7bb2ba9820ae561", + "sha256:3304bd5bc32e00954ac4b3f4cc382ca8824719bf348aacbec6347337d6b125fe", + "sha256:3f52470e0548cdb74fb8ddf06773ffdcca7c97550f903b1c51312ec19243a7f7", + "sha256:4729b41a4cdaf4cd011aeac816b532f990bdf97710cef59149d3e293115cf467", + "sha256:4ee952f39a4a4c7ba775a32b664b1f4b74818548b65f765987adc14bb78f5802", + "sha256:611f9cb459d0707dd8e4de0c96f86e93f61aac7475fcb225e9ec71fecdc5cebf", + "sha256:6b47d5fa7ea651054362561a28b1ccc8da9368a39514c1bbf6c0977a1c376764", + "sha256:71cfc96297617eab911e22216e8a8597703202e95636d9406df9af5c2ac99a2b", + "sha256:787749110a23502031fb1643c55a2236c99c6b989cca703ea2114d65e21728ef", + "sha256:90c07ba5f34f33299a428b0d4fa24c30d2ceba44d63f8385b2b05be460819fcb", + "sha256:a496b42dbcd04ea9924f5e92be63af3d8e0f43a274b769bfaca0a297327d54ee", + "sha256:bc61e3e5ff92d2f32bb263621d54a9cff5e3f7c420af3d1fa122ce2529de2bd9", + "sha256:c9951e3746b68974125e5e3445008a4163dd6d20ae0bbdae22b38cb8951dc11b", + "sha256:d1388fbac9dd591ea630da75c455f4cc637a7ca5ecb31a6b6cef430914749cde", + "sha256:d13f31457f2216e5705304d9f28e2826edf75487410a57aa99263fa4ffd792c2", + "sha256:d648aa85dd5074b1ed83008ae987c3fbb53d68af619fce1dee231f4d8bd40e2f", + "sha256:da9c6b336e540def0b7fd65603da8abeb306c5fc9a5f4238665cbbb5ff95cf58", + "sha256:e101bceeb9e65a90dadbc5ca31283403a2d4667b9c178db29109750568e8d112", + "sha256:efdd3825d54c58df2cc394366ca4b9166cf940a0ebddeb87b6c10053deb625ea" ], "index": "pypi", - "version": "==1.7.0" + "version": "==1.7.1" }, "six": { "hashes": [ @@ -354,21 +338,14 @@ }, "urllib3": { "hashes": [ - "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", - "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece", + "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", - "version": "==1.26.6" + "version": "==1.26.7" } }, "develop": { - "appdirs": { - "hashes": [ - "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", - "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" - ], - "version": "==1.4.4" - }, "attrs": { "hashes": [ "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1", @@ -379,11 +356,11 @@ }, "black": { "hashes": [ - "sha256:dc132348a88d103016726fe360cb9ede02cecf99b76e3660ce6c596be132ce04", - "sha256:dfb8c5a069012b2ab1e972e7b908f5fb42b6bbabcba0a788b86dc05067c7d9c7" + "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115", + "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91" ], "index": "pypi", - "version": "==21.6b0" + "version": "==21.9b0" }, "click": { "hashes": [ @@ -395,61 +372,39 @@ }, "coverage": { "hashes": [ - "sha256:004d1880bed2d97151facef49f08e255a20ceb6f9432df75f4eef018fdd5a78c", - "sha256:01d84219b5cdbfc8122223b39a954820929497a1cb1422824bb86b07b74594b6", - "sha256:040af6c32813fa3eae5305d53f18875bedd079960822ef8ec067a66dd8afcd45", - "sha256:06191eb60f8d8a5bc046f3799f8a07a2d7aefb9504b0209aff0b47298333302a", - "sha256:13034c4409db851670bc9acd836243aeee299949bd5673e11844befcb0149f03", - "sha256:13c4ee887eca0f4c5a247b75398d4114c37882658300e153113dafb1d76de529", - "sha256:184a47bbe0aa6400ed2d41d8e9ed868b8205046518c52464fde713ea06e3a74a", - "sha256:18ba8bbede96a2c3dde7b868de9dcbd55670690af0988713f0603f037848418a", - "sha256:1aa846f56c3d49205c952d8318e76ccc2ae23303351d9270ab220004c580cfe2", - "sha256:217658ec7187497e3f3ebd901afdca1af062b42cfe3e0dafea4cced3983739f6", - "sha256:24d4a7de75446be83244eabbff746d66b9240ae020ced65d060815fac3423759", - "sha256:2910f4d36a6a9b4214bb7038d537f015346f413a975d57ca6b43bf23d6563b53", - "sha256:2949cad1c5208b8298d5686d5a85b66aae46d73eec2c3e08c817dd3513e5848a", - "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4", - "sha256:2cafbbb3af0733db200c9b5f798d18953b1a304d3f86a938367de1567f4b5bff", - "sha256:2e0d881ad471768bf6e6c2bf905d183543f10098e3b3640fc029509530091502", - "sha256:30c77c1dc9f253283e34c27935fded5015f7d1abe83bc7821680ac444eaf7793", - "sha256:3487286bc29a5aa4b93a072e9592f22254291ce96a9fbc5251f566b6b7343cdb", - "sha256:372da284cfd642d8e08ef606917846fa2ee350f64994bebfbd3afb0040436905", - "sha256:41179b8a845742d1eb60449bdb2992196e211341818565abded11cfa90efb821", - "sha256:44d654437b8ddd9eee7d1eaee28b7219bec228520ff809af170488fd2fed3e2b", - "sha256:4a7697d8cb0f27399b0e393c0b90f0f1e40c82023ea4d45d22bce7032a5d7b81", - "sha256:51cb9476a3987c8967ebab3f0fe144819781fca264f57f89760037a2ea191cb0", - "sha256:52596d3d0e8bdf3af43db3e9ba8dcdaac724ba7b5ca3f6358529d56f7a166f8b", - "sha256:53194af30d5bad77fcba80e23a1441c71abfb3e01192034f8246e0d8f99528f3", - "sha256:5fec2d43a2cc6965edc0bb9e83e1e4b557f76f843a77a2496cbe719583ce8184", - "sha256:6c90e11318f0d3c436a42409f2749ee1a115cd8b067d7f14c148f1ce5574d701", - "sha256:74d881fc777ebb11c63736622b60cb9e4aee5cace591ce274fb69e582a12a61a", - "sha256:7501140f755b725495941b43347ba8a2777407fc7f250d4f5a7d2a1050ba8e82", - "sha256:796c9c3c79747146ebd278dbe1e5c5c05dd6b10cc3bcb8389dfdf844f3ead638", - "sha256:869a64f53488f40fa5b5b9dcb9e9b2962a66a87dab37790f3fcfb5144b996ef5", - "sha256:8963a499849a1fc54b35b1c9f162f4108017b2e6db2c46c1bed93a72262ed083", - "sha256:8d0a0725ad7c1a0bcd8d1b437e191107d457e2ec1084b9f190630a4fb1af78e6", - "sha256:900fbf7759501bc7807fd6638c947d7a831fc9fdf742dc10f02956ff7220fa90", - "sha256:92b017ce34b68a7d67bd6d117e6d443a9bf63a2ecf8567bb3d8c6c7bc5014465", - "sha256:970284a88b99673ccb2e4e334cfb38a10aab7cd44f7457564d11898a74b62d0a", - "sha256:972c85d205b51e30e59525694670de6a8a89691186012535f9d7dbaa230e42c3", - "sha256:9a1ef3b66e38ef8618ce5fdc7bea3d9f45f3624e2a66295eea5e57966c85909e", - "sha256:af0e781009aaf59e25c5a678122391cb0f345ac0ec272c7961dc5455e1c40066", - "sha256:b6d534e4b2ab35c9f93f46229363e17f63c53ad01330df9f2d6bd1187e5eaacf", - "sha256:b7895207b4c843c76a25ab8c1e866261bcfe27bfaa20c192de5190121770672b", - "sha256:c0891a6a97b09c1f3e073a890514d5012eb256845c451bd48f7968ef939bf4ae", - "sha256:c2723d347ab06e7ddad1a58b2a821218239249a9e4365eaff6649d31180c1669", - "sha256:d1f8bf7b90ba55699b3a5e44930e93ff0189aa27186e96071fac7dd0d06a1873", - "sha256:d1f9ce122f83b2305592c11d64f181b87153fc2c2bbd3bb4a3dde8303cfb1a6b", - "sha256:d314ed732c25d29775e84a960c3c60808b682c08d86602ec2c3008e1202e3bb6", - "sha256:d636598c8305e1f90b439dbf4f66437de4a5e3c31fdf47ad29542478c8508bbb", - "sha256:deee1077aae10d8fa88cb02c845cfba9b62c55e1183f52f6ae6a2df6a2187160", - "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c", - "sha256:f030f8873312a16414c0d8e1a1ddff2d3235655a2174e3648b4fa66b3f2f1079", - "sha256:f0b278ce10936db1a37e6954e15a3730bea96a0997c26d7fee88e6c396c2086d", - "sha256:f11642dddbb0253cc8853254301b51390ba0081750a8ac03f20ea8103f0c56b6" + "sha256:16db4173575901db8f3e6cc05e50fe19c7849b0256f6dc2e0979485184053417", + "sha256:18183948d5480e2ae30ad67edddf748149c778592b7e4ee649c058d5de2dcbb1", + "sha256:22888d3ce1b6fa1125f0be1602d8c634e00e7ec3a87bdb594ad87bde0b00b2b6", + "sha256:23c1611471cbfa2ac0e283862a76a333c13e5e7c4d499feb9919a5f52884610e", + "sha256:2dcc6d62b69a82759e5dddd788e09dd329124e493e62d92cfd01c0b918d7e511", + "sha256:40e30139113b141c238620b700aa5bd5c1b3a7b29ae47398936ff1c9166109d9", + "sha256:4528368196a90f11b70fb5668c13d92e88ba795eb4d37aab5855fd0479db417b", + "sha256:4cbdc51fc8c00ec6e53b30221d5757034aecf9839761bf97eaec0db7f0ff4955", + "sha256:6a585ba4087cc1fb5bfe34d1ecaaee183b854427992be2b42f1722ba8289fa82", + "sha256:79c136327e90ee46a2b3094263df94da5212890d6145678741eb805d79714971", + "sha256:7beec4df7542cf681356ef243fee3bf948775fc0d125bdcad3508e834229e07d", + "sha256:8394626a07e0a1b3695a16a4548d32e7259e00817d4bab1ef8172a1bd82a724e", + "sha256:84a1000f622d1df8824cd1ac629aa8392679c5c4de3f0de9e6889373f99ff3a0", + "sha256:91cd79f0f2996a4de737de89fdcbcd379a5bfd7b15129378ad1e5fc234e58d33", + "sha256:951e8d7bc98bceb61fc4fb426966fae854160301c0f8cd0945c62f2504f68615", + "sha256:95d2293d6a60da8952c675050231c02c9f4f1c1b9cf916315173e921d137d683", + "sha256:9981294b131023e63061ba88f4498fe27b9b15d908079d1866ee66a63d6e793f", + "sha256:a8826f6ecf079cb648534790ba59218a64e12a59bf2cd9ff00199abb39864a79", + "sha256:c1630e847ae0a2a366f18ddc3e017b69f80d729e95830579c61b5f9e9b94b91e", + "sha256:c6f46d5bbec8fe1ff25215356e819528a90d84b2801703514746b665742f1cd2", + "sha256:c8099c7033fb1ca73ac2246c3e52f45dd6a9c3826c59b3b5ad94e5be4e08d99b", + "sha256:ceb872b89c6461d4365be5f8fbf14f867be6b5217760980de7e014e54648f8ef", + "sha256:d6fbe69d52628b3e8a144265fd134f5da07cf287a00cf529730ae10380d315b2", + "sha256:da7de6e4162c69cc03cc56b7d051ae11147ac30872ff57df4ba4cac6d70ce5d9", + "sha256:ddb2287f66500ac57b24cce60341074b148977b74cd20eca755f95262928086f", + "sha256:e6a4260f0abf90c023b4f838905f645695b31666b76837152e2befad3d1ef5d6", + "sha256:e97b387f2744762b9984639b59abd7abb46ea6ae2ea24cb7c07893612328559b", + "sha256:ea784c96ca3b94912176d7adc9c4bb7d1988f36a0223a9ac128f4c834775202c", + "sha256:f0b250a03891255feb3ae69ac29d05cf9a62f5869bb8bac0e7f4968e7274efac", + "sha256:fdaa96733c9cf85491ad406fd78aa16025a1ea468951545b3da7ee133c150c7a" ], "index": "pypi", - "version": "==5.5" + "version": "==6.0b1" }, "iniconfig": { "hashes": [ @@ -475,18 +430,26 @@ }, "pathspec": { "hashes": [ - "sha256:86379d6b86d75816baba717e64b1a3a3469deb93bb76d613c9ce79edc5cb68fd", - "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d" + "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a", + "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1" ], - "version": "==0.8.1" + "version": "==0.9.0" + }, + "platformdirs": { + "hashes": [ + "sha256:15b056538719b1c94bdaccb29e5f81879c7f7f0f4a153f46086d155dffcd4f0f", + "sha256:8003ac87717ae2c7ee1ea5a84a1a61e87f3fbd16eb5aadba194ea30a9019f648" + ], + "markers": "python_version >= '3.6'", + "version": "==2.3.0" }, "pluggy": { "hashes": [ - "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0", - "sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d" + "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", + "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.13.1" + "markers": "python_version >= '3.6'", + "version": "==1.0.0" }, "py": { "hashes": [ @@ -498,19 +461,19 @@ }, "pyparsing": { "hashes": [ - "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", - "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + "sha256:14e99e14e11a14cadf4d99effd4c5c30a9f46b116551ee69b4e5f8f6004f62d5", + "sha256:61b247121581f50c7988eece6ebb2d87ccc3be46c5552daf910d56e20cf6da75" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.7" + "markers": "python_version >= '3.5'", + "version": "==3.0.0rc1" }, "pytest": { "hashes": [ - "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b", - "sha256:91ef2131a9bd6be8f76f1f08eac5c5317221d6ad1e143ae03894b862e8976890" + "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89", + "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134" ], "index": "pypi", - "version": "==6.2.4" + "version": "==6.2.5" }, "pytest-cov": { "hashes": [ @@ -522,49 +485,49 @@ }, "regex": { "hashes": [ - "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f", - "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad", - "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a", - "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf", - "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59", - "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d", - "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895", - "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4", - "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3", - "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222", - "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0", - "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c", - "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417", - "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d", - "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d", - "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761", - "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0", - "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026", - "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854", - "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb", - "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d", - "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068", - "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde", - "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d", - "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec", - "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa", - "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd", - "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b", - "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26", - "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2", - "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f", - "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694", - "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0", - "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407", - "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874", - "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035", - "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d", - "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c", - "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5", - "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985", - "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58" - ], - "version": "==2021.7.6" + "sha256:04f6b9749e335bb0d2f68c707f23bb1773c3fb6ecd10edf0f04df12a8920d468", + "sha256:08d74bfaa4c7731b8dac0a992c63673a2782758f7cfad34cf9c1b9184f911354", + "sha256:0fc1f8f06977c2d4f5e3d3f0d4a08089be783973fc6b6e278bde01f0544ff308", + "sha256:121f4b3185feaade3f85f70294aef3f777199e9b5c0c0245c774ae884b110a2d", + "sha256:1413b5022ed6ac0d504ba425ef02549a57d0f4276de58e3ab7e82437892704fc", + "sha256:1743345e30917e8c574f273f51679c294effba6ad372db1967852f12c76759d8", + "sha256:28fc475f560d8f67cc8767b94db4c9440210f6958495aeae70fac8faec631797", + "sha256:31a99a4796bf5aefc8351e98507b09e1b09115574f7c9dbb9cf2111f7220d2e2", + "sha256:328a1fad67445550b982caa2a2a850da5989fd6595e858f02d04636e7f8b0b13", + "sha256:473858730ef6d6ff7f7d5f19452184cd0caa062a20047f6d6f3e135a4648865d", + "sha256:4cde065ab33bcaab774d84096fae266d9301d1a2f5519d7bd58fc55274afbf7a", + "sha256:5f6a808044faae658f546dd5f525e921de9fa409de7a5570865467f03a626fc0", + "sha256:610b690b406653c84b7cb6091facb3033500ee81089867ee7d59e675f9ca2b73", + "sha256:66256b6391c057305e5ae9209941ef63c33a476b73772ca967d4a2df70520ec1", + "sha256:6eebf512aa90751d5ef6a7c2ac9d60113f32e86e5687326a50d7686e309f66ed", + "sha256:79aef6b5cd41feff359acaf98e040844613ff5298d0d19c455b3d9ae0bc8c35a", + "sha256:808ee5834e06f57978da3e003ad9d6292de69d2bf6263662a1a8ae30788e080b", + "sha256:8e44769068d33e0ea6ccdf4b84d80c5afffe5207aa4d1881a629cf0ef3ec398f", + "sha256:999ad08220467b6ad4bd3dd34e65329dd5d0df9b31e47106105e407954965256", + "sha256:9b006628fe43aa69259ec04ca258d88ed19b64791693df59c422b607b6ece8bb", + "sha256:9d05ad5367c90814099000442b2125535e9d77581855b9bee8780f1b41f2b1a2", + "sha256:a577a21de2ef8059b58f79ff76a4da81c45a75fe0bfb09bc8b7bb4293fa18983", + "sha256:a617593aeacc7a691cc4af4a4410031654f2909053bd8c8e7db837f179a630eb", + "sha256:abb48494d88e8a82601af905143e0de838c776c1241d92021e9256d5515b3645", + "sha256:ac88856a8cbccfc14f1b2d0b829af354cc1743cb375e7f04251ae73b2af6adf8", + "sha256:b4c220a1fe0d2c622493b0a1fd48f8f991998fb447d3cd368033a4b86cf1127a", + "sha256:b844fb09bd9936ed158ff9df0ab601e2045b316b17aa8b931857365ea8586906", + "sha256:bdc178caebd0f338d57ae445ef8e9b737ddf8fbc3ea187603f65aec5b041248f", + "sha256:c206587c83e795d417ed3adc8453a791f6d36b67c81416676cad053b4104152c", + "sha256:c61dcc1cf9fd165127a2853e2c31eb4fb961a4f26b394ac9fe5669c7a6592892", + "sha256:c7cb4c512d2d3b0870e00fbbac2f291d4b4bf2634d59a31176a87afe2777c6f0", + "sha256:d4a332404baa6665b54e5d283b4262f41f2103c255897084ec8f5487ce7b9e8e", + "sha256:d5111d4c843d80202e62b4fdbb4920db1dcee4f9366d6b03294f45ed7b18b42e", + "sha256:e1e8406b895aba6caa63d9fd1b6b1700d7e4825f78ccb1e5260551d168db38ed", + "sha256:e8690ed94481f219a7a967c118abaf71ccc440f69acd583cab721b90eeedb77c", + "sha256:ed283ab3a01d8b53de3a05bfdf4473ae24e43caee7dcb5584e86f3f3e5ab4374", + "sha256:ed4b50355b066796dacdd1cf538f2ce57275d001838f9b132fab80b75e8c84dd", + "sha256:ee329d0387b5b41a5dddbb6243a21cb7896587a651bebb957e2d2bb8b63c0791", + "sha256:f3bf1bc02bc421047bfec3343729c4bbbea42605bcfd6d6bfe2c07ade8b12d2a", + "sha256:f585cbbeecb35f35609edccb95efd95a3e35824cd7752b586503f7e6087303f1", + "sha256:f60667673ff9c249709160529ab39667d1ae9fd38634e006bec95611f632e759" + ], + "version": "==2021.8.28" }, "toml": { "hashes": [ @@ -573,6 +536,22 @@ ], "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" + }, + "tomli": { + "hashes": [ + "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f", + "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442" + ], + "markers": "python_version >= '3.6'", + "version": "==1.2.1" + }, + "typing-extensions": { + "hashes": [ + "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e", + "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7", + "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34" + ], + "version": "==3.10.0.2" } } } From 7dbaa31aca069df49e996c093ab9610b9bb6e672 Mon Sep 17 00:00:00 2001 From: Jon Hagg Date: Fri, 24 Sep 2021 15:21:33 -0700 Subject: [PATCH 10/21] chore: prevent import failure by ignoring files --- .../data_access/tests/{ => sql}/test_execute_table.py | 0 .../data_access/tests/{ => sql}/test_scenario_table.py | 0 .../data_access/tests/{ => sql}/test_sql_store.py | 0 pytest.ini | 7 ------- tox.ini | 8 ++++++++ 5 files changed, 8 insertions(+), 7 deletions(-) rename powersimdata/data_access/tests/{ => sql}/test_execute_table.py (100%) rename powersimdata/data_access/tests/{ => sql}/test_scenario_table.py (100%) rename powersimdata/data_access/tests/{ => sql}/test_sql_store.py (100%) delete mode 100644 pytest.ini diff --git a/powersimdata/data_access/tests/test_execute_table.py b/powersimdata/data_access/tests/sql/test_execute_table.py similarity index 100% rename from powersimdata/data_access/tests/test_execute_table.py rename to powersimdata/data_access/tests/sql/test_execute_table.py diff --git a/powersimdata/data_access/tests/test_scenario_table.py b/powersimdata/data_access/tests/sql/test_scenario_table.py similarity index 100% rename from powersimdata/data_access/tests/test_scenario_table.py rename to powersimdata/data_access/tests/sql/test_scenario_table.py diff --git a/powersimdata/data_access/tests/test_sql_store.py b/powersimdata/data_access/tests/sql/test_sql_store.py similarity index 100% rename from powersimdata/data_access/tests/test_sql_store.py rename to powersimdata/data_access/tests/sql/test_sql_store.py diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 4c08f3262..000000000 --- a/pytest.ini +++ /dev/null @@ -1,7 +0,0 @@ -[pytest] -addopts = --cov=powersimdata -markers = - integration: marks tests that require external dependencies (deselect with '-m "not integration"') - db: marks tests that connect to a local database - ssh: marks tests that connect to the server over ssh - wip: marks tests undergoing development diff --git a/tox.ini b/tox.ini index 3f8679dd4..b0ba5640a 100644 --- a/tox.ini +++ b/tox.ini @@ -27,3 +27,11 @@ ignore = E501,W503,E741,E203,W605 [isort] profile = black + +[pytest] +addopts = --cov=powersimdata --ignore-glob=**/sql/* +markers = + integration: marks tests that require external dependencies (deselect with '-m "not integration"') + db: marks tests that connect to a local database + ssh: marks tests that connect to the server over ssh + wip: marks tests undergoing development From fcf20528525668f8a23521a26cc32f44e4634a96 Mon Sep 17 00:00:00 2001 From: Ben RdO Date: Tue, 5 Oct 2021 20:42:09 -0700 Subject: [PATCH 11/21] docs: improve section on documentation in README (#558) --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c328eb8ea..4e3082d3e 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,8 @@ pip install -r requirements.txt ## Documentation -The official documentation can be found [here][docs]. +[Code documentation][docstrings] in form of Python docstrings along with an overview of +the [package][docs] are available on our [website][website]. ## Communication Channels @@ -82,4 +83,6 @@ Guide](https://breakthrough-energy.github.io/docs/dev/contribution_guide.html). -[docs]: https://breakthrough-energy.github.io/docs/index.html +[docs]: https://breakthrough-energy.github.io/docs/powersimdata/index.html +[docstrings]: https://breakthrough-energy.github.io/docs/powersimdata.html +[website]: https://breakthrough-energy.github.io/docs/ From be032b90cbf24432a31e59030bef290593a45eff Mon Sep 17 00:00:00 2001 From: Ben RdO Date: Tue, 12 Oct 2021 10:05:36 -0700 Subject: [PATCH 12/21] docs: change author (#559) --- setup.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 78217806a..53523b4a9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,8 +1,8 @@ [metadata] name = powersimdata version = 0.4.4 -author = Kaspar Mueller -author_email = kaspar@breakthroughenergy.org +author = Breakthrough Energy +author_email = sciences@breakthroughenergy.org description = Power Simulation Data long_description = file: README.md long_description_content_type = text/markdown @@ -33,7 +33,7 @@ install_requires = fs.sshfs [options.package_data] -powersimdata = +powersimdata = network/*/data/*.csv design/investment/data/*.csv design/investment/data/*/* From 8aa6d3974b005546d25f972d4f18a11ade86f548 Mon Sep 17 00:00:00 2001 From: jon-hagg <66005238+jon-hagg@users.noreply.github.com> Date: Wed, 20 Oct 2021 14:34:32 -0700 Subject: [PATCH 13/21] fix: prevent max recursion error (#563) Co-authored-by: Jon Hagg --- powersimdata/data_access/launcher.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/powersimdata/data_access/launcher.py b/powersimdata/data_access/launcher.py index 8598eea2e..daae53ae5 100644 --- a/powersimdata/data_access/launcher.py +++ b/powersimdata/data_access/launcher.py @@ -46,7 +46,10 @@ class Launcher: def __init__(self, scenario): self.scenario = scenario - self.scenario_id = scenario.scenario_id + + @property + def scenario_id(self): + return self.scenario.scenario_id def _launch(self, threads=None, solver=None, extract_data=True): """Launches simulation on target environment From ee0bd1ed07be0a6ce164185b70b43f55eeae6882 Mon Sep 17 00:00:00 2001 From: jon-hagg <66005238+jon-hagg@users.noreply.github.com> Date: Wed, 20 Oct 2021 15:58:48 -0700 Subject: [PATCH 14/21] refactor: simplify _check_file_exists and get_profile_version (#562) Co-authored-by: Jon Hagg --- powersimdata/data_access/data_access.py | 26 ++++++++----------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/powersimdata/data_access/data_access.py b/powersimdata/data_access/data_access.py index 55210f8aa..541519446 100644 --- a/powersimdata/data_access/data_access.py +++ b/powersimdata/data_access/data_access.py @@ -1,4 +1,3 @@ -import operator import posixpath import time from subprocess import Popen @@ -84,11 +83,11 @@ def _check_file_exists(self, path, should_exist=True): :param bool should_exist: whether the file is expected to exist :raises OSError: if the expected condition is not met """ - result = self.fs.exists(path) - compare = operator.ne if should_exist else operator.eq - if compare(result, True): - msg = "not found" if should_exist else "already exists" - raise OSError(f"{path} {msg} on {self.description}") + exists = self.fs.exists(path) + if should_exist and not exists: + raise OSError(f"{path} not found on {self.description}") + if not should_exist and exists: + raise OSError(f"{path} already exists on {self.description}") def makedir(self, path): """Create path in current environment @@ -128,7 +127,9 @@ def get_profile_version(self, grid_model, kind): :param str kind: *'demand'*, *'hydro'*, *'solar'* or *'wind'*. :return: (*list*) -- available profile version. """ - return ProfileHelper.get_profile_version_cloud(grid_model, kind) + blob_version = ProfileHelper.get_profile_version_cloud(grid_model, kind) + local_version = ProfileHelper.get_profile_version_local(grid_model, kind) + return list(set(blob_version + local_version)) class LocalDataAccess(DataAccess): @@ -170,17 +171,6 @@ def move_to(self, file_name, to_dir, change_name_to=None): self.makedir(to_dir) self.fs.move(file_name, dest) - def get_profile_version(self, grid_model, kind): - """Returns available raw profile from blob storage or local disk - - :param str grid_model: grid model. - :param str kind: *'demand'*, *'hydro'*, *'solar'* or *'wind'*. - :return: (*list*) -- available profile version. - """ - blob_version = super().get_profile_version(grid_model, kind) - local_version = ProfileHelper.get_profile_version_local(grid_model, kind) - return list(set(blob_version + local_version)) - class SSHDataAccess(DataAccess): """Interface to a remote data store, accessed via SSH.""" From 7a8d26deeee211b52a4f46ace8b986de585c1ecb Mon Sep 17 00:00:00 2001 From: Kaspar Mueller Date: Thu, 21 Oct 2021 16:49:21 -0700 Subject: [PATCH 15/21] fix: resolve _scenario_info property for state, fix typo, change ssh to fs according to PR #520 --- powersimdata/data_access/launcher.py | 4 ++-- powersimdata/data_access/tests/test_data_access.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/powersimdata/data_access/launcher.py b/powersimdata/data_access/launcher.py index daae53ae5..56e16359a 100644 --- a/powersimdata/data_access/launcher.py +++ b/powersimdata/data_access/launcher.py @@ -96,7 +96,7 @@ def _run_script(self, script, extra_args=None): if extra_args is None: extra_args = [] - engine = self.scenario._scenario_info["engine"] + engine = self.scenario.state._scenario_info["engine"] path_to_package = posixpath.join(server_setup.MODEL_DIR, engine) folder = "pyreise" if engine == "REISE" else "pyreisejl" @@ -111,7 +111,7 @@ def _run_script(self, script, extra_args=None): ] cmd_io_redirect = ["/dev/null 2>&1 &"] cmd = cmd_pythonpath + cmd_pythoncall + extra_args + cmd_io_redirect - process = self.scenario._data_access.execute_command_async(cmd) + process = self.scenario.data_access.execute_command_async(cmd) print("PID: %s" % process.pid) return process diff --git a/powersimdata/data_access/tests/test_data_access.py b/powersimdata/data_access/tests/test_data_access.py index ad46b3466..4106f5cd6 100644 --- a/powersimdata/data_access/tests/test_data_access.py +++ b/powersimdata/data_access/tests/test_data_access.py @@ -42,7 +42,7 @@ def test_tmp_folder(ssh_data_access): @pytest.mark.integration @pytest.mark.ssh def test_setup_server_connection(ssh_data_access): - _, stdout, _ = ssh_data_access.ssh.exec_command("whoami") + _, stdout, _ = ssh_data_access.fs.exec_command("whoami") assert stdout.read().decode("utf-8").strip() == server_setup.get_server_user() From 0415ef42675918efa15e70c924b04712d2587f9e Mon Sep 17 00:00:00 2001 From: Daniel Olsen Date: Tue, 28 Sep 2021 14:43:34 -0700 Subject: [PATCH 16/21] feat: add ChangeTable methods to remove elements --- powersimdata/input/change_table.py | 197 ++++++++++++++++++++++++++--- 1 file changed, 177 insertions(+), 20 deletions(-) diff --git a/powersimdata/input/change_table.py b/powersimdata/input/change_table.py index 53423a79f..e1e2c9bd8 100644 --- a/powersimdata/input/change_table.py +++ b/powersimdata/input/change_table.py @@ -1,6 +1,7 @@ import copy import os import pickle +from itertools import chain from powersimdata.design.transmission.upgrade import ( scale_congested_mesh_branches, @@ -124,6 +125,14 @@ class ChangeTable: keys in the dictionary are: *'lat'*, *'lon'*, one of *'zone_id'*/*'zone_name'*, and optionally *'Pd'*, specifying the location of the bus, the demand zone, and optionally the nominal demand at that bus (defaults to 0). + * *'remove_branch'*: + value is a set. Each entry in this set is a branch ID to be removed. + * *'remove_bus'*: + value is a set. Each entry in this set is a bus ID to be removed. + * *'remove_dcline'*: + value is a set. Each entry in this set is a DC line ID to be removed. + * *'remove_plant'*: + value is a set. Each entry in this set is a plant ID to be removed. """ def __init__(self, grid): @@ -133,7 +142,9 @@ def __init__(self, grid): """ self.grid = grid self.ct = {} - self._new_element_caches = {k: {} for k in {"branch", "bus", "dcline", "plant"}} + self._new_element_caches = { + k: {} for k in {"branch", "bus", "dcline", "plant", "storage_gen"} + } @staticmethod def _check_resource(resource): @@ -199,7 +210,7 @@ def clear(self, which=None): self.ct.clear() return # Input validation - allowed = {"branch", "dcline", "demand", "plant", "storage"} + allowed = {"branch", "bus", "dcline", "demand", "plant", "storage"} if isinstance(which, str): which = {which} if not isinstance(which, set): @@ -213,13 +224,19 @@ def clear(self, which=None): # Clear multiple keys for each entry in which for line_type in {"branch", "dcline"}: if line_type in which: - for prefix in {"", "new_"}: + for prefix in {"", "new_", "remove_"}: key = prefix + line_type if key in self.ct: del self.ct[key] + if "bus" in which: + for prefix in {"new_", "remove_"}: + key = prefix + "bus" + if key in self.ct: + del self.ct[key] if "plant" in which: - if "new_plant" in self.ct: - del self.ct["new_plant"] + for key in {"new_plant", "remove_plant"}: + if key in self.ct: + del self.ct[key] for r in _resources: for suffix in {"", "_cost", "_pmin"}: key = r + suffix @@ -262,7 +279,7 @@ def _add_plant_entries(self, resource, ct_key, zone_name=None, plant_id=None): if len(self.ct[ct_key]["zone_id"]) == 0: self.ct.pop(ct_key) if plant_id is not None: - anticipated_plant = self._get_df_with_new_elements("plant") + anticipated_plant = self._get_transformed_df("plant") diff = set(plant_id.keys()) - set(anticipated_plant.index) if len(diff) != 0: err_msg = f"No {resource} plant(s) with the following id: " @@ -352,7 +369,7 @@ def scale_branch_capacity(self, zone_name=None, branch_id=None): is (are) the id of the line(s) and the associated value is the scaling factor for the increase/decrease in capacity of the line(s). """ - anticipated_branch = self._get_df_with_new_elements("branch") + anticipated_branch = self._get_transformed_df("branch") if bool(zone_name) or bool(branch_id) is True: if "branch" not in self.ct: self.ct["branch"] = {} @@ -392,7 +409,7 @@ def scale_dcline_capacity(self, dcline_id): """ if "dcline" not in self.ct: self.ct["dcline"] = {} - anticipated_dcline = self._get_df_with_new_elements("dcline") + anticipated_dcline = self._get_transformed_df("dcline") diff = set(dcline_id.keys()) - set(anticipated_dcline.index) if len(diff) != 0: print("No dc line with the following id:") @@ -505,7 +522,7 @@ def add_storage_capacity(self, info): "terminal_min", "terminal_max", } - anticipated_bus = self._get_df_with_new_elements("bus") + anticipated_bus = self._get_transformed_df("bus") for i, storage in enumerate(info): self._check_entry_keys(storage, i, "storage", required, None, optional) if storage["bus_id"] not in anticipated_bus.index: @@ -609,7 +626,7 @@ def _add_line(self, key, info): :raises ValueError: if any of the new lines to be added have nonsensical values. """ info = copy.deepcopy(info) - anticipated_bus = self._get_df_with_new_elements("bus") + anticipated_bus = self._get_transformed_df("bus") new_lines = [] required = {"from_bus_id", "to_bus_id"} xor_sets = {("capacity", "Pmax"), ("capacity", "Pmin")} @@ -684,7 +701,7 @@ def add_plant(self, info): raise TypeError("Argument enclosing new plant(s) must be a list") info = copy.deepcopy(info) - anticipated_bus = self._get_df_with_new_elements("bus") + anticipated_bus = self._get_transformed_df("bus") new_plants = [] required = {"bus_id", "Pmax", "type"} optional = {"c0", "c1", "c2", "Pmin"} @@ -781,25 +798,165 @@ def add_bus(self, info): self.ct["new_bus"] = [] self.ct["new_bus"] += new_buses - def _get_df_with_new_elements(self, table): + def _get_transformed_df(self, table): """Get a post-transformation data table, for use with adding elements at new - buses, or scaling new elements. + buses, or scaling new elements. Transformed tables are cached to avoid + unnecessary re-calculation of identical tables. :param str table: the table of the grid to be fetched: - 'branch', 'bus', 'dcline', or 'plant'. + 'branch', 'bus', 'dcline', 'plant', or 'storage_gen'. :return: (*pandas.DataFrame*) -- the post-transformation table. """ - add_key = f"new_{table}" - if add_key not in self.ct: + if table == "storage_gen": + # Storage is a special case, since it's a dict of data frames + modification_keys = ["storage"] + try: + cache_key = tuple(tuple(sorted(b.items())) for b in self.ct["storage"]) + except KeyError: + # No 'storage' key, so we can just return the original 'gen' table + return self.grid.storage["gen"] + if cache_key in self._new_element_caches[table]: + return self._new_element_caches[table][cache_key] + else: + gen = TransformGrid(self.grid, self.ct).get_grid().storage["gen"] + self._new_element_caches[table][cache_key] = gen + return gen.copy() + # For all other tables, look at change table keys for additions & deletions + modification_keys = [f"new_{table}", f"remove_{table}"] + cache_key = tuple( + tuple(sorted(b.items())) for b in self.ct.get(f"new_{table}", {}) + ) + cache_key += ( + f"remove_{table}", + tuple(sorted(self.ct.get(f"remove_{table}", {}))), + ) + if table == "plant": + # For the plant table, also look at scaling (potentially to zero) + # These are needed to validate whether buses can be removed + modification_keys += sorted(self.grid.plant["type"].unique()) + cache_key += tuple( + chain.from_iterable( + [ + tuple([subkey] + sorted(subdict.items())) + for k in modification_keys[1:] + for subkey, subdict in self.ct.get(k, {}).items() + ] + ) + ) + if not any(m in self.ct for m in modification_keys): return getattr(self.grid, table) - new_elements_tuple = tuple(tuple(sorted(b.items())) for b in self.ct[add_key]) - if new_elements_tuple in self._new_element_caches[table]: - return self._new_element_caches[table][new_elements_tuple] + if cache_key in self._new_element_caches[table]: + return self._new_element_caches[table][cache_key] else: transformed = getattr(TransformGrid(self.grid, self.ct).get_grid(), table) - self._new_element_caches[table][new_elements_tuple] = transformed + self._new_element_caches[table][cache_key] = transformed return transformed.copy() + def remove_branch(self, info): + """Remove one or more branches. + + :param int/iterable info: iterable of branch indices, or a single branch index. + :raises ValueError: if ``info`` contains one or more entries not present in the + branch table index. + """ + if isinstance(info, int): + info = {info} + diff = set(info) - set(self._get_transformed_df("branch").index) + if len(diff) != 0: + raise ValueError(f"No branch with the following id(s): {sorted(diff)}") + if "remove_branch" not in self.ct: + self.ct["remove_branch"] = set() + self.ct["remove_branch"] |= set(info) + self._check_for_islanded_load_buses() + + def remove_bus(self, info): + """Remove one or more buses. + + :param int/iterable info: iterable of bus indices, or a single bus index. + :raises ValueError: if ``info`` contains one or more entries not present in the + bus table index. + """ + if isinstance(info, int): + info = {info} + # Check whether all buses to be removed are present in the grid + diff = set(info) - set(self._get_transformed_df("bus").index) + if len(diff) != 0: + raise ValueError(f"No bus with the following id(s): {sorted(diff)}") + # Check whether there exist any plants with non-zero capacity at these buses + anticipated_plant = self._get_transformed_df("plant").query("Pmax > 0") + plants_at_removal_buses = set(info) & set(anticipated_plant.bus_id) + if len(plants_at_removal_buses) > 0: + raise ValueError( + f"Generators exist at bus id(s): {sorted(plants_at_removal_buses)}" + ) + # Check whether storage exists at these buses + anticipated_storage = self._get_transformed_df("storage_gen") + storage_at_removal_buses = set(info) & set(anticipated_storage.bus_id) + if len(storage_at_removal_buses) > 0: + raise ValueError( + f"Storage units exist at bus id(s): {sorted(storage_at_removal_buses)}" + ) + # Check whether there exist branches or DC lines at these buses + for table in ("branch", "dcline"): + anticipated = self._get_transformed_df(table) + overlap = anticipated.query("from_bus_id in @info or to_bus_id in @info") + if len(overlap) > 0: + raise ValueError( + f"These {table} IDs connect to a bus to be removed: {overlap.index}" + ) + # All checks have passed, and we can add this to the change table + if "remove_bus" not in self.ct: + self.ct["remove_bus"] = set() + self.ct["remove_bus"] |= set(info) + + def remove_dcline(self, info): + """Remove one or more DC lines. + + :param int/iterable info: iterable of DC line indices, or a single index. + :raises ValueError: if ``info`` contains one or more entries not present in the + dcline table index. + """ + if isinstance(info, int): + info = {info} + diff = set(info) - set(self._get_transformed_df("dcline").index) + if len(diff) != 0: + raise ValueError(f"No DC line with the following id(s): {sorted(diff)}") + if "remove_dcline" not in self.ct: + self.ct["remove_dcline"] = set() + self.ct["remove_dcline"] |= set(info) + + def remove_plant(self, info): + """Remove one or more plants. + + :param int/iterable info: iterable of plant indices, or a single plant index. + :raises ValueError: if ``info`` contains one or more entries not present in the + plant table index. + """ + if isinstance(info, int): + info = {info} + diff = set(info) - set(self._get_transformed_df("plant").index) + if len(diff) != 0: + raise ValueError(f"No plant with the following id(s): {sorted(diff)}") + if "remove_plant" not in self.ct: + self.ct["remove_plant"] = set() + self.ct["remove_plant"] |= set(info) + + def _check_for_islanded_load_buses(self): + """Identifies buses with non-zero demand, with no connected lines, and warns.""" + bus = self._get_transformed_df("bus") + connected_buses = set().union( + *[ + set(self.grid.branch["from_bus_id"]), + set(self.grid.branch["to_bus_id"]), + set(self.grid.dcline["from_bus_id"]), + set(self.grid.dcline["to_bus_id"]), + ] + ) + load_buses = set(bus.query("Pd > 0").index) + diff = load_buses - connected_buses + if len(diff) > 0: + print(f"Warning: load buses connected to no lines exist: {sorted(diff)}") + def write(self, scenario_id): """Saves change table to disk. From 87e43690e7864da1625574f21693e6b1d699eea6 Mon Sep 17 00:00:00 2001 From: Daniel Olsen Date: Tue, 28 Sep 2021 14:58:47 -0700 Subject: [PATCH 17/21] feat: add element removal methods to TransformGrid --- powersimdata/input/transform_grid.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/powersimdata/input/transform_grid.py b/powersimdata/input/transform_grid.py index 004886dd7..b9bd319e1 100644 --- a/powersimdata/input/transform_grid.py +++ b/powersimdata/input/transform_grid.py @@ -71,7 +71,7 @@ def _apply_change_table(self): if "storage" in self.ct.keys(): self._add_storage() - # Finally, scale by IDs, so that additions can be scaled. + # Scale by IDs, so that additions can be scaled. for g in self.gen_types: if g in self.ct.keys(): self._scale_gen_by_id(g) @@ -86,6 +86,12 @@ def _apply_change_table(self): if "dcline" in self.ct.keys(): self._scale_dcline() + # Finally, remove elements (so that removal doesn't cause downstream errors) + if "remove_branch" in self.ct.keys(): + self._remove_branch() + if "remove_bus" in self.ct.keys(): + self._remove_bus() + def _scale_gen_by_zone(self, gen_type): """Scales capacity of generators, by zone. Also scales the associated generation cost curve (to maintain the same slopes at the start/end of the curve). @@ -473,6 +479,26 @@ def _add_storage_data(self, storage_id, entry): # Maintain int columns after the append converts them to float storage["StorageData"] = storage["StorageData"].astype({"UnitIdx": "int"}) + def _remove_branch(self): + """Removes branches.""" + branch = self.grid.branch + self.grid.branch = branch.loc[~branch.index.isin(self.ct["remove_branch"])] + + def _remove_bus(self): + """Removes buses.""" + bus = self.grid.bus + self.grid.bus = bus.loc[~bus.index.isin(self.ct["remove_bus"])] + + def _remove_dcline(self): + """Removes DC lines.""" + dcline = self.grid.dcline + self.grid.dcline = dcline.loc[~dcline.index.isin(self.ct["remove_dcline"])] + + def _remove_plant(self): + """Removes plants.""" + plant = self.grid.plant + self.grid.plant = plant.loc[~plant.index.isin(self.ct["remove_plant"])] + def voltage_to_x_per_distance(grid): """Calculates reactance per distance for voltage level. From 1bbd03c6208c6634dcd6a31f2238a2cea160706e Mon Sep 17 00:00:00 2001 From: Daniel Olsen Date: Tue, 28 Sep 2021 15:22:32 -0700 Subject: [PATCH 18/21] test: add tests for ChangeTable/TransformGrid element removal --- powersimdata/input/tests/test_change_table.py | 25 +++++++++++++++++++ .../input/tests/test_transform_grid.py | 20 +++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/powersimdata/input/tests/test_change_table.py b/powersimdata/input/tests/test_change_table.py index be3c1b8be..19447a157 100644 --- a/powersimdata/input/tests/test_change_table.py +++ b/powersimdata/input/tests/test_change_table.py @@ -467,3 +467,28 @@ def test_change_table_clear_bad_type(ct): def test_change_table_clear_bad_key(ct): with pytest.raises(ValueError): ct.clear({"plantttt"}) + + +def test_remove_branch(ct): + ct.remove_branch({0}) + with pytest.raises(ValueError): + # Can't remove again, because it shouldn't exist + ct.remove_branch({0}) + + +def test_remove_bus(ct): + with pytest.raises(ValueError): + # Can't remove, because there are branches attached to it + ct.remove_bus({1}) + ct.remove_branch({0, 1, 2}) + ct.remove_bus({1}) + with pytest.raises(ValueError): + # Can't remove again, because it shouldn't exist + ct.remove_bus({1}) + # Evan after we remove the branch connected to bus 845... + ct.remove_branch({1094}) + with pytest.raises(ValueError): + # We can't remove this bus, since there's a generator with non-zero capacity + ct.remove_bus({845}) + ct.scale_plant_capacity(resource="ng", plant_id={0: 0}) + ct.remove_bus({845}) diff --git a/powersimdata/input/tests/test_transform_grid.py b/powersimdata/input/tests/test_transform_grid.py index 2e52c8cac..f7c0cb093 100644 --- a/powersimdata/input/tests/test_transform_grid.py +++ b/powersimdata/input/tests/test_transform_grid.py @@ -558,3 +558,23 @@ def test_add_bus(ct): assert new_grid.bus.index.dtype == grid.bus.index.dtype assert new_grid.bus2sub.index.dtype == grid.bus2sub.index.dtype assert new_grid.sub.index.dtype == grid.sub.index.dtype + + +def test_remove_branch(ct): + assert 0 in grid.branch.index + ct.ct["remove_branch"] = {0} + new_grid = TransformGrid(grid, ct.ct).get_grid() + assert 0 not in new_grid.branch.index + ct.ct["remove_branch"] = {1, 2} + new_grid = TransformGrid(grid, ct.ct).get_grid() + assert all(i not in new_grid.branch.index for i in [1, 2]) + + +def test_remove_bus(ct): + assert 1 in grid.bus.index + ct.ct["remove_bus"] = {1} + new_grid = TransformGrid(grid, ct.ct).get_grid() + assert 1 not in new_grid.bus.index + ct.ct["remove_bus"] = {2, 3} + new_grid = TransformGrid(grid, ct.ct).get_grid() + assert all(i not in new_grid.bus.index for i in [2, 3]) From 4585721af2ebbf0549535068c9e2b13c61b58027 Mon Sep 17 00:00:00 2001 From: Lane Smith <40651626+lanesmith@users.noreply.github.com> Date: Wed, 5 Jan 2022 18:30:36 -0800 Subject: [PATCH 19/21] feat: add mapping from state abbreviations to load zone IDs (#568) --- powersimdata/network/usa_tamu/constants/zones.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/powersimdata/network/usa_tamu/constants/zones.py b/powersimdata/network/usa_tamu/constants/zones.py index 68c0adcb1..8b8338bca 100644 --- a/powersimdata/network/usa_tamu/constants/zones.py +++ b/powersimdata/network/usa_tamu/constants/zones.py @@ -1,9 +1,11 @@ import os +from collections import defaultdict import pandas as pd _exports = [ "abv", + "abv2id", "abv2interconnect", "abv2loadzone", "abv2state", @@ -129,6 +131,10 @@ # Map load zone id to state abbreviations id2abv = {k: state2abv[v] for k, v in zone_df.state.to_dict().items()} +# Map state abbreviations to load zone IDs +abv2id = defaultdict(set) +for k, v in id2abv.items(): + abv2id[v].add(k) # Map state abbreviations to load zone name abv2loadzone = { From 13ca189099271eaf48c139f99d92f58bdb97f75b Mon Sep 17 00:00:00 2001 From: Kaspar Mueller Date: Fri, 7 Jan 2022 19:24:56 -0800 Subject: [PATCH 20/21] chore: update assignees for issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index fc826015b..c25a24de7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -3,7 +3,7 @@ name: Bug report about: Create a report to help us improve title: Bug report labels: bug -assignees: ahurli, BainanXia, danielolsen, jon-hagg, rouille +assignees: BainanXia, danielolsen, jon-hagg, rouille --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index eed038089..5f3ec88d9 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -3,7 +3,7 @@ name: Feature request about: Suggest an idea for this project title: Feature request labels: feature request -assignees: ahurli, BainanXia, danielolsen, jon-hagg, rouille +assignees: BainanXia, danielolsen, jon-hagg, rouille --- From 97c75c28c75fea5d14db2252db13965acdded49a Mon Sep 17 00:00:00 2001 From: jon-hagg <66005238+jon-hagg@users.noreply.github.com> Date: Tue, 11 Jan 2022 13:24:26 -0800 Subject: [PATCH 21/21] chore: bump version number to v0.4.5 (#571) --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 53523b4a9..3afca991d 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = powersimdata -version = 0.4.4 +version = 0.4.5 author = Breakthrough Energy author_email = sciences@breakthroughenergy.org description = Power Simulation Data