surfdataverse 4.0.0__tar.gz → 4.0.1__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.
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/PKG-INFO +5 -5
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/README.md +4 -4
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/pyproject.toml +1 -1
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/src/surfdataverse/container.py +4 -4
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/src/surfdataverse/core.py +10 -28
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/src/surfdataverse/__init__.py +0 -0
- {surfdataverse-4.0.0 → surfdataverse-4.0.1}/src/surfdataverse/exceptions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: surfdataverse
|
|
3
|
-
Version: 4.0.
|
|
3
|
+
Version: 4.0.1
|
|
4
4
|
Summary: A Python package for ionysis Microsoft Dataverse integration
|
|
5
5
|
Keywords: dataverse,microsoft,crm,api
|
|
6
6
|
Author: ionysis
|
|
@@ -76,8 +76,8 @@ client.get_authenticated_session()
|
|
|
76
76
|
client.test_connection()
|
|
77
77
|
|
|
78
78
|
# Create entities/tables using modern DI factory functions
|
|
79
|
-
product = connect_entity("logical_table_name_1"
|
|
80
|
-
table_reader = connect_table("logical_table_name_1"
|
|
79
|
+
product = connect_entity("logical_table_name_1")
|
|
80
|
+
table_reader = connect_table("logical_table_name_1")
|
|
81
81
|
|
|
82
82
|
# Set data using write() method with automatic type detection
|
|
83
83
|
product.write("prefix_name", "My Product")
|
|
@@ -167,7 +167,7 @@ default_entity = connect_entity("prefix_tablename", "prefix_")
|
|
|
167
167
|
custom_entity = connect_entity("myorg_product", "myorg_")
|
|
168
168
|
|
|
169
169
|
# For reading data
|
|
170
|
-
table_reader = connect_table("prefix_tablename"
|
|
170
|
+
table_reader = connect_table("prefix_tablename")
|
|
171
171
|
|
|
172
172
|
# The system automatically:
|
|
173
173
|
# - Filters columns starting with your prefix
|
|
@@ -183,7 +183,7 @@ Fetch data from Dataverse tables as pandas DataFrames using modern DI patterns:
|
|
|
183
183
|
from surfdataverse import connect_table, get_client
|
|
184
184
|
|
|
185
185
|
# Create table reader using dependency injection
|
|
186
|
-
table_reader = connect_table("logical_table_name_1"
|
|
186
|
+
table_reader = connect_table("logical_table_name_1")
|
|
187
187
|
|
|
188
188
|
# Get table data as pandas DataFrame
|
|
189
189
|
df = table_reader.get_table_data()
|
|
@@ -47,8 +47,8 @@ client.get_authenticated_session()
|
|
|
47
47
|
client.test_connection()
|
|
48
48
|
|
|
49
49
|
# Create entities/tables using modern DI factory functions
|
|
50
|
-
product = connect_entity("logical_table_name_1"
|
|
51
|
-
table_reader = connect_table("logical_table_name_1"
|
|
50
|
+
product = connect_entity("logical_table_name_1")
|
|
51
|
+
table_reader = connect_table("logical_table_name_1")
|
|
52
52
|
|
|
53
53
|
# Set data using write() method with automatic type detection
|
|
54
54
|
product.write("prefix_name", "My Product")
|
|
@@ -138,7 +138,7 @@ default_entity = connect_entity("prefix_tablename", "prefix_")
|
|
|
138
138
|
custom_entity = connect_entity("myorg_product", "myorg_")
|
|
139
139
|
|
|
140
140
|
# For reading data
|
|
141
|
-
table_reader = connect_table("prefix_tablename"
|
|
141
|
+
table_reader = connect_table("prefix_tablename")
|
|
142
142
|
|
|
143
143
|
# The system automatically:
|
|
144
144
|
# - Filters columns starting with your prefix
|
|
@@ -154,7 +154,7 @@ Fetch data from Dataverse tables as pandas DataFrames using modern DI patterns:
|
|
|
154
154
|
from surfdataverse import connect_table, get_client
|
|
155
155
|
|
|
156
156
|
# Create table reader using dependency injection
|
|
157
|
-
table_reader = connect_table("logical_table_name_1"
|
|
157
|
+
table_reader = connect_table("logical_table_name_1")
|
|
158
158
|
|
|
159
159
|
# Get table data as pandas DataFrame
|
|
160
160
|
df = table_reader.get_table_data()
|
|
@@ -34,14 +34,14 @@ def get_client(config_path=None) -> DataverseClient:
|
|
|
34
34
|
return container.client()
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
def connect_table(logical_name: str = ""
|
|
37
|
+
def connect_table(logical_name: str = "") -> DataverseTable:
|
|
38
38
|
"""Connect to a Dataverse table"""
|
|
39
|
-
return container.table_factory(logical_name
|
|
39
|
+
return container.table_factory(logical_name)
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
def connect_entity(table_logical_name: str
|
|
42
|
+
def connect_entity(table_logical_name: str) -> DataverseEntity:
|
|
43
43
|
"""Connect to a new Dataverse entity instance"""
|
|
44
|
-
return container.entity_factory(table_logical_name
|
|
44
|
+
return container.entity_factory(table_logical_name)
|
|
45
45
|
|
|
46
46
|
|
|
47
47
|
def reset_container():
|
|
@@ -194,7 +194,7 @@ class DataverseClient:
|
|
|
194
194
|
class DataverseBase:
|
|
195
195
|
"""Base class for Dataverse operations with shared functionality"""
|
|
196
196
|
|
|
197
|
-
def __init__(self, table_logical_name: str = "",
|
|
197
|
+
def __init__(self, table_logical_name: str = "", client=None):
|
|
198
198
|
if client is None:
|
|
199
199
|
raise ValueError(
|
|
200
200
|
"Client is required. Use connect_entity() or connect_table() instead of direct instantiation."
|
|
@@ -202,10 +202,7 @@ class DataverseBase:
|
|
|
202
202
|
self.client = client
|
|
203
203
|
|
|
204
204
|
self.table_logical_name = table_logical_name
|
|
205
|
-
self.
|
|
206
|
-
self.name = (
|
|
207
|
-
table_logical_name.replace(self.table_logical_name_prefix, "").title().replace("_", " ")
|
|
208
|
-
)
|
|
205
|
+
self.name = table_logical_name.title().replace("_", " ")
|
|
209
206
|
|
|
210
207
|
# Stored values for this session
|
|
211
208
|
self._guid_mapping = {}
|
|
@@ -215,7 +212,6 @@ class DataverseBase:
|
|
|
215
212
|
self._table_metadata = {}
|
|
216
213
|
self._table_definitions = {}
|
|
217
214
|
self._table_relationships = {}
|
|
218
|
-
self._filtered_choices = {}
|
|
219
215
|
|
|
220
216
|
# === RELATIONSHIPS
|
|
221
217
|
@property
|
|
@@ -278,17 +274,6 @@ class DataverseBase:
|
|
|
278
274
|
|
|
279
275
|
return self._global_choices
|
|
280
276
|
|
|
281
|
-
@property
|
|
282
|
-
def filtered_choices(self):
|
|
283
|
-
"""Get choices filtered by table prefix"""
|
|
284
|
-
if not self._filtered_choices:
|
|
285
|
-
self._filtered_choices = {
|
|
286
|
-
name: options
|
|
287
|
-
for name, options in self.global_choices.items()
|
|
288
|
-
if self.table_logical_name_prefix in name
|
|
289
|
-
}
|
|
290
|
-
return self._filtered_choices
|
|
291
|
-
|
|
292
277
|
# === TABLES
|
|
293
278
|
def get_table_definitions(self):
|
|
294
279
|
if not self._table_definitions:
|
|
@@ -683,14 +668,13 @@ class DataverseTable(DataverseBase):
|
|
|
683
668
|
class DataverseEntity(DataverseBase):
|
|
684
669
|
"""Generic class for Dataverse entities"""
|
|
685
670
|
|
|
686
|
-
def __init__(self, table_logical_name,
|
|
671
|
+
def __init__(self, table_logical_name, client=None):
|
|
687
672
|
"""
|
|
688
673
|
Args:
|
|
689
674
|
table_logical_name: The pluralized name of the Dataverse table
|
|
690
|
-
table_prefix: The prefix used for custom table/column names (default: "prefix_")
|
|
691
675
|
client: Optional DataverseClient instance (will create singleton if not provided)
|
|
692
676
|
"""
|
|
693
|
-
super().__init__(table_logical_name,
|
|
677
|
+
super().__init__(table_logical_name, client)
|
|
694
678
|
|
|
695
679
|
self.guid = None
|
|
696
680
|
self.data = {} # Dictionary to store record fields
|
|
@@ -722,7 +706,7 @@ class DataverseEntity(DataverseBase):
|
|
|
722
706
|
elif column in self.get_table_relationships():
|
|
723
707
|
self.set_lookup(column, value)
|
|
724
708
|
# Choice columns (picklist/option sets)
|
|
725
|
-
elif column in self.
|
|
709
|
+
elif column in self.global_choices:
|
|
726
710
|
self.set_choice(column, value)
|
|
727
711
|
# Regular data columns (including DateTime, String, Integer, Decimal, etc.)
|
|
728
712
|
else:
|
|
@@ -762,7 +746,7 @@ class DataverseEntity(DataverseBase):
|
|
|
762
746
|
elif column in self.get_table_relationships():
|
|
763
747
|
return self.get_lookup(column)
|
|
764
748
|
# Choice columns (picklist/option sets)
|
|
765
|
-
elif column in self.
|
|
749
|
+
elif column in self.global_choices:
|
|
766
750
|
return self.get_choice(column)
|
|
767
751
|
# Regular data columns (including DateTime, String, Integer, Decimal, etc.)
|
|
768
752
|
else:
|
|
@@ -793,8 +777,7 @@ class DataverseEntity(DataverseBase):
|
|
|
793
777
|
|
|
794
778
|
# Update our data with the fresh record
|
|
795
779
|
for field, fresh_value in record.items():
|
|
796
|
-
|
|
797
|
-
self.data[field] = fresh_value
|
|
780
|
+
self.data[field] = fresh_value
|
|
798
781
|
|
|
799
782
|
logger.info(f"Refreshed data for {self.table_logical_name} GUID: {self.guid}")
|
|
800
783
|
return True
|
|
@@ -837,8 +820,7 @@ class DataverseEntity(DataverseBase):
|
|
|
837
820
|
|
|
838
821
|
# Update our data with the fresh record
|
|
839
822
|
for field, fresh_value in record.items():
|
|
840
|
-
|
|
841
|
-
self.data[field] = fresh_value
|
|
823
|
+
self.data[field] = fresh_value
|
|
842
824
|
|
|
843
825
|
# Return the requested value
|
|
844
826
|
value = self.data.get(column, "")
|
|
@@ -875,7 +857,7 @@ class DataverseEntity(DataverseBase):
|
|
|
875
857
|
# === CHOICE
|
|
876
858
|
def set_choice(self, column, value):
|
|
877
859
|
"""Adds a choice field by looking up its numeric value"""
|
|
878
|
-
choice_value = self.
|
|
860
|
+
choice_value = self.global_choices[column].get(value) # Get numeric value for choice
|
|
879
861
|
if choice_value is not None:
|
|
880
862
|
self.data[column] = choice_value
|
|
881
863
|
else:
|
|
@@ -885,7 +867,7 @@ class DataverseEntity(DataverseBase):
|
|
|
885
867
|
|
|
886
868
|
def get_choice(self, column):
|
|
887
869
|
"""Retrieves the readable choice name from its stored numeric value (Int → String)"""
|
|
888
|
-
choice_dict = self.
|
|
870
|
+
choice_dict = self.global_choices.get(column, {})
|
|
889
871
|
choices_invert = {v: k for k, v in choice_dict.items()} # Invert dict for reverse lookup
|
|
890
872
|
numeric_value = self.data.get(column, None)
|
|
891
873
|
return choices_invert.get(numeric_value, None)
|
|
File without changes
|
|
File without changes
|