pandahub 0.3.17__zip → 0.4.1__zip

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. {pandahub-0.3.17 → pandahub-0.4.1}/CHANGELOG.md +3 -0
  2. {pandahub-0.3.17 → pandahub-0.4.1}/PKG-INFO +1 -1
  3. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/PandaHub.py +184 -206
  4. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/datatypes.py +2 -10
  5. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/mongo_client.py +17 -4
  6. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/PKG-INFO +1 -1
  7. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/requires.txt +1 -1
  8. {pandahub-0.3.17 → pandahub-0.4.1}/pyproject.toml +1 -1
  9. {pandahub-0.3.17 → pandahub-0.4.1}/requirements.txt +1 -1
  10. {pandahub-0.3.17 → pandahub-0.4.1}/test/performance_test.py +1 -1
  11. {pandahub-0.3.17 → pandahub-0.4.1}/test/test_networks.py +3 -3
  12. {pandahub-0.3.17 → pandahub-0.4.1}/CONTRIBUTING.rst +0 -0
  13. {pandahub-0.3.17 → pandahub-0.4.1}/LICENSE +0 -0
  14. {pandahub-0.3.17 → pandahub-0.4.1}/MANIFEST.in +0 -0
  15. {pandahub-0.3.17 → pandahub-0.4.1}/README.md +0 -0
  16. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/__init__.py +0 -0
  17. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/__init__.py +0 -0
  18. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/dependencies.py +0 -0
  19. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/__init__.py +0 -0
  20. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/db.py +0 -0
  21. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/schemas.py +0 -0
  22. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/settings.py +0 -0
  23. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/toolbox.py +0 -0
  24. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/internal/users.py +0 -0
  25. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/main.py +0 -0
  26. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/__init__.py +0 -0
  27. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/auth.py +0 -0
  28. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/net.py +0 -0
  29. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/projects.py +0 -0
  30. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/timeseries.py +0 -0
  31. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/users.py +0 -0
  32. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/api/routers/variants.py +0 -0
  33. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/__init__.py +0 -0
  34. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/database_toolbox.py +0 -0
  35. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/mongodb_indexes.py +0 -0
  36. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/__init__.py +0 -0
  37. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/data_sources/__init__.py +0 -0
  38. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/data_sources/mongo_data.py +0 -0
  39. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub/lib/timeseries/output_writer_mongodb.py +0 -0
  40. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/SOURCES.txt +0 -0
  41. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/dependency_links.txt +0 -0
  42. {pandahub-0.3.17 → pandahub-0.4.1}/pandahub.egg-info/top_level.txt +0 -0
  43. {pandahub-0.3.17 → pandahub-0.4.1}/setup.cfg +0 -0
  44. {pandahub-0.3.17 → pandahub-0.4.1}/setup.py +0 -0
  45. {pandahub-0.3.17 → pandahub-0.4.1}/test/__init__.py +0 -0
  46. {pandahub-0.3.17 → pandahub-0.4.1}/test/conftest.py +0 -0
  47. {pandahub-0.3.17 → pandahub-0.4.1}/test/test_client.py +0 -0
  48. {pandahub-0.3.17 → pandahub-0.4.1}/test/test_projects.py +0 -0
  49. {pandahub-0.3.17 → pandahub-0.4.1}/test/test_timeseries.py +0 -0
  50. {pandahub-0.3.17 → pandahub-0.4.1}/tutorials/config.py +0 -0
@@ -1,5 +1,8 @@
1
1
  # Change Log
2
2
 
3
+ ## [0.4.0]
4
+ - IMPROVED: pandapower 3.0 support
5
+
3
6
  ## [0.3.13]
4
7
  - FIXED: fetching integer index on empty collection
5
8
  - IMPROVED: context manager for mongo client /database / collection
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pandahub
3
- Version: 0.3.17
3
+ Version: 0.4.1
4
4
  Summary: Data hub for pandapower and pandapipes networks based on MongoDB
5
5
  Author-email: Jan Ulffers <jan.ulffers@iee.fraunhofer.de>, Leon Thurner <leon.thurner@retoflow.de>, Jannis Kupka <jannis.kupka@retoflow.de>, Mike Vogt <mike.vogt@iee.fraunhofer.de>, Joschka Thurner <joschka.thurner@retoflow.de>, Alexander Scheidler <alexander.scheidler@iee.fraunhofer.de>
6
6
  License: Copyright (c) 2022 by University of Kassel, Fraunhofer Institute for Energy Economics
@@ -4,28 +4,29 @@ import json
4
4
  import logging
5
5
  import time
6
6
  import warnings
7
- from inspect import signature, _empty
8
7
  from collections.abc import Callable
8
+ from functools import reduce
9
+ from inspect import signature, _empty
10
+ from itertools import chain
11
+ from operator import getitem
9
12
  from types import NoneType
10
13
  from typing import Optional, Union, TypeVar
14
+ from uuid import UUID
11
15
 
12
16
  import numpy as np
17
+ import pandapipes as pps
18
+ import pandapower as pp
19
+ import pandapower.io_utils as io_pp
13
20
  import pandas as pd
14
21
  from bson.errors import InvalidId
15
22
  from bson.objectid import ObjectId
16
- from functools import reduce
17
- from operator import getitem
18
- from uuid import UUID
23
+ from pandapipes import from_json_string as from_json_pps, FromSerializableRegistryPpipe, BranchComponent
24
+ from pandapipes.component_models import NodeElementComponent
19
25
  from pymongo import MongoClient, ReplaceOne
20
- from pymongo.database import Database
21
26
  from pymongo.collection import Collection
27
+ from pymongo.database import Database
22
28
  from pymongo.errors import ServerSelectionTimeoutError, DuplicateKeyError
23
29
 
24
- import pandapipes as pps
25
- from pandapipes import from_json_string as from_json_pps, FromSerializableRegistryPpipe
26
- import pandapower as pp
27
- import pandapower.io_utils as io_pp
28
-
29
30
  from pandahub.api.internal.settings import MONGODB_URL, MONGODB_USER, MONGODB_PASSWORD, MONGODB_GLOBAL_DATABASE_URL, \
30
31
  MONGODB_GLOBAL_DATABASE_USER, MONGODB_GLOBAL_DATABASE_PASSWORD, CREATE_INDEXES_WITH_PROJECT, PANDAHUB_GLOBAL_DB_CLIENT
31
32
  from pandahub.lib.database_toolbox import (
@@ -77,6 +78,20 @@ def validate_variant_type(variant: int | None):
77
78
  msg = f"variant must be int or None, but got {variant} of type {type(variant)}"
78
79
  raise ValueError(msg)
79
80
 
81
+
82
+ def re_arg(kwarg_map: dict[str, str]) -> Callable:
83
+ def decorator(func: Callable) -> Callable:
84
+ def wrapped(*args, **kwargs):
85
+ new_kwargs = {}
86
+ for k, v in kwargs.items():
87
+ if k in kwarg_map:
88
+ print(f"DEPRECATION WARNING: keyword argument '{k}' is no longer valid. Use '{kwarg_map[k]}' instead.")
89
+ new_kwargs[kwarg_map.get(k, k)] = v
90
+ return func(*args, **new_kwargs)
91
+ return wrapped
92
+ return decorator
93
+
94
+
80
95
  class PandaHub:
81
96
  permissions = {
82
97
  "read": ["owner", "developer", "guest"],
@@ -856,15 +871,15 @@ class PandaHub:
856
871
  def get_subnet_by_name(
857
872
  self,
858
873
  name,
859
- bus_filter=None,
874
+ node_filter=None,
860
875
  include_results=True,
861
876
  add_edge_branches=True,
862
877
  geo_mode="string",
863
878
  variant=None,
864
879
  additional_filters: dict[
865
- str, Callable[[pp.auxiliary.pandapowerNet], dict]
880
+ str, Callable[[pp.auxiliary.pandapowerNet | pps.pandapipesNet], dict]
866
881
  ] = {},
867
- ):
882
+ ) -> pp.auxiliary.pandapowerNet | pps.pandapipesNet:
868
883
  self.check_permission("read")
869
884
  db = self._get_project_database()
870
885
  net_id = self._get_net_id_from_name(name, db)
@@ -872,7 +887,7 @@ class PandaHub:
872
887
  return None
873
888
  return self.get_subnet(
874
889
  net_id,
875
- bus_filter=bus_filter,
890
+ node_filter=node_filter,
876
891
  include_results=include_results,
877
892
  add_edge_branches=add_edge_branches,
878
893
  geo_mode=geo_mode,
@@ -880,221 +895,192 @@ class PandaHub:
880
895
  additional_filters=additional_filters,
881
896
  )
882
897
 
898
+ @re_arg({"bus_filter": "node_filter"})
883
899
  def get_subnet(
884
900
  self,
885
901
  net_id,
886
- bus_filter=None,
902
+ node_filter=None,
887
903
  include_results=True,
888
904
  add_edge_branches=True,
889
905
  geo_mode="string",
890
906
  variant=None,
891
- ignore_elements=[],
907
+ ignore_elements=tuple([]),
892
908
  additional_filters: dict[
893
- str, Callable[[pp.auxiliary.pandapowerNet], dict]
894
- ] = {},
895
- ) -> pp.pandapowerNet:
909
+ str, Callable[[pp.auxiliary.pandapowerNet | pps.pandapipesNet], dict]
910
+ ] | None = None,
911
+ additional_branch_node_cols: dict[str, list[str]] | None = None,
912
+ *,
913
+ return_edge_branch_nodes: bool = False
914
+ ) -> (pp.pandapowerNet | pps.pandapipesNet) | (tuple[pp.pandapowerNet | pps.pandapipesNet, list]):
896
915
  db = self._get_project_database()
897
916
  meta = self._get_network_metadata(db, net_id)
898
- dtypes = db["_networks"].find_one({"_id": net_id}, projection={"dtypes"})
917
+ dtypes = meta["dtypes"]
918
+ sector = meta["sector"]
919
+ is_power = sector == "power"
899
920
 
900
- net = pp.create_empty_network()
921
+ if additional_filters is None:
922
+ additional_filters = {}
923
+ if additional_branch_node_cols is None:
924
+ additional_branch_node_cols = {}
901
925
 
902
- if db[self._collection_name_of_element("bus")].find_one() is None:
926
+ def switch_filter(bus_filter):
927
+ return {
928
+ "$and": [
929
+ {"et": "b"},
930
+ bus_filter,
931
+ ]
932
+ }
933
+
934
+ def get_nodes_from_element(ntw, element, nd_cols):
935
+ return [ntw[element][ndc].to_numpy() for ndc in nd_cols]
936
+
937
+ def get_nodes_from_switch(ntw, _, _nd_cols):
938
+ return [ntw.switch.bus.to_numpy(), ntw.switch.loc[ntw.switch.et == "b", "element"].to_numpy()]
939
+
940
+ if is_power:
941
+ net = pp.create_empty_network()
942
+ node_name = "bus"
943
+ default_branches = ["line", "trafo", "trafo3w", "switch"]
944
+ default_node_cols = [
945
+ ("from_bus", "to_bus"),
946
+ ("hv_bus", "lv_bus"),
947
+ ("hv_bus", "lv_bus", "mv_bus"),
948
+ ("bus", "element")
949
+ ]
950
+ special_filters = {"switch": switch_filter}
951
+ get_nodes_func = {br: get_nodes_from_element for br in default_branches}
952
+ get_nodes_func["switch"] = get_nodes_from_switch
953
+ # add node elements
954
+ node_elements = [
955
+ "load",
956
+ "asymmetric_load",
957
+ "sgen",
958
+ "asymmetric_sgen",
959
+ "gen",
960
+ "ext_grid",
961
+ "shunt",
962
+ "xward",
963
+ "ward",
964
+ "motor",
965
+ "storage",
966
+ ]
967
+ branch_elements = ["trafo", "line", "trafo3w", "switch", "impedance"]
968
+ all_elements = (
969
+ node_elements + branch_elements + ["bus"] + list(additional_filters.keys())
970
+ )
971
+ all_elements = list(set(all_elements) - set(ignore_elements))
972
+ else:
973
+ net = pps.create_empty_network()
974
+ node_name = "junction"
975
+ component_list = []
976
+ if "data" in meta and "component_list" in meta["data"]:
977
+ component_list = json.loads(
978
+ meta["data"]["component_list"][11:], cls=io_pp.PPJSONDecoder,
979
+ registry_class=FromSerializableRegistryPpipe
980
+ )
981
+ default_branches = []
982
+ default_node_cols = []
983
+ node_elements = []
984
+ all_elements = []
985
+ for c in component_list:
986
+ pps.add_new_component(net, c)
987
+ all_elements.append(c.table_name())
988
+ if issubclass(c, BranchComponent):
989
+ default_branches.append(c.table_name())
990
+ default_node_cols.append(c.from_to_node_cols())
991
+ if issubclass(c, NodeElementComponent):
992
+ node_elements.append(c.table_name())
993
+ special_filters = dict()
994
+ get_nodes_func = {br: get_nodes_from_element for br in default_branches}
995
+
996
+ if db[self._collection_name_of_element(node_name)].find_one() is None:
903
997
  net["empty"] = True
904
998
 
999
+ add_args = {
1000
+ "net": net,
1001
+ "db": db,
1002
+ "net_id": net_id,
1003
+ "include_results": include_results,
1004
+ "geo_mode": geo_mode,
1005
+ "variant": variant,
1006
+ "dtypes": dtypes,
1007
+ "filter": node_filter,
1008
+ }
1009
+
905
1010
  # Add buses with filter
906
- if bus_filter is not None:
907
- self._add_element_from_collection(
908
- net,
909
- db,
910
- "bus",
911
- net_id,
912
- bus_filter,
913
- geo_mode=geo_mode,
914
- variant=variant,
915
- dtypes=dtypes,
916
- )
917
- buses = net.bus.index.tolist()
1011
+ if node_filter is not None:
1012
+ self._add_element_from_collection(element_type=node_name, **add_args)
1013
+ nodes = net[node_name].index.tolist()
918
1014
 
919
1015
  if isinstance(add_edge_branches, bool):
920
1016
  if add_edge_branches:
921
- add_edge_branches = ["line", "trafo", "switch"]
1017
+ add_edge_branches = default_branches
922
1018
  else:
923
1019
  add_edge_branches = []
924
1020
  elif not isinstance(add_edge_branches, list):
925
1021
  raise ValueError("add_edge_branches must be a list or a boolean")
926
- line_operator = "$or" if "line" in add_edge_branches else "$and"
927
- # Add branch elements connected to at least one bus
928
- self._add_element_from_collection(
929
- net,
930
- db,
931
- "line",
932
- net_id,
933
- {
934
- line_operator: [
935
- {"from_bus": {"$in": buses}},
936
- {"to_bus": {"$in": buses}},
937
- ]
938
- },
939
- geo_mode=geo_mode,
940
- variant=variant,
941
- dtypes=dtypes,
942
- )
943
- trafo_operator = "$or" if "trafo" in add_edge_branches else "$and"
944
- self._add_element_from_collection(
945
- net,
946
- db,
947
- "trafo",
948
- net_id,
949
- {trafo_operator: [{"hv_bus": {"$in": buses}}, {"lv_bus": {"$in": buses}}]},
950
- geo_mode=geo_mode,
951
- variant=variant,
952
- dtypes=dtypes,
953
- )
954
- self._add_element_from_collection(
955
- net,
956
- db,
957
- "trafo3w",
958
- net_id,
959
- {
960
- trafo_operator: [
961
- {"hv_bus": {"$in": buses}},
962
- {"mv_bus": {"$in": buses}},
963
- {"lv_bus": {"$in": buses}},
964
- ]
965
- },
966
- geo_mode=geo_mode,
967
- variant=variant,
968
- dtypes=dtypes,
969
- )
970
- switch_operator = "$or" if "switch" in add_edge_branches else "$and"
971
- self._add_element_from_collection(
972
- net,
973
- db,
974
- "switch",
975
- net_id,
976
- {
977
- "$and": [
978
- {"et": "b"},
1022
+
1023
+ # Add elements for which the user has provided a filter function
1024
+ for element, filter_func in additional_filters.items():
1025
+ if element in ignore_elements:
1026
+ continue
1027
+ add_args["filter"] = filter_func(net)
1028
+ self._add_element_from_collection(element_type=element, **add_args)
1029
+
1030
+ branch_nodes = set()
1031
+ for branch_name, node_cols in zip(default_branches, default_node_cols):
1032
+ operator = "$or" if branch_name in add_edge_branches else "$and"
1033
+ # Add branch elements connected to at least one node
1034
+ filter_ = {operator: [{b: {"$in": nodes}} for b in node_cols]}
1035
+ if branch_name in special_filters:
1036
+ filter_ = special_filters[branch_name](filter_)
1037
+ add_args["filter"] = filter_
1038
+ self._add_element_from_collection(element_type=branch_name, **add_args)
1039
+ get_nd_func = get_nodes_func[branch_name]
1040
+ branch_nodes.update(set(chain.from_iterable(get_nd_func(net, branch_name, node_cols))))
1041
+
1042
+ for branch_name, node_cols in additional_branch_node_cols.items():
1043
+ if branch_name not in net:
1044
+ continue
1045
+ branch_nodes.update(
1046
+ set(chain.from_iterable(get_nodes_from_element(net, branch_name, node_cols)))
1047
+ )
1048
+
1049
+ branch_nodes_outside = []
1050
+ if branch_nodes:
1051
+ # Add buses on the other side of the branches
1052
+ branch_nodes_outside = list(map(int, branch_nodes - set(nodes)))
1053
+ add_args["filter"] = {"index": {"$in": branch_nodes_outside}}
1054
+ self._add_element_from_collection(element_type=node_name, **add_args)
1055
+ nodes = net[node_name].index.tolist()
1056
+
1057
+ if is_power:
1058
+ add_args["filter"] = {
1059
+ "$or": [
1060
+ {"$and": [{"et": "t"}, {"element": {"$in": net.trafo.index.tolist()}}]},
1061
+ {"$and": [{"et": "l"}, {"element": {"$in": net.line.index.tolist()}}]},
979
1062
  {
980
- switch_operator: [
981
- {"bus": {"$in": buses}},
982
- {"element": {"$in": buses}},
1063
+ "$and": [
1064
+ {"et": "t3"},
1065
+ {"element": {"$in": net.trafo3w.index.tolist()}},
983
1066
  ]
984
1067
  },
985
1068
  ]
986
- },
987
- geo_mode=geo_mode,
988
- variant=variant,
989
- dtypes=dtypes,
990
- )
991
- if add_edge_branches:
992
- # Add buses on the other side of the branches
993
- branch_buses = (
994
- set(net.trafo.hv_bus.values)
995
- | set(net.trafo.lv_bus.values)
996
- | set(net.line.from_bus)
997
- | set(net.line.to_bus)
998
- | set(net.trafo3w.hv_bus.values)
999
- | set(net.trafo3w.mv_bus.values)
1000
- | set(net.trafo3w.lv_bus.values)
1001
- | set(net.switch.bus)
1002
- | set(net.switch.element)
1003
- )
1004
- branch_buses_outside = [int(b) for b in branch_buses - set(buses)]
1005
- self._add_element_from_collection(
1006
- net,
1007
- db,
1008
- "bus",
1009
- net_id,
1010
- geo_mode=geo_mode,
1011
- variant=variant,
1012
- filter={"index": {"$in": branch_buses_outside}},
1013
- dtypes=dtypes,
1014
- )
1015
- buses = net.bus.index.tolist()
1016
-
1017
- switch_filter = {
1018
- "$or": [
1019
- {"$and": [{"et": "t"}, {"element": {"$in": net.trafo.index.tolist()}}]},
1020
- {"$and": [{"et": "l"}, {"element": {"$in": net.line.index.tolist()}}]},
1021
- {
1022
- "$and": [
1023
- {"et": "t3"},
1024
- {"element": {"$in": net.trafo3w.index.tolist()}},
1025
- ]
1026
- },
1027
- ]
1028
- }
1029
- self._add_element_from_collection(
1030
- net,
1031
- db,
1032
- "switch",
1033
- net_id,
1034
- switch_filter,
1035
- geo_mode=geo_mode,
1036
- variant=variant,
1037
- dtypes=dtypes,
1038
- )
1039
-
1040
- # add node elements
1041
- node_elements = [
1042
- "load",
1043
- "asymmetric_load",
1044
- "sgen",
1045
- "asymmetric_sgen",
1046
- "gen",
1047
- "ext_grid",
1048
- "shunt",
1049
- "xward",
1050
- "ward",
1051
- "motor",
1052
- "storage",
1053
- ]
1054
- branch_elements = ["trafo", "line", "trafo3w", "switch", "impedance"]
1055
- all_elements = (
1056
- node_elements + branch_elements + ["bus"] + list(additional_filters.keys())
1057
- )
1058
- all_elements = list(set(all_elements) - set(ignore_elements))
1069
+ }
1070
+ self._add_element_from_collection(element_type="switch", **add_args)
1059
1071
 
1060
1072
  # add all node elements that are connected to buses within the network
1061
1073
  for element in node_elements:
1062
- element_filter = {"bus": {"$in": buses}}
1063
- self._add_element_from_collection(
1064
- net,
1065
- db,
1066
- element,
1067
- net_id,
1068
- filter=element_filter,
1069
- geo_mode=geo_mode,
1070
- include_results=include_results,
1071
- variant=variant,
1072
- dtypes=dtypes,
1073
- )
1074
-
1075
- # Add elements for which the user has provided a filter function
1076
- for element, filter_func in additional_filters.items():
1077
- if element in ignore_elements:
1078
- continue
1079
- element_filter = filter_func(net)
1080
- self._add_element_from_collection(
1081
- net,
1082
- db,
1083
- element,
1084
- net_id,
1085
- filter=element_filter,
1086
- geo_mode=geo_mode,
1087
- include_results=include_results,
1088
- variant=variant,
1089
- dtypes=dtypes,
1090
- )
1074
+ add_args["filter"] = {node_name: {"$in": nodes}}
1075
+ self._add_element_from_collection(element_type=element, **add_args)
1091
1076
 
1092
1077
  # add all other collections
1093
1078
  collection_names = self.get_net_collections(db)
1094
1079
  for collection in collection_names:
1095
1080
  table_name = self._element_name_of_collection(collection)
1096
1081
  # skip all element tables that we have already added
1097
- if table_name in all_elements or table_name in ignore_elements:
1082
+ if (table_name in all_elements or table_name in ignore_elements
1083
+ or table_name in additional_filters.keys()):
1098
1084
  continue
1099
1085
  # for tables that share an index with an element (e.g. load->res_load) load only relevant entries
1100
1086
  for element in all_elements:
@@ -1106,18 +1092,11 @@ class PandaHub:
1106
1092
  else:
1107
1093
  # all other tables (e.g. std_types) are loaded without filter
1108
1094
  element_filter = None
1109
- self._add_element_from_collection(
1110
- net,
1111
- db,
1112
- table_name,
1113
- net_id,
1114
- filter=element_filter,
1115
- geo_mode=geo_mode,
1116
- include_results=include_results,
1117
- variant=variant,
1118
- dtypes=dtypes,
1119
- )
1095
+ add_args["filter"] = element_filter
1096
+ self._add_element_from_collection(element_type=table_name, **add_args)
1120
1097
  self.deserialize_and_update_data(net, meta)
1098
+ if return_edge_branch_nodes:
1099
+ return net, branch_nodes_outside
1121
1100
  return net
1122
1101
 
1123
1102
  def _collection_name_of_element(self, element):
@@ -3217,7 +3196,6 @@ class PandaHub:
3217
3196
  return self.get_net_collections(db, with_areas)
3218
3197
 
3219
3198
 
3220
-
3221
3199
  if __name__ == "__main__":
3222
3200
  self = PandaHub()
3223
3201
  project_name = "test_project"
@@ -7,7 +7,7 @@ DATATYPES = {
7
7
  "zone": str,
8
8
  "in_service": bool,
9
9
  "max_vm_pu": float,
10
- "min_vm_pu": float
10
+ "min_vm_pu": float,
11
11
  },
12
12
  "load": {
13
13
  "name": str,
@@ -95,7 +95,7 @@ DATATYPES = {
95
95
  "type": str,
96
96
  "in_service": bool,
97
97
  "max_loading_percent": float,
98
- "std_type": str
98
+ "std_type": str,
99
99
  },
100
100
  "trafo": {
101
101
  "name": str,
@@ -306,12 +306,4 @@ DATATYPES = {
306
306
  'initial_run': bool,
307
307
  "recycle": str
308
308
  },
309
- "line_geodata": {
310
- "coords": object
311
- },
312
- "bus_geodata": {
313
- "x": float,
314
- "y": float,
315
- "coords": object
316
- },
317
309
  }
@@ -1,5 +1,5 @@
1
1
  from contextlib import contextmanager
2
- from typing import Iterator
2
+ from typing import Generator, overload
3
3
 
4
4
  from pymongo import MongoClient
5
5
  from pymongo.synchronous.collection import Collection
@@ -7,6 +7,7 @@ from pymongo.synchronous.database import Database
7
7
 
8
8
  from pandahub.api.internal.settings import PANDAHUB_GLOBAL_DB_CLIENT, MONGODB_URL, MONGODB_USER, MONGODB_PASSWORD
9
9
 
10
+
10
11
  def _get_mongo_client(connection_url: str = MONGODB_URL, connection_user: str = MONGODB_USER,
11
12
  connection_password: str = MONGODB_PASSWORD) -> MongoClient:
12
13
  mongo_client_args = {
@@ -27,8 +28,20 @@ else:
27
28
  _global_mongo_client = None
28
29
 
29
30
 
31
+
32
+
33
+ @overload
34
+ def get_mongo_client(database: None = None, collection: None = None,
35
+ connection_url: str = ..., connection_user: str = ..., connection_password: str = ...) -> MongoClient: ...
36
+ @overload
37
+ def get_mongo_client(database: str, collection: None=None,
38
+ connection_url: str = ..., connection_user: str = ..., connection_password: str = ...) -> Database: ...
39
+ @overload
40
+ def get_mongo_client(database: str, collection: str,
41
+ connection_url: str = ..., connection_user: str = ..., connection_password: str = ...) -> Collection: ...
42
+
30
43
  def get_mongo_client(database: str | None = None, collection: str | None = None, connection_url: str = MONGODB_URL, connection_user: str = MONGODB_USER,
31
- connection_password: str = MONGODB_PASSWORD) -> Iterator[MongoClient | Database | Collection]:
44
+ connection_password: str = MONGODB_PASSWORD) -> MongoClient | Database | Collection:
32
45
  if collection is not None and database is None:
33
46
  raise ValueError("Must specify database to access a collection!")
34
47
  if _global_mongo_client is None:
@@ -40,7 +53,7 @@ def get_mongo_client(database: str | None = None, collection: str | None = None,
40
53
 
41
54
  @contextmanager
42
55
  def mongo_client(database: str | None = None, collection: str | None = None, connection_url: str = MONGODB_URL,
43
- connection_user: str = MONGODB_USER, connection_password: str = MONGODB_PASSWORD) -> Iterator[MongoClient | Database | Collection]:
56
+ connection_user: str = MONGODB_USER, connection_password: str = MONGODB_PASSWORD) -> Generator[MongoClient | Database | Collection, None, None]:
44
57
  """Contextmanager for pymongo MongoClient / Database / Collection with close after use.
45
58
 
46
59
  Parameters
@@ -69,7 +82,7 @@ def mongo_client(database: str | None = None, collection: str | None = None, con
69
82
  client.close()
70
83
 
71
84
 
72
- def _get_db_or_coll(client: MongoClient, database: str | None = None, collection: str | None = None) -> Iterator[MongoClient | Database | Collection]:
85
+ def _get_db_or_coll(client: MongoClient, database: str | None = None, collection: str | None = None) -> MongoClient | Database | Collection:
73
86
  if database is not None and collection is not None:
74
87
  return client[database][collection]
75
88
  elif database is not None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pandahub
3
- Version: 0.3.17
3
+ Version: 0.4.1
4
4
  Summary: Data hub for pandapower and pandapipes networks based on MongoDB
5
5
  Author-email: Jan Ulffers <jan.ulffers@iee.fraunhofer.de>, Leon Thurner <leon.thurner@retoflow.de>, Jannis Kupka <jannis.kupka@retoflow.de>, Mike Vogt <mike.vogt@iee.fraunhofer.de>, Joschka Thurner <joschka.thurner@retoflow.de>, Alexander Scheidler <alexander.scheidler@iee.fraunhofer.de>
6
6
  License: Copyright (c) 2022 by University of Kassel, Fraunhofer Institute for Energy Economics
@@ -2,7 +2,7 @@ uvicorn>=0.24.0
2
2
  fastapi-users[beanie]>=12.0
3
3
  fastapi>=0.104.0
4
4
  fastapi-mail>=1.4.1
5
- pandapower~=2.14
5
+ pandapower>=3.0
6
6
  pandapipes>=0.7.0
7
7
  pymongo>=4.9
8
8
  pydantic
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pandahub"
7
- version = "0.3.17" # File format version '__format_version__' is tracked in __init__.py
7
+ version = "0.4.1" # File format version '__format_version__' is tracked in __init__.py
8
8
  authors=[
9
9
  { name = "Jan Ulffers", email = "jan.ulffers@iee.fraunhofer.de" },
10
10
  { name = "Leon Thurner", email = "leon.thurner@retoflow.de" },
@@ -2,7 +2,7 @@ uvicorn>=0.24.0
2
2
  fastapi-users[beanie]>=12.0
3
3
  fastapi>=0.104.0
4
4
  fastapi-mail>=1.4.1
5
- pandapower~=2.14
5
+ pandapower>=3.0
6
6
  pandapipes>=0.7.0
7
7
  pymongo>=4.9
8
8
  pydantic
@@ -46,7 +46,7 @@ def load_test_subnet_from_mongodb(project_name):
46
46
  buses = list(range(1000))
47
47
  t0 = time.time()
48
48
  subnet = ph.get_subnet_by_name("test_net",
49
- bus_filter={"index": {"$in": buses}})
49
+ node_filter={"index": {"$in": buses}})
50
50
  t1 = time.time()
51
51
  print("LOADED NET IN %.2fs"%(t1-t0))
52
52
  return subnet
@@ -90,20 +90,20 @@ def test_load_subnetwork(ph):
90
90
  net = nw_pp.mv_oberrhein()
91
91
  ph.write_network_to_db(net, name)
92
92
 
93
- subnet = ph.get_subnet_by_name(name, bus_filter={"vn_kv": 110})
93
+ subnet = ph.get_subnet_by_name(name, node_filter={"vn_kv": 110})
94
94
  expected_sizes = [("bus", 4), ("line", 0), ("trafo", 2), ("ext_grid", 2)]
95
95
 
96
96
  for element, size in expected_sizes:
97
97
  assert len(subnet[element]) == size
98
98
  assert len(subnet["res_" + element]) == size
99
99
 
100
- subnet = ph.get_subnet_by_name(name, bus_filter={"vn_kv": 110},
100
+ subnet = ph.get_subnet_by_name(name, node_filter={"vn_kv": 110},
101
101
  include_results=False)
102
102
  for element, size in expected_sizes:
103
103
  assert len(subnet[element]) == size
104
104
  assert len(subnet["res_" + element]) == 0
105
105
 
106
- subnet = ph.get_subnet_by_name(name, bus_filter={"vn_kv": 110},
106
+ subnet = ph.get_subnet_by_name(name, node_filter={"vn_kv": 110},
107
107
  add_edge_branches=False)
108
108
  expected_sizes = [("bus", 2), ("line", 0), ("trafo", 0), ("ext_grid", 2)]
109
109
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes