MSTR-Robotics-magerdaniel 0.3.11__tar.gz → 0.5.0__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 (59) hide show
  1. mstr_robotics_magerdaniel-0.5.0/MSTR_Robotics_magerdaniel.egg-info/PKG-INFO +68 -0
  2. mstr_robotics_magerdaniel-0.5.0/MSTR_Robotics_magerdaniel.egg-info/SOURCES.txt +39 -0
  3. mstr_robotics_magerdaniel-0.5.0/MSTR_Robotics_magerdaniel.egg-info/requires.txt +30 -0
  4. mstr_robotics_magerdaniel-0.5.0/PKG-INFO +68 -0
  5. mstr_robotics_magerdaniel-0.5.0/README.md +36 -0
  6. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/__init__.py +7 -0
  7. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/_connectors.py +289 -0
  8. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/_export.py +38 -0
  9. {mstr_robotics_magerdaniel-0.3.11 → mstr_robotics_magerdaniel-0.5.0}/mstr_robotics/_helper.py +201 -174
  10. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/_lu_data.py +138 -0
  11. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/_mod_prj_obj.py +80 -0
  12. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/_pa_etl.py +270 -0
  13. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/_paths.py +91 -0
  14. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/dossier.py +339 -0
  15. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/json_compare.py +819 -0
  16. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/_fetch_static_data.py +109 -0
  17. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/_osi_find_bi_data.py +110 -0
  18. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/_osi_object_analysis.py +88 -0
  19. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/_osi_specific_analysis.py +165 -0
  20. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/_run_mstr_report_wizzard.py +236 -0
  21. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/_server_config.py +113 -0
  22. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers/mstr_osi_mcp.py +57 -0
  23. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/ms_azure.py +127 -0
  24. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mstr_classes.py +415 -0
  25. {mstr_robotics_magerdaniel-0.3.11 → mstr_robotics_magerdaniel-0.5.0}/mstr_robotics/mstr_pandas.py +53 -48
  26. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/navigation.py +380 -0
  27. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/osi_exporter/__init__.py +1 -0
  28. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/osi_exporter/export_dashboard.py +653 -0
  29. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/prepare_ai_data.py +614 -0
  30. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/read_out_prj_obj.py +1311 -0
  31. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/redis_db.py +473 -0
  32. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/regam.py +279 -0
  33. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/report.py +427 -0
  34. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/select_mig_objects.py +218 -0
  35. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/setup.py +370 -0
  36. mstr_robotics_magerdaniel-0.5.0/mstr_robotics/user_rag.py +294 -0
  37. mstr_robotics_magerdaniel-0.5.0/pyproject.toml +83 -0
  38. {mstr_robotics_magerdaniel-0.3.11 → mstr_robotics_magerdaniel-0.5.0}/setup.cfg +4 -4
  39. mstr_robotics_magerdaniel-0.3.11/LICENSE +0 -0
  40. mstr_robotics_magerdaniel-0.3.11/MANIFEST.in +0 -1
  41. mstr_robotics_magerdaniel-0.3.11/MSTR_Robotics_magerdaniel.egg-info/PKG-INFO +0 -49
  42. mstr_robotics_magerdaniel-0.3.11/MSTR_Robotics_magerdaniel.egg-info/SOURCES.txt +0 -22
  43. mstr_robotics_magerdaniel-0.3.11/MSTR_Robotics_magerdaniel.egg-info/requires.txt +0 -7
  44. mstr_robotics_magerdaniel-0.3.11/PKG-INFO +0 -49
  45. mstr_robotics_magerdaniel-0.3.11/README.md +0 -19
  46. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/_connectors.py +0 -241
  47. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/_lu_data.py +0 -53
  48. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/_mod_prj_obj.py +0 -67
  49. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/dossier.py +0 -203
  50. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/mstr_classes.py +0 -383
  51. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/navigation.py +0 -201
  52. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/prepare_AI_data.py +0 -164
  53. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/read_out_prj_obj.py +0 -842
  54. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/report.py +0 -440
  55. mstr_robotics_magerdaniel-0.3.11/mstr_robotics/user_RAG.py +0 -149
  56. mstr_robotics_magerdaniel-0.3.11/setup.py +0 -34
  57. {mstr_robotics_magerdaniel-0.3.11 → mstr_robotics_magerdaniel-0.5.0}/MSTR_Robotics_magerdaniel.egg-info/dependency_links.txt +0 -0
  58. {mstr_robotics_magerdaniel-0.3.11 → mstr_robotics_magerdaniel-0.5.0}/MSTR_Robotics_magerdaniel.egg-info/top_level.txt +0 -0
  59. {mstr_robotics_magerdaniel-0.3.11/mstr_robotics → mstr_robotics_magerdaniel-0.5.0/mstr_robotics/mcp_servers}/__init__.py +0 -0
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: MSTR-Robotics-magerdaniel
3
+ Version: 0.5.0
4
+ Summary: Automation toolkit for MicroStrategy / Strategy One: object read-out, migration, comparison, RAG and OSI export.
5
+ Author-email: Daniel Mager <danielmager@gmx.de>
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: mstrio-py>=11.6
9
+ Requires-Dist: pandas>=2.2
10
+ Requires-Dist: numpy>=2.0
11
+ Requires-Dist: requests>=2.31
12
+ Requires-Dist: PyYAML>=6.0
13
+ Requires-Dist: ruamel.yaml>=0.18
14
+ Requires-Dist: python-dotenv>=1.0
15
+ Requires-Dist: openpyxl>=3.1
16
+ Provides-Extra: rag
17
+ Requires-Dist: openai>=1.0; extra == "rag"
18
+ Requires-Dist: flashtext>=2.7; extra == "rag"
19
+ Provides-Extra: redis
20
+ Requires-Dist: redis>=5.0; extra == "redis"
21
+ Provides-Extra: azure
22
+ Requires-Dist: azure-storage-blob>=12.0; extra == "azure"
23
+ Provides-Extra: servers
24
+ Requires-Dist: mcp; extra == "servers"
25
+ Requires-Dist: MSTR-Robotics-magerdaniel[rag]; extra == "servers"
26
+ Provides-Extra: all
27
+ Requires-Dist: MSTR-Robotics-magerdaniel[azure,rag,redis,servers]; extra == "all"
28
+ Provides-Extra: dev
29
+ Requires-Dist: ruff; extra == "dev"
30
+ Requires-Dist: vulture; extra == "dev"
31
+ Requires-Dist: jupyter; extra == "dev"
32
+
33
+ # MSTR Robotics
34
+
35
+ A Python toolkit for MicroStrategy automation, object comparison, and Redis-based BI analysis.
36
+
37
+ ## Features
38
+
39
+ - **Object Comparison**: Compare MicroStrategy objects between environments using JSON diff analysis
40
+ - **Redis Integration**: Store and analyze BI metadata using Redis
41
+ - **Migration Tools**: Automate MicroStrategy object migration workflows
42
+
43
+ ## Project Structure
44
+
45
+ - `mstr_robotics/` - Main package with core functionality
46
+ - `notebooks/` - Jupyter notebooks for analysis and exploration
47
+ - `Dansfiles/` - Migration and automation scripts
48
+ - `config/` - Configuration files (YAML, JSON)
49
+ - `export/` - Export utilities and logs
50
+ - `alt/` - Alternative implementations and experiments
51
+
52
+ ## Setup
53
+
54
+ 1. Clone the repository
55
+ 2. Create virtual environment: `python -m venv .venv`
56
+ 3. Activate: `.venv\Scripts\Activate.ps1`
57
+ 4. Install dependencies: `pip install -r requirements.txt`
58
+
59
+ ## Usage
60
+
61
+ The Jupyter notebooks in `notebooks/` are the primary entry points (object
62
+ export, schema monitoring, migration, REGAM regression testing).
63
+
64
+ ## Development
65
+
66
+ - Python 3.12 required
67
+ - Uses Redis for data storage
68
+ - Jupyter notebooks for exploratory analysis
@@ -0,0 +1,39 @@
1
+ README.md
2
+ pyproject.toml
3
+ MSTR_Robotics_magerdaniel.egg-info/PKG-INFO
4
+ MSTR_Robotics_magerdaniel.egg-info/SOURCES.txt
5
+ MSTR_Robotics_magerdaniel.egg-info/dependency_links.txt
6
+ MSTR_Robotics_magerdaniel.egg-info/requires.txt
7
+ MSTR_Robotics_magerdaniel.egg-info/top_level.txt
8
+ mstr_robotics/__init__.py
9
+ mstr_robotics/_connectors.py
10
+ mstr_robotics/_export.py
11
+ mstr_robotics/_helper.py
12
+ mstr_robotics/_lu_data.py
13
+ mstr_robotics/_mod_prj_obj.py
14
+ mstr_robotics/_pa_etl.py
15
+ mstr_robotics/_paths.py
16
+ mstr_robotics/dossier.py
17
+ mstr_robotics/json_compare.py
18
+ mstr_robotics/ms_azure.py
19
+ mstr_robotics/mstr_classes.py
20
+ mstr_robotics/mstr_pandas.py
21
+ mstr_robotics/navigation.py
22
+ mstr_robotics/prepare_ai_data.py
23
+ mstr_robotics/read_out_prj_obj.py
24
+ mstr_robotics/redis_db.py
25
+ mstr_robotics/regam.py
26
+ mstr_robotics/report.py
27
+ mstr_robotics/select_mig_objects.py
28
+ mstr_robotics/setup.py
29
+ mstr_robotics/user_rag.py
30
+ mstr_robotics/mcp_servers/__init__.py
31
+ mstr_robotics/mcp_servers/_fetch_static_data.py
32
+ mstr_robotics/mcp_servers/_osi_find_bi_data.py
33
+ mstr_robotics/mcp_servers/_osi_object_analysis.py
34
+ mstr_robotics/mcp_servers/_osi_specific_analysis.py
35
+ mstr_robotics/mcp_servers/_run_mstr_report_wizzard.py
36
+ mstr_robotics/mcp_servers/_server_config.py
37
+ mstr_robotics/mcp_servers/mstr_osi_mcp.py
38
+ mstr_robotics/osi_exporter/__init__.py
39
+ mstr_robotics/osi_exporter/export_dashboard.py
@@ -0,0 +1,30 @@
1
+ mstrio-py>=11.6
2
+ pandas>=2.2
3
+ numpy>=2.0
4
+ requests>=2.31
5
+ PyYAML>=6.0
6
+ ruamel.yaml>=0.18
7
+ python-dotenv>=1.0
8
+ openpyxl>=3.1
9
+
10
+ [all]
11
+ MSTR-Robotics-magerdaniel[azure,rag,redis,servers]
12
+
13
+ [azure]
14
+ azure-storage-blob>=12.0
15
+
16
+ [dev]
17
+ ruff
18
+ vulture
19
+ jupyter
20
+
21
+ [rag]
22
+ openai>=1.0
23
+ flashtext>=2.7
24
+
25
+ [redis]
26
+ redis>=5.0
27
+
28
+ [servers]
29
+ mcp
30
+ MSTR-Robotics-magerdaniel[rag]
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: MSTR-Robotics-magerdaniel
3
+ Version: 0.5.0
4
+ Summary: Automation toolkit for MicroStrategy / Strategy One: object read-out, migration, comparison, RAG and OSI export.
5
+ Author-email: Daniel Mager <danielmager@gmx.de>
6
+ Requires-Python: >=3.12
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: mstrio-py>=11.6
9
+ Requires-Dist: pandas>=2.2
10
+ Requires-Dist: numpy>=2.0
11
+ Requires-Dist: requests>=2.31
12
+ Requires-Dist: PyYAML>=6.0
13
+ Requires-Dist: ruamel.yaml>=0.18
14
+ Requires-Dist: python-dotenv>=1.0
15
+ Requires-Dist: openpyxl>=3.1
16
+ Provides-Extra: rag
17
+ Requires-Dist: openai>=1.0; extra == "rag"
18
+ Requires-Dist: flashtext>=2.7; extra == "rag"
19
+ Provides-Extra: redis
20
+ Requires-Dist: redis>=5.0; extra == "redis"
21
+ Provides-Extra: azure
22
+ Requires-Dist: azure-storage-blob>=12.0; extra == "azure"
23
+ Provides-Extra: servers
24
+ Requires-Dist: mcp; extra == "servers"
25
+ Requires-Dist: MSTR-Robotics-magerdaniel[rag]; extra == "servers"
26
+ Provides-Extra: all
27
+ Requires-Dist: MSTR-Robotics-magerdaniel[azure,rag,redis,servers]; extra == "all"
28
+ Provides-Extra: dev
29
+ Requires-Dist: ruff; extra == "dev"
30
+ Requires-Dist: vulture; extra == "dev"
31
+ Requires-Dist: jupyter; extra == "dev"
32
+
33
+ # MSTR Robotics
34
+
35
+ A Python toolkit for MicroStrategy automation, object comparison, and Redis-based BI analysis.
36
+
37
+ ## Features
38
+
39
+ - **Object Comparison**: Compare MicroStrategy objects between environments using JSON diff analysis
40
+ - **Redis Integration**: Store and analyze BI metadata using Redis
41
+ - **Migration Tools**: Automate MicroStrategy object migration workflows
42
+
43
+ ## Project Structure
44
+
45
+ - `mstr_robotics/` - Main package with core functionality
46
+ - `notebooks/` - Jupyter notebooks for analysis and exploration
47
+ - `Dansfiles/` - Migration and automation scripts
48
+ - `config/` - Configuration files (YAML, JSON)
49
+ - `export/` - Export utilities and logs
50
+ - `alt/` - Alternative implementations and experiments
51
+
52
+ ## Setup
53
+
54
+ 1. Clone the repository
55
+ 2. Create virtual environment: `python -m venv .venv`
56
+ 3. Activate: `.venv\Scripts\Activate.ps1`
57
+ 4. Install dependencies: `pip install -r requirements.txt`
58
+
59
+ ## Usage
60
+
61
+ The Jupyter notebooks in `notebooks/` are the primary entry points (object
62
+ export, schema monitoring, migration, REGAM regression testing).
63
+
64
+ ## Development
65
+
66
+ - Python 3.12 required
67
+ - Uses Redis for data storage
68
+ - Jupyter notebooks for exploratory analysis
@@ -0,0 +1,36 @@
1
+ # MSTR Robotics
2
+
3
+ A Python toolkit for MicroStrategy automation, object comparison, and Redis-based BI analysis.
4
+
5
+ ## Features
6
+
7
+ - **Object Comparison**: Compare MicroStrategy objects between environments using JSON diff analysis
8
+ - **Redis Integration**: Store and analyze BI metadata using Redis
9
+ - **Migration Tools**: Automate MicroStrategy object migration workflows
10
+
11
+ ## Project Structure
12
+
13
+ - `mstr_robotics/` - Main package with core functionality
14
+ - `notebooks/` - Jupyter notebooks for analysis and exploration
15
+ - `Dansfiles/` - Migration and automation scripts
16
+ - `config/` - Configuration files (YAML, JSON)
17
+ - `export/` - Export utilities and logs
18
+ - `alt/` - Alternative implementations and experiments
19
+
20
+ ## Setup
21
+
22
+ 1. Clone the repository
23
+ 2. Create virtual environment: `python -m venv .venv`
24
+ 3. Activate: `.venv\Scripts\Activate.ps1`
25
+ 4. Install dependencies: `pip install -r requirements.txt`
26
+
27
+ ## Usage
28
+
29
+ The Jupyter notebooks in `notebooks/` are the primary entry points (object
30
+ export, schema monitoring, migration, REGAM regression testing).
31
+
32
+ ## Development
33
+
34
+ - Python 3.12 required
35
+ - Uses Redis for data storage
36
+ - Jupyter notebooks for exploratory analysis
@@ -0,0 +1,7 @@
1
+ """mstr_robotics — automation toolkit for MicroStrategy / Strategy One.
2
+
3
+ Object read-out, migration packaging, environment comparison, RAG helpers
4
+ and OSI dashboard export, driven by the Jupyter notebooks in ``notebooks/``.
5
+ """
6
+
7
+ __version__ = "0.5.0"
@@ -0,0 +1,289 @@
1
+ import json
2
+ import uuid
3
+
4
+ from mstr_robotics._helper import Misc
5
+
6
+ i_msic = Misc()
7
+
8
+
9
+ class MstrApi:
10
+ def get_prj_tbl(self, conn):
11
+ inst_u = f"{conn.base_url}/api/model/tables"
12
+ r = conn.get(inst_u)
13
+ return r
14
+
15
+ def get_base_formula_(self, conn, base_formula_id):
16
+
17
+ inst_u = f"{conn.base_url}/api/model/formulas/{base_formula_id}?showExpressionAs=tokens"
18
+ r = conn.get(inst_u).json()
19
+ return r
20
+
21
+ def get_dossier_prp_l(self, conn, dossier_id):
22
+ endpoint = f"/api/documents/{dossier_id}/prompts"
23
+ prp_l = conn.get(endpoint=endpoint).json()
24
+ return prp_l
25
+
26
+ def get_proj_obj_by_id_l(self, conn, obj_id_l, org_def_fg=False):
27
+ obj_prop_path_d_l = []
28
+ endpoint = f"{conn.base_url}/api/searches/objects?includeAncestors=true&showNavigationPath=true"
29
+ obj_id_l = list(set(obj_id_l))
30
+ obj_id_l = [x for x in obj_id_l if x is not None]
31
+ body_d = {"projectIdAndObjectIds": [{"projectId": conn.project_id, "objectIds": obj_id_l}]}
32
+ body_d = json.dumps(body_d)
33
+ response = conn.post(endpoint, data=body_d)
34
+ response_d = response.json()
35
+ try:
36
+ if response_d["totalItems"] > 0:
37
+ for prop in response_d["result"]:
38
+ if not org_def_fg:
39
+ obj_prop_path_d = {}
40
+
41
+ obj_prop_path_d["id"] = prop["id"]
42
+ obj_prop_path_d["name"] = prop["name"]
43
+ obj_prop_path_d["obj_type"] = prop["type"]
44
+ # obj_prop_path_d["description"]=prop["description"]
45
+ obj_prop_path_d["subtype"] = prop["subtype"]
46
+ obj_prop_path_d["dateCreated"] = prop["dateCreated"]
47
+ obj_prop_path_d["dateModified"] = prop["dateModified"]
48
+ obj_prop_path_d["version"] = prop["version"]
49
+ obj_prop_path_d["dateModified"] = prop["dateModified"]
50
+ obj_prop_path_d["owner"] = prop["owner"]["name"]
51
+ fold_path = ""
52
+ for fold in prop["ancestors"]:
53
+ fold_path += "/" + fold["name"]
54
+
55
+ obj_prop_path_d["fold_path"] = fold_path
56
+ obj_prop_path_d_l.append(obj_prop_path_d)
57
+ else:
58
+ obj_prop_path_d_l.append(prop)
59
+ return obj_prop_path_d_l
60
+ except Exception as e:
61
+ print(e)
62
+ return {}
63
+
64
+ def get_ele_prp_ans(self, conn, report_id, instance_id, prompt_id, att_form_str=None, offset=0, limit=200):
65
+ # get availeble objects from an element prompt
66
+ # be carefull, this can be an performance issue
67
+ # if the attribute has too many elements
68
+ rest_limit = limit
69
+ all_values = []
70
+ while rest_limit >= 0:
71
+ if att_form_str is None:
72
+ inst_u = f"{conn.base_url}/api/reports/{report_id}/instances/{instance_id}/prompts/{prompt_id}/elements?offset={offset}&limit={limit}"
73
+ else:
74
+ inst_u = f"{conn.base_url}/api/reports/{report_id}/instances/{instance_id}/prompts/{prompt_id}/elements?offset={offset}&limit={limit}&searchPattern={att_form_str}"
75
+ r = conn.get(inst_u, headers=conn.headers)
76
+
77
+ all_values.append(r.json()["elements"])
78
+ rest_limit = int(r.headers["x-mstr-total-count"]) - offset
79
+ offset += limit
80
+ return all_values
81
+
82
+ def get_cube_att_eleme_d_l(self, conn, cube_id, att_id):
83
+ url = f"{conn.base_url}/api/cubes/{cube_id}/attributes/{att_id}/elements?offset=0&limit=1000&elementIdFormat=TERSE_LONG"
84
+ at_ele_l = conn.get(url).json()
85
+ return at_ele_l
86
+
87
+ def create_dossier_instance(self, conn, dossier_id, body=None, error_msg=None):
88
+ endpoint = f"{conn.base_url}/api/dossiers/{dossier_id}/instances"
89
+ return conn.post(url=endpoint, json=body).json()["mid"]
90
+
91
+ def get_prp_ans(self, conn, report_id, instance_id, prompt_id, offset=0, limit=200):
92
+ # get availeble objects from an object prompt
93
+ rest_limit = limit
94
+ prp_ans_base_l = []
95
+ while rest_limit >= 0:
96
+ inst_u = f"{conn.base_url}/api/reports/{report_id}/instances/{instance_id}/prompts/{prompt_id}/objects?offset={offset}&limit={limit}"
97
+ r = conn.get(inst_u, headers=conn.headers)
98
+ prp_ans_base_l.extend(r.json()["objects"])
99
+ rest_limit = int(r.headers["x-mstr-total-count"]) - offset
100
+ offset += limit
101
+
102
+ return prp_ans_base_l
103
+
104
+ def cr_short_cut(self, conn, object_id, object_type, folder_id):
105
+ # create an short.
106
+ short_cut_folder_j = f'{{"folderId": "{folder_id}"}}'
107
+ short_cut_url = f"{conn.base_url}/api/objects/{object_id}/type/{str(object_type)}/shortcuts"
108
+ short_cut_obj_j = conn.post(short_cut_url, data=short_cut_folder_j)
109
+ return short_cut_obj_j
110
+
111
+ def rename_object(self, conn, object_id, object_type, new_name, desc_str):
112
+ # rename an existing object
113
+ # if an object of the same type allready exists in
114
+ # the same folder, it simply adds a random string
115
+ # fuck nows the meaning of flags=70. I just took it over
116
+ # from the swagger page
117
+ base_url = f"{conn.base_url}/api/objects/{object_id}?type={object_type}&flags=70"
118
+ try:
119
+ # short_cut_obj.alter(name=str(new_name) , description=str(desc_str))
120
+ body = "{" + f'"name":"{new_name}","description":"{str(desc_str)}"' + "}"
121
+ resp = conn.put(base_url, data=str(body))
122
+ except Exception:
123
+ # short_cut_obj.alter(name=str(new_name+ uuid.uuid1().hex), description=str(desc_str))
124
+ body = {"name": str(new_name + uuid.uuid1().hex), "description": str(desc_str)}
125
+ body = "{" + f'"name":"{new_name}{uuid.uuid1().hex}","description":"{str(desc_str)}"' + "}"
126
+ resp = conn.put(base_url, data=str(body))
127
+
128
+ return resp
129
+
130
+ def get_project_name(self, conn, project_id):
131
+ # provides a readable project name for humans
132
+ project_resp = conn.get(f"{conn.base_url}/api/projects")
133
+ project_name = ""
134
+ for p in project_resp.json():
135
+ if p["id"] == project_id:
136
+ project_name = p["name"]
137
+
138
+ if project_name != "":
139
+ return project_name
140
+ else:
141
+ raise
142
+
143
+ def get_prompt_def(self, conn, prompt_id):
144
+ inst_u = f"{conn.base_url}/api/model/prompts/{prompt_id}?showExpressionAs=tree"
145
+ r = conn.get(inst_u, headers=conn.headers)
146
+ return r.json()
147
+
148
+ def get_custom_group(self, conn, custom_group_id, show_expression_as="tokens"):
149
+ url = f"{conn.base_url}/api/model/customGroups/{custom_group_id}?showExpressionAs={show_expression_as}"
150
+ custom_group_def = conn.get(url)
151
+ return custom_group_def.json()
152
+
153
+ def get_consolidation(self, conn, consolidation_id):
154
+ url = f"{conn.base_url}/api/model/consolidations/{consolidation_id}"
155
+ consolidation_def = conn.get(url)
156
+ return consolidation_def.json()
157
+
158
+ def get_derived_element(self, conn, derived_element_id):
159
+ url = f"{conn.base_url}/api/model/derivedElements/{derived_element_id}"
160
+ derived_element_def = conn.get(url).json()
161
+ return derived_element_def
162
+
163
+ def get_hier_att(self, conn, hier_id, displayForms="All", offset=0, limit=200):
164
+ # Available displayForms: all, browseForms, reportDisplayForms, customForms, unknown
165
+ # I develope initially to get the form_ids for attribute qualification prompts
166
+ # what I like here is, that you get th most relevant infos of attributes
167
+ # in an simple way
168
+ rest_limit = limit
169
+ prp_ans_base_l = []
170
+ while rest_limit >= 0:
171
+ inst_u = f"{conn.base_url}/api/hierarchies/{hier_id}/attributes?displayForms={displayForms}&offset={offset}&limit={limit}"
172
+ r = conn.get(inst_u, headers=conn.headers)
173
+ prp_ans_base_l.append(r.json())
174
+ rest_limit = int(r.headers["x-mstr-total-count"]) - offset
175
+ offset += limit
176
+
177
+ return prp_ans_base_l
178
+
179
+ def get_report_sql(self, conn, report_id, instance_id):
180
+ # if a report runs into an error due to wrong SQL or
181
+ # doesn't return data, this can bee a big help
182
+
183
+ url = f"{conn.base_url}/api/v2/reports/{report_id}/instances/{instance_id}/sqlView"
184
+ rep_sql = conn.get(url)
185
+ return rep_sql
186
+
187
+ def get_report_all_def(
188
+ self, conn, report_id, show_expression_as="tokens", show_filter_tokens="true", show_advanced_properties="true"
189
+ ):
190
+ url = f"{conn.base_url}/api/model/reports/{report_id}?showExpressionAs={show_expression_as}&showFilterTokens={show_filter_tokens}&showAdvancedProperties={show_advanced_properties}"
191
+ report_def = conn.get(url)
192
+ return report_def.json()
193
+
194
+ def get_cube_all_def(
195
+ self, conn, cube_id, showExpressionAs="tokens", showFilterTokens="true", showAdvancedProperties="true"
196
+ ):
197
+ url = f"{conn.base_url}/api/model/cubes/{cube_id}?showExpressionAs={showExpressionAs}&showFilterTokens={showFilterTokens}&showAdvancedProperties={showAdvancedProperties}"
198
+ cube_all_def_d = conn.get(url).json()
199
+ return cube_all_def_d
200
+
201
+ def get_report_raw(self, conn, report_id, instance_id):
202
+ # normaly I use the report libraries from mstrio
203
+ # to fetch the data. Sometimes they bring back an error. so this one is for trouble
204
+ # shooting
205
+ url = f"{conn.base_url}/api/v2/reports/{report_id}/instances/{instance_id}/sqlView"
206
+ rep_sql = conn.get(url)
207
+ return rep_sql
208
+
209
+ def _get_vis_raw_metric_val(self, conn, dossier_id, instance_id, chapter_key, visual_key, offset=0, limit=100):
210
+ # reads out the metric values of a visualisation
211
+ # primary use is to read out REGAM JOBs
212
+ # technicaly it's an interim solution as I hope there will be
213
+ # a standard class in mstrio to export data from visuals
214
+ total = limit + 1
215
+ raw_val_l = []
216
+ metric_guid_d = {}
217
+ while total > offset:
218
+ regam_jobs_col_l = []
219
+ regam_job_metric_guid_l = []
220
+ # endpoint brings back data and the definition of the visual
221
+ url = f"{conn.base_url}/api/v2/dossiers/{dossier_id}/instances/{instance_id}/chapters/{chapter_key}/visualizations/{visual_key}?offset={offset}&limit={limit}"
222
+ data_viz = conn.get(url).json()
223
+ # read out the metric_id's in the viz
224
+
225
+ for m in data_viz["definition"]["grid"]["columns"][0]["elements"]:
226
+ regam_jobs_col_l.append(m["name"])
227
+ if "derived" in m.keys():
228
+ metric_guid_d["derived"] = m["derived"]
229
+ else:
230
+ metric_guid_d["derived"] = False
231
+
232
+ metric_guid_d["id"] = m["id"]
233
+ regam_job_metric_guid_l.append(metric_guid_d.copy())
234
+
235
+ # read out the metric values. values & ID's are machted over the order
236
+ regam_jobs_val_l = data_viz["data"]["metricValues"]["raw"]
237
+ raw_val_l.extend(i_msic.list_to_dict(list_in_l=regam_jobs_val_l, col_l=regam_jobs_col_l))
238
+ total = data_viz["data"]["paging"]["total"]
239
+ offset += limit
240
+
241
+ return {"metric_val_l": raw_val_l, "metric_guid_l": regam_job_metric_guid_l}
242
+
243
+ def get_dossier_def(self, conn, dossier_id):
244
+ url = f"{conn.base_url}/api/v2/dossiers/{dossier_id}/definition"
245
+ doss_hier = conn.get(url)
246
+ doss_hier_d = doss_hier.json()
247
+ doss_hier_d["type"] = 55
248
+ doss_hier_d["subtype"] = 14081
249
+
250
+ return doss_hier_d
251
+
252
+ def get_dossier_detail(self, conn, dossier_id, instance_id, chapter_key, vis_id):
253
+ url = f"{conn.base_url}/api/v2/dossiers/{dossier_id}/instances/"
254
+ url += f"{instance_id}/chapters/{chapter_key}/visualizations/{vis_id}?offset=0&limit=100000"
255
+ return conn.get(url).json()
256
+
257
+ def get_v2_cube_instance(self, conn, cube_id, offset_val, limit_val):
258
+ url = f"{conn.base_url}/api/v2/cubes/{cube_id}/instances?offset={offset_val}&limit={limit_val}"
259
+ return conn.post(url)
260
+
261
+ def run_mstr_search(self, conn, search_id, limit=50, includeAcl="false"):
262
+ all_results = []
263
+ offset = 0
264
+ totalItems = 0
265
+ while True:
266
+ url = f"{conn.base_url}/api/searchObjects/{search_id}/results?offset={offset}&limit={limit}&includeAncestors=false&includeAcl={includeAcl}"
267
+ response = conn.get(url)
268
+ results = response.json()
269
+ totalItems += results["totalItems"]
270
+ all_results.extend(results["result"])
271
+
272
+ if results["totalItems"] < limit:
273
+ break
274
+
275
+ offset += limit
276
+
277
+ all_result_d = {"totalItems": totalItems, "result": all_results}
278
+ return all_result_d
279
+
280
+ def get_open_prp_stat(self, conn, report_id, instance_id):
281
+ url = f"{conn.base_url}/api/reports/{report_id}/instances/{instance_id}/status"
282
+ stat = conn.get(url)
283
+
284
+ try:
285
+ status = stat.json()["status"]
286
+ except Exception:
287
+ print(stat)
288
+ status = 1
289
+ return status
@@ -0,0 +1,38 @@
1
+ import json
2
+
3
+
4
+ class FileIo:
5
+ # this class handels th io
6
+ # with the folder sytems
7
+
8
+ def write_JSON_to_file(self, data, file_name):
9
+ # writes data to file,
10
+ # used here forREGAM logs
11
+ with open(file_name, "w") as outfile:
12
+ outfile.write(json.dumps(data, indent=4))
13
+
14
+ def write_list_to_JSON_to_file(self, obj_l, file_name_key="file_name"):
15
+ for obj in obj_l:
16
+ try:
17
+ file_name = obj["file_name_key"]
18
+ self.write_JSON_to_file(data=obj.pop(file_name_key), file_name=file_name)
19
+ except Exception:
20
+ print(obj)
21
+
22
+ def load_JSON_files(self, file_path):
23
+ with open(file_path, "r") as file:
24
+ rag_obj_l = json.load(file)
25
+
26
+ return rag_obj_l
27
+
28
+
29
+ class GetObjJson:
30
+ def extract_obj_JSON(self, conn, obj_id, obj_type_id):
31
+ pass
32
+ """
33
+ get_attribute(connection: Connection, id: str, changeset_id: Optional[str] = None,
34
+ show_expression_as: Optional[List[str]] = None,
35
+ show_potential_tables: Optional[str] = None, show_fields: Optional[str] = None,
36
+ fields: Optional[str] = None):
37
+ """
38
+ return