switch-api 0.6.13__tar.gz → 0.6.14__tar.gz

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 (70) hide show
  1. {switch_api-0.6.13 → switch_api-0.6.14}/HISTORY.md +8 -0
  2. {switch_api-0.6.13 → switch_api-0.6.14}/PKG-INFO +9 -1
  3. {switch_api-0.6.13 → switch_api-0.6.14}/setup.py +1 -1
  4. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/__init__.py +1 -1
  5. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/integration/integration.py +35 -16
  6. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api.egg-info/PKG-INFO +9 -1
  7. {switch_api-0.6.13 → switch_api-0.6.14}/AUTHORS.rst +0 -0
  8. {switch_api-0.6.13 → switch_api-0.6.14}/LICENCE +0 -0
  9. {switch_api-0.6.13 → switch_api-0.6.14}/MANIFEST.in +0 -0
  10. {switch_api-0.6.13 → switch_api-0.6.14}/README.md +0 -0
  11. {switch_api-0.6.13 → switch_api-0.6.14}/pyproject.toml +0 -0
  12. {switch_api-0.6.13 → switch_api-0.6.14}/setup.cfg +0 -0
  13. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_authentication/__init__.py +0 -0
  14. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_authentication/_authentication.py +0 -0
  15. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_authentication/_credentials_store/__init__.py +0 -0
  16. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_authentication/_credentials_store/_credentials_store.py +0 -0
  17. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_authentication/_msal/__init__.py +0 -0
  18. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_authentication/_msal/_custom_application.py +0 -0
  19. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_compute/__init__.py +0 -0
  20. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_compute/_commands.py +0 -0
  21. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_compute/_compute.py +0 -0
  22. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_compute/_iotservice.py +0 -0
  23. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_compute/_models.py +0 -0
  24. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_compute/_utils.py +0 -0
  25. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_guide/__init__.py +0 -0
  26. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_guide/main.py +0 -0
  27. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_guide/processor.py +0 -0
  28. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_utils/__init__.py +0 -0
  29. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_utils/_constants.py +0 -0
  30. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_utils/_marketplace.py +0 -0
  31. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_utils/_mqtt.py +0 -0
  32. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_utils/_platform.py +0 -0
  33. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/_utils/_utils.py +0 -0
  34. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/analytics/__init__.py +0 -0
  35. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/analytics/analytics.py +0 -0
  36. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/cache/__init__.py +0 -0
  37. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/cache/cache.py +0 -0
  38. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/controls/__init__.py +0 -0
  39. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/controls/_constants.py +0 -0
  40. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/controls/_enums.py +0 -0
  41. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/controls/_mqtt.py +0 -0
  42. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/controls/controls.py +0 -0
  43. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/dataset/__init__.py +0 -0
  44. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/dataset/dataset.py +0 -0
  45. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/email/__init__.py +0 -0
  46. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/email/email_sender.py +0 -0
  47. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/error_handlers/__init__.py +0 -0
  48. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/error_handlers/error_handlers.py +0 -0
  49. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/extensions/__init__.py +0 -0
  50. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/extensions/extensions.py +0 -0
  51. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/extensions/field_meta.py +0 -0
  52. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/extensions/helpers.py +0 -0
  53. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/extensions/pipeline.py +0 -0
  54. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/initialize.py +0 -0
  55. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/integration/__init__.py +0 -0
  56. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/integration/_utils.py +0 -0
  57. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/integration/helpers.py +0 -0
  58. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/pipeline/__init__.py +0 -0
  59. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/pipeline/automation.py +0 -0
  60. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/pipeline/definitions.py +0 -0
  61. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/pipeline/pipeline.py +0 -0
  62. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/platform_insights/__init__.py +0 -0
  63. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/platform_insights/platform_insights.py +0 -0
  64. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/realtime/__init__.py +0 -0
  65. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/realtime/_mqtt.py +0 -0
  66. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api/realtime/realtime.py +0 -0
  67. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api.egg-info/SOURCES.txt +0 -0
  68. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api.egg-info/dependency_links.txt +0 -0
  69. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api.egg-info/requires.txt +0 -0
  70. {switch_api-0.6.13 → switch_api-0.6.14}/switch_api.egg-info/top_level.txt +0 -0
@@ -1,5 +1,13 @@
1
1
  # History
2
2
 
3
+ #0.6.14
4
+ ### Modified
5
+ In the `integration` module:
6
+ - Updated `add_carbon_column()` to enforce priority selection of carbon calculation rules.
7
+ - When overlapping date ranges exist for the same `ObjectPropertyId`, the rule with a non-null `ObjectPropertyTemplateID` is now preferred over the default (NULL) rule.
8
+ - Ensured only one carbon calculation is applied per input row to prevent duplicate records.
9
+ - Refactored logic to preserve original row count and avoid row loss during rule matching.
10
+
3
11
  #0.6.13
4
12
  ### Added
5
13
  In the `controls` module
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: switch_api
3
- Version: 0.6.13
3
+ Version: 0.6.14
4
4
  Summary: A complete package for data ingestion into the Switch Automation Platform.
5
5
  Home-page: UNKNOWN
6
6
  Author: Switch Automation Pty Ltd.
@@ -38,6 +38,14 @@ pip install switch_api
38
38
 
39
39
  # History
40
40
 
41
+ #0.6.14
42
+ ### Modified
43
+ In the `integration` module:
44
+ - Updated `add_carbon_column()` to enforce priority selection of carbon calculation rules.
45
+ - When overlapping date ranges exist for the same `ObjectPropertyId`, the rule with a non-null `ObjectPropertyTemplateID` is now preferred over the default (NULL) rule.
46
+ - Ensured only one carbon calculation is applied per input row to prevent duplicate records.
47
+ - Refactored logic to preserve original row count and avoid row loss during rule matching.
48
+
41
49
  #0.6.13
42
50
  ### Added
43
51
  In the `controls` module
@@ -16,7 +16,7 @@ setup(
16
16
  long_description_content_type='text/markdown',
17
17
  license='MIT License',
18
18
  name="switch_api",
19
- version="0.6.13",
19
+ version="0.6.14",
20
20
  packages=find_packages(include=["switch_api", "switch_api.*"]),
21
21
  install_requires=['pandas==1.5.3', 'requests', 'azure-storage-blob', 'pandera[io]==0.7.1', 'azure-servicebus',
22
22
  'msal>=1.11.0', 'paho-mqtt==1.6.1', 'uvicorn==0.22.0', 'fastapi==0.98.0', 'pyodbc==4.0.39', 'cachetools==5.5.0',
@@ -42,4 +42,4 @@ from . import _guide
42
42
  # log.addHandler(_ch)
43
43
  # https://dev.to/joaomcteixeira/setting-up-python-logging-for-a-library-app-6ml
44
44
 
45
- __version__ = "0.6.13"
45
+ __version__ = "0.6.14"
@@ -1855,6 +1855,7 @@ def upsert_timeseries(df: pandas.DataFrame, api_inputs: ApiInputs, is_local_time
1855
1855
  df = df.assign(Carbon=0.0)
1856
1856
 
1857
1857
  df = df.copy()
1858
+ df['__row_id'] = np.arange(len(df))
1858
1859
  carbon_calcs_df = carbon_calculations_df.copy()
1859
1860
 
1860
1861
  if 'ObjectPropertyID' in carbon_calcs_df.columns:
@@ -1864,7 +1865,7 @@ def upsert_timeseries(df: pandas.DataFrame, api_inputs: ApiInputs, is_local_time
1864
1865
  if not pd.api.types.is_datetime64_any_dtype(df['TimestampLocal']):
1865
1866
  df['TimestampLocal'] = pd.to_datetime(df['TimestampLocal'])
1866
1867
 
1867
- required_carbon_cols = ['ObjectPropertyId', 'CarbonExpression', 'FromDate', 'ToDate']
1868
+ required_carbon_cols = ['ObjectPropertyId', 'CarbonExpression', 'FromDate', 'ToDate', 'ObjectPropertyTemplateID']
1868
1869
  if not all(col in carbon_calcs_df.columns for col in required_carbon_cols):
1869
1870
  logger.error(f"Missing required columns in carbon calculations DataFrame. Required: {required_carbon_cols}")
1870
1871
  return df.assign(Carbon=0.0)
@@ -1877,29 +1878,47 @@ def upsert_timeseries(df: pandas.DataFrame, api_inputs: ApiInputs, is_local_time
1877
1878
  carbon_calcs_df['ToDate'] = pd.to_datetime(carbon_calcs_df['ToDate'])
1878
1879
 
1879
1880
  merged_df = pd.merge(df, carbon_calcs_df, on='ObjectPropertyId', how='left', indicator=True)
1880
- no_valid_carbon_calcs = merged_df[merged_df._merge== 'left_only']
1881
1881
 
1882
1882
  matches_mask = (merged_df['TimestampLocal'] >= merged_df['FromDate']) & \
1883
1883
  (merged_df['TimestampLocal'] <= merged_df['ToDate'])
1884
- valid_carbon_calcs = merged_df[matches_mask]
1885
1884
 
1886
- if valid_carbon_calcs.shape[0]>0:
1887
- unique_expressions = valid_carbon_calcs['CarbonExpression'].unique()
1885
+ valid_carbon_calcs = merged_df[matches_mask].copy()
1886
+
1887
+ if not valid_carbon_calcs.empty:
1888
+ # priority: non-NULL ObjectPropertyTemplateID first
1889
+ valid_carbon_calcs["__tmplt_priority"] = valid_carbon_calcs["ObjectPropertyTemplateID"].notna().astype(int)
1890
+
1891
+ # choose ONE calc row per original df row
1892
+ valid_carbon_calcs = (
1893
+ valid_carbon_calcs
1894
+ .sort_values(["__row_id", "__tmplt_priority"], ascending=[True, False])
1895
+ .drop_duplicates(subset="__row_id", keep="first")
1896
+ )
1897
+
1898
+ unique_expressions = valid_carbon_calcs["CarbonExpression"].dropna().unique()
1888
1899
  for expr in unique_expressions:
1889
- expr_mask = valid_carbon_calcs['CarbonExpression'] == expr
1890
- numexpr_expression = expr.replace('[Value]', 'Value')
1891
- valid_carbon_calcs.loc[expr_mask, 'Carbon'] = numexpr.evaluate(
1892
- numexpr_expression,
1893
- local_dict = {'Value': valid_carbon_calcs.loc[expr_mask, 'Value'].values}
1900
+ expr_mask = valid_carbon_calcs["CarbonExpression"] == expr
1901
+ numexpr_expression = expr.replace("[Value]", "Value")
1902
+ valid_carbon_calcs.loc[expr_mask, "Carbon"] = numexpr.evaluate(
1903
+ numexpr_expression,
1904
+ local_dict={"Value": valid_carbon_calcs.loc[expr_mask, "Value"].values}
1894
1905
  )
1895
-
1896
- final_df = pd.concat([no_valid_carbon_calcs, valid_carbon_calcs])
1897
- final_row_count = final_df.shape[0]
1898
1906
 
1899
- logger.info(f"Original row count = {original_row_count}, final row count = {final_row_count}. Matches = {original_row_count==final_row_count}")
1900
- final_df = final_df.drop(columns=['CarbonExpression', 'FromDate', 'ToDate', '_merge'])
1907
+ df = df.merge(
1908
+ valid_carbon_calcs[["__row_id", "Carbon"]],
1909
+ on="__row_id",
1910
+ how="left",
1911
+ suffixes=("", "_calc"),
1912
+ )
1913
+ df["Carbon"] = df["Carbon_calc"].fillna(df["Carbon"])
1914
+ df = df.drop(columns=["Carbon_calc"])
1915
+
1916
+ final_row_count = df.shape[0]
1917
+ logger.info(
1918
+ f"Original row count = {original_row_count}, final row count = {final_row_count}. Matches = {original_row_count==final_row_count}"
1919
+ )
1901
1920
 
1902
- return final_df
1921
+ return df.drop(columns=["__row_id"])
1903
1922
 
1904
1923
  def create_meta_column(df, slice_columns, save_slices, cost_carbon_calculation):
1905
1924
  """Handles creating the 'Meta' column and optionally saves additional columns as slices."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: switch-api
3
- Version: 0.6.13
3
+ Version: 0.6.14
4
4
  Summary: A complete package for data ingestion into the Switch Automation Platform.
5
5
  Home-page: UNKNOWN
6
6
  Author: Switch Automation Pty Ltd.
@@ -38,6 +38,14 @@ pip install switch_api
38
38
 
39
39
  # History
40
40
 
41
+ #0.6.14
42
+ ### Modified
43
+ In the `integration` module:
44
+ - Updated `add_carbon_column()` to enforce priority selection of carbon calculation rules.
45
+ - When overlapping date ranges exist for the same `ObjectPropertyId`, the rule with a non-null `ObjectPropertyTemplateID` is now preferred over the default (NULL) rule.
46
+ - Ensured only one carbon calculation is applied per input row to prevent duplicate records.
47
+ - Refactored logic to preserve original row count and avoid row loss during rule matching.
48
+
41
49
  #0.6.13
42
50
  ### Added
43
51
  In the `controls` module
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes