diff --git a/README.md b/README.md index c824733..febc4c0 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,9 @@ the PLAXIS program you need to use. | :------------------------------------: | :----------------: | | PLAXIS 2D CONNECT Edition V22 Update 2 | 1.0.2 | +| PLAXIS 3D Versions | Repository Version | +| :----------------: | :----------------: | +| PLAXIS 3D 2023.2 | 1.0.4 | # Contribution @@ -80,11 +83,11 @@ pip install pip-tools Generate requirements.txt file with: ```bash -pip-compile --extra=test --extra=lint --extra=docs --output-file=requirements.txt pyproject.toml +pip-compile --extra=test --output-file=requirements.txt pyproject.toml ``` Update the requirements within the defined ranges with: ```bash -pip-compile --upgrade --extra=test --extra=lint --extra=docs --output-file=requirements.txt pyproject.toml +pip-compile --upgrade --extra=test --output-file=requirements.txt pyproject.toml ``` \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 2ecfba2..289142d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "plxscripting" -version = "1.0.2" +version = "1.0.4" description = "Python files required to interact with PLAXIS API" requires-python = ">=3.9" dependencies = [ diff --git a/requirements.txt b/requirements.txt index 5af8160..a02950a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.9 # by the following command: # -# pip-compile --extra=docs --extra=lint --extra=test --output-file=requirements.txt pyproject.toml +# pip-compile --extra=test --output-file=requirements.txt pyproject.toml # asttokens==2.4.1 # via stack-data @@ -12,18 +12,28 @@ charset-normalizer==3.3.2 # via requests comm==0.2.0 # via ipykernel +coverage==6.5.0 + # via coveralls +coveralls==3.3.1 + # via plxscripting (pyproject.toml) debugpy==1.8.0 # via ipykernel decorator==5.1.1 # via ipython +docopt==0.6.2 + # via coveralls exceptiongroup==1.1.3 - # via ipython + # via + # ipython + # pytest executing==2.0.1 # via stack-data idna==3.4 # via requests importlib-metadata==6.8.0 # via jupyter-client +iniconfig==2.0.0 + # via pytest ipykernel==6.26.0 # via plxscripting (pyproject.toml) ipython==8.17.2 @@ -43,13 +53,17 @@ matplotlib-inline==0.1.6 nest-asyncio==1.5.8 # via ipykernel packaging==23.2 - # via ipykernel + # via + # ipykernel + # pytest parso==0.8.3 # via jedi pexpect==4.8.0 # via ipython platformdirs==3.11.0 # via jupyter-core +pluggy==1.3.0 + # via pytest prompt-toolkit==3.0.39 # via ipython psutil==5.9.6 @@ -64,6 +78,8 @@ pycryptodome==3.19.0 # via plxscripting (pyproject.toml) pygments==2.16.1 # via ipython +pytest==7.4.3 + # via plxscripting (pyproject.toml) python-dateutil==2.8.2 # via jupyter-client pyzmq==25.1.1 @@ -71,13 +87,17 @@ pyzmq==25.1.1 # ipykernel # jupyter-client requests==2.31.0 - # via plxscripting (pyproject.toml) + # via + # coveralls + # plxscripting (pyproject.toml) six==1.16.0 # via # asttokens # python-dateutil stack-data==0.6.3 # via ipython +tomli==2.0.1 + # via pytest tornado==6.3.3 # via # ipykernel diff --git a/src/plxscripting/__init__.py b/src/plxscripting/__init__.py index 0fc75dc..57699ed 100644 --- a/src/plxscripting/__init__.py +++ b/src/plxscripting/__init__.py @@ -1,3 +1,11 @@ # Copyright (c) Plaxis bv. All rights reserved. from .__version__ import ( - __title__, __description__, __url__, __version__, __license__, __author__, __author_email__, __copyright__) \ No newline at end of file + __title__, + __description__, + __url__, + __version__, + __license__, + __author__, + __author_email__, + __copyright__, +) diff --git a/src/plxscripting/__version__.py b/src/plxscripting/__version__.py index 45341eb..b11c1b7 100644 --- a/src/plxscripting/__version__.py +++ b/src/plxscripting/__version__.py @@ -1,9 +1,9 @@ # Copyright (c) Plaxis bv. All rights reserved. -__title__ = 'plxscripting' -__description__ = 'Python wrapper for the PLAXIS Remote Scripting server API' -__url__ = 'https://requests.readthedocs.io' -__version__ = '1.0.2' -__author__ = 'Plaxis bv' -__author_email__ = 'prg-pypi-deploy@bentley.com' -__license__ = 'Plaxis Public License 1.0' -__copyright__ = 'Copyright (c) Plaxis bv' +__title__ = "plxscripting" +__description__ = "Python wrapper for the PLAXIS Remote Scripting server API" +__url__ = "https://www.bentley.com" +__version__ = "1.0.4" +__author__ = "Plaxis bv" +__author_email__ = "prg-pypi-deploy@bentley.com" +__license__ = "Plaxis Public License 1.0" +__copyright__ = "Copyright (c) Plaxis bv" diff --git a/src/plxscripting/connection.py b/src/plxscripting/connection.py index 4c147d0..41db87f 100644 --- a/src/plxscripting/connection.py +++ b/src/plxscripting/connection.py @@ -3,10 +3,6 @@ The methods accept commmand line strings and return JSON for parsing by the client. -Subversion data: - $Id: connection.py 19385 2015-06-01 12:49:43Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/connection.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -31,39 +27,82 @@ import encryption -from .const import (ENVIRONMENT, ACTION, COMMANDS, NAME, FILENAME, INTERNAL_SERVER_ERROR, TOKENIZER, TOKENIZE, - MEMBERS, NAMED_OBJECTS, PROPERTY_VALUES, LIST, NUMBER_OF_RETRIES, SECONDS_DELAY_BEFORE_RETRY, - LIST_QUERIES, ENUMERATION, SELECTION, OWNER, PROPERTYNAME, GETLAST, PEEKLAST, - PHASEGUID, OBJECTS, NULL_GUID, JSON_KEY_RESPONSE, - JSON_KEY_CODE, JSON_KEY_REQUEST_DATA, JSON_KEY_REPLY_CODE, EXCEPTIONS) - -from .plx_scripting_exceptions import PlxScriptingError, EncryptionError, PlxScriptingPreconditionError +from .const import ( + ENVIRONMENT, + ACTION, + COMMANDS, + NAME, + FILENAME, + INTERNAL_SERVER_ERROR, + TOKENIZER, + TOKENIZE, + MEMBERS, + NAMED_OBJECTS, + PROPERTY_VALUES, + LIST, + NUMBER_OF_RETRIES, + SECONDS_DELAY_BEFORE_RETRY, + LIST_QUERIES, + ENUMERATION, + SELECTION, + OWNER, + PROPERTYNAME, + GETLAST, + PEEKLAST, + PHASEGUID, + OBJECTS, + NULL_GUID, + JSON_KEY_RESPONSE, + JSON_KEY_CODE, + JSON_KEY_REQUEST_DATA, + JSON_KEY_REPLY_CODE, + EXCEPTIONS, +) + +from .plx_scripting_exceptions import ( + PlxScriptingError, + EncryptionError, + PlxScriptingPreconditionError, +) JSON_HEADER = {"content-type": "application/json"} -MAD_EXCEPTION_ITEMS_TO_KEEP = ['operating system', 'program up time', 'processors', 'physical memory', - 'free disk space', 'executable', 'version ', 'exception class', 'exception message'] +MAD_EXCEPTION_ITEMS_TO_KEEP = [ + "operating system", + "program up time", + "processors", + "physical memory", + "free disk space", + "executable", + "version ", + "exception class", + "exception message", +] def clean_mad_exception_log(exception): - matches = re.findall(r'^(.*): (.*)$', exception, re.MULTILINE) - matches = [match for match in matches if any([item in match[0] for item in MAD_EXCEPTION_ITEMS_TO_KEEP])] + matches = re.findall(r"^(.*): (.*)$", exception, re.MULTILINE) + matches = [ + match + for match in matches + if any([item in match[0] for item in MAD_EXCEPTION_ITEMS_TO_KEEP]) + ] is_async_exception = False for index, match in enumerate(matches): - if 'Original call stack' in match[0]: + if "Original call stack" in match[0]: is_async_exception = True - matches[index] = (match[0].replace('Original call stack', '') + '\r\n').split(': ') - cleaned_exception = '\n'.join(['{}: {}'.format(*match) for match in matches]) + matches[index] = (match[0].replace("Original call stack", "") + "\r\n").split(": ") + cleaned_exception = "\n".join(["{}: {}".format(*match) for match in matches]) if is_async_exception: - start_tag = 'thread' - end_tag = 'main thread' + start_tag = "thread" + end_tag = "main thread" else: - start_tag = 'main thread' - end_tag = 'thread' - main_thread = re.search(r'{} .*?:.*?{}'.format(start_tag, end_tag), exception, re.DOTALL) + start_tag = "main thread" + end_tag = "thread" + main_thread = re.search(r"{} .*?:.*?{}".format(start_tag, end_tag), exception, re.DOTALL) if main_thread: - cleaned_exception += '\n' + main_thread.group(0).replace('\r\n{}'.format(end_tag), '') + cleaned_exception += "\n" + main_thread.group(0).replace("\r\n{}".format(end_tag), "") return cleaned_exception @@ -93,16 +132,16 @@ def last_request_data(self): def encrypt(self, payload): if JSON_KEY_REPLY_CODE in payload: - raise EncryptionError("Payload must not have {} field before" - " encryption.".format(JSON_KEY_REPLY_CODE)) + raise EncryptionError( + "Payload must not have {} field before encryption.".format(JSON_KEY_REPLY_CODE) + ) self._reply_code = uuid.uuid4().hex payload[JSON_KEY_REPLY_CODE] = self._reply_code jsondata = json.dumps(payload) self._last_request_data = jsondata - encrypted_jsondata, init_vector = encryption.encrypt( - jsondata, self._password) + encrypted_jsondata, init_vector = encryption.encrypt(jsondata, self._password) outer = {} outer[JSON_KEY_CODE] = init_vector @@ -113,8 +152,9 @@ def decrypt(self, response): response_json = response.json() encrypted_response = response_json[JSON_KEY_RESPONSE] init_vector = response_json[JSON_KEY_CODE] - decrypted_response_text = encryption.decrypt(encrypted_response, init_vector, - self._password) + decrypted_response_text = encryption.decrypt( + encrypted_response, init_vector, self._password + ) if len(decrypted_response_text) == 0: raise EncryptionError("Couldn't decrypt response.") @@ -122,19 +162,20 @@ def decrypt(self, response): decrypted_response = json.loads(decrypted_response_text) # Detect possible MITM attacks by verifying the reply code. if decrypted_response[JSON_KEY_REPLY_CODE] != self._reply_code: - raise EncryptionError("Reply code is different from what " - "was sent! Server might be spoofed!") + raise EncryptionError( + "Reply code is different from what was sent! Server might be spoofed!" + ) return Response(response, decrypted_response_text, decrypted_response) -class HTTPConnection(): +class HTTPConnection: """ Simple helper class which provides methods to make http requests to a server. Accepts string input and provides JSON output. """ - def __init__(self, host, port, timeout=5.0, request_timeout=None, password='', error_mode=None): + def __init__(self, host, port, timeout=5.0, request_timeout=None, password="", error_mode=None): self.host = host self.port = port self.timeout = timeout @@ -147,20 +188,17 @@ def __init__(self, host, port, timeout=5.0, request_timeout=None, password='', e self.HTTP_HOST_PREFIX = "http://{0}:{1}/".format(host, str(port)) - self.ENVIRONMENT_ACTION_PREFIX = (self.HTTP_HOST_PREFIX + ENVIRONMENT) + self.ENVIRONMENT_ACTION_PREFIX = self.HTTP_HOST_PREFIX + ENVIRONMENT - self.COMMAND_ACTION_PREFIX = (self.HTTP_HOST_PREFIX + COMMANDS) + self.COMMAND_ACTION_PREFIX = self.HTTP_HOST_PREFIX + COMMANDS - self.QUERY_MEMBER_NAMES_ACTION_PREFIX = ( - self.HTTP_HOST_PREFIX + MEMBERS) + self.QUERY_MEMBER_NAMES_ACTION_PREFIX = self.HTTP_HOST_PREFIX + MEMBERS - self.QUERY_NAMED_OBJECT_ACTION_PREFIX = ( - self.HTTP_HOST_PREFIX + NAMED_OBJECTS) + self.QUERY_NAMED_OBJECT_ACTION_PREFIX = self.HTTP_HOST_PREFIX + NAMED_OBJECTS - self.QUERY_PROPERTY_VALUES_ACTION_PREFIX = ( - self.HTTP_HOST_PREFIX + PROPERTY_VALUES) + self.QUERY_PROPERTY_VALUES_ACTION_PREFIX = self.HTTP_HOST_PREFIX + PROPERTY_VALUES - self.QUERY_LIST_PREFIX = (self.HTTP_HOST_PREFIX + LIST) + self.QUERY_LIST_PREFIX = self.HTTP_HOST_PREFIX + LIST self.QUERY_ENUMERATION_PREFIX = self.HTTP_HOST_PREFIX + ENUMERATION @@ -224,8 +262,8 @@ def _send_request(self, operation_address, payload): retry_response = self._retry_request(operation_address, payload.copy()) if retry_response: return retry_response - cleaned_log = clean_mad_exception_log(response.json().get('bugreport', '')) - error = PlxScriptingError('\n'.join([response.reason, cleaned_log])) + cleaned_log = clean_mad_exception_log(response.json().get("bugreport", "")) + error = PlxScriptingError("\n".join([response.reason, cleaned_log])) self._trigger_error_mode_behavior(error) else: raise PlxScriptingError(response.reason) @@ -246,7 +284,11 @@ def _send_request_and_get_response(self, operation_address, payload): response = self._make_request(operation_address, json_payload) # We can only decrypt json content # Some APIs do not set a response object. In that case don't try to decrypt - if self._password and 'json' in response.headers.get('Content-Type', '') and response.text != '': + if ( + self._password + and "json" in response.headers.get("Content-Type", "") + and response.text != "" + ): response = encryption_handler.decrypt(response) if self.logger is not None: @@ -262,14 +304,15 @@ def _make_request(self, operation_address, json_payload): :param str json_payload: The json string to be send as payload :return: The request response """ - response = self.session.post(operation_address, data=json_payload, - headers=JSON_HEADER, timeout=self.request_timeout) - content_length = response.headers.get('content-length') + response = self.session.post( + operation_address, data=json_payload, headers=JSON_HEADER, timeout=self.request_timeout + ) + content_length = response.headers.get("content-length") if content_length and len(response.content) != int(content_length): return self._make_request(operation_address, json_payload) return response - def request_environment(self, command_string, filename=''): + def request_environment(self, command_string, filename=""): """ Send a Plaxis environment command to the server, such as creating a new project. A specific filename may be provided when opening a @@ -317,9 +360,7 @@ def request_propertyvalues(self, owner_guids, property_name, phase_guid=""): while properties that are objects are represented as GUIDs. """ property_values_json = [ - {OWNER: owner_guid, - PROPERTYNAME: property_name, - PHASEGUID: phase_guid} + {OWNER: owner_guid, PROPERTYNAME: property_name, PHASEGUID: phase_guid} for owner_guid in owner_guids ] @@ -329,8 +370,7 @@ def request_propertyvalues(self, owner_guids, property_name, phase_guid=""): property_values_json = property_values_json[0] payload = {ACTION: {PROPERTY_VALUES: property_values_json}} - request = self._send_request( - self.QUERY_PROPERTY_VALUES_ACTION_PREFIX, payload) + request = self._send_request(self.QUERY_PROPERTY_VALUES_ACTION_PREFIX, payload) return request.json() def request_list(self, *list_queries): @@ -367,8 +407,10 @@ def request_server_name(self): Send a query to the server to capture the server name from response headers """ payload = {ACTION: {MEMBERS: [NULL_GUID]}} - response = self._send_request_and_get_response(self.QUERY_MEMBER_NAMES_ACTION_PREFIX, payload) - return response.headers.get('Server') + response = self._send_request_and_get_response( + self.QUERY_MEMBER_NAMES_ACTION_PREFIX, payload + ) + return response.headers.get("Server") def request_exceptions(self, clear=True): """ diff --git a/src/plxscripting/console.py b/src/plxscripting/console.py index 7d3e0a8..21c0e71 100644 --- a/src/plxscripting/console.py +++ b/src/plxscripting/console.py @@ -22,20 +22,26 @@ import code from distutils.version import StrictVersion -from .const import ARG_APP_SERVER_ADDRESS, ARG_APP_SERVER_PORT, ARG_PASSWORD, APP_SERVER_TYPE_TO_VARIABLE_SUFFIX +from .const import ( + ARG_APP_SERVER_ADDRESS, + ARG_APP_SERVER_PORT, + ARG_PASSWORD, + APP_SERVER_TYPE_TO_VARIABLE_SUFFIX, +) from .server import new_server from .const import INTERPRETER try: - _input = raw_input # Py < 3.0 + _input = raw_input # Py < 3.0 except Exception: - _input = input # Py >= 3.0 + _input = input # Py >= 3.0 def get_IPython_module(): try: import IPython - if StrictVersion(IPython.__version__) >= StrictVersion('1.1.0'): + + if StrictVersion(IPython.__version__) >= StrictVersion("1.1.0"): return IPython else: return None @@ -46,6 +52,7 @@ def get_IPython_module(): def get_jupyter_qt_console_module(): try: import qtconsole + return qtconsole except ImportError: return None @@ -55,8 +62,7 @@ def build_splash_lines(ipython): splash_lines = ["\nPLAXIS Interactive Python Console"] version = sys.version_info - python_version_line = "Python {}.{}.{}".format( - version.major, version.minor, version.micro) + python_version_line = "Python {}.{}.{}".format(version.major, version.minor, version.micro) if ipython is not None: python_version_line += " - IPython {}".format(ipython.__version__) @@ -66,59 +72,59 @@ def build_splash_lines(ipython): def print_splash(ipython): splash_lines = build_splash_lines(ipython) - print('\n'.join(splash_lines)) - print('=' * max(len(line) for line in splash_lines)) + print("\n".join(splash_lines)) + print("=" * max(len(line) for line in splash_lines)) def build_instructions(address, port, server_object_name, global_object_name): messages = [] - messages.append('Connected to {} on port {}'.format(address, port)) - messages.append('Available variables:') - messages.append(' {}: the application server'.format(server_object_name)) - messages.append(' {}: the global environment'.format(global_object_name)) - - messages.append('Example session:') - if server_object_name == "s_i": # input - messages.append(' >>> s_i.new()') - messages.append(' >>> g_i.borehole(0) # for 3D: g_i.borehole(0, 0)') - messages.append(' >>> g_i.soillayer(2)') - elif server_object_name == "s_o": # output + messages.append("Connected to {} on port {}".format(address, port)) + messages.append("Available variables:") + messages.append(" {}: the application server".format(server_object_name)) + messages.append(" {}: the global environment".format(global_object_name)) + + messages.append("Example session:") + if server_object_name == "s_i": # input + messages.append(" >>> s_i.new()") + messages.append(" >>> g_i.borehole(0) # for 3D: g_i.borehole(0, 0)") + messages.append(" >>> g_i.soillayer(2)") + elif server_object_name == "s_o": # output messages.append(' >>> s_o.open(r"C:\\path\\to\\your\\project")') - messages.append(' >>> result_type = g_o.ResultTypes.Soil.Utot') + messages.append(" >>> result_type = g_o.ResultTypes.Soil.Utot") messages.append(' >>> results = g_o.getresults(g_o.Phases[-1], result_type, "node")') messages.append(' >>> max_result = g_o.filter(results, "max")') - messages.append(' >>> g_o.echo(max_result)') - elif server_object_name == "s_t": # soiltest - messages.append(' >>> triaxial = g_t.Triaxial') - messages.append(' >>> triaxial.CellPressure = 120') - messages.append(' >>> g_t.calculate(triaxial)') + messages.append(" >>> g_o.echo(max_result)") + elif server_object_name == "s_t": # soiltest + messages.append(" >>> triaxial = g_t.Triaxial") + messages.append(" >>> triaxial.CellPressure = 120") + messages.append(" >>> g_t.calculate(triaxial)") - messages.insert(0, '-' * max(len(m) for m in messages)) + messages.insert(0, "-" * max(len(m) for m in messages)) messages.append(messages[0]) - return '\n'.join(messages) + return "\n".join(messages) def start_console(address, port, appservertype, password): """Allows starting up an interactive console with a 'blank slate' namespace This is currently used in the 'Expert -> Python -> Interpreter' option in PLAXIS""" if not address: - address = _input('Address (leave blank for localhost): ') + address = _input("Address (leave blank for localhost): ") if not address: - address = 'localhost' + address = "localhost" while port <= 0: - port = _input('Port number: ') + port = _input("Port number: ") try: port = int(port) if port < 0: - raise Exception('') + raise Exception("") except Exception: - print('Invalid port number: {}\n'.format(port)) + print("Invalid port number: {}\n".format(port)) port = 0 if password is None: - password = _input('Password (leave blank for empty password): ') + password = _input("Password (leave blank for empty password): ") server_object_name = "s_{}".format(APP_SERVER_TYPE_TO_VARIABLE_SUFFIX[appservertype]) global_object_name = "g_{}".format(APP_SERVER_TYPE_TO_VARIABLE_SUFFIX[appservertype]) @@ -128,15 +134,17 @@ def start_console(address, port, appservertype, password): qtconsole = get_jupyter_qt_console_module() starting_message = build_instructions(address, port, server_object_name, global_object_name) if qtconsole is not None: - print('Opening Jupyter QtConsole...') + print("Opening Jupyter QtConsole...") from plxscripting.run_jupyter import set_environment_variables_with_plaxis_vars from plxscripting.win32_plxutils import hide_windows from qtconsole import qtconsoleapp + set_environment_variables_with_plaxis_vars(address, port, appservertype, password) hide_windows(os.getpid()) qtconsoleapp.JupyterQtConsoleApp.launch_instance( - argv=[r'--ConsoleWidget.font_family=\"Lucida\ Console\",\ Monaco,\ monospace'], - kernel_name="plaxis_python3") + argv=[r"--ConsoleWidget.font_family=\"Lucida\ Console\",\ Monaco,\ monospace"], + kernel_name="plaxis_python3", + ) else: s, g = new_server(address, port, password=password) namespace = { @@ -145,8 +153,8 @@ def start_console(address, port, appservertype, password): ARG_PASSWORD: password, server_object_name: s, global_object_name: g, - 'get_equivalent': get_equivalent, - 'ge': ge + "get_equivalent": get_equivalent, + "ge": ge, } open_ipython_or_interactive_console(namespace, starting_message) @@ -166,24 +174,24 @@ def start_interpreter_method(exception): if not started: started = True namespace = caller_frame.f_locals - namespace['exception'] = exception + namespace["exception"] = exception banner_messages = [ - 'An exception was raised while executing a command', - 'You can use this interactive console to further debug the problem', - 'The exception object was stored on a variable named exception', - 'You can inspect it by running:', - ' >>> print(exception)', - 'When you are done just call exit:', - ' >>> exit()', + "An exception was raised while executing a command", + "You can use this interactive console to further debug the problem", + "The exception object was stored on a variable named exception", + "You can inspect it by running:", + " >>> print(exception)", + "When you are done just call exit:", + " >>> exit()", ] - open_ipython_or_interactive_console(namespace, '\n'.join(banner_messages)) + open_ipython_or_interactive_console(namespace, "\n".join(banner_messages)) started = False server.error_mode.start_interpreter_method = start_interpreter_method server.error_mode.behaviour = INTERPRETER -def open_ipython_or_interactive_console(namespace, pre_banner=''): +def open_ipython_or_interactive_console(namespace, pre_banner=""): ipython = get_IPython_module() if ipython is not None: print_splash(ipython) @@ -195,7 +203,7 @@ def open_ipython_or_interactive_console(namespace, pre_banner=''): try: ic.interact(pre_banner) except SystemExit: - print('Terminated') + print("Terminated") def inplace_console(): diff --git a/src/plxscripting/const.py b/src/plxscripting/const.py index 6cccc6c..3adbf34 100644 --- a/src/plxscripting/const.py +++ b/src/plxscripting/const.py @@ -1,10 +1,6 @@ """ Purpose: Constants for the plxscripting package -Subversion data: - $Id: const.py 19744 2015-07-10 12:52:29Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/const.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -49,7 +45,7 @@ FILENAME = "filename" LIST_QUERIES = "listqueries" GUID = "guid" -TOKENIZE = 'tokenize' +TOKENIZE = "tokenize" COUNT = "count" METHOD = "method" @@ -67,8 +63,8 @@ STAGED_PREFIX = "staged." OBJECTS = "objects" -GETLAST = 'getlast' -PEEKLAST = 'peeklast' +GETLAST = "getlast" +PEEKLAST = "peeklast" # REST API response strings JSON_COMMANDS = "commands" @@ -87,21 +83,21 @@ JSON_PROPERTIES = "properties" JSON_NAMEDOBJECTS = "namedobjects" JSON_ISLISTABLE = "islistable" -JSON_OWNERGUID = 'ownerguid' +JSON_OWNERGUID = "ownerguid" JSON_LISTQUERIES = "listqueries" JSON_METHODNAME = "methodname" JSON_OUTPUTDATA = "outputdata" JSON_MEMBERNAMES = "membernames" JSON_ENUMVALUES = "enumvalues" JSON_TYPE_JSON = "JSON" -JSON_KEY_JSON = 'json' -JSON_KEY_CONTENT_TYPE = 'ContentType' -JSON_KEY_REPLY_CODE = 'ReplyCode' -JSON_KEY_CODE = 'Code' -JSON_KEY_RESPONSE = 'Response' -JSON_KEY_REQUEST_DATA = 'RequestData' -JSON_NAME = 'Name' -JSON_HEADERS = 'headers' +JSON_KEY_JSON = "json" +JSON_KEY_CONTENT_TYPE = "ContentType" +JSON_KEY_REPLY_CODE = "ReplyCode" +JSON_KEY_CODE = "Code" +JSON_KEY_RESPONSE = "Response" +JSON_KEY_REQUEST_DATA = "RequestData" +JSON_NAME = "Name" +JSON_HEADERS = "headers" # Unit test "recorder" RECORDER_FOLDER = "recorder" @@ -111,39 +107,31 @@ # Other constants PLX_GLOBAL = "GLOBAL" -NULL_GUID = '{00000000-0000-0000-0000-000000000000}' +NULL_GUID = "{00000000-0000-0000-0000-000000000000}" # Command line argument constants -ARG_APP_SERVER_ADDRESS = 'AppServerAddress' -ARG_APP_SERVER_PORT = 'AppServerPort' -ARG_PASSWORD = 'AppServerPassword' -ARG_APP_SERVER_TYPE = 'AppServerType' +ARG_APP_SERVER_ADDRESS = "AppServerAddress" +ARG_APP_SERVER_PORT = "AppServerPort" +ARG_PASSWORD = "AppServerPassword" +ARG_APP_SERVER_TYPE = "AppServerType" # PLAXIS application types to server & global variable suffix INPUT = "input" OUTPUT = "output" SOILTEST = "soiltest" -APP_SERVER_TYPE_TO_VARIABLE_SUFFIX = { - INPUT: 'i', - OUTPUT: 'o', - SOILTEST: 't' -} -APP_SERVER_TYPE_TO_DEFAULT_SERVER_PORT = { - INPUT: 10000, - OUTPUT: 10001, - SOILTEST: 10002 -} +APP_SERVER_TYPE_TO_VARIABLE_SUFFIX = {INPUT: "i", OUTPUT: "o", SOILTEST: "t"} +APP_SERVER_TYPE_TO_DEFAULT_SERVER_PORT = {INPUT: 10000, OUTPUT: 10001, SOILTEST: 10002} # Selection commands -SELECTION_GET = 'get' -SELECTION_SET = 'set' -SELECTION_APPEND = 'append' -SELECTION_REMOVE = 'remove' +SELECTION_GET = "get" +SELECTION_SET = "set" +SELECTION_APPEND = "append" +SELECTION_REMOVE = "remove" # Server names -PLAXIS_2D = 'PLAXIS 2D' -PLAXIS_3D = 'PLAXIS 3D' +PLAXIS_2D = "PLAXIS 2D" +PLAXIS_3D = "PLAXIS 3D" PLAXIS_PATH = "plaxis_path" PLAXIS_VERSION = "plaxis_version" @@ -156,11 +144,11 @@ PLAXIS_3D_OUTPUT_EXECUTABLE_FILENAME = "Plaxis3DOutput.exe" # Error mode -INTERPRETER = 'interpreter' -RAISE = 'raise' -RETRY = 'retry' -PRECONDITION = 'precondition' -NOCLEAR = 'noclear' +INTERPRETER = "interpreter" +RAISE = "raise" +RETRY = "retry" +PRECONDITION = "precondition" +NOCLEAR = "noclear" NUMBER_OF_RETRIES = 1 SECONDS_DELAY_BEFORE_RETRY = 0.2 diff --git a/src/plxscripting/easy.py b/src/plxscripting/easy.py index 5143003..e1c3716 100644 --- a/src/plxscripting/easy.py +++ b/src/plxscripting/easy.py @@ -1,10 +1,6 @@ """ Purpose: Gives some very easy-to-use wrappers than can be imported in one go -Subversion data: - $Id: easy.py 19675 2015-07-01 14:31:55Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/easy.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -22,13 +18,22 @@ """ import sys -from .const import LOCAL_HOST, ARG_APP_SERVER_ADDRESS, ARG_APP_SERVER_PORT, ARG_PASSWORD, PLAXIS_3D, PLAXIS_2D +from .const import ( + LOCAL_HOST, + ARG_APP_SERVER_ADDRESS, + ARG_APP_SERVER_PORT, + ARG_PASSWORD, + PLAXIS_3D, + PLAXIS_2D, +) from .server import new_server as n_serv from .console import inplace_console as console from .console import get_equivalent, ge -def new_server(address=None, port=None, timeout=5.0, request_timeout=None, password=None, error_mode=()): +def new_server( + address=None, port=None, timeout=5.0, request_timeout=None, password=None, error_mode=() +): invoking_module_namespace = sys._getframe(1).f_locals ns_keys = list(invoking_module_namespace.keys()) @@ -41,5 +46,11 @@ def new_server(address=None, port=None, timeout=5.0, request_timeout=None, passw if password is None and ARG_PASSWORD in ns_keys: password = invoking_module_namespace[ARG_PASSWORD] - return n_serv(address=address, port=port, timeout=timeout, request_timeout=request_timeout, - password=password, error_mode=error_mode) + return n_serv( + address=address, + port=port, + timeout=timeout, + request_timeout=request_timeout, + password=password, + error_mode=error_mode, + ) diff --git a/src/plxscripting/error_mode.py b/src/plxscripting/error_mode.py index 3729680..df57c35 100644 --- a/src/plxscripting/error_mode.py +++ b/src/plxscripting/error_mode.py @@ -28,6 +28,7 @@ class ErrorMode(object): Class used to manage the triggered behaviour that happens when an internal server error occurs after making a request to Plaxis Remote Scripting Server """ + def __init__(self, *args): self._behaviour = None self._modifiers = set() diff --git a/src/plxscripting/image.py b/src/plxscripting/image.py index ec0c17d..67e0cd7 100644 --- a/src/plxscripting/image.py +++ b/src/plxscripting/image.py @@ -1,10 +1,6 @@ """ Purpose: Provide objects that represent an image created by the server. -Subversion data: - $Id: image.py 19791 2015-07-16 13:26:27Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/image.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -25,7 +21,7 @@ import codecs -TYPE_NAME_IMAGE = 'image/png' +TYPE_NAME_IMAGE = "image/png" class ImageBytesWrapper(object): @@ -42,7 +38,7 @@ def bytes(self): return self._image_bytes def save(self, path): - with open(path, 'wb') as image_file: + with open(path, "wb") as image_file: image_file.write(self._image_bytes) @@ -64,14 +60,15 @@ def save(self, path): def create_image(json_object): - if 'data' not in json_object: + if "data" not in json_object: raise Exception("JSON for image must contain 'data' property.") - image_bytes_base64 = json_object['data'].encode('ascii') - image_bytes = codecs.decode(image_bytes_base64, 'base64') + image_bytes_base64 = json_object["data"].encode("ascii") + image_bytes = codecs.decode(image_bytes_base64, "base64") try: from PIL import Image + image = Image.open(io.BytesIO(image_bytes)) return PILImageWrapper(image) except ImportError: diff --git a/src/plxscripting/interactive.py b/src/plxscripting/interactive.py index 856ddf0..84e2ec3 100644 --- a/src/plxscripting/interactive.py +++ b/src/plxscripting/interactive.py @@ -5,10 +5,6 @@ python interactive.py python "c:\Program Files (x86)\Plaxis\PLAXIS 3D\plxscripting\interactive.py" -Subversion data: - $Id: interactive.py 16030 2014-03-31 09:21:45Z ac $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/interactive.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -43,11 +39,13 @@ def set_paths_of_activated_conda_environment(): base_path, _ = os.path.split(exe_path) split_original_path.insert(0, base_path) - sub_paths_to_add = (("Library", "mingw-w64", "bin"), - ("Library", "usr", "bin"), - ("Library", "bin"), - ("Scripts", ), - ("bin", )) + sub_paths_to_add = ( + ("Library", "mingw-w64", "bin"), + ("Library", "usr", "bin"), + ("Library", "bin"), + ("Scripts",), + ("bin",), + ) for sub_path_tuple in sub_paths_to_add: path_to_insert = base_path @@ -68,37 +66,67 @@ def set_paths_of_activated_conda_environment(): if sys.version_info.major == 3 and sys.version_info.minor > 4: set_paths_of_activated_conda_environment() import importlib.util - plxscripting = importlib.util.find_spec('plxscripting', paths) + + plxscripting = importlib.util.find_spec("plxscripting", paths) else: import imp - found_module = imp.find_module('plxscripting', paths) - plxscripting = imp.load_module('plxscripting', *found_module) -from plxscripting.const import ARG_APP_SERVER_ADDRESS, ARG_APP_SERVER_PORT, ARG_PASSWORD, ARG_APP_SERVER_TYPE, INPUT, OUTPUT, SOILTEST + found_module = imp.find_module("plxscripting", paths) + plxscripting = imp.load_module("plxscripting", *found_module) + +from plxscripting.const import ( + ARG_APP_SERVER_ADDRESS, + ARG_APP_SERVER_PORT, + ARG_PASSWORD, + ARG_APP_SERVER_TYPE, + INPUT, + OUTPUT, + SOILTEST, +) from plxscripting.console import start_console def create_parser(): parser = argparse.ArgumentParser() - parser.add_argument('--{}'.format(ARG_APP_SERVER_ADDRESS), type=str, default='', - help='The address of the server to connect to.') - parser.add_argument('--{}'.format(ARG_APP_SERVER_PORT), type=int, default=0, - help='The port of the server to connect to.') - parser.add_argument('--{}'.format(ARG_APP_SERVER_TYPE), type=str, default=INPUT, - choices=[INPUT, OUTPUT, SOILTEST], - help='The application from which the script is run.') - parser.add_argument('--{}'.format(ARG_PASSWORD), type=str, default=None, - help='The password that will be used to secure the communication.') + parser.add_argument( + "--{}".format(ARG_APP_SERVER_ADDRESS), + type=str, + default="", + help="The address of the server to connect to.", + ) + parser.add_argument( + "--{}".format(ARG_APP_SERVER_PORT), + type=int, + default=0, + help="The port of the server to connect to.", + ) + parser.add_argument( + "--{}".format(ARG_APP_SERVER_TYPE), + type=str, + default=INPUT, + choices=[INPUT, OUTPUT, SOILTEST], + help="The application from which the script is run.", + ) + parser.add_argument( + "--{}".format(ARG_PASSWORD), + type=str, + default=None, + help="The password that will be used to secure the communication.", + ) return parser def parse_args(): parser = create_parser() args = vars(parser.parse_args()) - return args[ARG_APP_SERVER_ADDRESS], args[ARG_APP_SERVER_PORT], args[ARG_APP_SERVER_TYPE], args[ARG_PASSWORD] + return ( + args[ARG_APP_SERVER_ADDRESS], + args[ARG_APP_SERVER_PORT], + args[ARG_APP_SERVER_TYPE], + args[ARG_PASSWORD], + ) -if __name__ == '__main__': +if __name__ == "__main__": address, port, appservertype, password = parse_args() start_console(address, port, appservertype, password) - diff --git a/src/plxscripting/logger.py b/src/plxscripting/logger.py index 24d81d6..2301293 100644 --- a/src/plxscripting/logger.py +++ b/src/plxscripting/logger.py @@ -1,10 +1,6 @@ """ Purpose: Interfaces for logging things in the scripting layer. -Subversion data: - $Id: logger.py 16029 2014-03-28 16:00:15Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/logger.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -44,12 +40,12 @@ class Logger(object): def __init__(self, **kwargs): super(Logger, self).__init__() - if 'file' in kwargs: - self._file = kwargs['file'] - elif 'path' in kwargs: - self._file = open(kwargs['path'], 'w') + if "file" in kwargs: + self._file = kwargs["file"] + elif "path" in kwargs: + self._file = open(kwargs["path"], "w") else: - self._file = open(_getDefaultLogPath(), 'w') + self._file = open(_getDefaultLogPath(), "w") self._request_start_time = 0 self._payload = "" @@ -63,14 +59,18 @@ def log_request_end(self, request): ms_duration = int(1000.0 * duration) isodate = datetime.datetime.now().isoformat() request_text = "[{date}][{duration}ms][{status}({reason})][{url}]\n".format( - date=isodate, duration=ms_duration, status=request.status_code, - reason=request.reason, url=request.url) + date=isodate, + duration=ms_duration, + status=request.status_code, + reason=request.reason, + url=request.url, + ) self._file.write(request_text) self._file.write("Payload: {}\n".format(self._payload)) self._file.write("Returned Headers: {}\n".format(dumps(dict(request.headers)))) # The returned text contains double newlines, which is somewhat annoying to read. - returned = request.text.replace('\x0D\x0A', '\n') + returned = request.text.replace("\x0d\x0a", "\n") self._file.write("Returned: {}\n".format(returned)) self._file.flush() diff --git a/src/plxscripting/plaxis_connector.py b/src/plxscripting/plaxis_connector.py index fef59c8..33c208a 100644 --- a/src/plxscripting/plaxis_connector.py +++ b/src/plxscripting/plaxis_connector.py @@ -27,22 +27,34 @@ import winreg as wr from contextlib import closing import subprocess as sp -from .const import (PLAXIS_2D, PLAXIS_3D, PLAXIS_PATH, PLAXIS_BASE_REGEDIT_PATH, PLAXIS_2D_INPUT_EXECUTABLE_FILENAME, - PLAXIS_CLASSIC_2D_INPUT_EXECUTABLE_FILENAME, PLAXIS_3D_INPUT_EXECUTABLE_FILENAME, - PLAXIS_3D_OUTPUT_EXECUTABLE_FILENAME, PLAXIS_2D_OUTPUT_EXECUTABLE_FILENAME) +from .const import ( + PLAXIS_2D, + PLAXIS_3D, + PLAXIS_PATH, + PLAXIS_BASE_REGEDIT_PATH, + PLAXIS_2D_INPUT_EXECUTABLE_FILENAME, + PLAXIS_CLASSIC_2D_INPUT_EXECUTABLE_FILENAME, + PLAXIS_3D_INPUT_EXECUTABLE_FILENAME, + PLAXIS_3D_OUTPUT_EXECUTABLE_FILENAME, + PLAXIS_2D_OUTPUT_EXECUTABLE_FILENAME, +) from .easy import new_server # This is needed to prevent the OSError: [WinError 6] The handle is invalid sp._cleanup = lambda *args, **kwargs: None +FIRST_VERSION_WITH_OFFSET = 23 +FILE_VERSION_OFFSET = 2000 + + def get_free_port(): """ Searches for a free port that can be used on localhost :return int: The port number """ with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: - s.bind(('', 0)) + s.bind(("", 0)) return s.getsockname()[1] @@ -52,13 +64,13 @@ def generate_random_key(length=20): :param int length: The length of the string to generate :return string: A random generated string """ - return ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(length)) + return "".join(random.choice(string.ascii_letters + string.digits) for _ in range(length)) def _retrieve_registry_path(plaxis_reg_path): try: with wr.OpenKey(wr.HKEY_LOCAL_MACHINE, plaxis_reg_path, 0) as rk: - return wr.QueryValueEx(rk, 'Path')[0] + return wr.QueryValueEx(rk, "Path")[0] except EnvironmentError: pass @@ -87,28 +99,32 @@ def registry_key_enum_values(key): break -def find_path_from_registry_for_connect_edition(product_name, major_version): +def find_path_from_registry_generated_with_bentley_wix(product_name, major_version): """ - Returns the install directory for a CONNECT edition product + Returns the installation directory for the application installed with Bentley Wix installer framework :param str product_name: The name of the product (ex: Plaxis2D, Plaxis3D) :param int major_version: The major version of the product :return: """ path = r"SOFTWARE\Bentley\Installed_Products" + # Since version 2023, the registry and file versions are offset by 2000 + if major_version >= FILE_VERSION_OFFSET + FIRST_VERSION_WITH_OFFSET: + major_version -= FILE_VERSION_OFFSET try: with wr.OpenKey(wr.HKEY_LOCAL_MACHINE, path, 0) as rk: for sub_key_name in sub_keys_from_registry_key(rk): found_product_name = False found_version = False location = None - with wr.OpenKey(wr.HKEY_LOCAL_MACHINE, f'{path}\\{sub_key_name}', 0) as sk: + with wr.OpenKey(wr.HKEY_LOCAL_MACHINE, f"{path}\\{sub_key_name}", 0) as sk: for v in registry_key_enum_values(sk): - if v[0] == 'ProductName' and (v[1].lower().replace(' ', '') == - product_name.lower().replace(' ', '')): + if v[0] == "ProductName" and ( + v[1].lower().replace(" ", "") == product_name.lower().replace(" ", "") + ): found_product_name = True - if v[0] == 'Version' and v[1].startswith(f'{major_version}.'): + if v[0] == "Version" and v[1].startswith(f"{major_version}."): found_version = True - if v[0] == 'InstallDir': + if v[0] == "InstallDir": location = v[1] if found_product_name and found_version: return location @@ -118,16 +134,19 @@ def find_path_from_registry_for_connect_edition(product_name, major_version): class PlaxisConnectorException(Exception): """Base class for exceptions raised due to errors while using the PlaxisConnector""" + pass class TimeoutPlaxisConnectorException(PlaxisConnectorException): """Exception raised since call to PLAXIS timed out""" + pass class OtherPlaxisInstanceConnectorException(PlaxisConnectorException): """Exceptions raised when there is another instance of PLAXIS already open""" + pass @@ -136,10 +155,19 @@ class PlaxisConnector(object): This class is used to start PLAXIS input application and make the plxscripting server available to be used by clients """ + PASSWORD_SIZE = 20 - def __init__(self, plx_path=None, timeout=60.0, plx_server_name=PLAXIS_3D, extra_args=None, is_input=True, - password=None, connect_edition_major_version=None): + def __init__( + self, + plx_path=None, + timeout=60.0, + plx_server_name=PLAXIS_3D, + extra_args=None, + is_input=True, + password=None, + major_version=None, + ): """ :param str plx_path: Path of the PLAXIS application to open (if it's not provided than it will try to find one trough the registry @@ -149,10 +177,10 @@ def __init__(self, plx_path=None, timeout=60.0, plx_server_name=PLAXIS_3D, extra :param list extra_args: List of extra arguments that will be passed when starting the PLAXIS application :param bool is_input: True will open Input. False will open Output :param str password: sets password to communicate with the PLAXIS server - :param int connect_edition_major_version: The major version of the PLAXIS Connect edition to connect + :param int major_version: The major version of the PLAXIS application to connect """ self.plx_server_name = plx_server_name - self.connect_edition_major_version = connect_edition_major_version + self.major_version = major_version self.is_input = is_input self.plx_path = self.get_plaxis_path_from_registry() if plx_path is None else plx_path self._timeout = timeout @@ -191,18 +219,21 @@ def _get_plx_executable_path(self): def _open_server(self): plx_exe_path = self._get_plx_executable_path() if not plx_exe_path: - raise PlaxisConnectorException('Did not find {}'.format(self.plx_server_name)) + raise PlaxisConnectorException("Did not find {}".format(self.plx_server_name)) if self.is_input: # User can have only one Input instance opened at once self._check_no_other_plaxis_is_running() try: - args = [plx_exe_path, '--AppServerPort={}'.format(self.port), - '--AppServerPassword={}'.format(self.password)] + args = [ + plx_exe_path, + "--AppServerPort={}".format(self.port), + "--AppServerPassword={}".format(self.password), + ] if self.extra_args: args.extend(self.extra_args) process = sp.Popen(args, stdin=sp.DEVNULL, shell=True) except FileNotFoundError: - raise PlaxisConnectorException('Did not find {}'.format(plx_exe_path)) - server, plx_global = new_server('localhost', self.port, password=self.password) + raise PlaxisConnectorException("Did not find {}".format(plx_exe_path)) + server, plx_global = new_server("localhost", self.port, password=self.password) self._wait_for_server(server, process) return process, server, plx_global @@ -211,27 +242,31 @@ def _wait_for_server(self, server, process): start_time = time.perf_counter() while time.perf_counter() < start_time + self._timeout: if not psutil.pid_exists(process.pid): - raise PlaxisConnectorException('Did not find a running PLAXIS application') + raise PlaxisConnectorException("Did not find a running PLAXIS application") elif server.active: return else: time.sleep(0.1) self.terminate_process_and_child_processes() - raise TimeoutPlaxisConnectorException('Timeout exceeded when trying to connect to PLAXIS server') + raise TimeoutPlaxisConnectorException( + "Timeout exceeded when trying to connect to PLAXIS server" + ) def get_plaxis_path_from_registry(self): - if self.connect_edition_major_version: + if self.major_version: return self._get_plaxis_connect_edition_path_from_registry() server_executables = self._get_server_executables(force_input=True) for executable in server_executables: - plaxis_reg_path = PLAXIS_BASE_REGEDIT_PATH + '{}' + plaxis_reg_path = PLAXIS_BASE_REGEDIT_PATH + "{}" plaxis_reg_path = plaxis_reg_path.format(executable) path_found = _retrieve_registry_path(plaxis_reg_path) if path_found: return path_found def _get_plaxis_connect_edition_path_from_registry(self): - return find_path_from_registry_for_connect_edition(self.plx_server_name, self.connect_edition_major_version) + return find_path_from_registry_generated_with_bentley_wix( + self.plx_server_name, self.major_version + ) def terminate_process_and_child_processes(self): """A Windows OS specific approach""" @@ -239,7 +274,7 @@ def terminate_process_and_child_processes(self): startupinfo.dwFlags |= sp.STARTF_USESHOWWINDOW pid = self._get_plaxis_pid() if pid: - command = ['TASKKILL', '/F', '/T', '/PID', str(pid)] + command = ["TASKKILL", "/F", "/T", "/PID", str(pid)] sp.Popen(command, startupinfo=startupinfo) while self.is_plaxis_running(): time.sleep(0.2) @@ -258,13 +293,15 @@ def _get_plaxis_pid(self): def _check_no_other_plaxis_is_running(self): if self.is_plaxis_running(): - raise OtherPlaxisInstanceConnectorException('PLAXIS 3D is already running') + raise OtherPlaxisInstanceConnectorException("PLAXIS 3D is already running") def _get_server_executables(self, force_input=False): mapping = { (PLAXIS_3D, True): (PLAXIS_3D_INPUT_EXECUTABLE_FILENAME.lower(),), - (PLAXIS_2D, True): (PLAXIS_2D_INPUT_EXECUTABLE_FILENAME.lower(), - PLAXIS_CLASSIC_2D_INPUT_EXECUTABLE_FILENAME.lower()), + (PLAXIS_2D, True): ( + PLAXIS_2D_INPUT_EXECUTABLE_FILENAME.lower(), + PLAXIS_CLASSIC_2D_INPUT_EXECUTABLE_FILENAME.lower(), + ), (PLAXIS_3D, False): (PLAXIS_3D_OUTPUT_EXECUTABLE_FILENAME.lower(),), (PLAXIS_2D, False): (PLAXIS_2D_OUTPUT_EXECUTABLE_FILENAME.lower(),), } diff --git a/src/plxscripting/plaxis_jupyter_kernel.py b/src/plxscripting/plaxis_jupyter_kernel.py index 4a77237..2e24e65 100644 --- a/src/plxscripting/plaxis_jupyter_kernel.py +++ b/src/plxscripting/plaxis_jupyter_kernel.py @@ -22,12 +22,16 @@ from ipykernel.comm import CommManager from plxscripting.easy import * from plxscripting.console import build_instructions, build_splash_lines, get_IPython_module -from plxscripting.const import APP_SERVER_TYPE_TO_VARIABLE_SUFFIX, APP_SERVER_TYPE_TO_DEFAULT_SERVER_PORT, INPUT +from plxscripting.const import ( + APP_SERVER_TYPE_TO_VARIABLE_SUFFIX, + APP_SERVER_TYPE_TO_DEFAULT_SERVER_PORT, + INPUT, +) -ENV_VAR_PLAXIS_SERVER_ADDRESS = 'PLAXIS_SERVER_ADDRESS' -ENV_VAR_PLAXIS_SERVER_PORT = 'PLAXIS_SERVER_PORT' -ENV_VAR_PLAXIS_SERVER_PASSWORD = 'PLAXIS_SERVER_PASSWORD' -ENV_VAR_PLAXIS_SERVER_APP_TYPE = 'PLAXIS_APP_TYPE' +ENV_VAR_PLAXIS_SERVER_ADDRESS = "PLAXIS_SERVER_ADDRESS" +ENV_VAR_PLAXIS_SERVER_PORT = "PLAXIS_SERVER_PORT" +ENV_VAR_PLAXIS_SERVER_PASSWORD = "PLAXIS_SERVER_PASSWORD" +ENV_VAR_PLAXIS_SERVER_APP_TYPE = "PLAXIS_APP_TYPE" class PlaxisIPythonKernel(IPythonKernel): @@ -37,56 +41,66 @@ def __init__(self, **kwargs): # Initialize the InteractiveShell subclass self.user_ns = self.get_user_ns() - self.shell = self.shell_class.instance(parent=self, - profile_dir = self.profile_dir, - user_module = self.user_module, - user_ns = self.user_ns, - kernel = self, + self.shell = self.shell_class.instance( + parent=self, + profile_dir=self.profile_dir, + user_module=self.user_module, + user_ns=self.user_ns, + kernel=self, ) self.shell.displayhook.session = self.session self.shell.displayhook.pub_socket = self.iopub_socket - self.shell.displayhook.topic = self._topic('execute_result') + self.shell.displayhook.topic = self._topic("execute_result") self.shell.display_pub.session = self.session self.shell.display_pub.pub_socket = self.iopub_socket self.comm_manager = CommManager(parent=self, kernel=self) self.shell.configurables.append(self.comm_manager) - comm_msg_types = ['comm_open', 'comm_msg', 'comm_close'] + comm_msg_types = ["comm_open", "comm_msg", "comm_close"] for msg_type in comm_msg_types: self.shell_handlers[msg_type] = getattr(self.comm_manager, msg_type) def _init_from_environment(self): self.appservertype = os.environ.get(ENV_VAR_PLAXIS_SERVER_APP_TYPE, INPUT) - self.address = os.environ.get(ENV_VAR_PLAXIS_SERVER_ADDRESS, 'localhost') - self.password = os.environ.get(ENV_VAR_PLAXIS_SERVER_PASSWORD, '') - self.port = os.environ.get(ENV_VAR_PLAXIS_SERVER_PORT, APP_SERVER_TYPE_TO_DEFAULT_SERVER_PORT[self.appservertype]) - self.server_object_name = "s_{}".format(APP_SERVER_TYPE_TO_VARIABLE_SUFFIX[self.appservertype]) - self.global_object_name = "g_{}".format(APP_SERVER_TYPE_TO_VARIABLE_SUFFIX[self.appservertype]) + self.address = os.environ.get(ENV_VAR_PLAXIS_SERVER_ADDRESS, "localhost") + self.password = os.environ.get(ENV_VAR_PLAXIS_SERVER_PASSWORD, "") + self.port = os.environ.get( + ENV_VAR_PLAXIS_SERVER_PORT, APP_SERVER_TYPE_TO_DEFAULT_SERVER_PORT[self.appservertype] + ) + self.server_object_name = "s_{}".format( + APP_SERVER_TYPE_TO_VARIABLE_SUFFIX[self.appservertype] + ) + self.global_object_name = "g_{}".format( + APP_SERVER_TYPE_TO_VARIABLE_SUFFIX[self.appservertype] + ) def get_user_ns(self): s, g = new_server(self.address, self.port, password=self.password) namespace = { self.server_object_name: s, self.global_object_name: g, - 'get_equivalent': get_equivalent, - 'ge': ge + "get_equivalent": get_equivalent, + "ge": ge, } return namespace @property def banner(self): ipython = get_IPython_module() - splash_lines = build_splash_lines(ipython) + [''] - banner = '\n'.join(splash_lines) - banner += build_instructions(self.address, self.port, self.server_object_name, self.global_object_name) + splash_lines = build_splash_lines(ipython) + [""] + banner = "\n".join(splash_lines) + banner += build_instructions( + self.address, self.port, self.server_object_name, self.global_object_name + ) return banner def main(): from ipykernel.kernelapp import IPKernelApp + IPKernelApp.launch_instance(kernel_class=PlaxisIPythonKernel) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/src/plxscripting/plx_scripting_exceptions.py b/src/plxscripting/plx_scripting_exceptions.py index 1fd8a36..d3a453c 100644 --- a/src/plxscripting/plx_scripting_exceptions.py +++ b/src/plxscripting/plx_scripting_exceptions.py @@ -1,10 +1,6 @@ """ Purpose: exceptions for the plxscripting package. -Subversion data: - $Id: plx_scripting_exceptions.py 13488 2013-09-04 13:21:01Z ac $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/plx_scripting_exceptions.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -30,18 +26,18 @@ class PlxScriptingError(Exception): class EncryptionError(Exception): - """ Can be raised for all kinds of encryption related problems """ + """Can be raised for all kinds of encryption related problems""" class PlxScriptingLocalError(Exception): - """ This exception can be raised for client-side errors + """This exception can be raised for client-side errors that happens before we send commands to server or while we processing the results""" class PlxScriptingPreconditionError(Exception): - """ Base class for exceptions raised when there was an error on server-side before the request was made """ + """Base class for exceptions raised when there was an error on server-side before the request was made""" class PlxScriptingTokenizerError(Exception): - """ Base class for exceptions raised when there was an error while tokenizing """ + """Base class for exceptions raised when there was an error while tokenizing""" diff --git a/src/plxscripting/plxobjects.py b/src/plxscripting/plxobjects.py index 433c632..6fe0ad6 100644 --- a/src/plxscripting/plxobjects.py +++ b/src/plxscripting/plxobjects.py @@ -18,7 +18,8 @@ language governing rights and limitations under the PPL. """ -from .const import (MEMBERSUBLIST, MEMBERINDEX) +from .const import MEMBERSUBLIST, MEMBERINDEX + # used to import PlxProxyObject, but not referencing it directly, # otherwise cannot import because of circular reference from . import plxproxy @@ -47,9 +48,11 @@ def __repr__(self): if self._property_type is None: try: self._ensure_objects_cache_exists_for_key(0) - self._property_type = self._owner_objects_cache[0].__getattr__(self._property_name)._plx_type + self._property_type = ( + self._owner_objects_cache[0].__getattr__(self._property_name)._plx_type + ) except Exception: - self._property_type = 'Property' + self._property_type = "Property" return "<{} list>".format(self._property_type) @@ -68,8 +71,7 @@ def _ensure_objects_cache_exists_for_key(self, key): raise IndexError("list index out of range") else: - raise TypeError("list indices must be integers, not {}".format( - key.__class__.__name__)) + raise TypeError("list indices must be integers, not {}".format(key.__class__.__name__)) self._owner_objects_cache[key] = self._listable_parent[key] @@ -80,38 +82,45 @@ def _get_staged_properties_for_key(self, key): self._ensure_objects_cache_exists_for_key(key) if isinstance(key, slice): - return self._server.get_objects_property(proxy_objects=self._owner_objects_cache[key], - prop_name=self._property_name, - phase_object=self._phase_object) + return self._server.get_objects_property( + proxy_objects=self._owner_objects_cache[key], + prop_name=self._property_name, + phase_object=self._phase_object, + ) if not isinstance(key, int): - raise TypeError("list indices must be integers, not {}".format( - key.__class__.__name__)) + raise TypeError("list indices must be integers, not {}".format(key.__class__.__name__)) if key >= len(self): raise IndexError("list index out of range") - return self._server.get_object_property(proxy_object=self._owner_objects_cache[key], - prop_name=self._property_name, - phase_object=self._phase_object) + return self._server.get_object_property( + proxy_object=self._owner_objects_cache[key], + prop_name=self._property_name, + phase_object=self._phase_object, + ) def _get_properties_for_key(self, key): self._ensure_objects_cache_exists_for_key(key) if isinstance(key, slice): return self._server.call_listable_method( - self._listable_parent, MEMBERSUBLIST, startindex=key.start, stopindex=key.stop, - property_name=self._property_name) + self._listable_parent, + MEMBERSUBLIST, + startindex=key.start, + stopindex=key.stop, + property_name=self._property_name, + ) if not isinstance(key, int): - raise TypeError("list indices must be integers, not {}".format( - key.__class__.__name__)) + raise TypeError("list indices must be integers, not {}".format(key.__class__.__name__)) if key >= len(self): raise IndexError("list index out of range") - return self._server.call_listable_method(self._listable_parent, MEMBERINDEX, startindex=key, - property_name=self._property_name) + return self._server.call_listable_method( + self._listable_parent, MEMBERINDEX, startindex=key, property_name=self._property_name + ) def __getitem__(self, key): if self._phase_object is not None: @@ -148,8 +157,10 @@ def value(self): return self._get_value() def _get_value(self): - plx_objects_in_list = self._listable_parent[0:len(self)] - properties = self._server.get_objects_property(plx_objects_in_list, self._property_name, self._phase_object) + plx_objects_in_list = self._listable_parent[0 : len(self)] + properties = self._server.get_objects_property( + plx_objects_in_list, self._property_name, self._phase_object + ) # For staged IPs, the returned object is a staged IP proxy object and not the value directly, # so we query the value here @@ -174,9 +185,11 @@ def __getitem__(self, phase_object): # by defining __getitem__, the object can be iterated in a for loop with an integer key starting from 0. # if no exception is raised, the for loop is infinite. The following check solves this. if not isinstance(phase_object, plxproxy.PlxProxyObject): - raise TypeError('Expected phase object key') + raise TypeError("Expected phase object key") - return PlxObjectPropertyList(self._server, self._listable_parent, self._property_name, phase_object) + return PlxObjectPropertyList( + self._server, self._listable_parent, self._property_name, phase_object + ) def __repr__(self): return "" diff --git a/src/plxscripting/plxproxy.py b/src/plxscripting/plxproxy.py index 69b008a..da1df02 100644 --- a/src/plxscripting/plxproxy.py +++ b/src/plxscripting/plxproxy.py @@ -4,10 +4,6 @@ objects using Python without requiring knowledge of the underlying communication. -Subversion data: - $Id: plxproxy.py 21333 2016-02-22 14:14:52Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/plxproxy.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -29,11 +25,11 @@ from .plx_scripting_exceptions import PlxScriptingError from .plxobjects import PlxObjectPropertyList, PlxStagedIPList from .selection import Selection -from .const import (COUNT, SUBLIST, INDEX, STAGED_PREFIX, SELECTION) +from .const import COUNT, SUBLIST, INDEX, STAGED_PREFIX, SELECTION class PlxProxyObject_Abstract(object): - """ Abstract base class for plaxis proxy objects. """ + """Abstract base class for plaxis proxy objects.""" def __init__(self, server, guid): self._attr_cache = {} @@ -42,7 +38,7 @@ def __init__(self, server, guid): @abc.abstractmethod def __repr__(self): - """ Returns a representation of the object """ + """Returns a representation of the object""" return @property @@ -52,7 +48,7 @@ def attr_cache(self): @abc.abstractmethod def _ensure_cache_is_valid(self): - """ Ensures that the attribute cache is up to date """ + """Ensures that the attribute cache is up to date""" return def get_cmd_line_repr(self): @@ -66,8 +62,7 @@ def __dir__(self): """ Return all attributes of the object (both from Plaxis and locally) """ - return dir(super(PlxProxyObject_Abstract, self)) + list( - self.attr_cache) + return dir(super(PlxProxyObject_Abstract, self)) + list(self.attr_cache) def get_equivalent(self, object=None): if object is None: @@ -84,8 +79,7 @@ def get_equivalent(self, object=None): return self._server.get_named_object(object_name) except PlxScriptingError: pass - raise AttributeError( - "Requested object '{}' is not present".format(object_name)) + raise AttributeError("Requested object '{}' is not present".format(object_name)) class PlxProxyGlobalObject(PlxProxyObject_Abstract): @@ -151,7 +145,7 @@ def _is_model_group(proxy): # e.g. the Lines object and a Line_1 object. Both are listable, but # in the second case the points that make up the line shouldn't be # selected. Just the line. - return proxy.TypeName.value.endswith('ModelGroup') + return proxy.TypeName.value.endswith("ModelGroup") @selection.setter def selection(self, value): @@ -167,7 +161,7 @@ def __selection__(self, value): self._selection.set(list(value)) elif isinstance(value, PlxProxyObject): self._selection.set([value]) - elif hasattr(value, '__iter__'): + elif hasattr(value, "__iter__"): self._selection.set(value) elif isinstance(value, Selection): # Needed for +/- operators. Effectively a no-op @@ -195,7 +189,7 @@ def _ensure_cache_is_valid(self): class PlxProxyObject(PlxProxyObject_Abstract): - """ A proxy Plaxis object """ + """A proxy Plaxis object""" def __init__(self, server, guid, plx_type): super(PlxProxyObject, self).__init__(server, guid) @@ -219,21 +213,21 @@ def __getattr__(self, attr_name): # runtime, unlike IPs. try: # Access UserFeatures through _attr_cache to prevent infinite recursion of __getattr__ - userfeatures = self._attr_cache['UserFeatures'].value + userfeatures = self._attr_cache["UserFeatures"].value for uf in userfeatures: featureTypeName = uf._plx_type if featureTypeName.startswith(STAGED_PREFIX): - featureTypeName = featureTypeName[len(STAGED_PREFIX):] + featureTypeName = featureTypeName[len(STAGED_PREFIX) :] if featureTypeName == attr_name: return uf - except Exception: # don't catch BaseException and direct children (e.g. KeyboardInterrupt/SystemExit) + # don't catch BaseException and direct children (e.g. KeyboardInterrupt/SystemExit) + except Exception: pass # The requested attribute is not an attribute from the HTTP API (nor # another attribute of the python object). - raise AttributeError( - "Requested attribute '{}' is not present".format(attr_name)) + raise AttributeError("Requested attribute '{}' is not present".format(attr_name)) def __setattr__(self, name, value): """ @@ -302,11 +296,11 @@ def __getitem__(self, key): if isinstance(key, slice): # The server can process the original slice indices on its own return self._server.call_listable_method( - self, SUBLIST, startindex=key.start, stopindex=key.stop) + self, SUBLIST, startindex=key.start, stopindex=key.stop + ) if not isinstance(key, int): - raise TypeError("list indices must be integers, not {}".format( - key.__class__.__name__)) + raise TypeError("list indices must be integers, not {}".format(key.__class__.__name__)) if key >= len(self): raise IndexError("list index out of range") @@ -326,9 +320,9 @@ def __iter__(self): length = len(self) while cache_start < length: cache_end = min(cache_start + PlxProxyListable.ITER_CACHE_COUNT, length) - iter_cache = self._server.call_listable_method(self, SUBLIST, - startindex=cache_start, - stopindex=cache_end) + iter_cache = self._server.call_listable_method( + self, SUBLIST, startindex=cache_start, stopindex=cache_end + ) cache_start = cache_end for element in iter_cache: yield element @@ -357,7 +351,9 @@ def _ensure_cache_is_valid(self): if isinstance(attr, PlxProxyIPStaged): self._attr_cache[attr_name] = PlxStagedIPList(self._server, self, attr_name) else: - self._attr_cache[attr_name] = PlxObjectPropertyList(self._server, self, attr_name) + self._attr_cache[attr_name] = PlxObjectPropertyList( + self._server, self, attr_name + ) class PlxProxyValues(PlxProxyListable): @@ -374,10 +370,10 @@ def __exit__(self, type_, value, trace): class PlxProxyObjectMethod(object): - """ A proxy method for a PlxProxyObject """ + """A proxy method for a PlxProxyObject""" def __init__(self, server, proxy_object, method_name): - """ Create a proxy object method. """ + """Create a proxy object method.""" self._server = server self._proxy_object = proxy_object @@ -388,8 +384,7 @@ def __call__(self, *params): Method call on the target proxy object. The result of this call may be an exception, a list of new proxy objects, a boolean or a message. """ - return self._server.call_plx_object_method( - self._proxy_object, self._method_name, params) + return self._server.call_plx_object_method(self._proxy_object, self._method_name, params) class PlxProxyMaterial(PlxProxyObject): @@ -409,7 +404,7 @@ def reset_cache(self): class PlxProxyObjectProperty(PlxProxyObject): - """ A proxy property for a PlxProxyObject """ + """A proxy property for a PlxProxyObject""" def __init__(self, server, guid, plx_type, property_name, owner): super(PlxProxyObjectProperty, self).__init__(server, guid, plx_type) @@ -584,7 +579,7 @@ def _get_value_properties_dict(self): # PreviousPhase property of a phase. if isinstance(attr, PlxProxyIPObject): value_props_dict[attr_name] = attr - elif '__call__' not in attr.__dict__: + elif "__call__" not in attr.__dict__: value_props_dict[attr_name] = attr return value_props_dict @@ -604,28 +599,24 @@ def _ensure_cache_is_valid(self): # Merge the value properties with the intrinsic property # every time, since the value may change any time. - self._attr_cache = dict(self._ip_attr_cache, - **self._get_value_properties_dict()) + self._attr_cache = dict(self._ip_attr_cache, **self._get_value_properties_dict()) def __len__(self): value = self.value if not isinstance(value, PlxProxyListable): - raise TypeError("object of type '{}' has no len()".format( - type(value))) + raise TypeError("object of type '{}' has no len()".format(type(value))) return len(value) def __getitem__(self, index): value = self.value if not isinstance(value, PlxProxyListable): - raise TypeError("'{}' object is not subscriptable".format( - type(value))) + raise TypeError("'{}' object is not subscriptable".format(type(value))) return value[index] def __iter__(self): value = self.value if not isinstance(value, PlxProxyListable): - raise TypeError("'{}' object is not iterable".format( - type(value))) + raise TypeError("'{}' object is not iterable".format(type(value))) return iter(value) @@ -647,8 +638,7 @@ def __ne__(self, other): @property def enum_dict(self): type_dict = type(self).__dict__ - return {k: type_dict[k] for k in type_dict - if not k.startswith('__')} + return {k: type_dict[k] for k in type_dict if not k.startswith("__")} @property def strvalue(self): @@ -665,9 +655,10 @@ def strvalue(self): def strvalue(self, string): enum_dict = self.enum_dict if string not in enum_dict: - key_names = ', '.join(self.enum_dict.keys()) - raise ValueError("Invalid enum name '{}', valid values are '{}'".format( - string, key_names)) + key_names = ", ".join(self.enum_dict.keys()) + raise ValueError( + "Invalid enum name '{}', valid values are '{}'".format(string, key_names) + ) # Access type descriptor setter directly since assigning to self # doesn't work. @@ -701,18 +692,17 @@ def __getitem__(self, phase_object): # by defining __getitem__, the object can be iterated in a for loop with an integer key starting from 0. # if no exception is raised, the for loop is infinite. The following check solves this. if not isinstance(phase_object, PlxProxyObject): - raise TypeError('Expected phase object key') + raise TypeError("Expected phase object key") - return self._server.get_object_property( - self._owner, self._property_name, phase_object) + return self._server.get_object_property(self._owner, self._property_name, phase_object) def __setitem__(self, phase_object, value): - if value is None: # cannot set staged to None, as the Plaxis command line doesn't support the concept of None + # cannot set staged to None, as the Plaxis command line doesn't support the concept of None + if value is None: return None # ProxyObjects that are not ProxyIP need to be de-referenced by its value if isinstance(value, PlxProxyObjectProperty) and not isinstance(value, PlxProxyIPStaged): value = value.value - return self._server.set_object_property( - self, [phase_object, value]) + return self._server.set_object_property(self, [phase_object, value]) diff --git a/src/plxscripting/plxproxyfactory.py b/src/plxscripting/plxproxyfactory.py index ac39c79..d8d1ecb 100644 --- a/src/plxscripting/plxproxyfactory.py +++ b/src/plxscripting/plxproxyfactory.py @@ -1,10 +1,6 @@ """ Purpose: Create proxy objects from data supplied by the Plaxis HTTP API -Subversion data: - $Id: plxproxyfactory.py 20186 2015-09-09 13:04:15Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/plxproxyfactory.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -21,12 +17,22 @@ language governing rights and limitations under the PPL. """ -from .plxproxy import (PlxProxyObject, PlxProxyObjectMethod, - PlxProxyGlobalObject, PlxProxyObjectProperty, - PlxProxyListable, PlxProxyValues, PlxProxyIPBoolean, - PlxProxyIPInteger, PlxProxyIPDouble, PlxProxyMaterial, - PlxProxyIPObject, PlxProxyIPText, - PlxProxyIPEnumeration, PlxProxyIPStaged) +from .plxproxy import ( + PlxProxyObject, + PlxProxyObjectMethod, + PlxProxyGlobalObject, + PlxProxyObjectProperty, + PlxProxyListable, + PlxProxyValues, + PlxProxyIPBoolean, + PlxProxyIPInteger, + PlxProxyIPDouble, + PlxProxyMaterial, + PlxProxyIPObject, + PlxProxyIPText, + PlxProxyIPEnumeration, + PlxProxyIPStaged, +) TYPE_BOOLEAN = "Boolean" TYPE_TEXT = "Text" @@ -38,7 +44,7 @@ ENUM = "enum" STAGED = "staged" -from .const import (JSON_SUCCESS, JSON_ENUMVALUES, JSON_QUERIES, JSON_EXTRAINFO) +from .const import JSON_SUCCESS, JSON_ENUMVALUES, JSON_QUERIES, JSON_EXTRAINFO def is_primitive(plx_type): @@ -49,36 +55,41 @@ def is_primitive(plx_type): return plx_type in primitives or plx_type.startswith(ENUM) -class PlxProxyFactory(): +class PlxProxyFactory: """ Responsible for creation of proxy objects based on data supplied from HTTP API responses """ def __init__(self, connection): - """" + """ Store the mixin class to avoid creating the same class for every listable. """ self._connection = connection self.PlxProxyObjectListable = self.mix_in( - PlxProxyObject, PlxProxyListable, 'PlxProxyObjectListable') + PlxProxyObject, PlxProxyListable, "PlxProxyObjectListable" + ) self.PlxProxyObjectValues = self.mix_in( - PlxProxyObject, PlxProxyValues, 'PlxProxyObjectValues') + PlxProxyObject, PlxProxyValues, "PlxProxyObjectValues" + ) self.PlxProxyObjectMaterial = self.mix_in( - PlxProxyObject, PlxProxyMaterial, 'PlxProxyObjectMaterial') + PlxProxyObject, PlxProxyMaterial, "PlxProxyObjectMaterial" + ) self.PlxProxyObjectPropertyListable = self.mix_in( - PlxProxyObjectProperty, PlxProxyListable, 'PlxProxyObjectPropertyListable') + PlxProxyObjectProperty, PlxProxyListable, "PlxProxyObjectPropertyListable" + ) self.PlxProxyIPObjectListable = self.mix_in( - PlxProxyIPObject, PlxProxyListable, 'PlxProxyIPObjectListable') + PlxProxyIPObject, PlxProxyListable, "PlxProxyIPObjectListable" + ) - self.proxy_object_cache = {} # Maps GUIDs to proxies - self._proxy_enum_classes = {} # Maps enum names to enum classes + self.proxy_object_cache = {} # Maps GUIDs to proxies + self._proxy_enum_classes = {} # Maps enum names to enum classes def clear_proxy_object_cache(self): # Do NOT call this method if it's not truly needed (on account of @@ -94,8 +105,9 @@ def get_proxy_object_if_exists(self, guid): else: return None - def create_plx_proxy_object(self, server, guid, plx_type, is_listable, - property_name='', owner=None): + def create_plx_proxy_object( + self, server, guid, plx_type, is_listable, property_name="", owner=None + ): """ Creates a new PlxProxyObject with the supplied guid and object type """ @@ -104,10 +116,11 @@ def create_plx_proxy_object(self, server, guid, plx_type, is_listable, if owner is not None: proxy_object = self._create_plx_proxy_property( - server, guid, plx_type, is_listable, property_name, owner) - elif plx_type == 'PlxValues': + server, guid, plx_type, is_listable, property_name, owner + ) + elif plx_type == "PlxValues": proxy_object = self.PlxProxyObjectValues(server, guid, plx_type) - elif plx_type == 'SoilMat': + elif plx_type == "SoilMat": proxy_object = self.PlxProxyObjectMaterial(server, guid, plx_type) elif is_listable: proxy_object = self.PlxProxyObjectListable(server, guid, plx_type) @@ -118,53 +131,47 @@ def create_plx_proxy_object(self, server, guid, plx_type, is_listable, return proxy_object - def create_plx_proxy_object_method(self, server, proxy_object, - method_name): - """ Creates a new PlxProxyObjectMethod with the supplied name """ + def create_plx_proxy_object_method(self, server, proxy_object, method_name): + """Creates a new PlxProxyObjectMethod with the supplied name""" proxy_method = PlxProxyObjectMethod(server, proxy_object, method_name) return proxy_method def create_plx_proxy_global(self, server): - """ Creates a global proxy object """ + """Creates a global proxy object""" proxy_global = PlxProxyGlobalObject(server) return proxy_global - def _create_plx_proxy_property(self, server, guid, plx_type, is_listable, - property_name, owner): - """ Creates a new PlxProxyObjectProperty """ + def _create_plx_proxy_property(self, server, guid, plx_type, is_listable, property_name, owner): + """Creates a new PlxProxyObjectProperty""" if plx_type == TYPE_BOOLEAN: - proxy_property = PlxProxyIPBoolean(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyIPBoolean(server, guid, plx_type, property_name, owner) elif plx_type.startswith(ENUM): proxy_enum_class = self._create_proxy_enumeration(guid, plx_type) - proxy_property = proxy_enum_class( - server, guid, plx_type, property_name, owner) + proxy_property = proxy_enum_class(server, guid, plx_type, property_name, owner) elif plx_type == TYPE_NUMBER: - proxy_property = PlxProxyIPDouble(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyIPDouble(server, guid, plx_type, property_name, owner) elif plx_type == TYPE_INTEGER: - proxy_property = PlxProxyIPInteger(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyIPInteger(server, guid, plx_type, property_name, owner) elif plx_type == TYPE_OBJECT: if is_listable: proxy_property = self.PlxProxyIPObjectListable( - server, guid, plx_type, property_name, owner) + server, guid, plx_type, property_name, owner + ) else: - proxy_property = PlxProxyIPObject(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyIPObject(server, guid, plx_type, property_name, owner) elif plx_type == TYPE_TEXT: - proxy_property = PlxProxyIPText(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyIPText(server, guid, plx_type, property_name, owner) elif plx_type.startswith(STAGED): - proxy_property = PlxProxyIPStaged(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyIPStaged(server, guid, plx_type, property_name, owner) else: if is_listable: proxy_property = self.PlxProxyObjectPropertyListable( - server, guid, plx_type, property_name, owner) + server, guid, plx_type, property_name, owner + ) else: - proxy_property = PlxProxyObjectProperty(server, guid, plx_type, - property_name, owner) + proxy_property = PlxProxyObjectProperty( + server, guid, plx_type, property_name, owner + ) return proxy_property @@ -194,8 +201,9 @@ def _create_proxy_enumeration(self, proxy_enum_guid, proxy_enum_name): if proxy_enum_name in self._proxy_enum_classes: return self._proxy_enum_classes[proxy_enum_name] - response = self._connection.request_enumeration( - proxy_enum_guid)[JSON_QUERIES][proxy_enum_guid] + response = self._connection.request_enumeration(proxy_enum_guid)[JSON_QUERIES][ + proxy_enum_guid + ] enum_dict = self._handle_enumeration_request(response) @@ -204,7 +212,7 @@ class PlxProxyIPEnumerationLocal(PlxProxyIPEnumeration): for key, val in enum_dict.items(): # Python 2.7 doesn't allow non-ascii chars to be used in attribute names. - sanitized_key = ''.join(c for c in key if ord(c) < 128) + sanitized_key = "".join(c for c in key if ord(c) < 128) setattr(PlxProxyIPEnumerationLocal, sanitized_key, val) PlxProxyIPEnumerationLocal.__name__ = proxy_enum_name diff --git a/src/plxscripting/run_jupyter.py b/src/plxscripting/run_jupyter.py index d7d0131..0e3b653 100644 --- a/src/plxscripting/run_jupyter.py +++ b/src/plxscripting/run_jupyter.py @@ -39,15 +39,27 @@ set_paths_of_activated_conda_environment() import notebook.notebookapp -from plxscripting.plaxis_jupyter_kernel import (ENV_VAR_PLAXIS_SERVER_PASSWORD, ENV_VAR_PLAXIS_SERVER_APP_TYPE, - ENV_VAR_PLAXIS_SERVER_ADDRESS, ENV_VAR_PLAXIS_SERVER_PORT) +from plxscripting.plaxis_jupyter_kernel import ( + ENV_VAR_PLAXIS_SERVER_PASSWORD, + ENV_VAR_PLAXIS_SERVER_APP_TYPE, + ENV_VAR_PLAXIS_SERVER_ADDRESS, + ENV_VAR_PLAXIS_SERVER_PORT, +) from plxscripting.easy import new_server from plxscripting.const import PLAXIS_2D, PLAXIS_3D, INPUT, OUTPUT, SOILTEST -NOTEBOOK_TEMPLATE_PATHS = {PLAXIS_2D: {INPUT: "template_2d_input.ipynb", OUTPUT: "template_2d_output.ipynb", - SOILTEST: "template_2d_soiltest.ipynb"}, - PLAXIS_3D: {INPUT: "template_3d_input.ipynb", OUTPUT: "template_3d_output.ipynb", - SOILTEST: "template_3d_soiltest.ipynb"}} +NOTEBOOK_TEMPLATE_PATHS = { + PLAXIS_2D: { + INPUT: "template_2d_input.ipynb", + OUTPUT: "template_2d_output.ipynb", + SOILTEST: "template_2d_soiltest.ipynb", + }, + PLAXIS_3D: { + INPUT: "template_3d_input.ipynb", + OUTPUT: "template_3d_output.ipynb", + SOILTEST: "template_3d_soiltest.ipynb", + }, +} EMPTY_NOTEBOOK_PATH = "empty_notebook.ipynb" @@ -72,44 +84,54 @@ def is_file(arg_file): dirname = os.path.dirname(arg_file) readable_dir(dirname) basename = os.path.basename(arg_file) - if not basename.endswith('.ipynb'): + if not basename.endswith(".ipynb"): raise ArgumentTypeError("{0} is not a valid notebook file".format(arg_file)) return arg_file def create_notebook(path, is_plaxis_2d, appservertype, create_empty_notebook=False): - template_notebook_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "template_notebooks") + template_notebook_path = os.path.join( + os.path.dirname(os.path.realpath(__file__)), "template_notebooks" + ) if create_empty_notebook: final_path = EMPTY_NOTEBOOK_PATH else: - final_path = NOTEBOOK_TEMPLATE_PATHS[PLAXIS_2D if is_plaxis_2d else PLAXIS_3D][appservertype] + final_path = NOTEBOOK_TEMPLATE_PATHS[PLAXIS_2D if is_plaxis_2d else PLAXIS_3D][ + appservertype + ] template_notebook_path = os.path.join(template_notebook_path, final_path) shutil.copy(template_notebook_path, path) -def set_environment_variables_with_plaxis_vars(server_address, server_port, server_apptype, server_password): +def set_environment_variables_with_plaxis_vars( + server_address, server_port, server_apptype, server_password +): os.environ[ENV_VAR_PLAXIS_SERVER_ADDRESS] = str(server_address) os.environ[ENV_VAR_PLAXIS_SERVER_PORT] = str(server_port) os.environ[ENV_VAR_PLAXIS_SERVER_APP_TYPE] = str(server_apptype) os.environ[ENV_VAR_PLAXIS_SERVER_PASSWORD] = str(server_password) -if __name__ == '__main__': +if __name__ == "__main__": parser = create_parser() - parser.add_argument('--notebookdir', type=readable_dir, - help='The directory where the Jupyter notebooks are located.') - parser.add_argument('--notebook', type=is_file, help='The notebook to open or create.') + parser.add_argument( + "--notebookdir", + type=readable_dir, + help="The directory where the Jupyter notebooks are located.", + ) + parser.add_argument("--notebook", type=is_file, help="The notebook to open or create.") args = parser.parse_args() - set_environment_variables_with_plaxis_vars(args.AppServerAddress, args.AppServerPort, args.AppServerType, - args.AppServerPassword) - s, s.plx_global = new_server(address=args.AppServerAddress, port=args.AppServerPort, - password=args.AppServerPassword) + set_environment_variables_with_plaxis_vars( + args.AppServerAddress, args.AppServerPort, args.AppServerType, args.AppServerPassword + ) + s, s.plx_global = new_server( + address=args.AppServerAddress, port=args.AppServerPort, password=args.AppServerPassword + ) notebook_args = [] if args.notebookdir: - notebook_args.append('--notebook-dir={}'.format(args.notebookdir)) + notebook_args.append("--notebook-dir={}".format(args.notebookdir)) if args.notebook: if not os.path.isfile(args.notebook): create_notebook(args.notebook, s.is_2d, args.AppServerType) - notebook_args.append('{}'.format(args.notebook)) + notebook_args.append("{}".format(args.notebook)) sys.exit(notebook.notebookapp.main(notebook_args)) - diff --git a/src/plxscripting/selection.py b/src/plxscripting/selection.py index e8c6892..024f538 100644 --- a/src/plxscripting/selection.py +++ b/src/plxscripting/selection.py @@ -83,4 +83,3 @@ def __setitem__(self, index, obj): def __delitem__(self, index): self.remove(self._objects[index]) - diff --git a/src/plxscripting/server.py b/src/plxscripting/server.py index 57a343a..56fc528 100644 --- a/src/plxscripting/server.py +++ b/src/plxscripting/server.py @@ -10,10 +10,6 @@ the request is not sucessful then a scripting exception is raised with the message that was returned from the interpreter. -Subversion data: - $Id: server.py 20240 2015-09-22 13:24:27Z tj $ - $URL: https://tools.plaxis.com/svn/sharelib/trunk/PlxObjectLayer/Server/plxscripting/server.py $ - Copyright (c) Plaxis bv. All rights reserved. Unless explicitly acquired and licensed from Licensor under another @@ -38,17 +34,55 @@ from .plxproxyfactory import is_primitive, TYPE_OBJECT, PlxProxyFactory from .connection import HTTPConnection from .image import TYPE_NAME_IMAGE, create_image -from .const import (PLX_CMD_NEW, PLX_CMD_CLOSE, PLX_CMD_OPEN, PLX_CMD_RECOVER, TOKENIZE, - JSON_COMMANDS, JSON_FEEDBACK, JSON_SUCCESS, JSON_EXTRAINFO, - JSON_GUID, JSON_TYPE, JSON_RETURNED_OBJECTS, JSON_RETURNED_VALUES, - JSON_PROPERTIES, JSON_QUERIES, JSON_NAMEDOBJECTS, JSON_MEMBERNAMES, - JSON_RETURNED_OBJECT, JSON_OWNERGUID, JSON_ISLISTABLE, - JSON_TYPE_JSON, JSON_KEY_JSON, JSON_KEY_CONTENT_TYPE, JSON_VALUE, - METHOD, GUID, COUNT, STAGED_PREFIX, - JSON_LISTQUERIES, JSON_METHODNAME, JSON_OUTPUTDATA, JSON_SELECTION, - SUBLIST, INDEX, MEMBERSUBLIST, MEMBERINDEX, STARTINDEX, STOPINDEX, MEMBERNAMES, - NULL_GUID, LOCAL_HOST, - JSON_NAME, PLAXIS_2D, PLAXIS_3D, ARG_APP_SERVER_ADDRESS, ARG_APP_SERVER_PORT, ARG_PASSWORD) +from .const import ( + PLX_CMD_NEW, + PLX_CMD_CLOSE, + PLX_CMD_OPEN, + PLX_CMD_RECOVER, + TOKENIZE, + JSON_COMMANDS, + JSON_FEEDBACK, + JSON_SUCCESS, + JSON_EXTRAINFO, + JSON_GUID, + JSON_TYPE, + JSON_RETURNED_OBJECTS, + JSON_RETURNED_VALUES, + JSON_PROPERTIES, + JSON_QUERIES, + JSON_NAMEDOBJECTS, + JSON_MEMBERNAMES, + JSON_RETURNED_OBJECT, + JSON_OWNERGUID, + JSON_ISLISTABLE, + JSON_TYPE_JSON, + JSON_KEY_JSON, + JSON_KEY_CONTENT_TYPE, + JSON_VALUE, + METHOD, + GUID, + COUNT, + STAGED_PREFIX, + JSON_LISTQUERIES, + JSON_METHODNAME, + JSON_OUTPUTDATA, + JSON_SELECTION, + SUBLIST, + INDEX, + MEMBERSUBLIST, + MEMBERINDEX, + STARTINDEX, + STOPINDEX, + MEMBERNAMES, + NULL_GUID, + LOCAL_HOST, + JSON_NAME, + PLAXIS_2D, + PLAXIS_3D, + ARG_APP_SERVER_ADDRESS, + ARG_APP_SERVER_PORT, + ARG_PASSWORD, +) from .selection import Selection from .logger import Logger from .error_mode import ErrorMode @@ -58,13 +92,15 @@ try: basestring # will give NameError on Py3.x, but exists on Py2.x (ancestor of str and unicode) - def is_str(s): return isinstance(s, basestring) + except NameError: + def is_str(s): # Py3.x only has one type of string return isinstance(s, str) + plx_string_wrappers = ['"', "'", '"""', "'''"] @@ -83,10 +119,13 @@ def param_to_string(self, param): for wrapper in plx_string_wrappers: if not wrapper in param: return wrapper + param + wrapper - raise PlxScriptingLocalError("Cannot convert string parameter to valid Plaxis string" - " representation, try removing some quotes: " + param) + raise PlxScriptingLocalError( + "Cannot convert string parameter to valid Plaxis string" + " representation, try removing some quotes: " + + param + ) elif isinstance(param, (tuple, list)): # tuples/lists wrapped with parens - return '(' + self.params_to_string(param) + ')' + return "(" + self.params_to_string(param) + ")" elif isinstance(param, Selection): return self.param_to_string(list(param)) elif isinstance(param, GeneratorType): # expand generator contents (it gets consumed) @@ -164,7 +203,8 @@ def _handle_successful_command(self, commands_response): information from the command line or True as a fallback. """ obj_list = self._create_proxies_from_returned_objects( - commands_response[JSON_RETURNED_OBJECTS]) + commands_response[JSON_RETURNED_OBJECTS] + ) if obj_list is not None: return obj_list @@ -187,10 +227,12 @@ def handle_namedobjects_response(self, namedobjects_response): if is_namedobject_successful: return self._create_proxies_from_returned_objects( - [namedobjects_response[JSON_RETURNED_OBJECT]]) + [namedobjects_response[JSON_RETURNED_OBJECT]] + ) else: - raise PlxScriptingError("Unsuccessful command:\n" + - namedobjects_response[JSON_EXTRAINFO]) + raise PlxScriptingError( + "Unsuccessful command:\n" + namedobjects_response[JSON_EXTRAINFO] + ) def handle_commands_response(self, commands_response): """ @@ -204,8 +246,7 @@ def handle_commands_response(self, commands_response): if is_command_successful: return self._handle_successful_command(commands_response) else: - raise PlxScriptingError("Unsuccessful command:\n" + - commands_response[JSON_EXTRAINFO]) + raise PlxScriptingError("Unsuccessful command:\n" + commands_response[JSON_EXTRAINFO]) def handle_members_response(self, members_response, proxy_obj): """ @@ -225,14 +266,15 @@ def handle_members_response(self, members_response, proxy_obj): # Also append a _ when the method name conflicts with a Python # keyword. exposed_name = method_name - if exposed_name.startswith('__'): + if exposed_name.startswith("__"): exposed_name = exposed_name[2:] if keyword.iskeyword(exposed_name): - exposed_name = exposed_name + '_' + exposed_name = exposed_name + "_" proxy_method = self.proxy_factory.create_plx_proxy_object_method( - self.server, proxy_obj, method_name) + self.server, proxy_obj, method_name + ) proxy_attributes[exposed_name] = proxy_method if JSON_PROPERTIES in members_response: @@ -240,7 +282,8 @@ def handle_members_response(self, members_response, proxy_obj): for property_name in sorted(properties_dict.keys()): ip = self._create_proxy_object( - properties_dict[property_name], property_name, proxy_obj) + properties_dict[property_name], property_name, proxy_obj + ) proxy_attributes[property_name] = ip return proxy_attributes @@ -263,27 +306,25 @@ def handle_list_response(self, list_response): # return either a line object directly or a list of line objects. This # makes it rather hard to write code using list slices, as you never # know what to expect out of them. - return self._create_proxies_from_returned_objects(output_data, - allow_one_item_list_result=True) - elif method_name == INDEX: return self._create_proxies_from_returned_objects( - [output_data]) + output_data, allow_one_item_list_result=True + ) + elif method_name == INDEX: + return self._create_proxies_from_returned_objects([output_data]) elif method_name == MEMBERSUBLIST: # We assume that a single member name has been queried for now queried_member = list_response[JSON_MEMBERNAMES][0] - return self._create_proxies_from_returned_objects(output_data[queried_member], - allow_one_item_list_result=True) + return self._create_proxies_from_returned_objects( + output_data[queried_member], allow_one_item_list_result=True + ) elif method_name == MEMBERINDEX: # We assume that a single member name has been queried for now queried_member = list_response[JSON_MEMBERNAMES][0] - return self._create_proxies_from_returned_objects( - [output_data[queried_member]]) + return self._create_proxies_from_returned_objects([output_data[queried_member]]) - raise PlxScriptingError("Unsuccessful command:\n" + - list_response[JSON_EXTRAINFO]) + raise PlxScriptingError("Unsuccessful command:\n" + list_response[JSON_EXTRAINFO]) - def handle_propertyvalues_response(self, propertyvalues_response_list, - attr_name, owner_type): + def handle_propertyvalues_response(self, propertyvalues_response_list, attr_name, owner_type): """ Handle the request for a list of properties. Returns a list of properties. If there is no such attribute for one @@ -291,7 +332,9 @@ def handle_propertyvalues_response(self, propertyvalues_response_list, """ response = [] for single_property_json in propertyvalues_response_list: - single_property_response = self._get_single_propertyvalues(single_property_json, attr_name, owner_type) + single_property_response = self._get_single_propertyvalues( + single_property_json, attr_name, owner_type + ) response.append(single_property_response) return response @@ -331,8 +374,9 @@ def _get_single_propertyvalues(self, single_property_json, attr_name, owner_type def handle_selection_response(self, selection_response): selection_objects = selection_response[JSON_SELECTION] - result = self._create_proxies_from_returned_objects(selection_objects, - allow_one_item_list_result=True) + result = self._create_proxies_from_returned_objects( + selection_objects, allow_one_item_list_result=True + ) if result is None: # No selected objects is perfectly valid. return [] @@ -340,12 +384,13 @@ def handle_selection_response(self, selection_response): return result def _create_stagedIP_proxy(self, returned_object, attr_name): - """"Creates a proxy for the staged IP primitive values""" + """Creates a proxy for the staged IP primitive values""" guid = returned_object[JSON_GUID] primitive_type = returned_object[JSON_TYPE] # The owner of stagedIP's are not set. - primitive_proxy = self.proxy_factory._create_plx_proxy_property(self.server, guid, primitive_type, False, - attr_name, None) + primitive_proxy = self.proxy_factory._create_plx_proxy_property( + self.server, guid, primitive_type, False, attr_name, None + ) # The value is set here since their owner is None primitive_proxy.set_stagedIP_value(returned_object[JSON_VALUE]) return primitive_proxy @@ -364,8 +409,7 @@ def _create_proxy_object(self, returned_object, prop_name=None, owner=None): constructor_name = json_object[JSON_KEY_CONTENT_TYPE] constructor = self._json_constructors.get(constructor_name) if constructor is None: - raise Exception("Constructor {} is not registered.".format( - constructor_name)) + raise Exception("Constructor {} is not registered.".format(constructor_name)) return constructor(json_object) @@ -382,13 +426,19 @@ def _create_proxy_object(self, returned_object, prop_name=None, owner=None): # returns intrinsic property objects that have NOT YET been cached as # proxies, we still need to identify them as intrprops and create the # appropriate proxy objects for them. - if owner is None: # cannot simply write "if not owner", because proxies may implement __bool__ and return False even if the owner does exist + + # cannot simply write "if not owner", because proxies may implement __bool__ and return False even if the owner does exist + if owner is None: if JSON_OWNERGUID in returned_object: - owner = self.proxy_factory.get_proxy_object_if_exists(returned_object[JSON_OWNERGUID]) + owner = self.proxy_factory.get_proxy_object_if_exists( + returned_object[JSON_OWNERGUID] + ) # It shouldn't be possible to get a property back *before* we have # instantiated a proxy object for that property's owner. - if owner is None: # also here cannot simply write "if not owner" for similar reasons as above - raise PlxScriptingError('Missing owner object for property object!') + + # also here cannot simply write "if not owner" for similar reasons as above + if owner is None: + raise PlxScriptingError("Missing owner object for property object!") # The fact that the owner exists, doesn't necessarily mean all # its intrinsic properties have been retrieved too; and we need # them retrieved, because in the problematic situation we're @@ -399,9 +449,12 @@ def _create_proxy_object(self, returned_object, prop_name=None, owner=None): self.server.get_object_attributes(owner) return self.proxy_factory.create_plx_proxy_object( - self.server, guid, plx_obj_type, is_listable, prop_name, owner) + self.server, guid, plx_obj_type, is_listable, prop_name, owner + ) - def _create_proxies_from_returned_objects(self, returned_objects, allow_one_item_list_result=False): + def _create_proxies_from_returned_objects( + self, returned_objects, allow_one_item_list_result=False + ): """ Given a returned objects list from the API, creates relevant proxy objects for each returned object representation. If the list contains @@ -485,19 +538,19 @@ def last_response(self): @property def major_version(self): - matches = search(r'(\d*)\.(\d*).(\d*)\.(\d*)', self.server_full_name) + matches = search(r"(\d*)\.(\d*).(\d*)\.(\d*)", self.server_full_name) return int(matches.group(1)) @property def minor_version(self): - matches = search(r'(\d*)\.(\d*).(\d*)\.(\d*)', self.server_full_name) + matches = search(r"(\d*)\.(\d*).(\d*)\.(\d*)", self.server_full_name) return int(matches.group(2)) @property def name(self): - if 'PLAXIS 3D' in self.server_full_name: + if "PLAXIS 3D" in self.server_full_name: return PLAXIS_3D - if 'PLAXIS 2D' in self.server_full_name: + if "PLAXIS 2D" in self.server_full_name: return PLAXIS_2D @property @@ -541,7 +594,7 @@ def reset_caches(self): self.__listables_cache = {} def new(self): - """Create a new project """ + """Create a new project""" result = self.connection.request_environment(PLX_CMD_NEW) if result: self.reset_caches() @@ -549,7 +602,7 @@ def new(self): return result def recover(self): - """Recover a project """ + """Recover a project""" result = self.connection.request_environment(PLX_CMD_RECOVER) if result: self.reset_caches() @@ -557,7 +610,7 @@ def recover(self): return result def open(self, filename): - """Open a project with the supplied name """ + """Open a project with the supplied name""" result = self.connection.request_environment(PLX_CMD_OPEN, filename) if result: self.reset_caches() @@ -565,7 +618,7 @@ def open(self, filename): return result def close(self): - """Close the current project """ + """Close the current project""" result = self.connection.request_environment(PLX_CMD_CLOSE) if result: self.reset_caches() @@ -589,7 +642,9 @@ def __get_with_cache(self, key, cache, func_if_not_found): return result - def __call_listable_method_no_cache(self, proxy_listable, method_name, startindex, stopindex, property_name): + def __call_listable_method_no_cache( + self, proxy_listable, method_name, startindex, stopindex, property_name + ): optional_parameters = {} # Attach any supplied index arguments to the query @@ -604,54 +659,68 @@ def __call_listable_method_no_cache(self, proxy_listable, method_name, startinde listable_query.update(optional_parameters) response = self.connection.request_list(listable_query) - return self.result_handler.handle_list_response( - response[JSON_LISTQUERIES][0]) + return self.result_handler.handle_list_response(response[JSON_LISTQUERIES][0]) - def call_listable_method(self, proxy_listable, method_name, startindex=None, - stopindex=None, property_name=None): + def call_listable_method( + self, proxy_listable, method_name, startindex=None, stopindex=None, property_name=None + ): """ Constructs a listable query and returns the handled response. """ key = (proxy_listable._guid, method_name, startindex, stopindex, property_name) - return self.__get_with_cache(key, self.__listables_cache, - lambda: self.__call_listable_method_no_cache( - proxy_listable, method_name, startindex, stopindex, property_name)) + return self.__get_with_cache( + key, + self.__listables_cache, + lambda: self.__call_listable_method_no_cache( + proxy_listable, method_name, startindex, stopindex, property_name + ), + ) def __get_name_object_no_cache(self, object_name): response = self.connection.request_namedobjects(object_name) return self.result_handler.handle_namedobjects_response( - response[JSON_NAMEDOBJECTS][object_name]) + response[JSON_NAMEDOBJECTS][object_name] + ) def get_named_object(self, object_name): """ Return a representation of the named object. """ - return self.__get_with_cache(object_name, self.__globals_cache, - lambda: self.__get_name_object_no_cache(object_name)) + return self.__get_with_cache( + object_name, self.__globals_cache, lambda: self.__get_name_object_no_cache(object_name) + ) def __get_objects_property_no_cache(self, proxy_objects, prop_name, phase_object): if phase_object: response = self.connection.request_propertyvalues( - [po._guid for po in proxy_objects], prop_name, phase_object._guid) + [po._guid for po in proxy_objects], prop_name, phase_object._guid + ) else: response = self.connection.request_propertyvalues( - [po._guid for po in proxy_objects], prop_name) + [po._guid for po in proxy_objects], prop_name + ) # handle a legacy signature response that is used in case of a single object request - response_list = [response[JSON_QUERIES][proxy_objects[0]._guid]] if len(proxy_objects) == 1 else [ - response[JSON_QUERIES][i][po._guid] for (i, po) in enumerate(proxy_objects)] + response_list = ( + [response[JSON_QUERIES][proxy_objects[0]._guid]] + if len(proxy_objects) == 1 + else [response[JSON_QUERIES][i][po._guid] for (i, po) in enumerate(proxy_objects)] + ) return self.result_handler.handle_propertyvalues_response( - response_list, prop_name, proxy_objects[0]._plx_type) + response_list, prop_name, proxy_objects[0]._plx_type + ) def get_objects_property(self, proxy_objects, prop_name, phase_object=None): """ Gets the specified property value for a list of proxy objects. """ - key = (' '.join([po._guid for po in proxy_objects]), prop_name, phase_object) - return self.__get_with_cache(key, self.__values_cache, - lambda: self.__get_objects_property_no_cache(proxy_objects, prop_name, - phase_object)) + key = (" ".join([po._guid for po in proxy_objects]), prop_name, phase_object) + return self.__get_with_cache( + key, + self.__values_cache, + lambda: self.__get_objects_property_no_cache(proxy_objects, prop_name, phase_object), + ) def get_object_property(self, proxy_object, prop_name, phase_object=None): """ @@ -664,8 +733,7 @@ def set_object_property(self, proxy_property, prop_value): Sets the specified property value for the specified proxy object. """ self.reset_caches() - return self.call_plx_object_method(proxy_property, - 'set', prop_value) + return self.call_plx_object_method(proxy_property, "set", prop_value) def get_object_attributes(self, proxy_obj): """ @@ -674,7 +742,8 @@ def get_object_attributes(self, proxy_obj): """ response = self.connection.request_members(proxy_obj._guid) return self.result_handler.handle_members_response( - response[JSON_QUERIES][proxy_obj._guid], proxy_obj) + response[JSON_QUERIES][proxy_obj._guid], proxy_obj + ) def call_plx_object_method(self, proxy_obj, method_name, params): """ @@ -694,8 +763,7 @@ def call_plx_object_method(self, proxy_obj, method_name, params): returns a list of PlxProxyObjects """ self.reset_caches() - method_call_cmd = self.input_proc.create_method_call_cmd( - proxy_obj, method_name, params) + method_call_cmd = self.input_proc.create_method_call_cmd(proxy_obj, method_name, params) return self.call_and_handle_command(method_call_cmd) @@ -713,9 +781,7 @@ def call_and_handle_commands(self, *commands): resource. Returns the handled response to that command. """ response = self.call_commands(*commands) - return [ - self.result_handler.handle_commands_response(r[JSON_FEEDBACK]) - for r in response] + return [self.result_handler.handle_commands_response(r[JSON_FEEDBACK]) for r in response] def call_commands(self, *commands): """ @@ -750,12 +816,14 @@ def tokenize(self, command): def _get_argument(arg_name): for arg in sys.argv: if arg_name.lower() in arg.lower(): - ignore, value = arg.split('=', 1) + ignore, value = arg.split("=", 1) return value raise Exception("Couldn't get {} from command line arguments.".format(arg_name)) -def new_server(address=None, port=None, timeout=5.0, request_timeout=None, password=None, error_mode=()): +def new_server( + address=None, port=None, timeout=5.0, request_timeout=None, password=None, error_mode=() +): ip = InputProcessor() if address is None: diff --git a/src/plxscripting/tokenizer.py b/src/plxscripting/tokenizer.py index dfb4c31..cc08d90 100644 --- a/src/plxscripting/tokenizer.py +++ b/src/plxscripting/tokenizer.py @@ -22,10 +22,10 @@ from abc import ABC from .plx_scripting_exceptions import PlxScriptingTokenizerError -KEY_POSITION = 'position' -KEY_TYPE = 'type' -KEY_TOKENS = 'tokens' -KEY_ERROR_POSITION = 'errorpos' +KEY_POSITION = "position" +KEY_TYPE = "type" +KEY_TOKENS = "tokens" +KEY_ERROR_POSITION = "errorpos" class TokenBase(ABC): @@ -38,6 +38,7 @@ class TokenBase(ABC): - end_position (indicates the end position of the token in the original string) - length (the number of characters the token consumed from the original string) """ + def __init__(self, raw_data): self._raw_data = raw_data for key in raw_data: @@ -50,7 +51,7 @@ def __init__(self, raw_data): setattr(self, key, value) def __repr__(self): - return '{}.{}({})'.format(self.__module__, self.__class__.__name__, self._raw_data) + return "{}.{}({})".format(self.__module__, self.__class__.__name__, self._raw_data) def __str__(self): return str(self.value) @@ -62,6 +63,7 @@ def end_position(self): class TokenIdentifier(TokenBase): """Something that will act either as command or as object identifier""" + pass @@ -72,6 +74,7 @@ class TokenComment(TokenBase): Additional properties: - content: the text after the # sign (e.g. running in the case of #running) """ + pass @@ -85,6 +88,7 @@ class TokenExternalInterpreter(TokenBase): - externalcommand: the command to be executed (e.g. echo Points) - content: (e.g. output echo Points) """ + pass @@ -95,11 +99,13 @@ class TokenText(TokenBase): Additional properties: - content: text inside the quotation marks (e.g. input in the case of "input") """ + pass class TokenInteger(TokenBase): """Identifies a number that can be represented by a 32-bit signed integer""" + def __init__(self, raw_data): super().__init__(raw_data) self.value = int(self.value) @@ -107,6 +113,7 @@ def __init__(self, raw_data): class TokenFloat(TokenBase): """Identifies a number that can be represented as a floating point value""" + def __init__(self, raw_data): super().__init__(raw_data) self.value = float(self.value) @@ -119,46 +126,55 @@ class TokenBracket(TokenBase): - brackettype: can be round, square, curly for (), [] respectively {} - bracketstate: can be open or close for {[( respectively )]} """ + pass class TokenMember(TokenBase): """Identifies a bracket type""" + pass class TokenOperand(TokenBase): """Identifies an operand type""" + pass class TokenPlus(TokenBase): """Identifies the plus operand type""" + pass class TokenMinus(TokenBase): """Identifies the minus operand type""" + pass class TokenMultiplier(TokenBase): """Identifies the multiplier operand type""" + pass class TokenDivider(TokenBase): """Identifies the divider operand type""" + pass class TokenComma(TokenBase): """Identifies the comma operand type""" + pass class TokenAssign(TokenBase): """Identifies the assign operand type""" + pass @@ -169,13 +185,13 @@ def token_factory(token_raw_data): :return TokenBase: The token object """ type_to_class_name_mapping = { - 'externalinterpreter': 'ExternalInterpreter', + "externalinterpreter": "ExternalInterpreter", } token_type = token_raw_data.get(KEY_TYPE) class_name = type_to_class_name_mapping.get(token_type) if not class_name: class_name = token_type.title() - token_class = globals()['Token{}'.format(class_name)] + token_class = globals()["Token{}".format(class_name)] return token_class(token_raw_data) @@ -188,14 +204,14 @@ def __init__(self, response): self.partial_tokens = [] for key in response: if key != KEY_TOKENS: - attribute_name = key if key != KEY_ERROR_POSITION else 'error_position' + attribute_name = key if key != KEY_ERROR_POSITION else "error_position" setattr(self, attribute_name, response[key]) else: for token in response.get(KEY_TOKENS): self.partial_tokens.append(token_factory(token)) if not self.success: self.error_position -= 1 - self.error = 'Unrecognized token at position {}'.format(self.error_position) + self.error = "Unrecognized token at position {}".format(self.error_position) @property def tokens(self): diff --git a/src/plxscripting/unittests/mock_connection.py b/src/plxscripting/unittests/mock_connection.py index 481340b..f188d22 100644 --- a/src/plxscripting/unittests/mock_connection.py +++ b/src/plxscripting/unittests/mock_connection.py @@ -17,11 +17,11 @@ language governing rights and limitations under the PPL. """ -MOCK_GUID_FORMAT = '{}{:012x}{}' -MOCK_GUID_PREFIX = '{FFFFFFFF - FFFF - FFFF - FFFF - ' -MOCK_GUID_SUFFIX = '}' +MOCK_GUID_FORMAT = "{}{:012x}{}" +MOCK_GUID_PREFIX = "{FFFFFFFF - FFFF - FFFF - FFFF - " +MOCK_GUID_SUFFIX = "}" -MOCK_EXCEPTION = '''operating system : MockOS 1.0 build 7 +MOCK_EXCEPTION = """operating system : MockOS 1.0 build 7 program up time : 13 minutes 37 seconds processors : 1x Plaxis UnitTestCore© CPU @ 0.0GHZ physical memory : 0/0 MB (free/total) @@ -37,13 +37,13 @@ ffffffff +ff PlaxisXDXput.exe PlxTasks 531 +9 ThreadProc ffffffff +ff PlaxisXDXput.exe System ThreadWrapper ffffffff +ff KERNEL32.DLL BaseThreadInitThunk -ffffffff +ff ntdll.dll RtlUserThreadStart''' +ffffffff +ff ntdll.dll RtlUserThreadStart""" class HTTPConnection: - MAGIC_REQUEST_OBJECT = 'give_me_an_object' + MAGIC_REQUEST_OBJECT = "give_me_an_object" - def __init__(self, host, port, timeout=5.0, request_timeout=None, password='', error_mode=None): + def __init__(self, host, port, timeout=5.0, request_timeout=None, password="", error_mode=None): self.host = host self.port = port self.timeout = timeout @@ -62,237 +62,281 @@ def __init__(self, host, port, timeout=5.0, request_timeout=None, password='', e @property def _next_guid(self): self._guid_counter += 1 - return MOCK_GUID_FORMAT.format(MOCK_GUID_PREFIX, self._guid_counter, MOCK_GUID_SUFFIX).upper() + return MOCK_GUID_FORMAT.format( + MOCK_GUID_PREFIX, self._guid_counter, MOCK_GUID_SUFFIX + ).upper() def poll_connection(self): return self.test_poll_status - def request_environment(self, command_string, filename=''): + def request_environment(self, command_string, filename=""): if self.test_success: - return 'OK' + return "OK" else: - return '???' # environment commands cannot fail gracefully, they crash plaxis -_-" + return "???" # environment commands cannot fail gracefully, they crash plaxis -_-" def request_commands(self, *commands): - reply = {'commands': [], - 'ReplyCode': '0' * 32} + reply = {"commands": [], "ReplyCode": "0" * 32} for command in commands: if self.test_success: - reply['commands'].append({ - 'feedback': { - 'extrainfo': 'Reply_to_command: {}'.format(command), - 'returnedobjects': [ - { - 'islistable': False, - 'guid': self._next_guid, - 'type': 'Mock_reply_object_{}'.format(self._guid_counter) - } - ] if HTTPConnection.MAGIC_REQUEST_OBJECT in command else [], - 'debuginfo': '', - 'success': True, - 'errorpos': -1, - 'returnedvalues': [] - }, - 'command': command - }) + reply["commands"].append( + { + "feedback": { + "extrainfo": "Reply_to_command: {}".format(command), + "returnedobjects": ( + [ + { + "islistable": False, + "guid": self._next_guid, + "type": "Mock_reply_object_{}".format(self._guid_counter), + } + ] + if HTTPConnection.MAGIC_REQUEST_OBJECT in command + else [] + ), + "debuginfo": "", + "success": True, + "errorpos": -1, + "returnedvalues": [], + }, + "command": command, + } + ) else: - reply['commands'].append({ - 'feedback': { - 'extrainfo': 'Cannot intersect unless there is at least one volume or surface in the geometry', - 'debuginfo': '', - 'success': False, - 'errorpos': -1}, - 'command': command # 'gotomesh' - }) + reply["commands"].append( + { + "feedback": { + "extrainfo": ( + "Cannot intersect unless there is at least one volume or surface in" + " the geometry" + ), + "debuginfo": "", + "success": False, + "errorpos": -1, + }, + "command": command, # 'gotomesh' + } + ) return reply def request_members(self, *guids): - reply = {'queries': {}, - 'ReplyCode': '0' * 32} + reply = {"queries": {}, "ReplyCode": "0" * 32} for guid in guids: - reply['queries'].update({guid: { - 'extrainfo': '', - 'success': True, - 'properties': { - 'Mock_number': {'islistable': False, - 'value': 42, - 'type': 'Number', - 'guid': self._next_guid, - 'ispublished': True, - 'ownerguid': guid, - 'caption': 'Mock_number#'}, - 'TypeName': {'islistable': False, - 'value': 'MockItem', - 'type': 'Text', - 'guid': self._next_guid, - 'ispublished': False, - 'ownerguid': guid, - 'caption': 'TypeName'}, - 'IsDynamicComponent': {'islistable': False, - 'value': False, - 'type': 'Boolean', - 'guid': self._next_guid, - 'ispublished': False, - 'ownerguid': guid, - 'caption': 'IsDynamicComponent'}, - 'Name': {'islistable': False, - 'value': 'MockItem_Name_memb', - 'type': 'Text', - 'guid': self._next_guid, - 'ispublished': False, - 'ownerguid': guid, - 'caption': 'Name'}, - 'UserFeatures': {'islistable': False, - 'value': {'islistable': True, - 'type': 'PlxUserFeatureList', - 'guid': self._next_guid}, - 'type': 'Object', - 'guid': self._next_guid, - 'ispublished': False, - 'ownerguid': guid, - 'caption': 'UserFeatures'}, - }, - 'commands': ['echo'], - 'commandlinename': 'LineLoad_1'}}) + reply["queries"].update( + { + guid: { + "extrainfo": "", + "success": True, + "properties": { + "Mock_number": { + "islistable": False, + "value": 42, + "type": "Number", + "guid": self._next_guid, + "ispublished": True, + "ownerguid": guid, + "caption": "Mock_number#", + }, + "TypeName": { + "islistable": False, + "value": "MockItem", + "type": "Text", + "guid": self._next_guid, + "ispublished": False, + "ownerguid": guid, + "caption": "TypeName", + }, + "IsDynamicComponent": { + "islistable": False, + "value": False, + "type": "Boolean", + "guid": self._next_guid, + "ispublished": False, + "ownerguid": guid, + "caption": "IsDynamicComponent", + }, + "Name": { + "islistable": False, + "value": "MockItem_Name_memb", + "type": "Text", + "guid": self._next_guid, + "ispublished": False, + "ownerguid": guid, + "caption": "Name", + }, + "UserFeatures": { + "islistable": False, + "value": { + "islistable": True, + "type": "PlxUserFeatureList", + "guid": self._next_guid, + }, + "type": "Object", + "guid": self._next_guid, + "ispublished": False, + "ownerguid": guid, + "caption": "UserFeatures", + }, + }, + "commands": ["echo"], + "commandlinename": "LineLoad_1", + } + } + ) return reply def request_namedobjects(self, *object_names): - reply = {'namedobjects': {}, - 'ReplyCode': '0' * 32} # 32 chars + reply = {"namedobjects": {}, "ReplyCode": "0" * 32} # 32 chars for obj in object_names: - reply['namedobjects'][obj] = { - 'extrainfo': '', - 'success': True, - 'returnedobject': { - 'islistable': False, - 'type': 'MockItem_{}'.format(self._guid_counter), - 'guid': self._next_guid - } + reply["namedobjects"][obj] = { + "extrainfo": "", + "success": True, + "returnedobject": { + "islistable": False, + "type": "MockItem_{}".format(self._guid_counter), + "guid": self._next_guid, + }, } return reply def request_propertyvalues(self, owner_guids, property_name, phase_guid=""): if phase_guid: - raise Exception('Phase guid not supported') - - reply = {'queries': [{owner_guid: {}} for owner_guid in owner_guids], - 'ReplyCode': '0' * 32} # 32 chars - - if property_name == 'Name': - for (i, owner_guid) in enumerate(owner_guids): - reply['queries'][i][owner_guid].update({ - 'extrainfo': '', - 'success': True, - 'properties': {'Name': 'MockItem_Name_pval'} - }) - - elif property_name == 'UserFeatures': - for (i, owner_guid) in enumerate(owner_guids): - reply['queries'][i][owner_guid].update({ - 'extrainfo': '', - 'success': True, - 'properties': { - 'UserFeatures': { - 'islistable': False, - 'type': 'MockItem_{}'.format(self._guid_counter), - 'guid': self._next_guid - } + raise Exception("Phase guid not supported") + + reply = { + "queries": [{owner_guid: {}} for owner_guid in owner_guids], + "ReplyCode": "0" * 32, + } # 32 chars + + if property_name == "Name": + for i, owner_guid in enumerate(owner_guids): + reply["queries"][i][owner_guid].update( + {"extrainfo": "", "success": True, "properties": {"Name": "MockItem_Name_pval"}} + ) + + elif property_name == "UserFeatures": + for i, owner_guid in enumerate(owner_guids): + reply["queries"][i][owner_guid].update( + { + "extrainfo": "", + "success": True, + "properties": { + "UserFeatures": { + "islistable": False, + "type": "MockItem_{}".format(self._guid_counter), + "guid": self._next_guid, + } + }, } - }) + ) else: raise Exception('property_name "{}" not supported'.format(property_name)) # in case of a single owner query, use the legacy signature if len(owner_guids) == 1: - reply['queries'] = reply['queries'][0] + reply["queries"] = reply["queries"][0] return reply def request_list(self, *list_queries): - reply = {'listqueries': [], - 'ReplyCode': '0' * 32} # 32 chars + reply = {"listqueries": [], "ReplyCode": "0" * 32} # 32 chars for query in list_queries: - if query['method'] == 'count': - reply['listqueries'].append({ - 'extrainfo': '', - 'success': True, - 'methodname': 'count', - 'guid': query['guid'], - 'outputdata': 3 - }) - elif query['method'] == 'index': - reply['listqueries'].append({ - 'extrainfo': '', - 'success': True, - 'startindex': query['startindex'], - 'methodname': 'index', - 'guid': query['guid'], - 'outputdata': { - 'islistable': False, # Let's not nest lists... - 'type': 'MockItem_{}'.format(self._guid_counter), - 'guid': self._next_guid} - }) - elif query['method'] == 'memberindex': - reply['listqueries'].append({ - 'extrainfo': '', - 'success': True, - 'startindex': query['startindex'], - 'methodname': 'index', - 'membernames': query['membernames'], - 'guid': query['guid'], - 'outputdata': {} # will be filled in the for loop below - }) - - for member_name in query['membernames']: - reply['listqueries'][-1]['outputdata'][member_name] = { - 'islistable': False, # Let's not nest lists... - 'type': 'MockNumber', - 'guid': self._next_guid, - 'ownerguid': self._next_guid, + if query["method"] == "count": + reply["listqueries"].append( + { + "extrainfo": "", + "success": True, + "methodname": "count", + "guid": query["guid"], + "outputdata": 3, + } + ) + elif query["method"] == "index": + reply["listqueries"].append( + { + "extrainfo": "", + "success": True, + "startindex": query["startindex"], + "methodname": "index", + "guid": query["guid"], + "outputdata": { + "islistable": False, # Let's not nest lists... + "type": "MockItem_{}".format(self._guid_counter), + "guid": self._next_guid, + }, } - elif query['method'] == 'sublist': - reply['listqueries'].append({ - 'extrainfo': '', - 'stopindex': query['stopindex'], - 'success': True, - 'startindex': query['startindex'], - 'methodname': 'sublist', - 'guid': query['guid'], - 'outputdata': [] # will be filled in the for loop below - }) - - for x in range(int(query['stopindex']) - int(query['startindex'])): - reply['listqueries'][-1]['outputdata'].append({ - 'islistable': False, # Let's not nest lists... - 'type': 'MockItem_{}'.format(self._guid_counter), - 'guid': self._next_guid - }) - elif query['method'] == 'membersublist': - reply['listqueries'].append({ - 'extrainfo': '', - 'stopindex': query['stopindex'], - 'success': True, - 'startindex': query['startindex'], - 'membernames': query['membernames'], - 'methodname': 'membersublist', - 'guid': query['guid'], - 'outputdata': {} # will be filled in the for loop below - }) - - for member_name in query['membernames']: - reply['listqueries'][-1]['outputdata'][member_name] = [] - for x in range(int(query['stopindex']) - int(query['startindex'])): - reply['listqueries'][-1]['outputdata'][member_name].append({ - 'islistable': False, # Let's not nest lists... - 'type': 'MockNumber', - 'guid': self._next_guid, - 'ownerguid': self._next_guid, - }) + ) + elif query["method"] == "memberindex": + reply["listqueries"].append( + { + "extrainfo": "", + "success": True, + "startindex": query["startindex"], + "methodname": "index", + "membernames": query["membernames"], + "guid": query["guid"], + "outputdata": {}, # will be filled in the for loop below + } + ) + + for member_name in query["membernames"]: + reply["listqueries"][-1]["outputdata"][member_name] = { + "islistable": False, # Let's not nest lists... + "type": "MockNumber", + "guid": self._next_guid, + "ownerguid": self._next_guid, + } + elif query["method"] == "sublist": + reply["listqueries"].append( + { + "extrainfo": "", + "stopindex": query["stopindex"], + "success": True, + "startindex": query["startindex"], + "methodname": "sublist", + "guid": query["guid"], + "outputdata": [], # will be filled in the for loop below + } + ) + + for x in range(int(query["stopindex"]) - int(query["startindex"])): + reply["listqueries"][-1]["outputdata"].append( + { + "islistable": False, # Let's not nest lists... + "type": "MockItem_{}".format(self._guid_counter), + "guid": self._next_guid, + } + ) + elif query["method"] == "membersublist": + reply["listqueries"].append( + { + "extrainfo": "", + "stopindex": query["stopindex"], + "success": True, + "startindex": query["startindex"], + "membernames": query["membernames"], + "methodname": "membersublist", + "guid": query["guid"], + "outputdata": {}, # will be filled in the for loop below + } + ) + + for member_name in query["membernames"]: + reply["listqueries"][-1]["outputdata"][member_name] = [] + for x in range(int(query["stopindex"]) - int(query["startindex"])): + reply["listqueries"][-1]["outputdata"][member_name].append( + { + "islistable": False, # Let's not nest lists... + "type": "MockNumber", + "guid": self._next_guid, + "ownerguid": self._next_guid, + } + ) else: raise Exception(f"Unsupported method: {query['method']}") @@ -300,60 +344,49 @@ def request_list(self, *list_queries): return reply def request_enumeration(self, *guids): - reply = {'queries': {}, - 'ReplyCode': '0' * 32} + reply = {"queries": {}, "ReplyCode": "0" * 32} for guid in guids: - reply['queries'][guid] = { - 'extrainfo': '', - 'success': True, - 'enumvalues': { - 'item_0': 0, - 'item_2': 2, - 'item_1': 1, - 'item_3': 3 - } + reply["queries"][guid] = { + "extrainfo": "", + "success": True, + "enumvalues": {"item_0": 0, "item_2": 2, "item_1": 1, "item_3": 3}, } return reply def request_selection(self, command, *guids): - reply = {'selection': [], - 'ReplyCode': '0' * 32} + reply = {"selection": [], "ReplyCode": "0" * 32} - if command == 'get': + if command == "get": pass - elif command == 'set': + elif command == "set": self._selection = [] for guid in guids: - self._selection.append({ - 'islistable': False, - 'type': 'MockItem_Selection', - 'guid': guid - }) - elif command == 'append': + self._selection.append( + {"islistable": False, "type": "MockItem_Selection", "guid": guid} + ) + elif command == "append": for guid in guids: - self._selection.append({ - 'islistable': False, - 'type': 'MockItem_Selection', - 'guid': guid - }) - elif command == 'remove': + self._selection.append( + {"islistable": False, "type": "MockItem_Selection", "guid": guid} + ) + elif command == "remove": newselection = [] for selecteditem in self._selection: - if selecteditem['guid'] not in guids: + if selecteditem["guid"] not in guids: newselection.append(selecteditem) self._selection = newselection else: raise Exception(f"Invalid command: {command}") - reply['selection'] = self._selection + reply["selection"] = self._selection return reply def request_server_name(self): - return 'mock_connection_py' + return "mock_connection_py" def request_exceptions(self, clear=True): - reply = '' + reply = "" if not self.test_exception_cleared: reply = MOCK_EXCEPTION @@ -362,51 +395,75 @@ def request_exceptions(self, clear=True): return reply def request_tokenizer(self, commands): - reply = {'tokenize': [], - 'ReplyCode': '0' * 32} + reply = {"tokenize": [], "ReplyCode": "0" * 32} for command in commands: if self.test_success: if self.test_tokenize_external: - reply['tokenize'].append({ - 'extrainfo': '', - 'tokenize': command, # '/command object "param" "param2" 2 3 4' - 'tokens': [{ - 'interpretername': 'command', - 'position': 1, - 'externalcommand': 'object "param" "param2" 2 3 4', - 'length': 38, - 'value': '/command object "param" "param2" 2 3 4', - 'content': '/command object "param" "param2" 2 3 4', - 'type': 'externalinterpreter'}], - 'success': True, - 'errorpos': -1 - }) + reply["tokenize"].append( + { + "extrainfo": "", + "tokenize": command, # '/command object "param" "param2" 2 3 4' + "tokens": [ + { + "interpretername": "command", + "position": 1, + "externalcommand": 'object "param" "param2" 2 3 4', + "length": 38, + "value": '/command object "param" "param2" 2 3 4', + "content": '/command object "param" "param2" 2 3 4', + "type": "externalinterpreter", + } + ], + "success": True, + "errorpos": -1, + } + ) else: - reply['tokenize'].append({ - 'extrainfo': '', - 'tokenize': command, # 'command object "param" "param2" 2 3 4' - 'tokens': [{'position': 1, 'length': 7, 'value': 'command', 'type': 'identifier'}, - {'position': 9, 'length': 6, 'value': 'object', 'type': 'operand'}, - {'position': 16, 'length': 7, 'value': '"param"', 'content': 'param', - 'type': 'text'}, - {'position': 24, 'length': 8, 'value': '"param2"', 'content': 'param2', - 'type': 'text'}, - {'position': 33, 'length': 1, 'value': '2', 'type': 'integer'}, - {'position': 35, 'length': 1, 'value': '3', 'type': 'integer'}, - {'position': 37, 'length': 1, 'value': '4', 'type': 'integer'} - ], - 'success': True, - 'errorpos': -1 - }) + reply["tokenize"].append( + { + "extrainfo": "", + "tokenize": command, # 'command object "param" "param2" 2 3 4' + "tokens": [ + { + "position": 1, + "length": 7, + "value": "command", + "type": "identifier", + }, + {"position": 9, "length": 6, "value": "object", "type": "operand"}, + { + "position": 16, + "length": 7, + "value": '"param"', + "content": "param", + "type": "text", + }, + { + "position": 24, + "length": 8, + "value": '"param2"', + "content": "param2", + "type": "text", + }, + {"position": 33, "length": 1, "value": "2", "type": "integer"}, + {"position": 35, "length": 1, "value": "3", "type": "integer"}, + {"position": 37, "length": 1, "value": "4", "type": "integer"}, + ], + "success": True, + "errorpos": -1, + } + ) else: - reply['tokenize'].append({ - 'extrainfo': 'Unbalanced quotes', - 'tokenize': command, # '1234 "bla bla 542 2' - 'tokens': [ - {'position': 1, 'length': 4, 'value': '1234', 'type': 'integer'} - ], - 'success': False, - 'errorpos': 6 - }) + reply["tokenize"].append( + { + "extrainfo": "Unbalanced quotes", + "tokenize": command, # '1234 "bla bla 542 2' + "tokens": [ + {"position": 1, "length": 4, "value": "1234", "type": "integer"} + ], + "success": False, + "errorpos": 6, + } + ) return reply diff --git a/src/plxscripting/unittests/mock_server.py b/src/plxscripting/unittests/mock_server.py index afbb922..091b8c0 100644 --- a/src/plxscripting/unittests/mock_server.py +++ b/src/plxscripting/unittests/mock_server.py @@ -22,25 +22,24 @@ class MockProxyObject(PlxProxyObject): - def __init__(self, server, guid): - super(MockProxyObject, self).__init__(server, guid, 'MockProxyObject') + super(MockProxyObject, self).__init__(server, guid, "MockProxyObject") class MockProxyObjectProperty(PlxProxyObjectProperty): - def __init__(self, server, guid, owner, name): - super(MockProxyObjectProperty, self).__init__(server, guid, 'MockProxyObjectProperty', name, owner) + super(MockProxyObjectProperty, self).__init__( + server, guid, "MockProxyObjectProperty", name, owner + ) class Server: - def __init__(self): self._function_call_count = 0 self.proxies_to_reset = [] self.object_property_store = None self.object_property_phase_store = None - self.object_property_to_send = 'uninitialized' + self.object_property_to_send = "uninitialized" self.listable_count = 5 def log_function_call(self): @@ -59,14 +58,16 @@ def get_named_object(self, object_name): def get_object_attributes(self, obj): attributes = { - 'test_attribute': 12345, - 'UserFeatures': '', # MockProxyObject(self, 'abcde'), - 'test_property_except_listable': MockProxyObjectProperty(self, 'mock_property_guid', obj, 'test_property_except_listable'), - 'delete': self.log_function_call + "test_attribute": 12345, + "UserFeatures": "", # MockProxyObject(self, 'abcde'), + "test_property_except_listable": MockProxyObjectProperty( + self, "mock_property_guid", obj, "test_property_except_listable" + ), + "delete": self.log_function_call, } if isinstance(obj, PlxProxyListable): - del attributes['test_property_except_listable'] + del attributes["test_property_except_listable"] return attributes @@ -81,26 +82,34 @@ def set_object_property(self, proxy_property, prop_value): self.object_property_store = prop_value return True - def call_listable_method(self, proxy_listable, method_name, startindex=None, stopindex=None, property_name=None): + def call_listable_method( + self, proxy_listable, method_name, startindex=None, stopindex=None, property_name=None + ): if method_name == const.COUNT: return self.listable_count elif method_name == const.SUBLIST: - return ['mock_call_listable_method::command:{}::index:{}'.format(method_name, i) for i in - range(startindex, stopindex)] + return [ + "mock_call_listable_method::command:{}::index:{}".format(method_name, i) + for i in range(startindex, stopindex) + ] elif method_name == const.INDEX: - return 'mock_call_listable_method::command:{}::index:{}'.format(method_name, startindex) + return "mock_call_listable_method::command:{}::index:{}".format(method_name, startindex) elif method_name == const.MEMBERSUBLIST: - return ['mock_call_listable_method::command:{}::index:{}::member_names:{}'.format(method_name, i, - [property_name]) for i in - range(startindex, stopindex)] + return [ + "mock_call_listable_method::command:{}::index:{}::member_names:{}".format( + method_name, i, [property_name] + ) + for i in range(startindex, stopindex) + ] elif method_name == const.MEMBERINDEX: - return 'mock_call_listable_method::command:{}::index:{}::member_names:{}'.format(method_name, startindex, - [property_name]) + return "mock_call_listable_method::command:{}::index:{}::member_names:{}".format( + method_name, startindex, [property_name] + ) else: - return 'mock_call_listable_method::command:{}'.format(method_name) + return "mock_call_listable_method::command:{}".format(method_name) def call_plx_object_method(self, proxy_obj, method_name, params): - return '{}.{}({})'.format(proxy_obj, method_name, ', '.join([repr(p) for p in params])) + return "{}.{}({})".format(proxy_obj, method_name, ", ".join([repr(p) for p in params])) def call_selection_command(self, command, *args): return [str(a) for a in args] diff --git a/src/plxscripting/unittests/test_plxproxy.py b/src/plxscripting/unittests/test_plxproxy.py index 66276c3..6dc40b7 100644 --- a/src/plxscripting/unittests/test_plxproxy.py +++ b/src/plxscripting/unittests/test_plxproxy.py @@ -25,9 +25,9 @@ @pytest.fixture def environment(): - GUID = '' - GUID_OWNER = '' - PLX_TYPE = 'fake_type' + GUID = "" + GUID_OWNER = "" + PLX_TYPE = "fake_type" server = mock_server.Server() owner = plxproxy.PlxProxyObject_Abstract(server, GUID_OWNER) return server, owner, GUID, GUID_OWNER, PLX_TYPE @@ -47,13 +47,14 @@ def test_PlxProxyGlobalObject(environment): with pytest.raises(PlxScriptingError) as exc: obj.selection = 12345 - assert '12345' in str(exc.value) + assert "12345" in str(exc.value) - selection = ['fake_object_selection_1', 'fake_object_selection_2'] + selection = ["fake_object_selection_1", "fake_object_selection_2"] obj.selection = selection assert list(obj._selection) == selection - assert str(obj.selection) == '' # should try to get selection from server + # should try to get selection from server + assert str(obj.selection) == "" def test_PlxProxyObject(environment): @@ -63,10 +64,10 @@ def test_PlxProxyObject(environment): assert GUID in str(obj) obj.custom_attribute = 54321 - assert hasattr(obj, 'custom_attribute') + assert hasattr(obj, "custom_attribute") assert obj.custom_attribute == 54321 - assert hasattr(obj, 'test_attribute') + assert hasattr(obj, "test_attribute") assert obj.test_attribute == 12345 # todo test userfeatures @@ -92,7 +93,7 @@ class Mixer(plxproxy.PlxProxyListable, plxproxy.PlxProxyObject): obj[server.listable_count] # get within range - assert 'index::index:1' in obj[1] + assert "index::index:1" in obj[1] # get out of range with pytest.raises(IndexError): @@ -100,7 +101,7 @@ class Mixer(plxproxy.PlxProxyListable, plxproxy.PlxProxyObject): # iterate with cache for indx, val in enumerate(obj): - assert 'sublist::index:{}'.format(indx) in val + assert "sublist::index:{}".format(indx) in val assert indx == 4 @@ -135,10 +136,10 @@ class Mixer(plxproxy.PlxProxyObject, plxproxy.PlxProxyValues): def test_PlxProxyObjectMethod(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment parent = plxproxy.PlxProxyObject(server, GUID, PLX_TYPE) - obj = plxproxy.PlxProxyObjectMethod(server, parent, 'sandwich') + obj = plxproxy.PlxProxyObjectMethod(server, parent, "sandwich") blt = f"<{PLX_TYPE} {GUID}>.sandwich('tomato', 'lettuce', 'bacon')" - assert obj('tomato', 'lettuce', 'bacon') == blt + assert obj("tomato", "lettuce", "bacon") == blt def test_PlxProxyMaterial(environment): @@ -149,7 +150,7 @@ def test_PlxProxyMaterial(environment): def test_PlxProxyObjectProperty(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyObjectProperty(server, GUID, PLX_TYPE, 'property', owner) + obj = plxproxy.PlxProxyObjectProperty(server, GUID, PLX_TYPE, "property", owner) class Temp: property = obj @@ -169,7 +170,7 @@ class Temp: def test_PlxProxyIPBoolean(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyIPBoolean(server, GUID, PLX_TYPE, 'boolean', owner) + obj = plxproxy.PlxProxyIPBoolean(server, GUID, PLX_TYPE, "boolean", owner) obj.set_stagedIP_value(True) assert obj.value is True @@ -185,7 +186,7 @@ def test_PlxProxyIPBoolean(environment): def test_PlxProxyIPNumber(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyIPNumber(server, GUID, PLX_TYPE, 'number', owner) + obj = plxproxy.PlxProxyIPNumber(server, GUID, PLX_TYPE, "number", owner) server.object_property_to_send = 20 assert obj + obj + 20 + 0.1 == 60.1 # Should be mostly tested by test_PlxProxyIPInteger and test_PlxProxyIPDouble, this is just a unit-smoketest @@ -193,7 +194,7 @@ def test_PlxProxyIPNumber(environment): def test_PlxProxyIPInteger(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyIPInteger(server, GUID, PLX_TYPE, 'integer', owner) + obj = plxproxy.PlxProxyIPInteger(server, GUID, PLX_TYPE, "integer", owner) server.object_property_to_send = 10 assert obj.value == 10 @@ -205,8 +206,8 @@ def test_PlxProxyIPInteger(environment): assert obj * 5 == 50 assert obj - 1 == 9 assert 1 - obj == -9 - assert obj ** 2 == 100 - assert 2 ** obj == 1024 + assert obj**2 == 100 + assert 2**obj == 1024 assert obj % 3 == 1 assert 19 % obj == 9 assert 1 < obj @@ -221,7 +222,7 @@ def test_PlxProxyIPInteger(environment): def test_PlxProxyIPDouble(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyIPDouble(server, GUID, PLX_TYPE, 'double', owner) + obj = plxproxy.PlxProxyIPDouble(server, GUID, PLX_TYPE, "double", owner) server.object_property_to_send = 10.1 assert obj.value == 10.1 @@ -233,8 +234,8 @@ def test_PlxProxyIPDouble(environment): assert obj * 5 == 50.5 assert obj - 1 == 9.1 assert 1 - obj == -9.1 - assert round(obj ** 2, 2) == 102.01 - assert 1 ** obj == 1 + assert round(obj**2, 2) == 102.01 + assert 1**obj == 1 assert round(obj % 3, 2) == 1.1 assert 19 % obj == 8.9 assert 1 < obj @@ -250,10 +251,10 @@ def test_PlxProxyIPDouble(environment): def test_PlxProxyIPObject(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj_as_value = plxproxy.PlxProxyObject(server, GUID, PLX_TYPE) - obj_as_value.attribute_1 = '1' - obj_as_value.attribute_2 = '2' + obj_as_value.attribute_1 = "1" + obj_as_value.attribute_2 = "2" - obj = plxproxy.PlxProxyIPObject(server, GUID, PLX_TYPE, 'ipobject', owner) + obj = plxproxy.PlxProxyIPObject(server, GUID, PLX_TYPE, "ipobject", owner) obj.set_stagedIP_value(obj_as_value) assert obj.value == obj_as_value @@ -266,73 +267,75 @@ def test_PlxProxyIPEnumeration(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment class TstEnum(plxproxy.PlxProxyIPEnumeration): - enum_a = 'a' - enum_b = 'b' + enum_a = "a" + enum_b = "b" - obj = TstEnum(server, GUID, PLX_TYPE, 'ipenum', owner) + obj = TstEnum(server, GUID, PLX_TYPE, "ipenum", owner) # attribute exists, value matches server - server.object_property_to_send = 'a' - obj.strvalue = 'enum_a' - assert obj.strvalue == 'enum_a' + server.object_property_to_send = "a" + obj.strvalue = "enum_a" + assert obj.strvalue == "enum_a" # attribute does not exist in class - server.object_property_to_send = 'd' + server.object_property_to_send = "d" with pytest.raises(ValueError): - obj.strvalue = 'enum_d' + obj.strvalue = "enum_d" # attribute value does not match server response - server.object_property_to_send = 'z' + server.object_property_to_send = "z" with pytest.raises(ValueError): - obj.strvalue = 'enum_b' + obj.strvalue = "enum_b" def test_PlxProxyIPText(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyIPText(server, GUID, PLX_TYPE, 'iptext', owner) - server.object_property_to_send = 'abcd' - assert obj == 'abcd' - assert obj + 'efgh' == 'abcdefgh' - assert obj[2] == 'c' - assert obj != 'dcba' + obj = plxproxy.PlxProxyIPText(server, GUID, PLX_TYPE, "iptext", owner) + server.object_property_to_send = "abcd" + assert obj == "abcd" + assert obj + "efgh" == "abcdefgh" + assert obj[2] == "c" + assert obj != "dcba" def test_PlxProxyIPStaged(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - obj = plxproxy.PlxProxyIPStaged(server, GUID, PLX_TYPE, 'ipstaged', owner) + obj = plxproxy.PlxProxyIPStaged(server, GUID, PLX_TYPE, "ipstaged", owner) - some_phase = plxproxy.PlxProxyObject(server, '', 'Phase') - another_phase = plxproxy.PlxProxyObject(server, '', 'Phase') - server.object_property_to_send = 'not_relevant' + some_phase = plxproxy.PlxProxyObject(server, "", "Phase") + another_phase = plxproxy.PlxProxyObject(server, "", "Phase") + server.object_property_to_send = "not_relevant" server.object_property_phase_store = None __ = obj[some_phase] assert server.object_property_phase_store == some_phase server.object_property_store = None - obj[another_phase] = 'some_value' - assert server.object_property_store == [another_phase, 'some_value'] + obj[another_phase] = "some_value" + assert server.object_property_store == [another_phase, "some_value"] def test_PlxProxyFactory_mix_in(): - connection = 'fake' + connection = "fake" obj = plxproxyfactory.PlxProxyFactory(connection) - class a: pass + class a: + pass - class b: pass + class b: + pass - c = obj.mix_in(a, b, name='test_name')() + c = obj.mix_in(a, b, name="test_name")() assert isinstance(c, b) assert isinstance(c, a) and isinstance(c, b) - assert type(c).__name__ == 'test_name' + assert type(c).__name__ == "test_name" c = obj.mix_in(b, a)() assert isinstance(c, a) and isinstance(c, b) def test_PlxProxyFactory_create_plx_proxy_global(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - connection = 'fake' + connection = "fake" obj = plxproxyfactory.PlxProxyFactory(connection) ret_obj = obj.create_plx_proxy_global(server) assert isinstance(ret_obj, plxproxy.PlxProxyGlobalObject) @@ -340,20 +343,20 @@ def test_PlxProxyFactory_create_plx_proxy_global(environment): def test_PlxProxyFactory_create_plx_proxy_object_method(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - connection = 'fake' + connection = "fake" obj = plxproxyfactory.PlxProxyFactory(connection) - ret_obj = obj.create_plx_proxy_object_method(server, owner, 'cheese') + ret_obj = obj.create_plx_proxy_object_method(server, owner, "cheese") assert isinstance(ret_obj, plxproxy.PlxProxyObjectMethod) def proxyfactory(): class mock_connection: def request_enumeration(self, *args, **kwargs): - return {const.JSON_QUERIES: { - 'test_guid_1_2': { - const.JSON_SUCCESS: True, - const.JSON_ENUMVALUES: {} - }}} + return { + const.JSON_QUERIES: { + "test_guid_1_2": {const.JSON_SUCCESS: True, const.JSON_ENUMVALUES: {}} + } + } connection = mock_connection() return plxproxyfactory.PlxProxyFactory(connection) @@ -363,8 +366,9 @@ def test_PlxProxyFactory_create_plx_proxy_object(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1', 'test_plxtype', False, property_name='test_property', - owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, "test_guid_1", "test_plxtype", False, property_name="test_property", owner=owner + ) assert isinstance(ret_obj, plxproxy.PlxProxyObject) assert not isinstance(ret_obj, plxproxy.PlxProxyValues) assert not isinstance(ret_obj, plxproxy.PlxProxyMaterial) @@ -377,8 +381,14 @@ def test_PlxProxyFactory_create_PlxProxyIPBoolean(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_1', plxproxyfactory.TYPE_BOOLEAN, False, - property_name='test_property', owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_1", + plxproxyfactory.TYPE_BOOLEAN, + False, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyIPBoolean) @@ -387,9 +397,14 @@ def test_PlxProxyFactory_create_PlxProxyIPEnumeration(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_2', plxproxyfactory.ENUM, False, - property_name='test_property', - owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_2", + plxproxyfactory.ENUM, + False, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyIPEnumeration) @@ -398,8 +413,14 @@ def test_PlxProxyFactory_create_PlxProxyIPDouble(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_3', plxproxyfactory.TYPE_NUMBER, False, - property_name='test_property', owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_3", + plxproxyfactory.TYPE_NUMBER, + False, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyIPDouble) @@ -408,8 +429,14 @@ def test_PlxProxyFactory_create_PlxProxyIPInteger(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_4', plxproxyfactory.TYPE_INTEGER, False, - property_name='test_property', owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_4", + plxproxyfactory.TYPE_INTEGER, + False, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyIPInteger) @@ -418,8 +445,14 @@ def test_PlxProxyFactory_create_PlxProxyObjectProperty_non_listable(environment) server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_5', plxproxyfactory.TYPE_OBJECT, False, - property_name='test_property', owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_5", + plxproxyfactory.TYPE_OBJECT, + False, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert not isinstance(ret_obj, plxproxy.PlxProxyListable) @@ -428,8 +461,14 @@ def test_PlxProxyFactory_create_PlxProxyListable(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_6', plxproxyfactory.TYPE_OBJECT, True, - property_name='test_property', owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_6", + plxproxyfactory.TYPE_OBJECT, + True, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyListable) @@ -438,9 +477,14 @@ def test_PlxProxyFactory_create_PlxProxyIPStaged(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_7', plxproxyfactory.STAGED, False, - property_name='test_property', - owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, + "test_guid_1_7", + plxproxyfactory.STAGED, + False, + property_name="test_property", + owner=owner, + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyIPStaged) @@ -449,8 +493,9 @@ def test_PlxProxyFactory_create_PlxProxyListable_unknown_type(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_1_8', 'test_plxtype', True, property_name='test_property', - owner=owner) + ret_obj = obj.create_plx_proxy_object( + server, "test_guid_1_8", "test_plxtype", True, property_name="test_property", owner=owner + ) assert isinstance(ret_obj, plxproxy.PlxProxyObjectProperty) assert isinstance(ret_obj, plxproxy.PlxProxyListable) @@ -459,8 +504,9 @@ def test_PlxProxyFactory_create_PlxProxyValues(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_2', 'PlxValues', False, property_name='test_property', - owner=None) + ret_obj = obj.create_plx_proxy_object( + server, "test_guid_2", "PlxValues", False, property_name="test_property", owner=None + ) assert isinstance(ret_obj, plxproxy.PlxProxyObject) assert isinstance(ret_obj, plxproxy.PlxProxyValues) assert not isinstance(ret_obj, plxproxy.PlxProxyMaterial) @@ -473,8 +519,9 @@ def test_PlxProxyFactory_create_PlxProxyMaterial(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_3', 'SoilMat', False, property_name='test_property', - owner=None) + ret_obj = obj.create_plx_proxy_object( + server, "test_guid_3", "SoilMat", False, property_name="test_property", owner=None + ) assert isinstance(ret_obj, plxproxy.PlxProxyObject) assert not isinstance(ret_obj, plxproxy.PlxProxyValues) assert isinstance(ret_obj, plxproxy.PlxProxyMaterial) @@ -487,8 +534,9 @@ def test_PlxProxyFactory_create_PlxProxyListable_unknown_type_no_owner(environme server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_uid_4', 'test_plxtype', True, property_name='test_property', - owner=None) + ret_obj = obj.create_plx_proxy_object( + server, "test_uid_4", "test_plxtype", True, property_name="test_property", owner=None + ) assert isinstance(ret_obj, plxproxy.PlxProxyObject) assert not isinstance(ret_obj, plxproxy.PlxProxyValues) assert not isinstance(ret_obj, plxproxy.PlxProxyMaterial) @@ -501,8 +549,9 @@ def test_PlxProxyFactory_create_PlxProxyObjectProperty_no_list_no_own(environmen server, owner, GUID, GUID_OWNER, PLX_TYPE = environment obj = proxyfactory() - ret_obj = obj.create_plx_proxy_object(server, 'test_guid_5', 'test_plxtype', False, property_name='test_property', - owner=None) + ret_obj = obj.create_plx_proxy_object( + server, "test_guid_5", "test_plxtype", False, property_name="test_property", owner=None + ) assert isinstance(ret_obj, plxproxy.PlxProxyObject) assert not isinstance(ret_obj, plxproxy.PlxProxyValues) assert not isinstance(ret_obj, plxproxy.PlxProxyMaterial) @@ -513,23 +562,25 @@ def test_PlxProxyFactory_create_PlxProxyObjectProperty_no_list_no_own(environmen def test_PlxProxyFactory_get_proxy_object_if_exists(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - connection = 'fake' + connection = "fake" obj = plxproxyfactory.PlxProxyFactory(connection) - assert obj.get_proxy_object_if_exists('test_guid') is None - obj.create_plx_proxy_object(server, 'test_guid', 'test_plxtype', False, property_name='test_property', - owner=None) - assert obj.get_proxy_object_if_exists('test_guid') is not None + assert obj.get_proxy_object_if_exists("test_guid") is None + obj.create_plx_proxy_object( + server, "test_guid", "test_plxtype", False, property_name="test_property", owner=None + ) + assert obj.get_proxy_object_if_exists("test_guid") is not None def test_PlxProxyFactory_clear_proxy_object_cache(environment): server, owner, GUID, GUID_OWNER, PLX_TYPE = environment - connection = 'fake' + connection = "fake" obj = plxproxyfactory.PlxProxyFactory(connection) - obj.create_plx_proxy_object(server, 'testymctestface', 'test_plxtype', False, property_name='test_property', - owner=None) - assert obj.get_proxy_object_if_exists('testymctestface') is not None + obj.create_plx_proxy_object( + server, "testymctestface", "test_plxtype", False, property_name="test_property", owner=None + ) + assert obj.get_proxy_object_if_exists("testymctestface") is not None obj.clear_proxy_object_cache() - assert obj.get_proxy_object_if_exists('testymctestface') is None + assert obj.get_proxy_object_if_exists("testymctestface") is None diff --git a/src/plxscripting/unittests/test_selection.py b/src/plxscripting/unittests/test_selection.py index 456de26..5a49e06 100644 --- a/src/plxscripting/unittests/test_selection.py +++ b/src/plxscripting/unittests/test_selection.py @@ -35,8 +35,10 @@ def get_cmd_line_repr(self): @pytest.fixture def get_prerequisites(): - connection = mock_connection.HTTPConnection('fake_host', 12345) - _server = server.Server(connection, plxproxyfactory.PlxProxyFactory(connection), server.InputProcessor()) + connection = mock_connection.HTTPConnection("fake_host", 12345) + _server = server.Server( + connection, plxproxyfactory.PlxProxyFactory(connection), server.InputProcessor() + ) selection = Selection(_server) return connection, _server, selection @@ -53,65 +55,65 @@ def test_refresh(get_prerequisites): def test_set(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) - assert connection._selection[0]['guid'] == 'guid1' - assert connection._selection[1]['guid'] == 'guid2' + assert connection._selection[0]["guid"] == "guid1" + assert connection._selection[1]["guid"] == "guid2" def test_append(get_prerequisites): connection, server_instance, selection = get_prerequisites - selection.append(fake_proxy_obj('etc', 'guid3'), fake_proxy_obj('...', 'guid4')) - assert connection._selection[0]['guid'] == 'guid3' - assert connection._selection[1]['guid'] == 'guid4' + selection.append(fake_proxy_obj("etc", "guid3"), fake_proxy_obj("...", "guid4")) + assert connection._selection[0]["guid"] == "guid3" + assert connection._selection[1]["guid"] == "guid4" - selection.append(fake_proxy_obj('bla', 'guid5'), fake_proxy_obj('~~~', 'guid6')) - assert connection._selection[0]['guid'] == 'guid3' - assert connection._selection[1]['guid'] == 'guid4' - assert connection._selection[2]['guid'] == 'guid5' - assert connection._selection[3]['guid'] == 'guid6' + selection.append(fake_proxy_obj("bla", "guid5"), fake_proxy_obj("~~~", "guid6")) + assert connection._selection[0]["guid"] == "guid3" + assert connection._selection[1]["guid"] == "guid4" + assert connection._selection[2]["guid"] == "guid5" + assert connection._selection[3]["guid"] == "guid6" def test_extend(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) - selection.extend([fake_proxy_obj('....', 'guid5'), fake_proxy_obj('.....', 'guid6')]) - assert connection._selection[0]['guid'] == 'guid1' - assert connection._selection[1]['guid'] == 'guid2' - assert connection._selection[2]['guid'] == 'guid5' - assert connection._selection[3]['guid'] == 'guid6' + selection.extend([fake_proxy_obj("....", "guid5"), fake_proxy_obj(".....", "guid6")]) + assert connection._selection[0]["guid"] == "guid1" + assert connection._selection[1]["guid"] == "guid2" + assert connection._selection[2]["guid"] == "guid5" + assert connection._selection[3]["guid"] == "guid6" def test_remove(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) - selection.extend([fake_proxy_obj('....', 'guid5'), fake_proxy_obj('.....', 'guid6')]) + selection.extend([fake_proxy_obj("....", "guid5"), fake_proxy_obj(".....", "guid6")]) selection.remove(*objlist) - assert connection._selection[0]['guid'] == 'guid5' - assert connection._selection[1]['guid'] == 'guid6' + assert connection._selection[0]["guid"] == "guid5" + assert connection._selection[1]["guid"] == "guid6" def test_pop(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) selection.pop() assert len(connection._selection) == 1 - assert connection._selection[0]['guid'] == 'guid1' + assert connection._selection[0]["guid"] == "guid1" def test_clear(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) selection.clear() assert connection._selection == [] @@ -132,11 +134,11 @@ def test_magic_add_list_get(get_prerequisites): connection._selection = [] selection.refresh() - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection += objlist assert len(selection) == 2 - assert selection[0]._guid == 'guid1' - assert selection[1]._guid == 'guid2' + assert selection[0]._guid == "guid1" + assert selection[1]._guid == "guid2" with pytest.raises(IndexError): selection[1234] @@ -145,81 +147,81 @@ def test_magic_add_list_get(get_prerequisites): def test_magic_add_obj(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) - selection = selection + fake_proxy_obj('etc', 'guid3') + selection = selection + fake_proxy_obj("etc", "guid3") assert len(selection) == 3 - assert selection[0]._guid == 'guid1' - assert selection[1]._guid == 'guid2' - assert selection[2]._guid == 'guid3' + assert selection[0]._guid == "guid1" + assert selection[1]._guid == "guid2" + assert selection[2]._guid == "guid3" with pytest.raises(AttributeError) as exc: - selection += 'not_a_proxy_object' + selection += "not_a_proxy_object" assert "has no attribute '_guid'" in str(exc.value) def test_magic_sub(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) selection -= selection._objects[0] assert len(selection) == 1 - assert selection[0]._guid == 'guid2' + assert selection[0]._guid == "guid2" with pytest.raises(AttributeError): - selection -= 'not_in_the_list' + selection -= "not_in_the_list" def test_magic_setitem(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) - selection[1] = fake_proxy_obj('...', 'guid4') + selection[1] = fake_proxy_obj("...", "guid4") assert len(selection) == 2 - assert selection[0]._guid == 'guid1' - assert selection[1]._guid == 'guid4' + assert selection[0]._guid == "guid1" + assert selection[1]._guid == "guid4" def test_magic_contains(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) assert selection[1] in selection - assert 'cheese' not in selection + assert "cheese" not in selection def test_magic_delitem(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) del selection[0] assert len(selection) == 1 - assert selection[0]._guid == 'guid2' + assert selection[0]._guid == "guid2" def test_magic_repr(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection += objlist - assert repr(selection) == '[, ]' + assert repr(selection) == "[, ]" def test_magic_iter(get_prerequisites): connection, server_instance, selection = get_prerequisites - objlist = [fake_proxy_obj('stuff', 'guid1'), fake_proxy_obj('things', 'guid2')] + objlist = [fake_proxy_obj("stuff", "guid1"), fake_proxy_obj("things", "guid2")] selection.set(objlist) for item in selection: - assert 'guid' in item._guid + assert "guid" in item._guid diff --git a/src/plxscripting/unittests/test_server.py b/src/plxscripting/unittests/test_server.py index dafb72e..02f5b48 100644 --- a/src/plxscripting/unittests/test_server.py +++ b/src/plxscripting/unittests/test_server.py @@ -25,7 +25,7 @@ def newsrv(): - con = mock_connection.HTTPConnection('fake_host', 12345) + con = mock_connection.HTTPConnection("fake_host", 12345) return con, server.Server(con, plxproxyfactory.PlxProxyFactory(con), server.InputProcessor()) @@ -33,7 +33,7 @@ class fake_proxy_obj: def __init__(self, name, guid): self.__name__ = name self._guid = guid - self._plx_type = 'MockItem_UnitTest' + self._plx_type = "MockItem_UnitTest" def get_cmd_line_repr(self): return self.__name__ @@ -43,48 +43,49 @@ def test_InputProcessor_param_to_string(): obj = server.InputProcessor() # Simple tests - assert obj.param_to_string('test') == '"test"' - assert obj.param_to_string(54321) == '54321' - assert obj.param_to_string([54321]) == '(54321)' - assert obj.param_to_string((54321,)) == '(54321)' - assert obj.param_to_string([54321, 'cheese']) == '(54321 "cheese")' - assert obj.param_to_string((54321, 'cake')) == '(54321 "cake")' + assert obj.param_to_string("test") == '"test"' + assert obj.param_to_string(54321) == "54321" + assert obj.param_to_string([54321]) == "(54321)" + assert obj.param_to_string((54321,)) == "(54321)" + assert obj.param_to_string([54321, "cheese"]) == '(54321 "cheese")' + assert obj.param_to_string((54321, "cake")) == '(54321 "cake")' # Generator object def generator(n=5): for x in range(1, n + 1): yield x - assert obj.param_to_string(generator()) == '(1 2 3 4 5)' + assert obj.param_to_string(generator()) == "(1 2 3 4 5)" # Selection object - sel = Selection('i_am_a_fake_server_object') + sel = Selection("i_am_a_fake_server_object") sel._objects = [1, 2, 3, 4, 5] - assert obj.param_to_string(sel) == '(1 2 3 4 5)' + assert obj.param_to_string(sel) == "(1 2 3 4 5)" class RandomObject: def __str__(self): - return 'random_object' + return "random_object" # fallback behaviour is to str() the input - assert obj.param_to_string(RandomObject()) == 'random_object' + assert obj.param_to_string(RandomObject()) == "random_object" def test_InputProcessor_create_method_call_cmd(): obj = server.InputProcessor() # Simple list - resp2 = obj.create_method_call_cmd(fake_proxy_obj('fakeobj', 'fake_guid'), '_fakefunc', [12345]) - assert resp2 == '_fakefunc fakeobj 12345' + resp2 = obj.create_method_call_cmd(fake_proxy_obj("fakeobj", "fake_guid"), "_fakefunc", [12345]) + assert resp2 == "_fakefunc fakeobj 12345" # Mixed list - resp = obj.create_method_call_cmd(fake_proxy_obj('Object_1_2', 'fake_guid'), 'function', - ['param1', 'param2', 'param3', 4, 5]) + resp = obj.create_method_call_cmd( + fake_proxy_obj("Object_1_2", "fake_guid"), "function", ["param1", "param2", "param3", 4, 5] + ) assert resp == 'function Object_1_2 "param1" "param2" "param3" 4 5' # No object - resp2 = obj.create_method_call_cmd(None, '_fakefuncnoobj', [54321]) - assert resp2 == '_fakefuncnoobj 54321' + resp2 = obj.create_method_call_cmd(None, "_fakefuncnoobj", [54321]) + assert resp2 == "_fakefuncnoobj 54321" def test_ResultHandler_handle_namedobjects_response(): @@ -92,26 +93,30 @@ def test_ResultHandler_handle_namedobjects_response(): pf = plxproxyfactory.PlxProxyFactory(con) obj = server.ResultHandler(srv, pf) - input_ok = {'extrainfo': '', - 'success': True, - 'returnedobject': { - 'islistable': True, - 'type': 'ModelGroup', - 'guid': '{5B0FCDB3-F02B-4356-AC82-683628DF3555}' - }} + input_ok = { + "extrainfo": "", + "success": True, + "returnedobject": { + "islistable": True, + "type": "ModelGroup", + "guid": "{5B0FCDB3-F02B-4356-AC82-683628DF3555}", + }, + } - response_ok = '' + response_ok = "" - input_fail = {'extrainfo': 'Named object does not exist in current registry.', - 'success': False, - 'returnedobject': {}} + input_fail = { + "extrainfo": "Named object does not exist in current registry.", + "success": False, + "returnedobject": {}, + } - response_fail = 'Named object does not exist in current registry.' + response_fail = "Named object does not exist in current registry." result = obj.handle_namedobjects_response(input_ok) assert isinstance(result, plxproxy.PlxProxyObject) - assert result._plx_type == 'ModelGroup' - assert result._guid == '{5B0FCDB3-F02B-4356-AC82-683628DF3555}' + assert result._plx_type == "ModelGroup" + assert result._guid == "{5B0FCDB3-F02B-4356-AC82-683628DF3555}" with pytest.raises(PlxScriptingError) as exc: obj.handle_namedobjects_response(input_fail) @@ -123,29 +128,40 @@ def test_ResultHandler_handle_commands_response(): pf = plxproxyfactory.PlxProxyFactory(con) obj = server.ResultHandler(srv, pf) - input_ok = {'extrainfo': 'Added Borehole_1', - 'returnedobjects': [{ - 'islistable': True, - 'type': 'Borehole', - 'guid': '{2A3F1B63-A6F2-48B0-9D3A-2A8F39E6D2D9}'}], - 'debuginfo': '', - 'success': True, - 'errorpos': -1, - 'returnedvalues': []} - - response_ok = '' - - input_fail = {'extrainfo': 'Cannot intersect unless there is at least one volume or surface in the geometry', - 'debuginfo': '', - 'success': False, - 'errorpos': -1} - - response_fail = 'Cannot intersect unless there is at least one volume or surface in the geometry' + input_ok = { + "extrainfo": "Added Borehole_1", + "returnedobjects": [ + { + "islistable": True, + "type": "Borehole", + "guid": "{2A3F1B63-A6F2-48B0-9D3A-2A8F39E6D2D9}", + } + ], + "debuginfo": "", + "success": True, + "errorpos": -1, + "returnedvalues": [], + } + + response_ok = "" + + input_fail = { + "extrainfo": ( + "Cannot intersect unless there is at least one volume or surface in the geometry" + ), + "debuginfo": "", + "success": False, + "errorpos": -1, + } + + response_fail = ( + "Cannot intersect unless there is at least one volume or surface in the geometry" + ) result = obj.handle_commands_response(input_ok) assert isinstance(result, plxproxy.PlxProxyObject) - assert result._plx_type == 'Borehole' - assert result._guid == '{2A3F1B63-A6F2-48B0-9D3A-2A8F39E6D2D9}' + assert result._plx_type == "Borehole" + assert result._guid == "{2A3F1B63-A6F2-48B0-9D3A-2A8F39E6D2D9}" with pytest.raises(PlxScriptingError) as exc: obj.handle_commands_response(input_fail) @@ -157,61 +173,69 @@ def test_ResultHandler_handle_members_response(): pf = plxproxyfactory.PlxProxyFactory(con) obj = server.ResultHandler(srv, pf) - input_ok = {'extrainfo': '', - 'success': True, - 'properties': { - 'TypeName': { - 'islistable': False, - 'value': 'ModelGroup', - 'type': 'Text', - 'guid': '{52F2A950-7AAC-4413-8FCE-E9AEE3287CF1}', - 'ispublished': False, - 'ownerguid': '{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}', - 'caption': 'TypeName'}, - 'Name': { - 'islistable': False, - 'value': 'Boreholes', - 'type': 'Text', - 'guid': '{CF6CB8A7-1944-4967-A789-3C744BF339D3}', - 'ispublished': False, - 'ownerguid': '{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}', - 'caption': 'Name'}, - 'UserFeatures': { - 'islistable': False, - 'value': { - 'islistable': True, - 'type': 'PlxUserFeatureList', - 'guid': '{C325B1E0-809F-4113-8F78-1037098857B6}'}, - 'type': 'Object', - 'guid': '{E8F956DD-6F67-4DC7-96F5-AB31573D4336}', - 'ispublished': False, - 'ownerguid': '{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}', - 'caption': 'UserFeatures'}, - 'Comments': { - 'islistable': False, - 'value': '', - 'type': 'Text', - 'guid': '{9A5D6095-1D2A-49C6-BD94-6B32DC4465C1}', - 'ispublished': False, - 'ownerguid': '{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}', - 'caption': 'Comments'} + input_ok = { + "extrainfo": "", + "success": True, + "properties": { + "TypeName": { + "islistable": False, + "value": "ModelGroup", + "type": "Text", + "guid": "{52F2A950-7AAC-4413-8FCE-E9AEE3287CF1}", + "ispublished": False, + "ownerguid": "{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}", + "caption": "TypeName", + }, + "Name": { + "islistable": False, + "value": "Boreholes", + "type": "Text", + "guid": "{CF6CB8A7-1944-4967-A789-3C744BF339D3}", + "ispublished": False, + "ownerguid": "{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}", + "caption": "Name", + }, + "UserFeatures": { + "islistable": False, + "value": { + "islistable": True, + "type": "PlxUserFeatureList", + "guid": "{C325B1E0-809F-4113-8F78-1037098857B6}", }, - 'commands': [ - 'echo', - '__dump', - 'commands', - 'multiply', - 'info', - '__observers', - 'setproperties', - 'setmaterial'], - 'commandlinename': 'Boreholes'} - result = obj.handle_members_response(input_ok, fake_proxy_obj('fake_name', 'fake_guid')) - - assert 'Name' in result - assert result['Name']._guid == '{CF6CB8A7-1944-4967-A789-3C744BF339D3}' - assert 'UserFeatures' in result - assert hasattr(result['UserFeatures'], '__iter__') + "type": "Object", + "guid": "{E8F956DD-6F67-4DC7-96F5-AB31573D4336}", + "ispublished": False, + "ownerguid": "{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}", + "caption": "UserFeatures", + }, + "Comments": { + "islistable": False, + "value": "", + "type": "Text", + "guid": "{9A5D6095-1D2A-49C6-BD94-6B32DC4465C1}", + "ispublished": False, + "ownerguid": "{AE5F2EF3-D5EA-4F46-84B2-909061DFD5A4}", + "caption": "Comments", + }, + }, + "commands": [ + "echo", + "__dump", + "commands", + "multiply", + "info", + "__observers", + "setproperties", + "setmaterial", + ], + "commandlinename": "Boreholes", + } + result = obj.handle_members_response(input_ok, fake_proxy_obj("fake_name", "fake_guid")) + + assert "Name" in result + assert result["Name"]._guid == "{CF6CB8A7-1944-4967-A789-3C744BF339D3}" + assert "UserFeatures" in result + assert hasattr(result["UserFeatures"], "__iter__") # This function has no error handler, so there is no failure to test. @@ -222,58 +246,67 @@ def test_ResultHandler_handle_list_response(): obj = server.ResultHandler(srv, pf) # count - input_ok = {'extrainfo': '', - 'success': True, - 'methodname': 'count', - 'guid': '{8D251E47-C14C-4A08-8506-4D5CE6C316CF}', - 'outputdata': 3} + input_ok = { + "extrainfo": "", + "success": True, + "methodname": "count", + "guid": "{8D251E47-C14C-4A08-8506-4D5CE6C316CF}", + "outputdata": 3, + } response = 3 result = obj.handle_list_response(input_ok) assert result == 3 # index - input_ok = {'extrainfo': '', - 'success': True, - 'startindex': 0, - 'methodname': 'index', - 'guid': '{F9A93D18-4FB2-4A74-A564-C2F25D9814FB}', - 'outputdata': { - 'islistable': True, - 'type': 'Line', - 'guid': '{6D4BAEF4-E8EF-45B0-B796-E86F51D02DFB}'}} + input_ok = { + "extrainfo": "", + "success": True, + "startindex": 0, + "methodname": "index", + "guid": "{F9A93D18-4FB2-4A74-A564-C2F25D9814FB}", + "outputdata": { + "islistable": True, + "type": "Line", + "guid": "{6D4BAEF4-E8EF-45B0-B796-E86F51D02DFB}", + }, + } result = obj.handle_list_response(input_ok) assert isinstance(result, plxproxy.PlxProxyObject) - assert result._plx_type == 'Line' + assert result._plx_type == "Line" # sublist - input_ok = {'extrainfo': '', - 'stopindex': 3, - 'success': True, - 'startindex': 0, - 'methodname': 'sublist', - 'guid': '{28444FD3-7BC6-4039-9264-D605EC85C2CA}', - 'outputdata': [ - {'islistable': False, - 'type': 'Soil', - 'guid': '{D535EAB7-8498-491E-B655-F954B34B2C33}'}, - {'islistable': True, - 'type': 'PorePressure', - 'guid': '{CBCB4813-098F-4278-A48A-C4CCA78EECDA}'}, - {'islistable': True, - 'type': 'LayerZone', - 'guid': '{F2C65547-8B8F-41C1-BEA7-0C4A1D105B50}'}] - } + input_ok = { + "extrainfo": "", + "stopindex": 3, + "success": True, + "startindex": 0, + "methodname": "sublist", + "guid": "{28444FD3-7BC6-4039-9264-D605EC85C2CA}", + "outputdata": [ + {"islistable": False, "type": "Soil", "guid": "{D535EAB7-8498-491E-B655-F954B34B2C33}"}, + { + "islistable": True, + "type": "PorePressure", + "guid": "{CBCB4813-098F-4278-A48A-C4CCA78EECDA}", + }, + { + "islistable": True, + "type": "LayerZone", + "guid": "{F2C65547-8B8F-41C1-BEA7-0C4A1D105B50}", + }, + ], + } result = obj.handle_list_response(input_ok) assert len(result) == 3 assert isinstance(result[0], plxproxy.PlxProxyObject) - assert result[0]._plx_type == 'Soil' + assert result[0]._plx_type == "Soil" assert isinstance(result[1], plxproxy.PlxProxyObject) - assert result[1]._plx_type == 'PorePressure' + assert result[1]._plx_type == "PorePressure" assert isinstance(result[2], plxproxy.PlxProxyObject) - assert result[2]._plx_type == 'LayerZone' + assert result[2]._plx_type == "LayerZone" # This function has no error handler, so there is no failure to test. @@ -283,76 +316,81 @@ def test_ResultHandler_handle_propertyvalues_response(): pf = plxproxyfactory.PlxProxyFactory(con) obj = server.ResultHandler(srv, pf) - input1_ok = {'extrainfo': '', - 'success': True, - 'properties': { - 'UserFeatures': { - 'islistable': True, - 'type': 'PlxUserFeatureList', - 'guid': '{C325B1E0-809F-4113-8F78-1037098857B6}'} - }} - - input2_ok = {'extrainfo': '', - 'success': True, - 'properties': { - 'UserFeatures': { - 'islistable': True, - 'type': 'PlxUserFeatureList', - 'guid': '{C0CA551D-DFD7-4FD0-AB3B-BAAD739BC820}'} - }} - - input_fail = {'extrainfo': 'Fake error :)', - 'success': False, - 'properties': {}} - - [result1, result2] = obj.handle_propertyvalues_response([input1_ok, input2_ok], 'UserFeatures', 'ModelGroup') + input1_ok = { + "extrainfo": "", + "success": True, + "properties": { + "UserFeatures": { + "islistable": True, + "type": "PlxUserFeatureList", + "guid": "{C325B1E0-809F-4113-8F78-1037098857B6}", + } + }, + } + + input2_ok = { + "extrainfo": "", + "success": True, + "properties": { + "UserFeatures": { + "islistable": True, + "type": "PlxUserFeatureList", + "guid": "{C0CA551D-DFD7-4FD0-AB3B-BAAD739BC820}", + } + }, + } + + input_fail = {"extrainfo": "Fake error :)", "success": False, "properties": {}} + + [result1, result2] = obj.handle_propertyvalues_response( + [input1_ok, input2_ok], "UserFeatures", "ModelGroup" + ) assert isinstance(result1, plxproxy.PlxProxyObject) assert isinstance(result2, plxproxy.PlxProxyObject) - assert result1._plx_type == 'PlxUserFeatureList' - assert result2._plx_type == 'PlxUserFeatureList' - assert result1._guid == '{C325B1E0-809F-4113-8F78-1037098857B6}' - assert result2._guid == '{C0CA551D-DFD7-4FD0-AB3B-BAAD739BC820}' + assert result1._plx_type == "PlxUserFeatureList" + assert result2._plx_type == "PlxUserFeatureList" + assert result1._guid == "{C325B1E0-809F-4113-8F78-1037098857B6}" + assert result2._guid == "{C0CA551D-DFD7-4FD0-AB3B-BAAD739BC820}" - result = obj.handle_propertyvalues_response([input_fail], 'FakeAttribute', 'FakeType')[0] + result = obj.handle_propertyvalues_response([input_fail], "FakeAttribute", "FakeType")[0] assert result is None # Should also fail if one of the responses is failure - result = obj.handle_propertyvalues_response([input1_ok, input_fail], 'FakeAttribute', 'FakeType') + result = obj.handle_propertyvalues_response( + [input1_ok, input_fail], "FakeAttribute", "FakeType" + ) for r in result: assert r is None + def test_ResultHandler_handle_selection_response(): con, srv = newsrv() pf = plxproxyfactory.PlxProxyFactory(con) obj = server.ResultHandler(srv, pf) - input_ok = {'ReplyCode': '00000000000000000000000000000000', - 'selection': [ - {'islistable': True, - 'type': 'Line', - 'guid': '{27498209-C64B-476B-8583-97233801C0DB}'}, - {'islistable': True, - 'type': 'Line', - 'guid': '{5E480CA7-001C-4435-9888-1CFC029CD48E}'}, - {'islistable': True, - 'type': 'Line', - 'guid': '{9430A8A8-DC90-4006-8EBE-0835799BB1F1}'}] - } - - input_empty = {'ReplyCode': '00000000000000000000000000000000', 'selection': []} + input_ok = { + "ReplyCode": "00000000000000000000000000000000", + "selection": [ + {"islistable": True, "type": "Line", "guid": "{27498209-C64B-476B-8583-97233801C0DB}"}, + {"islistable": True, "type": "Line", "guid": "{5E480CA7-001C-4435-9888-1CFC029CD48E}"}, + {"islistable": True, "type": "Line", "guid": "{9430A8A8-DC90-4006-8EBE-0835799BB1F1}"}, + ], + } + + input_empty = {"ReplyCode": "00000000000000000000000000000000", "selection": []} result = obj.handle_selection_response(input_ok) assert isinstance(result, list) assert len(result) == 3 assert isinstance(result[0], plxproxy.PlxProxyObject) - assert result[0]._guid == '{27498209-C64B-476B-8583-97233801C0DB}' - assert result[0]._plx_type == 'Line' + assert result[0]._guid == "{27498209-C64B-476B-8583-97233801C0DB}" + assert result[0]._plx_type == "Line" assert isinstance(result[1], plxproxy.PlxProxyObject) - assert result[1]._guid == '{5E480CA7-001C-4435-9888-1CFC029CD48E}' - assert result[1]._plx_type == 'Line' + assert result[1]._guid == "{5E480CA7-001C-4435-9888-1CFC029CD48E}" + assert result[1]._plx_type == "Line" assert isinstance(result[2], plxproxy.PlxProxyObject) - assert result[2]._guid == '{9430A8A8-DC90-4006-8EBE-0835799BB1F1}' - assert result[2]._plx_type == 'Line' + assert result[2]._guid == "{9430A8A8-DC90-4006-8EBE-0835799BB1F1}" + assert result[2]._plx_type == "Line" result = obj.handle_selection_response(input_empty) assert result == [] @@ -362,12 +400,12 @@ def test_Server_new(): con, srv = newsrv() # Artificially put something in the caches - srv._Server__globals_cache = {'a': 'b'} - srv._Server__values_cache = {'a': 'b'} - srv._Server__listables_cache = {'a': 'b'} - srv._Server__proxy_factory.proxy_object_cache = {'a': 'b'} + srv._Server__globals_cache = {"a": "b"} + srv._Server__values_cache = {"a": "b"} + srv._Server__listables_cache = {"a": "b"} + srv._Server__proxy_factory.proxy_object_cache = {"a": "b"} - assert srv.new() == 'OK' + assert srv.new() == "OK" # Make sure the caches are cleared assert srv._Server__globals_cache == {} @@ -380,12 +418,12 @@ def test_Server_recover(): con, srv = newsrv() # Artificially put something in the caches - srv._Server__globals_cache = {'a': 'b'} - srv._Server__values_cache = {'a': 'b'} - srv._Server__listables_cache = {'a': 'b'} - srv._Server__proxy_factory.proxy_object_cache = {'a': 'b'} + srv._Server__globals_cache = {"a": "b"} + srv._Server__values_cache = {"a": "b"} + srv._Server__listables_cache = {"a": "b"} + srv._Server__proxy_factory.proxy_object_cache = {"a": "b"} - assert srv.recover() == 'OK' + assert srv.recover() == "OK" # Make sure the caches are cleared assert srv._Server__globals_cache == {} @@ -398,12 +436,12 @@ def test_Server_open(): con, srv = newsrv() # Artificially put something in the caches - srv._Server__globals_cache = {'a': 'b'} - srv._Server__values_cache = {'a': 'b'} - srv._Server__listables_cache = {'a': 'b'} - srv._Server__proxy_factory.proxy_object_cache = {'a': 'b'} + srv._Server__globals_cache = {"a": "b"} + srv._Server__values_cache = {"a": "b"} + srv._Server__listables_cache = {"a": "b"} + srv._Server__proxy_factory.proxy_object_cache = {"a": "b"} - assert srv.open('filepath') == 'OK' + assert srv.open("filepath") == "OK" # Make sure the caches are cleared assert srv._Server__globals_cache == {} @@ -416,12 +454,12 @@ def test_Server_close(): con, srv = newsrv() # Artificially put something in the caches - srv._Server__globals_cache = {'a': 'b'} - srv._Server__values_cache = {'a': 'b'} - srv._Server__listables_cache = {'a': 'b'} - srv._Server__proxy_factory.proxy_object_cache = {'a': 'b'} + srv._Server__globals_cache = {"a": "b"} + srv._Server__values_cache = {"a": "b"} + srv._Server__listables_cache = {"a": "b"} + srv._Server__proxy_factory.proxy_object_cache = {"a": "b"} - assert srv.close() == 'OK' + assert srv.close() == "OK" # Make sure the caches are cleared assert srv._Server__globals_cache == {} @@ -433,153 +471,161 @@ def test_Server_close(): def test_Server_call_listable_method(): con, srv = newsrv() - guid = 'mock_guid' - obj = fake_proxy_obj('name', guid) + guid = "mock_guid" + obj = fake_proxy_obj("name", guid) - resp = srv.call_listable_method(obj, 'count') + resp = srv.call_listable_method(obj, "count") assert resp == 3 - resp = srv.call_listable_method(obj, 'index', startindex=2) + resp = srv.call_listable_method(obj, "index", startindex=2) assert mock_connection.MOCK_GUID_PREFIX in resp._guid - assert 'MockItem_' in resp._plx_type + assert "MockItem_" in resp._plx_type - resp = srv.call_listable_method(obj, 'sublist', startindex=3, stopindex=6) + resp = srv.call_listable_method(obj, "sublist", startindex=3, stopindex=6) assert len(resp) == 3 for r in resp: assert mock_connection.MOCK_GUID_PREFIX in r._guid - assert 'MockItem_' in r._plx_type + assert "MockItem_" in r._plx_type def test_Server_get_named_object(): con, srv = newsrv() - resp = srv.get_named_object('fake_name') + resp = srv.get_named_object("fake_name") assert mock_connection.MOCK_GUID_PREFIX in resp._guid - assert 'MockItem_' in resp._plx_type + assert "MockItem_" in resp._plx_type def test_Server_get_object_property(): con, srv = newsrv() - obj = fake_proxy_obj('fake_name', 'fake_guid') + obj = fake_proxy_obj("fake_name", "fake_guid") - resp = srv.get_object_property(obj, 'Name') - assert resp == 'MockItem_Name_pval' + resp = srv.get_object_property(obj, "Name") + assert resp == "MockItem_Name_pval" - resp = srv.get_object_property(obj, 'UserFeatures') + resp = srv.get_object_property(obj, "UserFeatures") assert mock_connection.MOCK_GUID_PREFIX in resp._guid - assert 'MockItem_' in resp._plx_type + assert "MockItem_" in resp._plx_type + def test_Server_get_objects_property(): con, srv = newsrv() - obj1 = fake_proxy_obj('fake_name_1', 'fake_guid_1') - obj2 = fake_proxy_obj('fake_name_2', 'fake_guid_2') + obj1 = fake_proxy_obj("fake_name_1", "fake_guid_1") + obj2 = fake_proxy_obj("fake_name_2", "fake_guid_2") - [resp1, resp2] = srv.get_objects_property([obj1, obj2], 'Name') - assert resp1 == 'MockItem_Name_pval' - assert resp2 == 'MockItem_Name_pval' + [resp1, resp2] = srv.get_objects_property([obj1, obj2], "Name") + assert resp1 == "MockItem_Name_pval" + assert resp2 == "MockItem_Name_pval" - [resp1, resp2] = srv.get_objects_property([obj1, obj2], 'UserFeatures') + [resp1, resp2] = srv.get_objects_property([obj1, obj2], "UserFeatures") assert mock_connection.MOCK_GUID_PREFIX in resp1._guid assert mock_connection.MOCK_GUID_PREFIX in resp2._guid - assert 'MockItem_' in resp1._plx_type - assert 'MockItem_' in resp2._plx_type + assert "MockItem_" in resp1._plx_type + assert "MockItem_" in resp2._plx_type + def test_Server_get_name_by_guid(): con, srv = newsrv() - assert srv.get_name_by_guid('fake_guid') == 'MockItem_Name_pval' + assert srv.get_name_by_guid("fake_guid") == "MockItem_Name_pval" def test_Server_get_object_attributes(): con, srv = newsrv() - obj = fake_proxy_obj('fake_name', 'fake_guid') + obj = fake_proxy_obj("fake_name", "fake_guid") resp = srv.get_object_attributes(obj) - assert isinstance(resp['Mock_number'], plxproxy.PlxProxyIPNumber) - assert isinstance(resp['Name'], plxproxy.PlxProxyIPText) - assert isinstance(resp['IsDynamicComponent'], plxproxy.PlxProxyIPBoolean) + assert isinstance(resp["Mock_number"], plxproxy.PlxProxyIPNumber) + assert isinstance(resp["Name"], plxproxy.PlxProxyIPText) + assert isinstance(resp["IsDynamicComponent"], plxproxy.PlxProxyIPBoolean) def test_Server_call_commands(): con, srv = newsrv() - resp = srv.call_commands('Command 1', 'Command 2') - assert resp[0]['feedback']['success'] == True - assert resp[0]['feedback']['extrainfo'] == 'Reply_to_command: Command 1' - assert resp[1]['feedback']['extrainfo'] == 'Reply_to_command: Command 2' + resp = srv.call_commands("Command 1", "Command 2") + assert resp[0]["feedback"]["success"] == True + assert resp[0]["feedback"]["extrainfo"] == "Reply_to_command: Command 1" + assert resp[1]["feedback"]["extrainfo"] == "Reply_to_command: Command 2" con.test_success = False - resp = srv.call_commands('gotomesh') - assert resp[0]['feedback']['success'] == False - assert resp[0]['feedback']['extrainfo'] == 'Cannot intersect unless there is at least one volume or surface in the geometry' + resp = srv.call_commands("gotomesh") + assert resp[0]["feedback"]["success"] == False + assert ( + resp[0]["feedback"]["extrainfo"] + == "Cannot intersect unless there is at least one volume or surface in the geometry" + ) def test_Server_call_and_handle_commands(): con, srv = newsrv() - resp = srv.call_and_handle_commands('Command 1', 'Command 2', con.MAGIC_REQUEST_OBJECT) - assert resp[0] == 'Reply_to_command: Command 1' - assert resp[1] == 'Reply_to_command: Command 2' + resp = srv.call_and_handle_commands("Command 1", "Command 2", con.MAGIC_REQUEST_OBJECT) + assert resp[0] == "Reply_to_command: Command 1" + assert resp[1] == "Reply_to_command: Command 2" assert isinstance(resp[2], plxproxy.PlxProxyObject) def test_Server_call_plx_object_method(): con, srv = newsrv() - obj = fake_proxy_obj('fake_object', 'fake_guid') + obj = fake_proxy_obj("fake_object", "fake_guid") - resp = srv.call_plx_object_method(obj, 'method', ['param_1', 2, 'param_3']) + resp = srv.call_plx_object_method(obj, "method", ["param_1", 2, "param_3"]) assert resp == 'Reply_to_command: method fake_object "param_1" 2 "param_3"' - resp = srv.call_plx_object_method(obj, con.MAGIC_REQUEST_OBJECT, ['param_1', 2, 'param_3']) + resp = srv.call_plx_object_method(obj, con.MAGIC_REQUEST_OBJECT, ["param_1", 2, "param_3"]) assert isinstance(resp, plxproxy.PlxProxyObject) def test_Server_set_object_property(): con, srv = newsrv() - obj = fake_proxy_obj('fake_name', 'fake_guid') - assert srv.set_object_property(obj, ['fake_value_1', 2, 3]) == 'Reply_to_command: set fake_name "fake_value_1" 2 3' + obj = fake_proxy_obj("fake_name", "fake_guid") + assert ( + srv.set_object_property(obj, ["fake_value_1", 2, 3]) + == 'Reply_to_command: set fake_name "fake_value_1" 2 3' + ) def test_Server_call_selection_command(): con, srv = newsrv() - obj1 = fake_proxy_obj('obj_boter', '') - obj2 = fake_proxy_obj('obj_kaas', '') - obj3 = fake_proxy_obj('obj_eieren', '') + obj1 = fake_proxy_obj("obj_boter", "") + obj2 = fake_proxy_obj("obj_kaas", "") + obj3 = fake_proxy_obj("obj_eieren", "") # set + response data + get - resp = srv.call_selection_command('set', obj1, obj2, obj3) + resp = srv.call_selection_command("set", obj1, obj2, obj3) assert len(resp) == 3 - assert resp[0]._guid == '' - assert resp[1]._guid == '' - assert resp[2]._guid == '' - assert len(srv.call_selection_command('get')) == 3 + assert resp[0]._guid == "" + assert resp[1]._guid == "" + assert resp[2]._guid == "" + assert len(srv.call_selection_command("get")) == 3 # remove specific items + get - resp = srv.call_selection_command('remove', obj2) + resp = srv.call_selection_command("remove", obj2) assert len(resp) == 2 - resp = srv.call_selection_command('get') - assert resp[0]._guid == '' - assert resp[1]._guid == '' + resp = srv.call_selection_command("get") + assert resp[0]._guid == "" + assert resp[1]._guid == "" # append + get - resp = srv.call_selection_command('append', obj2) + resp = srv.call_selection_command("append", obj2) assert len(resp) == 3 - resp = srv.call_selection_command('get') - assert resp[0]._guid == '' - assert resp[1]._guid == '' - assert resp[2]._guid == '' + resp = srv.call_selection_command("get") + assert resp[0]._guid == "" + assert resp[1]._guid == "" + assert resp[2]._guid == "" # clear - assert len(srv.call_selection_command('set')) == 0 + assert len(srv.call_selection_command("set")) == 0 def test_Server_get_error(): con, srv = newsrv() assert srv.get_error() == mock_connection.MOCK_EXCEPTION - assert srv.get_error() == '' + assert srv.get_error() == "" con.test_exception_cleared = False assert srv.get_error(False) == mock_connection.MOCK_EXCEPTION assert srv.get_error() == mock_connection.MOCK_EXCEPTION @@ -590,14 +636,14 @@ def test_Server_tokenize(): resp = srv.tokenize('plaxis_command object_name "string_arg" 1 2 "string_arg2"') assert isinstance(resp, tokenizer.TokenizerResultHandler) - assert resp.extrainfo == '' + assert resp.extrainfo == "" assert resp.success == True assert isinstance(resp.tokens[0], tokenizer.TokenIdentifier) - assert resp.tokens[0].value == 'command' + assert resp.tokens[0].value == "command" assert resp.tokens[0].position == 0 assert resp.tokens[0].length == 7 assert isinstance(resp.tokens[1], tokenizer.TokenOperand) - assert resp.tokens[1].value == 'object' + assert resp.tokens[1].value == "object" assert resp.tokens[1].position == 8 assert resp.tokens[1].length == 6 assert isinstance(resp.tokens[2], tokenizer.TokenText) @@ -612,8 +658,8 @@ def test_Server_tokenize(): con.test_success = False resp = srv.tokenize('1234 "bla bla 542 2') assert isinstance(resp, tokenizer.TokenizerResultHandler) - assert resp.extrainfo == 'Unbalanced quotes' + assert resp.extrainfo == "Unbalanced quotes" assert resp.success == False with pytest.raises(PlxScriptingTokenizerError) as exc: resp.tokens[0] - assert str(exc.value) == 'Unrecognized token at position 5' + assert str(exc.value) == "Unrecognized token at position 5" diff --git a/src/plxscripting/unittests/test_tokenizer.py b/src/plxscripting/unittests/test_tokenizer.py index 0e6372f..2bc4b9c 100644 --- a/src/plxscripting/unittests/test_tokenizer.py +++ b/src/plxscripting/unittests/test_tokenizer.py @@ -24,10 +24,11 @@ def test_successful_tokenization(): - con = mock_connection.HTTPConnection('fake_host', 12345) + con = mock_connection.HTTPConnection("fake_host", 12345) s = server.Server(con, plxproxyfactory.PlxProxyFactory(con), server.InputProcessor()) - tokenizer = s.tokenize('addpoint Polygon_2 0 4.2 0 # comment') # 'command object "param" "param2" 2 3 4' + # 'command object "param" "param2" 2 3 4' + tokenizer = s.tokenize("addpoint Polygon_2 0 4.2 0 # comment") assert tokenizer.success assert tokenizer.error_position == -1 assert tokenizer.tokens == tokenizer.partial_tokens @@ -39,7 +40,7 @@ def test_successful_tokenization(): assert token.position == 0 assert token.length == 7 assert token.end_position == 6 - assert token.value == 'command' + assert token.value == "command" assert tokens[2].value == '"param"' @@ -47,28 +48,28 @@ def test_successful_tokenization(): def test_unsuccessful_tokenization(): - con = mock_connection.HTTPConnection('fake_host', 12345) + con = mock_connection.HTTPConnection("fake_host", 12345) s = server.Server(con, plxproxyfactory.PlxProxyFactory(con), server.InputProcessor()) con.test_success = False - tokenizer = s.tokenize('abc ?') + tokenizer = s.tokenize("abc ?") with pytest.raises(PlxScriptingTokenizerError) as exception_info: tokenizer.tokens - assert str(exception_info.value) == 'Unrecognized token at position 5' + assert str(exception_info.value) == "Unrecognized token at position 5" assert not tokenizer.success - assert tokenizer.error == 'Unrecognized token at position 5' + assert tokenizer.error == "Unrecognized token at position 5" assert tokenizer.error_position == 5 assert len(tokenizer.partial_tokens) == 1 # Since the first token is OK def test_external_interpreter(): - con = mock_connection.HTTPConnection('fake_host', 12345) + con = mock_connection.HTTPConnection("fake_host", 12345) s = server.Server(con, plxproxyfactory.PlxProxyFactory(con), server.InputProcessor()) con.test_tokenize_external = True tokenizer = s.tokenize('/command object "param" "param2" 2 3 4') token = tokenizer.tokens[0] - assert token.interpretername == 'command' + assert token.interpretername == "command" assert token.externalcommand == 'object "param" "param2" 2 3 4' assert token.content == '/command object "param" "param2" 2 3 4' diff --git a/src/plxscripting/utils.py b/src/plxscripting/utils.py index 9cf465c..869b90f 100644 --- a/src/plxscripting/utils.py +++ b/src/plxscripting/utils.py @@ -24,12 +24,14 @@ def force_list(func): """ Decorator that forces the result to be a list or None """ + @wraps(func) def wrapper(*args, **kwargs): result = func(*args, **kwargs) if result is None or isinstance(result, list): return result return [result] + return wrapper