From 5c267d50f8de4ade22a5492e80678cc8c2f45921 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:24:03 +0100 Subject: [PATCH 01/20] Removed disable rules --- .pylintrc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/.pylintrc b/.pylintrc index e6d1055..662f255 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,13 +1,5 @@ [pylint.messages_control] disable = - C0303, # Trailing whitespace - C0103, # Variable names - C0305, # Trailing newlines - C0304, # Missing final line C0301, # Line too long I1101, E1101, # C-modules members - W0621, # Redefine outer name R0913 # Too many arguments - -[MASTER] -ignore-paths = ^tests/ # Ignore the tests folder From 5dce3f284b2d952b670ae6ff0124fd7e8f07ab14 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:28:24 +0100 Subject: [PATCH 02/20] Lint fix --- ITK_dev_shared_components/graph/mail.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/ITK_dev_shared_components/graph/mail.py b/ITK_dev_shared_components/graph/mail.py index 0333b06..ff991e4 100644 --- a/ITK_dev_shared_components/graph/mail.py +++ b/ITK_dev_shared_components/graph/mail.py @@ -234,8 +234,6 @@ def delete_email(email: Email, graph_access: GraphAccess, *, permanent: bool=Fal move_email(email, "deleteditems", graph_access, well_known_folder=True) - - def _find_folder(response: dict, target_folder: str) -> str: """Find the target folder in From 142ef3d18d2bee6460f65300c8447dc6459603db Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:41:55 +0100 Subject: [PATCH 03/20] Bunch o fixes --- .../SAP/gridview_util.py | 72 ++++++------------- .../SAP/multi_session.py | 61 ++++++++-------- ITK_dev_shared_components/SAP/sap_login.py | 2 +- tests/test_gridview_util.py | 2 +- tests/test_opret_kundekontakt.py | 2 +- tests/test_tree_util.py | 8 +-- 6 files changed, 60 insertions(+), 87 deletions(-) diff --git a/ITK_dev_shared_components/SAP/gridview_util.py b/ITK_dev_shared_components/SAP/gridview_util.py index f927675..8889c74 100644 --- a/ITK_dev_shared_components/SAP/gridview_util.py +++ b/ITK_dev_shared_components/SAP/gridview_util.py @@ -1,4 +1,4 @@ -"""This module provides static functions to peform common tasks with SAP GuiGridView COM objects.""" +"""This module provides static functions to perform common tasks with SAP GuiGridView COM objects.""" def scroll_entire_table(grid_view, return_to_top=False) -> None: """This function scrolls through the entire table to load all cells. @@ -6,14 +6,13 @@ def scroll_entire_table(grid_view, return_to_top=False) -> None: Args: grid_view: A SAP GuiGridView object. return_to_top: Whether to return the table to the first row after scrolling. Defaults to False. - - Returns: - _type_: _description_ - """ + """ + if grid_view.RowCount == 0 or grid_view.VisibleRowCount == 0: + return for i in range(0, grid_view.RowCount, grid_view.VisibleRowCount): grid_view.FirstVisibleRow = i - + if return_to_top: grid_view.FirstVisibleRow = 0 @@ -28,7 +27,7 @@ def get_all_rows(grid_view, pre_load=True) -> tuple[tuple[str]]: Returns: tuple[tuple[str]]: A 2D tuple of all cell values in the gridview. - """ + """ if pre_load: scroll_entire_table(grid_view, True) @@ -43,9 +42,9 @@ def get_all_rows(grid_view, pre_load=True) -> tuple[tuple[str]]: for c in columns: v = grid_view.GetCellValue(r, c) row_data.append(v) - + output.append(tuple(row_data)) - + return tuple(output) @@ -60,7 +59,7 @@ def get_row(grid_view, row:int, scroll_to_row=False) -> tuple[str]: Returns: tuple[str]: A tuple of the row's data. - """ + """ if scroll_to_row: grid_view.FirstVisibleRow = row @@ -83,7 +82,7 @@ def iterate_rows(grid_view) -> tuple[str]: Yields: tuple[str]: A tuple of the next row's data. - """ + """ row = 0 while row < grid_view.RowCount: @@ -104,7 +103,7 @@ def get_column_titles(grid_view) -> tuple[str]: Returns: tuple[str]: A tuple of the gridview's column titles. - """ + """ return tuple(grid_view.GetColumnTitles(c)[0] for c in grid_view.ColumnOrder) @@ -123,7 +122,7 @@ def find_row_index_by_value(grid_view, column:str, value:str) -> int: Returns: int: The index of the first row which column value matches the given value. - """ + """ if column not in grid_view.ColumnOrder: raise ValueError(f"Column '{column}' not in grid_view") @@ -132,14 +131,14 @@ def find_row_index_by_value(grid_view, column:str, value:str) -> int: # Only scroll when row isn't visible if not grid_view.FirstVisibleRow <= row <= grid_view.FirstVisibleRow + grid_view.VisibleRowCount-1: grid_view.FirstVisibleRow = row - + if grid_view.GetCellValue(row, column) == value: return row - + return -1 -def find_all_row_indecies_by_value(grid_view, column:str, value:str) -> list[int]: - """Find all indecies of the rows where the given column's value +def find_all_row_indices_by_value(grid_view, column:str, value:str) -> list[int]: + """Find all indices of the rows where the given column's value match the given value. Returns an empty list if no row is found. Args: @@ -151,8 +150,8 @@ def find_all_row_indecies_by_value(grid_view, column:str, value:str) -> list[int ValueError: If the column name doesn't exist in the grid view. Returns: - list[int]: A list of row indecies where the value matches. - """ + list[int]: A list of row indices where the value matches. + """ if column not in grid_view.ColumnOrder: raise ValueError(f"Column '{column}' not in grid_view") @@ -162,39 +161,8 @@ def find_all_row_indecies_by_value(grid_view, column:str, value:str) -> list[int # Only scroll when row isn't visible if not grid_view.FirstVisibleRow <= row <= grid_view.FirstVisibleRow + grid_view.VisibleRowCount-1: grid_view.FirstVisibleRow = row - + if grid_view.GetCellValue(row, column) == value: rows.append(row) - - return rows - - - - -if __name__=='__main__': - import win32com.client - - SAP = win32com.client.GetObject("SAPGUI") - app = SAP.GetScriptingEngine - connection = app.Connections(0) - session = connection.Sessions(0) - - table = session.findById("wnd[0]/usr/cntlGRID1/shellcont/shell") - - rows = find_all_row_indecies_by_value(table, "ZZ_PARTNER", '15879880') - print(rows) - table.setCurrentCell(rows[0], "ZZ_PARTNER") - - # print(get_row(table, 1, True)) - - # scroll_entire_table(table) - - # data = get_all_rows(table) - # print(len(data), len(data[0])) - - # for r in iterate_rows(table): - # print(r) - - # print(get_column_titles(table)) - + return rows diff --git a/ITK_dev_shared_components/SAP/multi_session.py b/ITK_dev_shared_components/SAP/multi_session.py index f1ce075..b3d01de 100644 --- a/ITK_dev_shared_components/SAP/multi_session.py +++ b/ITK_dev_shared_components/SAP/multi_session.py @@ -5,13 +5,15 @@ import time import threading from typing import Callable +import math + import pythoncom import win32com.client import win32gui def run_with_session(session_index:int, func:Callable, args:tuple) -> None: - """Run a function in a sepcific session based on the sessions index. - This function is meant to be run inside a seperate thread. + """Run a function in a specific session based on the sessions index. + This function is meant to be run inside a separate thread. The function must take a session object as its first argument. Note that this function will not spawn the sessions before running, use spawn_sessions to do that. @@ -19,8 +21,8 @@ def run_with_session(session_index:int, func:Callable, args:tuple) -> None: pythoncom.CoInitialize() - SAP = win32com.client.GetObject("SAPGUI") - app = SAP.GetScriptingEngine + sap = win32com.client.GetObject("SAPGUI") + app = sap.GetScriptingEngine connection = app.Connections(0) session = connection.Sessions(session_index) @@ -28,6 +30,7 @@ def run_with_session(session_index:int, func:Callable, args:tuple) -> None: pythoncom.CoUninitialize() + def run_batch(func:Callable, args:tuple[tuple], num_sessions=6) -> None: """Run a function in parallel sessions. The function will be run {num_sessions} times with args[i] as input. @@ -40,7 +43,7 @@ def run_batch(func:Callable, args:tuple[tuple], num_sessions=6) -> None: for i in range(num_sessions): t = ExThread(target=run_with_session, args=(i, func, args[i])) threads.append(t) - + for t in threads: t.start() for t in threads: @@ -49,6 +52,7 @@ def run_batch(func:Callable, args:tuple[tuple], num_sessions=6) -> None: if t.error: raise t.error + def run_batches(func:Callable, args:tuple[tuple], num_sessions=6): """Run a function in parallel batches. This function runs the input function for each set of arguments in args. @@ -62,16 +66,25 @@ def run_batches(func:Callable, args:tuple[tuple], num_sessions=6): batch = args[b:b+num_sessions] run_batch(func, args, len(batch)) + def spawn_sessions(num_sessions=6) -> list: """A function to spawn multiple sessions of SAP. This function will attempt to spawn the desired number of sessions. - If the current number of open sessions exceeds the desired number of sessions + If the current number of already open sessions exceeds the desired number of sessions the already open sessions will not be closed to match the desired number. The number of sessions must be between 1 and 6. - Returns a list of all open sessions. + + Args: + num_sessions: The number of sessions desired. Defaults to 6. + + Raises: + ValueError: If the number of sessions is not between 1 and 6. + + Returns: + tuple: A tuple of all currently open sessions. """ - SAP = win32com.client.GetObject("SAPGUI") - app = SAP.GetScriptingEngine + sap = win32com.client.GetObject("SAPGUI") + app = sap.GetScriptingEngine connection = app.Connections(0) session = connection.Sessions(0) @@ -82,25 +95,17 @@ def spawn_sessions(num_sessions=6) -> list: for _ in range(num_sessions - connection.Sessions.count): session.CreateSession() - + # Wait for the sessions to spawn while connection.Sessions.count < num_sessions: time.sleep(0.1) - sessions = list(connection.Sessions) + sessions = tuple(connection.Sessions) num_sessions = len(sessions) - if num_sessions == 1: - c = 1 - elif num_sessions <= 4: - c = 2 - elif num_sessions <= 6: - c = 3 - - if num_sessions < 3: - r = 1 - else: - r = 2 + # Calculate number of columns and rows + c = math.ceil(math.sqrt(num_sessions)) + r = math.ceil(num_sessions / c) w, h = 1920//c, 1040//r @@ -111,20 +116,22 @@ def spawn_sessions(num_sessions=6) -> list: x = i % c * w y = i // c * h win32gui.MoveWindow(hwnd, x, y, w, h, True) - + return sessions -def get_all_SAP_sessions() -> tuple: + +def get_all_sap_sessions() -> tuple: """Returns a tuple of all open SAP sessions (on connection index 0). Returns: tuple: A tuple of SAP GuiSession objects. """ - SAP = win32com.client.GetObject("SAPGUI") - app = SAP.GetScriptingEngine + sap = win32com.client.GetObject("SAPGUI") + app = sap.GetScriptingEngine connection = app.Connections(0) return tuple(connection.Sessions) + class ExThread(threading.Thread): """A thread with a handle to get an exception raised inside the thread: ExThread.error""" def __init__(self, *args, **kwargs): @@ -136,5 +143,3 @@ def run(self): self._target(*self._args, **self._kwargs) except Exception as e: # pylint: disable=broad-exception-caught self.error = e - - diff --git a/ITK_dev_shared_components/SAP/sap_login.py b/ITK_dev_shared_components/SAP/sap_login.py index c2c98f5..2a54b91 100644 --- a/ITK_dev_shared_components/SAP/sap_login.py +++ b/ITK_dev_shared_components/SAP/sap_login.py @@ -97,7 +97,7 @@ def _wait_for_sap_to_open() -> None: for _ in range(10): time.sleep(1) try: - sessions = multi_session.get_all_SAP_sessions() + sessions = multi_session.get_all_sap_sessions() if len(sessions) > 0: return except pywintypes.com_error: diff --git a/tests/test_gridview_util.py b/tests/test_gridview_util.py index 846c355..40daac2 100644 --- a/tests/test_gridview_util.py +++ b/tests/test_gridview_util.py @@ -19,7 +19,7 @@ def tearDownClass(cls): def setUp(self) -> None: # Find SAP gridview (table) object for testing - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] self.table = session.findById("wnd[0]/usr/tabsDATA_DISP/tabpDATA_DISP_FC1/ssubDATA_DISP_SCA:RFMCA_COV:0202/cntlRFMCA_COV_0100_CONT5/shellcont/shell") def test_scroll_entire_table(self): diff --git a/tests/test_opret_kundekontakt.py b/tests/test_opret_kundekontakt.py index e6e1cf5..1fa2425 100644 --- a/tests/test_opret_kundekontakt.py +++ b/tests/test_opret_kundekontakt.py @@ -20,7 +20,7 @@ def test_opret_kundekontakt(self): fp = "25564617" aftaler = ("2544577", "1990437", "1473781") - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] # Test with 3 aftaler opret_kundekontakt.opret_kundekontakter(session, fp, aftaler, 'Orientering', "Test 1") diff --git a/tests/test_tree_util.py b/tests/test_tree_util.py index 98e6463..c9da187 100644 --- a/tests/test_tree_util.py +++ b/tests/test_tree_util.py @@ -22,7 +22,7 @@ def test_get_node_key_by_text(self): Test that strict search and fuzzy search works and throws errors on nonsense input. """ - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] tree = session.findById("wnd[0]/shellcont/shell") result = tree_util.get_node_key_by_text(tree, "25564617") @@ -43,7 +43,7 @@ def test_get_item_by_text(self): Test that strict search and fuzzy search works and throws errors on nonsense input. """ - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] tree = session.findById("wnd[0]/shellcont/shell") result = tree_util.get_item_by_text(tree, "25564617") @@ -62,7 +62,7 @@ def test_get_item_by_text(self): def test_check_uncheck_all_check_boxes(self): """Test check_all_check_boxes and uncheck_all_check_boxes.""" # Open popup with tree containing many checkboxes. - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] session.findById("wnd[0]/shellcont/shell").nodeContextMenu("GP0000000001") session.findById("wnd[0]/shellcont/shell").selectContextMenuItem("FLERE") @@ -83,7 +83,7 @@ def navigate_to_test_page(): """Launch SAP and navigate to fmcacov on FP 25564617.""" user, password = os.environ['SAP Login'].split(';') sap_login.login_using_cli(user, password) - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] session.startTransaction("fmcacov") session.findById("wnd[0]/usr/ctxtGPART_DYN").text = "25564617" session.findById("wnd[0]").sendVKey(0) From a52f51a559681be3e7481ab0ada007a865ed853d Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:45:14 +0100 Subject: [PATCH 04/20] Fix --- .../SAP/opret_kundekontakt.py | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/ITK_dev_shared_components/SAP/opret_kundekontakt.py b/ITK_dev_shared_components/SAP/opret_kundekontakt.py index e084b67..8fd67ce 100644 --- a/ITK_dev_shared_components/SAP/opret_kundekontakt.py +++ b/ITK_dev_shared_components/SAP/opret_kundekontakt.py @@ -6,7 +6,7 @@ def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, - art:Literal[' ', 'Automatisk', 'Fakturagrundlag', 'Fuldmagt ifm. værge', 'Konverteret', 'Myndighedshenvend.', 'Orientering', 'Returpost', 'Ringeaktivitet', 'Skriftlig henvend.', 'Telefonisk henvend.'], + art:Literal[' ', 'Automatisk', 'Fakturagrundlag', 'Fuldmagt ifm. værge', 'Konverteret', 'Myndighedshenvend.', 'Orientering', 'Returpost', 'Ringeaktivitet', 'Skriftlig henvend.', 'Telefonisk henvend.'], notat:str, lock=None) -> None: """Creates a kundekontakt on the given FP and aftaler. @@ -41,11 +41,11 @@ def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, # Go to editor and paste (lock if multithreaded) session.findById("wnd[0]/usr/subNOTICE:SAPLEENO:1002/btnEENO_TEXTE-EDITOR").press() - if lock: + if lock: lock.acquire() - _setClipboard(notat) + _set_clipboard(notat) session.findById("wnd[0]/tbar[1]/btn[9]").press() - if lock: + if lock: lock.release() # Back and save @@ -53,21 +53,13 @@ def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, session.findById("wnd[0]/tbar[0]/btn[11]").press() -def _setClipboard(text:str) -> None: +def _set_clipboard(text:str) -> None: + """Private function to set text to the clipboard. + + Args: + text: Text to set to clipboard. + """ win32clipboard.OpenClipboard() win32clipboard.EmptyClipboard() win32clipboard.SetClipboardText(text) win32clipboard.CloseClipboard() - - -if __name__ == '__main__': - from ITK_dev_shared_components.SAP import multi_session - from datetime import datetime - - session = multi_session.spawn_sessions(1)[0] - fp = '25564617' - aftaler = ['2291987', '2421562', '2311094'] - art = 'Orientering' - notat = 'Test '+ str(datetime.now()) - - opret_kundekontakter(session, fp, aftaler, 'Automatisk', notat) \ No newline at end of file From b4f6b823e4ab6a8ffe93d999677e5cf39111be69 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:48:52 +0100 Subject: [PATCH 05/20] fix --- ITK_dev_shared_components/SAP/sap_login.py | 137 +++++++++++++++------ 1 file changed, 102 insertions(+), 35 deletions(-) diff --git a/ITK_dev_shared_components/SAP/sap_login.py b/ITK_dev_shared_components/SAP/sap_login.py index 2a54b91..ed6f6a2 100644 --- a/ITK_dev_shared_components/SAP/sap_login.py +++ b/ITK_dev_shared_components/SAP/sap_login.py @@ -1,18 +1,21 @@ -"""This module provides a functions to open SAP GUI.""" +"""This module provides functions to handle opening and closing SAP Gui +as well as a function to change user passwords.""" import os import pathlib import subprocess import time + from selenium import webdriver from selenium.webdriver.common.by import By import pywintypes +import win32com.client + from ITK_dev_shared_components.SAP import multi_session def login_using_portal(username:str, password:str): """Open KMD Portal in Edge, login and start SAP GUI. - Args: user: KMD Portal username. password: KMD Portal password. @@ -26,13 +29,10 @@ def login_using_portal(username:str, password:str): user_field = driver.find_element(By.ID, 'logonuidfield') pass_field = driver.find_element(By.ID, 'logonpassfield') login_button = driver.find_element(By.ID, 'buttonLogon') - user_field.clear() user_field.send_keys(username) - pass_field.clear() pass_field.send_keys(password) - login_button.click() #Opus @@ -43,13 +43,11 @@ def login_using_portal(username:str, password:str): _wait_for_download() driver.quit() - - _wait_for_sap_to_open() + _wait_for_sap_session(10) def _wait_for_download(): """Private function that checks if the SAP.erp file has been downloaded. - Raises: TimeoutError: If the file hasn't been downloaded within 5 seconds. """ @@ -60,21 +58,24 @@ def _wait_for_download(): path = os.path.join(downloads_folder, file) os.startfile(path) return - + time.sleep(0.5) raise TimeoutError(f".SAP file not found in {downloads_folder}") -def login_using_cli(username: str, password: str, client='751', system='P02') -> None: +def login_using_cli(username: str, password: str, client:str='751', system:str='P02', timeout:int=10) -> None: """Open and login to SAP with commandline expressions. - Args: - username (str): AZ username - password (str): password - client (str, optional): Kommune ID (Aarhus = 751). Defaults to '751'. - system (str, optional): Environment SID (e.g. P02 = 'KMD OPUS Produktion [P02]'). Defaults to 'P02'. - """ - + username: AZ username + password: password + client: Kommune ID (Aarhus = 751). Defaults to '751'. + system: Environment SID (e.g. P02 = 'KMD OPUS Produktion [P02]'). Defaults to 'P02'. + timeout: The time in seconds to wait for SAP Logon to start. Defaults to 10. + Raises: + TimeoutError: If SAP doesn't start within timeout limit. + ValueError: If SAP is unable to log in using the given credentials. + """ + command_args = [ r"C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapshcut.exe", f"-system={system}", @@ -84,36 +85,102 @@ def login_using_cli(username: str, password: str, client='751', system='P02') -> ] subprocess.run(command_args, check=False) + _wait_for_sap_session(timeout) + if not _check_for_splash_screen(): + raise ValueError("Unable to log in. Please check username and password.") - _wait_for_sap_to_open() - - -def _wait_for_sap_to_open() -> None: - """Check every second for 10 seconds if the SAP Gui scripting engine is available. +def _wait_for_sap_session(timeout:int) -> None: + """Check every second if the SAP Gui scripting engine is available until timeout is reached. + Args: + timeout: The time in seconds to wait for SAP Logon to start. Defaults to 10. Raises: - TimeoutError: If SAP doesn't start within 10 seconds. - """ - for _ in range(10): + TimeoutError: If SAP doesn't start within timeout limit. + """ + for _ in range(timeout): time.sleep(1) try: - sessions = multi_session.get_all_sap_sessions() + sessions = multi_session.get_all_SAP_sessions() if len(sessions) > 0: return except pywintypes.com_error: pass - raise TimeoutError("SAP didn't respond within 10 seconds.") + raise TimeoutError(f"SAP didn't respond within timeout limit: {timeout} seconds.") -def kill_sap(): - """Kills all SAP processes currently running.""" - os.system("taskkill /F /IM saplogon.exe") -if __name__=="__main__": - # user = "az12345" - # password = "Hunter2" - # login_using_portal(user, password) - # login_using_cli(user, password) +def _check_for_splash_screen() -> bool: + """Check if the splash screen image is currently present. + Returns: + bool: True if the splash screen image is currently present. + """ + session = multi_session.get_all_SAP_sessions()[0] + image = session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[1]/shell", False) + + return image is not None + + +def change_password(username:str, old_password:str, new_password:str, + client:str='751', + system:str='...KMD OPUS Produktion [P02]', + timeout:int=10) -> None: + """Change the password of a user in SAP Gui. Closes SAP when done. + Args: + username: The username of the user. + old_password: The current password of the user. + new_password: The new password to change to. + client: The client number. Defaults to '751'. + system: The description string of the connection as displayed in SAP Logon. Defaults to '...KMD OPUS Produktion [P02]'. + timeout: The time in seconds to wait for SAP Logon to start. Defaults to 10. + Raises: + TimeoutError: If the connection couldn't be established within the timeout limit. + ValueError: If the current credentials are not valid or if the password can't be changed. + ValueError: If the new password is not valid. + + """ + + subprocess.Popen(r"C:\Program Files (x86)\SAP\FrontEnd\SAPgui\saplogon.exe") #pylint: disable=consider-using-with + + # Wait for SAP Logon to open + for _ in range(timeout): + time.sleep(1) + try: + sap = win32com.client.GetObject("SAPGUI") + app = sap.GetScriptingEngine + app.OpenConnection(system) + break + except pywintypes.com_error: + pass + else: + raise TimeoutError(f"SAP Logon didn't open within timeout limit: {timeout} seconds.") + + session = multi_session.get_all_SAP_sessions()[0] + + # Enter credentials + session.findById("wnd[0]/usr/txtRSYST-MANDT").text = client + session.findById("wnd[0]/usr/txtRSYST-BNAME").text = username + session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = old_password + session.findById("wnd[0]/tbar[1]/btn[5]").press() + + # Check status bar + status_bar = session.findById("wnd[0]/sbar") + if status_bar.MessageType != 'S': + text = status_bar.Text + kill_sap() + raise ValueError(f"Password change was blocked: {text}") + + # Enter new password + session.findById("wnd[1]/usr/pwdRSYST-NCODE").text = new_password + session.findById("wnd[1]/usr/pwdRSYST-NCOD2").text = new_password + session.findById("wnd[1]/tbar[0]/btn[0]").press() + + if not _check_for_splash_screen(): + kill_sap() + raise ValueError("New password couldn't be set. Please check password requirements.") + kill_sap() +def kill_sap(): + """Kills all SAP processes currently running.""" + os.system("taskkill /F /IM saplogon.exe > NUL 2>&1") From 3ea40198e1dcf18325db08e58338408ab6c3b2f9 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:51:43 +0100 Subject: [PATCH 06/20] fix --- ITK_dev_shared_components/SAP/sap_util.py | 12 +--- ITK_dev_shared_components/SAP/tree_util.py | 74 +++++++++++----------- 2 files changed, 38 insertions(+), 48 deletions(-) diff --git a/ITK_dev_shared_components/SAP/sap_util.py b/ITK_dev_shared_components/SAP/sap_util.py index 698d17a..70d022d 100644 --- a/ITK_dev_shared_components/SAP/sap_util.py +++ b/ITK_dev_shared_components/SAP/sap_util.py @@ -1,7 +1,7 @@ """This module provides miscellaneous static functions to peform common tasks in SAP.""" def print_all_descendants(container, max_depth=-1, indent=0): - """Prints the object and all of its decendants recursivly + """Prints the object and all of its descendants recursively to the console. Args: @@ -23,13 +23,3 @@ def print_all_descendants(container, max_depth=-1, indent=0): print_all_descendants(child, max_depth, indent+1) else: print(indent_text) - - -if __name__=='__main__': - from ITK_dev_shared_components.SAP import multi_session - - session = multi_session.spawn_sessions(1)[0] - - usr = session.FindById('/app/con[0]/ses[0]/wnd[0]/usr') - - print_all_descendants(usr) \ No newline at end of file diff --git a/ITK_dev_shared_components/SAP/tree_util.py b/ITK_dev_shared_components/SAP/tree_util.py index 034186e..3eeca44 100644 --- a/ITK_dev_shared_components/SAP/tree_util.py +++ b/ITK_dev_shared_components/SAP/tree_util.py @@ -1,71 +1,71 @@ -"""This module provides static functions to peform common tasks with SAP GuiTree COM objects.""" +"""This module provides static functions to perform common tasks with SAP GuiTree COM objects.""" -def get_node_key_by_text(tree, text: str, fuzzy=False) -> str: +def get_node_key_by_text(tree, text: str, fuzzy: bool=False) -> str: """Get the node key of a node based on its text. - tree: A SAP GuiTree object. - text: The text to search for. - fuzzy: Whether to check if the node text just contains the search text. + + Args: + tree: A SAP GuiTree object. + text: The text to search for. + fuzzy: Whether to check if the node text just contains the search text. + + Raises: + ValueError: If no node is found with the given text. + + Returns: + str: The node key of the found node. """ for key in tree.GetAllNodeKeys(): t = tree.GetNodeTextByKey(key) if t == text or (fuzzy and text in t): return key - + raise ValueError(f"No node with the text '{text}' was found.") -def get_item_by_text(tree, text: str, fuzzy=False) -> tuple[str,str]: + +def get_item_by_text(tree, text: str, fuzzy: bool=False) -> tuple[str,str]: """Get the node key and item name of an item based on its text. - tree: A SAP GuiTree object. - text: The text to search for. - fuzzy: Whether to check if the item text just contains the search text. + + Args: + tree: A SAP GuiTree object. + text: The text to search for. + fuzzy: Whether to check if the item text just contains the search text. + + Raises: + ValueError: If no tem is found with the given text. + + Returns: + tuple[str,str]: The node key and item name of the found item. """ for key in tree.GetAllNodeKeys(): for name in tree.GetColumnNames(): t = tree.GetItemText(key, name) - + if t == text or (fuzzy and text in t): return (key, name) - + raise ValueError(f"No item with the text '{text}' was found.") + def check_all_check_boxes(tree) -> None: """Find and check all checkboxes in the tree. - tree: A SAP GuiTree object. + + Args: + tree: A SAP GuiTree object. """ for key in tree.GetAllNodeKeys(): for name in tree.GetColumnNames(): if tree.GetItemType(key, name) == 3: tree.ChangeCheckBox(key, name, True) + def uncheck_all_check_boxes(tree) -> None: """Find and uncheck all checkboxes in the tree. - tree: A SAP GuiTree object. + + Args: + tree: A SAP GuiTree object. """ for key in tree.GetAllNodeKeys(): for name in tree.GetColumnNames(): if tree.GetItemType(key, name) == 3: tree.ChangeCheckBox(key, name, False) - - - - -if __name__ == '__main__': - from ITK_dev_shared_components.SAP import multi_session - - session = multi_session.spawn_sessions(1)[0] - - tree = session.findById('/app/con[0]/ses[0]/wnd[1]/usr/cntlCONTAINER_PSOBKEY/shellcont/shell/shellcont[1]/shell[1]') - - # print([tree.GetNodeTextByKey(key) for key in tree.GetAllNodeKeys()]) - # print([tree.GetItemText(key, '&Hierarchy') for key in tree.GetAllNodeKeys()]) - - # print(list(tree.GetColumnNames())) - - # print(tree.GetItemText(' 2', '&Hierarchy')) - - # key, name = get_item_by_text(tree, '2291987', True) - # tree.ChangeCheckBox(key, name, True) - - check_all_check_boxes(tree) - uncheck_all_check_boxes(tree) \ No newline at end of file From 6be8ca67796c45443f4aed9ca1de3de1d88cdab9 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:52:18 +0100 Subject: [PATCH 07/20] Moved test files --- tests/{ => test_sap}/test_gridview_util.py | 0 tests/{ => test_sap}/test_opret_kundekontakt.py | 0 tests/{ => test_sap}/test_sap_login.py | 0 tests/{ => test_sap}/test_tree_util.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/{ => test_sap}/test_gridview_util.py (100%) rename tests/{ => test_sap}/test_opret_kundekontakt.py (100%) rename tests/{ => test_sap}/test_sap_login.py (100%) rename tests/{ => test_sap}/test_tree_util.py (100%) diff --git a/tests/test_gridview_util.py b/tests/test_sap/test_gridview_util.py similarity index 100% rename from tests/test_gridview_util.py rename to tests/test_sap/test_gridview_util.py diff --git a/tests/test_opret_kundekontakt.py b/tests/test_sap/test_opret_kundekontakt.py similarity index 100% rename from tests/test_opret_kundekontakt.py rename to tests/test_sap/test_opret_kundekontakt.py diff --git a/tests/test_sap_login.py b/tests/test_sap/test_sap_login.py similarity index 100% rename from tests/test_sap_login.py rename to tests/test_sap/test_sap_login.py diff --git a/tests/test_tree_util.py b/tests/test_sap/test_tree_util.py similarity index 100% rename from tests/test_tree_util.py rename to tests/test_sap/test_tree_util.py From bbccdb123fb97cee54a175440d43e23adda28362 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 11:56:14 +0100 Subject: [PATCH 08/20] fix --- tests/run_tests.bat | 28 ++++++++++++ tests/test_sap/test_gridview_util.py | 11 +++-- tests/test_sap/test_multi_session.py | 67 ++++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) create mode 100644 tests/run_tests.bat create mode 100644 tests/test_sap/test_multi_session.py diff --git a/tests/run_tests.bat b/tests/run_tests.bat new file mode 100644 index 0000000..7b7dd49 --- /dev/null +++ b/tests/run_tests.bat @@ -0,0 +1,28 @@ +@echo off + +:: Change dir to parent dir +echo Changing directory... +cd /d %~dp0.. + + +choice /C YN /M "Do you want to reset venv?" +if errorlevel 2 ( + echo Activating excisting venv... + call venv\Scripts\activate + +) else ( + echo Removing old venv... + rmdir /s /q venv + + echo Setting up new venv... + python -m venv venv + call venv\Scripts\activate + + echo Installing package... + pip install . +) + +echo Running unit tests... +python -m unittest discover + +pause \ No newline at end of file diff --git a/tests/test_sap/test_gridview_util.py b/tests/test_sap/test_gridview_util.py index 40daac2..010d0bc 100644 --- a/tests/test_sap/test_gridview_util.py +++ b/tests/test_sap/test_gridview_util.py @@ -11,7 +11,12 @@ def setUpClass(cls): """Launch SAP and navigate to fmcacov on FP 25564617 (Test person).""" sap_login.kill_sap() - test_tree_util.navigate_to_test_page() + user, password = os.environ['SAP Login'].split(';') + sap_login.login_using_cli(user, password) + session = multi_session.get_all_SAP_sessions()[0] + session.startTransaction("fmcacov") + session.findById("wnd[0]/usr/ctxtGPART_DYN").text = "25564617" + session.findById("wnd[0]").sendVKey(0) @classmethod def tearDownClass(cls): @@ -19,7 +24,7 @@ def tearDownClass(cls): def setUp(self) -> None: # Find SAP gridview (table) object for testing - session = multi_session.get_all_sap_sessions()[0] + session = multi_session.get_all_SAP_sessions()[0] self.table = session.findById("wnd[0]/usr/tabsDATA_DISP/tabpDATA_DISP_FC1/ssubDATA_DISP_SCA:RFMCA_COV:0202/cntlRFMCA_COV_0100_CONT5/shellcont/shell") def test_scroll_entire_table(self): @@ -73,7 +78,7 @@ def test_find_row_index_by_value(self): with self.assertRaises(ValueError): gridview_util.find_row_index_by_value(self.table, "Foo", "Bar") - def test_find_all_row_indecies_by_value(self): + def test_find_all_row_indices_by_value(self): """Test finding all rows by column value.""" # Test finding an actual value. indices = gridview_util.find_all_row_indices_by_value(self.table, "TXTU2", "Gebyr") diff --git a/tests/test_sap/test_multi_session.py b/tests/test_sap/test_multi_session.py new file mode 100644 index 0000000..db55199 --- /dev/null +++ b/tests/test_sap/test_multi_session.py @@ -0,0 +1,67 @@ +"""Tests relating to the module SAP.multi_session.""" + +import unittest +import os +import threading +from ITK_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt + +class TestMultiSession(unittest.TestCase): + """Tests relating to the module SAP.multi_session.""" + + def setUp(self): + sap_login.kill_sap() + user, password = os.environ['SAP Login'].split(';') + sap_login.login_using_cli(user, password) + + def tearDown(self): + sap_login.kill_sap() + + def test_spawn_sessions(self): + """Test spawning of multiple sessions. + It should only be possible to spawn between 1-6 sessions. + Also test getting already open sessions. + """ + with self.assertRaises(ValueError): + multi_session.spawn_sessions(0) + + with self.assertRaises(ValueError): + multi_session.spawn_sessions(7) + + sessions = multi_session.spawn_sessions(1) + self.assertEqual(len(sessions), 1) + + sessions = multi_session.spawn_sessions(6) + self.assertEqual(len(sessions), 6) + + sessions = multi_session.get_all_SAP_sessions() + self.assertEqual(len(sessions), 6) + + def test_run_batches(self): + """Test running a task in parallel in multiple sessions. + This also tests: + run_batch, run_with_session, ExThread + """ + + num_sessions = 6 + + multi_session.spawn_sessions(num_sessions) + + #Data + lock = threading.Lock() + + data = [ + ("25564617", None, 'Orientering', f"Hej {i}", lock) for i in range(12) + ] + + # Test with 12 cases + multi_session.run_batches(opret_kundekontakt.opret_kundekontakter, data, num_sessions) + + # Test with 5 cases + multi_session.run_batches(opret_kundekontakt.opret_kundekontakter, data[0:5], num_sessions) + + # Test with 1 case + multi_session.run_batches(opret_kundekontakt.opret_kundekontakter, data[0:1], num_sessions) + + +if __name__ == '__main__': + unittest.main() From 1ed74d4203b9afa27dc78b744b3b3ecacd070f15 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:29:13 +0100 Subject: [PATCH 09/20] Rename folder --- ITK_dev_shared_components/{SAP => sap}/__init__.py | 0 ITK_dev_shared_components/{SAP => sap}/gridview_util.py | 0 ITK_dev_shared_components/{SAP => sap}/multi_session.py | 0 ITK_dev_shared_components/{SAP => sap}/opret_kundekontakt.py | 0 ITK_dev_shared_components/{SAP => sap}/sap_login.py | 0 ITK_dev_shared_components/{SAP => sap}/sap_util.py | 0 ITK_dev_shared_components/{SAP => sap}/tree_util.py | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename ITK_dev_shared_components/{SAP => sap}/__init__.py (100%) rename ITK_dev_shared_components/{SAP => sap}/gridview_util.py (100%) rename ITK_dev_shared_components/{SAP => sap}/multi_session.py (100%) rename ITK_dev_shared_components/{SAP => sap}/opret_kundekontakt.py (100%) rename ITK_dev_shared_components/{SAP => sap}/sap_login.py (100%) rename ITK_dev_shared_components/{SAP => sap}/sap_util.py (100%) rename ITK_dev_shared_components/{SAP => sap}/tree_util.py (100%) diff --git a/ITK_dev_shared_components/SAP/__init__.py b/ITK_dev_shared_components/sap/__init__.py similarity index 100% rename from ITK_dev_shared_components/SAP/__init__.py rename to ITK_dev_shared_components/sap/__init__.py diff --git a/ITK_dev_shared_components/SAP/gridview_util.py b/ITK_dev_shared_components/sap/gridview_util.py similarity index 100% rename from ITK_dev_shared_components/SAP/gridview_util.py rename to ITK_dev_shared_components/sap/gridview_util.py diff --git a/ITK_dev_shared_components/SAP/multi_session.py b/ITK_dev_shared_components/sap/multi_session.py similarity index 100% rename from ITK_dev_shared_components/SAP/multi_session.py rename to ITK_dev_shared_components/sap/multi_session.py diff --git a/ITK_dev_shared_components/SAP/opret_kundekontakt.py b/ITK_dev_shared_components/sap/opret_kundekontakt.py similarity index 100% rename from ITK_dev_shared_components/SAP/opret_kundekontakt.py rename to ITK_dev_shared_components/sap/opret_kundekontakt.py diff --git a/ITK_dev_shared_components/SAP/sap_login.py b/ITK_dev_shared_components/sap/sap_login.py similarity index 100% rename from ITK_dev_shared_components/SAP/sap_login.py rename to ITK_dev_shared_components/sap/sap_login.py diff --git a/ITK_dev_shared_components/SAP/sap_util.py b/ITK_dev_shared_components/sap/sap_util.py similarity index 100% rename from ITK_dev_shared_components/SAP/sap_util.py rename to ITK_dev_shared_components/sap/sap_util.py diff --git a/ITK_dev_shared_components/SAP/tree_util.py b/ITK_dev_shared_components/sap/tree_util.py similarity index 100% rename from ITK_dev_shared_components/SAP/tree_util.py rename to ITK_dev_shared_components/sap/tree_util.py From a72165b3352a4cc9f6c971872b3f6fffd0d672e2 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:33:11 +0100 Subject: [PATCH 10/20] folder name changed --- .../__init__.py | 0 .../graph/__init__.py | 0 .../graph/authentication.py | 0 .../graph/mail.py | 0 .../sap/__init__.py | 0 .../sap/gridview_util.py | 0 .../sap/multi_session.py | 0 .../sap/opret_kundekontakt.py | 0 .../sap/sap_login.py | 0 .../sap/sap_util.py | 0 .../sap/tree_util.py | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename {ITK_dev_shared_components => itk_dev_shared_components}/__init__.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/graph/__init__.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/graph/authentication.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/graph/mail.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/__init__.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/gridview_util.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/multi_session.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/opret_kundekontakt.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/sap_login.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/sap_util.py (100%) rename {ITK_dev_shared_components => itk_dev_shared_components}/sap/tree_util.py (100%) diff --git a/ITK_dev_shared_components/__init__.py b/itk_dev_shared_components/__init__.py similarity index 100% rename from ITK_dev_shared_components/__init__.py rename to itk_dev_shared_components/__init__.py diff --git a/ITK_dev_shared_components/graph/__init__.py b/itk_dev_shared_components/graph/__init__.py similarity index 100% rename from ITK_dev_shared_components/graph/__init__.py rename to itk_dev_shared_components/graph/__init__.py diff --git a/ITK_dev_shared_components/graph/authentication.py b/itk_dev_shared_components/graph/authentication.py similarity index 100% rename from ITK_dev_shared_components/graph/authentication.py rename to itk_dev_shared_components/graph/authentication.py diff --git a/ITK_dev_shared_components/graph/mail.py b/itk_dev_shared_components/graph/mail.py similarity index 100% rename from ITK_dev_shared_components/graph/mail.py rename to itk_dev_shared_components/graph/mail.py diff --git a/ITK_dev_shared_components/sap/__init__.py b/itk_dev_shared_components/sap/__init__.py similarity index 100% rename from ITK_dev_shared_components/sap/__init__.py rename to itk_dev_shared_components/sap/__init__.py diff --git a/ITK_dev_shared_components/sap/gridview_util.py b/itk_dev_shared_components/sap/gridview_util.py similarity index 100% rename from ITK_dev_shared_components/sap/gridview_util.py rename to itk_dev_shared_components/sap/gridview_util.py diff --git a/ITK_dev_shared_components/sap/multi_session.py b/itk_dev_shared_components/sap/multi_session.py similarity index 100% rename from ITK_dev_shared_components/sap/multi_session.py rename to itk_dev_shared_components/sap/multi_session.py diff --git a/ITK_dev_shared_components/sap/opret_kundekontakt.py b/itk_dev_shared_components/sap/opret_kundekontakt.py similarity index 100% rename from ITK_dev_shared_components/sap/opret_kundekontakt.py rename to itk_dev_shared_components/sap/opret_kundekontakt.py diff --git a/ITK_dev_shared_components/sap/sap_login.py b/itk_dev_shared_components/sap/sap_login.py similarity index 100% rename from ITK_dev_shared_components/sap/sap_login.py rename to itk_dev_shared_components/sap/sap_login.py diff --git a/ITK_dev_shared_components/sap/sap_util.py b/itk_dev_shared_components/sap/sap_util.py similarity index 100% rename from ITK_dev_shared_components/sap/sap_util.py rename to itk_dev_shared_components/sap/sap_util.py diff --git a/ITK_dev_shared_components/sap/tree_util.py b/itk_dev_shared_components/sap/tree_util.py similarity index 100% rename from ITK_dev_shared_components/sap/tree_util.py rename to itk_dev_shared_components/sap/tree_util.py From 5cc55b62ff744eb84357c05857098f2d81e0e159 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:41:47 +0100 Subject: [PATCH 11/20] Whitespace --- itk_dev_shared_components/sap/opret_kundekontakt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itk_dev_shared_components/sap/opret_kundekontakt.py b/itk_dev_shared_components/sap/opret_kundekontakt.py index 8fd67ce..7cec041 100644 --- a/itk_dev_shared_components/sap/opret_kundekontakt.py +++ b/itk_dev_shared_components/sap/opret_kundekontakt.py @@ -5,7 +5,7 @@ from ITK_dev_shared_components.SAP import tree_util -def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, +def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, art:Literal[' ', 'Automatisk', 'Fakturagrundlag', 'Fuldmagt ifm. værge', 'Konverteret', 'Myndighedshenvend.', 'Orientering', 'Returpost', 'Ringeaktivitet', 'Skriftlig henvend.', 'Telefonisk henvend.'], notat:str, lock=None) -> None: """Creates a kundekontakt on the given FP and aftaler. From 8ba639fdbf976e8a4be04962c87e6072a4fc35e9 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:45:45 +0100 Subject: [PATCH 12/20] Updated tests --- tests/run_tests.bat | 10 ++++------ tests/test_sap/__init__.py | 0 2 files changed, 4 insertions(+), 6 deletions(-) create mode 100644 tests/test_sap/__init__.py diff --git a/tests/run_tests.bat b/tests/run_tests.bat index 7b7dd49..c1e6516 100644 --- a/tests/run_tests.bat +++ b/tests/run_tests.bat @@ -6,17 +6,15 @@ cd /d %~dp0.. choice /C YN /M "Do you want to reset venv?" + if errorlevel 2 ( echo Activating excisting venv... - call venv\Scripts\activate + call .venv\Scripts\activate ) else ( - echo Removing old venv... - rmdir /s /q venv - echo Setting up new venv... - python -m venv venv - call venv\Scripts\activate + python -m venv .venv + call .venv\Scripts\activate echo Installing package... pip install . diff --git a/tests/test_sap/__init__.py b/tests/test_sap/__init__.py new file mode 100644 index 0000000..e69de29 From b56e18153de701b0d8da15b958ccfa29e8d4a3aa Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:48:32 +0100 Subject: [PATCH 13/20] Project name changed --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a52a9a5..94cd2c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["setuptools>=65.0"] build-backend = "setuptools.build_meta" [project] -name = "ITK_dev_shared_components" +name = "itk_dev_shared_components" version = "0.0.6" authors = [ { name="ITK Development", email="itk-rpa@mkb.aarhus.dk" }, From 2795b5127296c2d6add5632521bbdb0c0dc386e8 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:48:36 +0100 Subject: [PATCH 14/20] Fix --- tests/run_tests.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run_tests.bat b/tests/run_tests.bat index c1e6516..8303530 100644 --- a/tests/run_tests.bat +++ b/tests/run_tests.bat @@ -2,7 +2,7 @@ :: Change dir to parent dir echo Changing directory... -cd /d %~dp0.. +cd /d %~dp0. choice /C YN /M "Do you want to reset venv?" From d7c642cdb0125d9539bdea950f6bdbf0b7ccdeb6 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 12:50:04 +0100 Subject: [PATCH 15/20] Module name changed --- itk_dev_shared_components/graph/mail.py | 2 +- itk_dev_shared_components/sap/opret_kundekontakt.py | 2 +- itk_dev_shared_components/sap/sap_login.py | 2 +- tests/test_graph/test_mail.py | 2 +- tests/test_sap/test_gridview_util.py | 2 +- tests/test_sap/test_multi_session.py | 2 +- tests/test_sap/test_opret_kundekontakt.py | 2 +- tests/test_sap/test_sap_login.py | 2 +- tests/test_sap/test_tree_util.py | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/itk_dev_shared_components/graph/mail.py b/itk_dev_shared_components/graph/mail.py index ff991e4..5bd120a 100644 --- a/itk_dev_shared_components/graph/mail.py +++ b/itk_dev_shared_components/graph/mail.py @@ -6,7 +6,7 @@ import requests from bs4 import BeautifulSoup -from ITK_dev_shared_components.graph.authentication import GraphAccess +from itk_dev_shared_components.graph.authentication import GraphAccess @dataclass diff --git a/itk_dev_shared_components/sap/opret_kundekontakt.py b/itk_dev_shared_components/sap/opret_kundekontakt.py index 7cec041..bdaf3c2 100644 --- a/itk_dev_shared_components/sap/opret_kundekontakt.py +++ b/itk_dev_shared_components/sap/opret_kundekontakt.py @@ -2,7 +2,7 @@ from typing import Literal import win32clipboard -from ITK_dev_shared_components.SAP import tree_util +from itk_dev_shared_components.SAP import tree_util def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, diff --git a/itk_dev_shared_components/sap/sap_login.py b/itk_dev_shared_components/sap/sap_login.py index ed6f6a2..777dadc 100644 --- a/itk_dev_shared_components/sap/sap_login.py +++ b/itk_dev_shared_components/sap/sap_login.py @@ -11,7 +11,7 @@ import pywintypes import win32com.client -from ITK_dev_shared_components.SAP import multi_session +from itk_dev_shared_components.SAP import multi_session def login_using_portal(username:str, password:str): diff --git a/tests/test_graph/test_mail.py b/tests/test_graph/test_mail.py index 476c983..681baf2 100644 --- a/tests/test_graph/test_mail.py +++ b/tests/test_graph/test_mail.py @@ -4,7 +4,7 @@ import json import os -from ITK_dev_shared_components.graph import authentication, mail +from itk_dev_shared_components.graph import authentication, mail class EmailTest(unittest.TestCase): """Tests relating to the graph.mail module.""" diff --git a/tests/test_sap/test_gridview_util.py b/tests/test_sap/test_gridview_util.py index 010d0bc..d2c48f3 100644 --- a/tests/test_sap/test_gridview_util.py +++ b/tests/test_sap/test_gridview_util.py @@ -2,7 +2,7 @@ import unittest import os -from ITK_dev_shared_components.SAP import gridview_util, sap_login, multi_session +from itk_dev_shared_components.SAP import gridview_util, sap_login, multi_session class TestGridviewUtil(unittest.TestCase): """Tests relating to the module SAP.gridview_util.""" diff --git a/tests/test_sap/test_multi_session.py b/tests/test_sap/test_multi_session.py index db55199..3311a80 100644 --- a/tests/test_sap/test_multi_session.py +++ b/tests/test_sap/test_multi_session.py @@ -3,7 +3,7 @@ import unittest import os import threading -from ITK_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt +from itk_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt class TestMultiSession(unittest.TestCase): """Tests relating to the module SAP.multi_session.""" diff --git a/tests/test_sap/test_opret_kundekontakt.py b/tests/test_sap/test_opret_kundekontakt.py index 1fa2425..497c058 100644 --- a/tests/test_sap/test_opret_kundekontakt.py +++ b/tests/test_sap/test_opret_kundekontakt.py @@ -2,7 +2,7 @@ import unittest import os -from ITK_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt +from itk_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt class TestOpretKundekontakt(unittest.TestCase): """Test relating to the module SAP.opret_kundekontakt.""" diff --git a/tests/test_sap/test_sap_login.py b/tests/test_sap/test_sap_login.py index a564fe7..6906dca 100644 --- a/tests/test_sap/test_sap_login.py +++ b/tests/test_sap/test_sap_login.py @@ -4,7 +4,7 @@ import unittest from tkinter import simpledialog -from ITK_dev_shared_components.SAP import sap_login +from itk_dev_shared_components.SAP import sap_login class TestSapLogin(unittest.TestCase): """Tests relating to the module SAP.sap_login.""" diff --git a/tests/test_sap/test_tree_util.py b/tests/test_sap/test_tree_util.py index c9da187..9609af2 100644 --- a/tests/test_sap/test_tree_util.py +++ b/tests/test_sap/test_tree_util.py @@ -3,7 +3,7 @@ import unittest import os -from ITK_dev_shared_components.SAP import tree_util, sap_login, multi_session +from itk_dev_shared_components.SAP import tree_util, sap_login, multi_session class TestTreeUtil(unittest.TestCase): """Tests relating to the module SAP.tree_util.""" From 3411fcfc0415503e64c8660c789416a033fb8330 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 13:09:16 +0100 Subject: [PATCH 16/20] Changed module name --- itk_dev_shared_components/sap/opret_kundekontakt.py | 2 +- itk_dev_shared_components/sap/sap_login.py | 4 ++-- tests/test_sap/test_gridview_util.py | 2 +- tests/test_sap/test_multi_session.py | 2 +- tests/test_sap/test_opret_kundekontakt.py | 2 +- tests/test_sap/test_sap_login.py | 2 +- tests/test_sap/test_tree_util.py | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/itk_dev_shared_components/sap/opret_kundekontakt.py b/itk_dev_shared_components/sap/opret_kundekontakt.py index bdaf3c2..306abff 100644 --- a/itk_dev_shared_components/sap/opret_kundekontakt.py +++ b/itk_dev_shared_components/sap/opret_kundekontakt.py @@ -2,7 +2,7 @@ from typing import Literal import win32clipboard -from itk_dev_shared_components.SAP import tree_util +from itk_dev_shared_components.sap import tree_util def opret_kundekontakter(session, fp:str, aftaler:list[str] | None, diff --git a/itk_dev_shared_components/sap/sap_login.py b/itk_dev_shared_components/sap/sap_login.py index 777dadc..f17492a 100644 --- a/itk_dev_shared_components/sap/sap_login.py +++ b/itk_dev_shared_components/sap/sap_login.py @@ -11,7 +11,7 @@ import pywintypes import win32com.client -from itk_dev_shared_components.SAP import multi_session +from itk_dev_shared_components.sap import multi_session def login_using_portal(username:str, password:str): @@ -60,7 +60,7 @@ def _wait_for_download(): return time.sleep(0.5) - raise TimeoutError(f".SAP file not found in {downloads_folder}") + raise TimeoutError(f".sap file not found in {downloads_folder}") def login_using_cli(username: str, password: str, client:str='751', system:str='P02', timeout:int=10) -> None: diff --git a/tests/test_sap/test_gridview_util.py b/tests/test_sap/test_gridview_util.py index d2c48f3..f99e3ee 100644 --- a/tests/test_sap/test_gridview_util.py +++ b/tests/test_sap/test_gridview_util.py @@ -2,7 +2,7 @@ import unittest import os -from itk_dev_shared_components.SAP import gridview_util, sap_login, multi_session +from itk_dev_shared_components.sap import gridview_util, sap_login, multi_session class TestGridviewUtil(unittest.TestCase): """Tests relating to the module SAP.gridview_util.""" diff --git a/tests/test_sap/test_multi_session.py b/tests/test_sap/test_multi_session.py index 3311a80..1091a65 100644 --- a/tests/test_sap/test_multi_session.py +++ b/tests/test_sap/test_multi_session.py @@ -3,7 +3,7 @@ import unittest import os import threading -from itk_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt +from itk_dev_shared_components.sap import sap_login, multi_session, opret_kundekontakt class TestMultiSession(unittest.TestCase): """Tests relating to the module SAP.multi_session.""" diff --git a/tests/test_sap/test_opret_kundekontakt.py b/tests/test_sap/test_opret_kundekontakt.py index 497c058..78b13e3 100644 --- a/tests/test_sap/test_opret_kundekontakt.py +++ b/tests/test_sap/test_opret_kundekontakt.py @@ -2,7 +2,7 @@ import unittest import os -from itk_dev_shared_components.SAP import sap_login, multi_session, opret_kundekontakt +from itk_dev_shared_components.sap import sap_login, multi_session, opret_kundekontakt class TestOpretKundekontakt(unittest.TestCase): """Test relating to the module SAP.opret_kundekontakt.""" diff --git a/tests/test_sap/test_sap_login.py b/tests/test_sap/test_sap_login.py index 6906dca..4f4786d 100644 --- a/tests/test_sap/test_sap_login.py +++ b/tests/test_sap/test_sap_login.py @@ -4,7 +4,7 @@ import unittest from tkinter import simpledialog -from itk_dev_shared_components.SAP import sap_login +from itk_dev_shared_components.sap import sap_login class TestSapLogin(unittest.TestCase): """Tests relating to the module SAP.sap_login.""" diff --git a/tests/test_sap/test_tree_util.py b/tests/test_sap/test_tree_util.py index 9609af2..eaadf33 100644 --- a/tests/test_sap/test_tree_util.py +++ b/tests/test_sap/test_tree_util.py @@ -3,7 +3,7 @@ import unittest import os -from itk_dev_shared_components.SAP import tree_util, sap_login, multi_session +from itk_dev_shared_components.sap import tree_util, sap_login, multi_session class TestTreeUtil(unittest.TestCase): """Tests relating to the module SAP.tree_util.""" From 6de1121ced9f2b6ae2d1bef6d7762e3afd04c6c5 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 13:09:23 +0100 Subject: [PATCH 17/20] Updated test --- tests/__init__.py | 0 tests/run_tests.bat | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 tests/__init__.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/run_tests.bat b/tests/run_tests.bat index 8303530..c1e6516 100644 --- a/tests/run_tests.bat +++ b/tests/run_tests.bat @@ -2,7 +2,7 @@ :: Change dir to parent dir echo Changing directory... -cd /d %~dp0. +cd /d %~dp0.. choice /C YN /M "Do you want to reset venv?" From 0e1534e1b1430362e6c93310995ac1d5ffb81557 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 13:16:22 +0100 Subject: [PATCH 18/20] Changed function name --- tests/test_sap/test_gridview_util.py | 4 ++-- tests/test_sap/test_multi_session.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_sap/test_gridview_util.py b/tests/test_sap/test_gridview_util.py index f99e3ee..db0bb91 100644 --- a/tests/test_sap/test_gridview_util.py +++ b/tests/test_sap/test_gridview_util.py @@ -13,7 +13,7 @@ def setUpClass(cls): user, password = os.environ['SAP Login'].split(';') sap_login.login_using_cli(user, password) - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] session.startTransaction("fmcacov") session.findById("wnd[0]/usr/ctxtGPART_DYN").text = "25564617" session.findById("wnd[0]").sendVKey(0) @@ -24,7 +24,7 @@ def tearDownClass(cls): def setUp(self) -> None: # Find SAP gridview (table) object for testing - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] self.table = session.findById("wnd[0]/usr/tabsDATA_DISP/tabpDATA_DISP_FC1/ssubDATA_DISP_SCA:RFMCA_COV:0202/cntlRFMCA_COV_0100_CONT5/shellcont/shell") def test_scroll_entire_table(self): diff --git a/tests/test_sap/test_multi_session.py b/tests/test_sap/test_multi_session.py index 1091a65..5e89358 100644 --- a/tests/test_sap/test_multi_session.py +++ b/tests/test_sap/test_multi_session.py @@ -33,7 +33,7 @@ def test_spawn_sessions(self): sessions = multi_session.spawn_sessions(6) self.assertEqual(len(sessions), 6) - sessions = multi_session.get_all_SAP_sessions() + sessions = multi_session.get_all_sap_sessions() self.assertEqual(len(sessions), 6) def test_run_batches(self): From ff5472296ee461b70d68485e84b696b09f124fb3 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 13:58:03 +0100 Subject: [PATCH 19/20] function name changed --- itk_dev_shared_components/sap/sap_login.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/itk_dev_shared_components/sap/sap_login.py b/itk_dev_shared_components/sap/sap_login.py index f17492a..27ffc78 100644 --- a/itk_dev_shared_components/sap/sap_login.py +++ b/itk_dev_shared_components/sap/sap_login.py @@ -100,7 +100,7 @@ def _wait_for_sap_session(timeout:int) -> None: for _ in range(timeout): time.sleep(1) try: - sessions = multi_session.get_all_SAP_sessions() + sessions = multi_session.get_all_sap_sessions() if len(sessions) > 0: return except pywintypes.com_error: @@ -114,7 +114,7 @@ def _check_for_splash_screen() -> bool: Returns: bool: True if the splash screen image is currently present. """ - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] image = session.findById("wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell/shellcont[1]/shell", False) return image is not None @@ -154,7 +154,7 @@ def change_password(username:str, old_password:str, new_password:str, else: raise TimeoutError(f"SAP Logon didn't open within timeout limit: {timeout} seconds.") - session = multi_session.get_all_SAP_sessions()[0] + session = multi_session.get_all_sap_sessions()[0] # Enter credentials session.findById("wnd[0]/usr/txtRSYST-MANDT").text = client From 877c720092ad943db42ae9514743eba4f9d64382 Mon Sep 17 00:00:00 2001 From: Mathias G Date: Fri, 10 Nov 2023 13:58:09 +0100 Subject: [PATCH 20/20] Lint fix --- tests/test_sap/test_gridview_util.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_sap/test_gridview_util.py b/tests/test_sap/test_gridview_util.py index db0bb91..b033a44 100644 --- a/tests/test_sap/test_gridview_util.py +++ b/tests/test_sap/test_gridview_util.py @@ -4,6 +4,8 @@ import os from itk_dev_shared_components.sap import gridview_util, sap_login, multi_session +# Some tests might look similiar, and we want this. pylint: disable=duplicate-code + class TestGridviewUtil(unittest.TestCase): """Tests relating to the module SAP.gridview_util.""" @classmethod