From 275619d299678651857f3831b7cdfa7c19f80bf3 Mon Sep 17 00:00:00 2001 From: Philip Usher Date: Fri, 26 Jan 2024 13:04:15 +0000 Subject: [PATCH] updated proj depednancies finished tests --- doc/source/index.rst | 4 +- pyproject.toml | 14 +- src/ansys/conceptev/core/main.py | 337 ++++++++++++++++++------------- tests/test_main.py | 218 +++++++++++++------- tox.ini | 6 +- 5 files changed, 351 insertions(+), 228 deletions(-) diff --git a/doc/source/index.rst b/doc/source/index.rst index c693a842..55a82f8f 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -7,7 +7,7 @@ ConceptEV Specific Instructions -------------- +------------------------------- .. WARNING:: Beware this api is in a state of rapid to change and should be considered unstable. @@ -20,7 +20,7 @@ You need to: Configure Session using .env file -^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ you need to create a .env file to keep your password and other configurable data it should look something like this: .. code-block:: bash diff --git a/pyproject.toml b/pyproject.toml index 6cd6c7b1..b3c32642 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ packages = [ ] [tool.poetry.dependencies] -python = ">=3.11,<4.0" +python = ">=3.9,<4.0" importlib-metadata = {version = "^7.0", python = "<3.8"} python-dotenv = "^1.0.0" plotly = "^5.18.0" @@ -44,8 +44,10 @@ optional = true [tool.poetry.group.tests.dependencies] pytest = "^7.3.0" pytest-cov = "^4.0.0" - +pytest-httpx = "^0.28.0" +pytest-mock = "^3.12.0" # Optional build requirements + [tool.poetry.group.build] optional = true [tool.poetry.group.build.dependencies] @@ -53,11 +55,13 @@ build = "^1.0.3" twine = "^4.0.2" -[tool.poetry.group.test.dependencies] -pytest-httpx = "^0.28.0" -pytest-mock = "^3.12.0" + +[tool.poetry.group.dev.dependencies] +tox = "^4.12.1" +pytest-cov = "^4.1.0" + [tool.black] line-length = 100 diff --git a/src/ansys/conceptev/core/main.py b/src/ansys/conceptev/core/main.py index a045280f..fdeefd42 100644 --- a/src/ansys/conceptev/core/main.py +++ b/src/ansys/conceptev/core/main.py @@ -1,22 +1,24 @@ -# A Simple API Client for ConceptEV +"""A Simple API Client for ConceptEV.""" +import datetime +from json import JSONDecodeError import os +from pathlib import Path +import time +from typing import Literal +import warnings + import dotenv import httpx -import warnings -import datetime -import time import plotly.graph_objects as go -from typing import Literal -from json import JSONDecodeError -from pathlib import Path DATADIR = Path(__file__).parents[0] dotenv.load_dotenv() # Warning as this is not automated so changes to the API will cause changes here. -warnings.warn("Warning: The API is in rapidly changing state and this may become " - "out of date very quickly.") +warnings.warn( + "Warning: The API is in rapidly changing state and this may become " "out of date very quickly." +) Router = Literal[ "/architectures", @@ -39,27 +41,37 @@ def get_token() -> str: + """Get Token from OCM.""" username = os.environ["CONCEPTEV_USERNAME"] password = os.environ["CONCEPTEV_PASSWORD"] ocm_url = os.environ["OCM_URL"] - response = httpx.post(url=ocm_url + "/auth/login/", - json={"emailAddress": username, "password": password}) + response = httpx.post( + url=ocm_url + "/auth/login/", json={"emailAddress": username, "password": password} + ) if response.status_code != 200: raise Exception(f"Failed to get token {response.content}") - return response.json()['accessToken'] + return response.json()["accessToken"] def get_http_client(token: str, concept_id: str | None = None) -> httpx.Client: - base_url = os.environ['CONCEPTEV_URL'] + """Get a http client. + + This http client creates and maintains the connection and is more performant than + re-creating that connection for each call. + """ + base_url = os.environ["CONCEPTEV_URL"] if concept_id: params = {"concept_id": concept_id} else: params = None - return httpx.Client(headers={"Authorization": token}, params=params, - base_url=base_url) + return httpx.Client(headers={"Authorization": token}, params=params, base_url=base_url) def processed_response(response) -> dict: + """Process response. + + Check the return from the api and if it's not successful raise an error. + """ if response.status_code == 200 or response.status_code == 201: # Success try: return response.json() @@ -68,56 +80,76 @@ def processed_response(response) -> dict: raise Exception(f"Response Failed:{response}") -def get(client: httpx.Client, router: Router, id: str | None = None, - params: dict | None = None) -> dict: +def get( + client: httpx.Client, router: Router, id: str | None = None, params: dict | None = None +) -> dict: + """Get/read from the client at the specific route. + + A http verb. Performs the get request adding the route to the base client. + """ if id: - path = '/'.join([router, id]) + path = "/".join([router, id]) else: path = router response = client.get(url=path, params=params) return processed_response(response) -def post(client: httpx.Client, router: Router, data: dict,params:dict = {}) -> dict: - response = client.post(url=router, json=data,params=params) +def post(client: httpx.Client, router: Router, data: dict, params: dict = {}) -> dict: + """Post/create from the client at the specific route. + + A http verb. Performs the post request adding the route to the base client. + """ + response = client.post(url=router, json=data, params=params) return processed_response(response) def delete(client: httpx.Client, router: Router, id: str) -> dict: - path = '/'.join([router, id]) + """Delete from the client at the specific route. + + A http verb. Performs the delete request adding the route to the base client. + """ + path = "/".join([router, id]) response = client.delete(url=path) if response.status_code != 204: raise Exception(f"Failed to delete from {router} with id:{id}") -def create_new_project(client: httpx.Client, account_id: str, hpc_id: str, title: str, - project_goal: str = "Created from the CLI"): - osm_url = os.environ['OCM_URL'] - token = client.headers['Authorization'] +def create_new_project( + client: httpx.Client, + account_id: str, + hpc_id: str, + title: str, + project_goal: str = "Created from the CLI", +): + """Create a new project.""" + osm_url = os.environ["OCM_URL"] + token = client.headers["Authorization"] project_data = { "accountId": account_id, "hpcId": hpc_id, "projectTitle": title, - "projectGoal": project_goal + "projectGoal": project_goal, } - created_project = httpx.post(osm_url + '/project/create', - headers={"Authorization": token}, json=project_data) + created_project = httpx.post( + osm_url + "/project/create", headers={"Authorization": token}, json=project_data + ) if created_project.status_code != 200 and created_project.status_code != 204: raise Exception(f"Failed to create a project on OCM {created_project}") design_data = { - "projectId": created_project.json()['projectId'], + "projectId": created_project.json()["projectId"], "productId": "ec987729-a125-4f9d-ae3f-c3a81ca75112", "designTitle": "Branch 1", } - created_design = httpx.post(osm_url + '/design/create', - headers={"Authorization": token}, json=design_data) + created_design = httpx.post( + osm_url + "/design/create", headers={"Authorization": token}, json=design_data + ) if created_design.status_code != 200 and created_design.status_code != 204: raise Exception(f"Failed to create a design on OCM {created_design}") - user_details = httpx.post(osm_url + '/user/details', - headers={"Authorization": token}) + user_details = httpx.post(osm_url + "/user/details", headers={"Authorization": token}) if user_details.status_code != 200 and user_details.status_code != 204: raise Exception(f"Failed to get a user details on OCM {user_details}") @@ -125,15 +157,14 @@ def create_new_project(client: httpx.Client, account_id: str, hpc_id: str, title "capabilities_ids": [], "components_ids": [], "configurations_ids": [], - "design_id": created_design.json()['designId'], - "design_instance_id": created_design.json()['designInstanceList'][0][ - 'designInstanceId'], + "design_id": created_design.json()["designId"], + "design_instance_id": created_design.json()["designInstanceList"][0]["designInstanceId"], "drive_cycles_ids": [], "jobs_ids": [], "name": "Branch 1", - "project_id": created_project.json()['projectId'], + "project_id": created_project.json()["projectId"], "requirements_ids": [], - "user_id": user_details.json()['userId'], + "user_id": user_details.json()["userId"], } created_concept = post(client, "/concepts", data=concept_data) @@ -141,68 +172,84 @@ def create_new_project(client: httpx.Client, account_id: str, hpc_id: str, title def get_concept_ids(client: httpx.Client): + """Get Concept Ids.""" concepts = get(client, "/concepts") - return {concept['name']: concept['id'] for concept in concepts} + return {concept["name"]: concept["id"] for concept in concepts} def get_account_ids(token: str) -> dict: + """Get account ids.""" ocm_url = os.environ["OCM_URL"] - response = httpx.post(url=ocm_url + "/account/list", - headers={"authorization": token}) + response = httpx.post(url=ocm_url + "/account/list", headers={"authorization": token}) if response.status_code != 200: raise Exception(f"Failed to get accounts {response}") - accounts = {account["account"]['accountName']: account["account"]["accountId"] for - account in response.json()} + accounts = { + account["account"]["accountName"]: account["account"]["accountId"] + for account in response.json() + } return accounts def get_default_hpc(token: str, account_id: str): + """Get default hpc id.""" ocm_url = os.environ["OCM_URL"] - response = httpx.post(url=ocm_url + "/account/hpc/default", - json={"accountId": account_id}, - headers={"authorization": token}) + response = httpx.post( + url=ocm_url + "/account/hpc/default", + json={"accountId": account_id}, + headers={"authorization": token}, + ) if response.status_code != 200: raise Exception(f"Failed to get accounts {response}") - return response.json()['hpcId'] + return response.json()["hpcId"] -def create_submit_job(client, concept: dict, account_id: str, hpc_id: str, - job_name: str = "cli_job: " + datetime.datetime.now().strftime( - "%Y-%m-%d %H:%M:%S.%f")): +def create_submit_job( + client, + concept: dict, + account_id: str, + hpc_id: str, + job_name: str = "cli_job: " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), +): + """Create and then submit a job.""" job_input = { "job_name": job_name, - "requirement_ids": concept['requirements_ids'], - "architecture_id": concept['architecture_id'], - "concept_id": concept['id'], - "design_instance_id": concept['design_instance_id'], + "requirement_ids": concept["requirements_ids"], + "architecture_id": concept["architecture_id"], + "concept_id": concept["id"], + "design_instance_id": concept["design_instance_id"], } - job, uploaded_file = post(client, '/jobs', data=job_input) + job, uploaded_file = post(client, "/jobs", data=job_input) job_start = { "job": job, "uploaded_file": uploaded_file, "account_id": account_id, "hpc_id": hpc_id, } - job_info = post(client, '/jobs:start', data=job_start) + job_info = post(client, "/jobs:start", data=job_start) return job_info def put(client: httpx.Client, router: Router, id: str, data: dict) -> dict: - path = '/'.join([router, id]) + """Put/update from the client at the specific route. + + A http verb. Performs the put request adding the route to the base client. + """ + path = "/".join([router, id]) response = client.put(url=path, json=data) return processed_response(response) def read_file(filename: str) -> str: + """Read file.""" with open(filename) as f: content = f.read() return content -def read_results(client, job_info: dict, no_of_tries: int = 100, - rate_limit: float = 0.3) -> dict: +def read_results(client, job_info: dict, no_of_tries: int = 100, rate_limit: float = 0.3) -> dict: + """Keep trying for results if the results aren't completed try again.""" for i in range(0, no_of_tries): - response = client.post(url='/jobs:result', json=job_info) + response = client.post(url="/jobs:result", json=job_info) time.sleep(rate_limit) if response.status_code == 200: return response.json() @@ -210,9 +257,13 @@ def read_results(client, job_info: dict, no_of_tries: int = 100, raise Exception(f"To many request: {response}") -def post_file(client: httpx.Client, router: Router, filename: str, - params: dict) -> dict: - path = ':'.join([router, 'from_file']) +def post_file(client: httpx.Client, router: Router, filename: str, params: dict) -> dict: + """Post/create from the client at the specific route with a file. + + A http verb. Performs the post request adding the route to the base client. + Adds the file as a multipart form request. + """ + path = ":".join([router, "from_file"]) file_contents = read_file(filename) response = client.post(url=path, files={"file": file_contents}, params=params) return processed_response(response) @@ -220,18 +271,19 @@ def post_file(client: httpx.Client, router: Router, filename: str, # Example data can be got from the schema sections of the api docs. -aero = {"name": "New Aero Config", - "drag_coefficient": 0.3, - "cross_sectional_area": 2, - "config_type": "aero", - } - -aero2 = {"name": "Second Aero Configuration", - "drag_coefficient": 0.6, - "cross_sectional_area": 3, - "config_type": "aero", +aero = { + "name": "New Aero Config", + "drag_coefficient": 0.3, + "cross_sectional_area": 2, + "config_type": "aero", +} - } +aero2 = { + "name": "Second Aero Configuration", + "drag_coefficient": 0.6, + "cross_sectional_area": 3, + "config_type": "aero", +} mass = { "name": "New Mass Config", "mass": 3000, @@ -244,30 +296,32 @@ def post_file(client: httpx.Client, router: Router, filename: str, "config_type": "wheel", } -transmission = {"gear_ratios": [5], - "headline_efficiencies": [0.95], - "max_torque": 500, - "max_speed": 2000, - "static_drags": [0.5], - "friction_ratios": [60], - "windage_ratios": [40], - "component_type": "TransmissionLossCoefficients"} - -motor_file_name = str(DATADIR.joinpath('e9.lab')) -motor_params = {"component_name": "e9", - "component_file_type": "motor_lab_file"} - -battery = {"capacity": 86400000, - "charge_acceptance_limit": 0, - "component_type": "BatteryFixedVoltages", - "internal_resistance": 0.1, - "name": "New Battery", - "voltage_max": 400, - "voltage_mid": 350, - "voltage_min": 300, - } - -if __name__ == '__main__': +transmission = { + "gear_ratios": [5], + "headline_efficiencies": [0.95], + "max_torque": 500, + "max_speed": 2000, + "static_drags": [0.5], + "friction_ratios": [60], + "windage_ratios": [40], + "component_type": "TransmissionLossCoefficients", +} + +motor_file_name = str(DATADIR.joinpath("e9.lab")) +motor_params = {"component_name": "e9", "component_file_type": "motor_lab_file"} + +battery = { + "capacity": 86400000, + "charge_acceptance_limit": 0, + "component_type": "BatteryFixedVoltages", + "internal_resistance": 0.1, + "name": "New Battery", + "voltage_max": 400, + "voltage_mid": 350, + "voltage_min": 300, +} + +if __name__ == "__main__": token = get_token() with get_http_client(token) as client: # Create a client to talk to the api @@ -279,85 +333,86 @@ def post_file(client: httpx.Client, router: Router, filename: str, accounts = get_account_ids(token) account_id = accounts["conceptev_saas@ansys.com"] hpc_id = get_default_hpc(token, account_id) - created_concept = create_new_project(client, account_id, hpc_id, - f"New Project +{datetime.datetime.now()}") # Create a new concept. - - concept_id = created_concept['id'] # get the id of the newly created concept. - design_instance_id = created_concept['design_instance_id'] - with get_http_client(token, - concept_id) as client: # get client with concept id embedded in + created_concept = create_new_project( + client, account_id, hpc_id, f"New Project +{datetime.datetime.now()}" + ) # Create a new concept. + concept_id = created_concept["id"] # get the id of the newly created concept. + design_instance_id = created_concept["design_instance_id"] + with get_http_client(token, concept_id) as client: # get client with concept id embedded in ### Basic Post(create) and get(read) operations on Configurations - created_aero = post(client, '/configurations', data=aero) # create an aero - created_aero2 = post(client, '/configurations', data=aero2) # create an aero - created_mass = post(client, '/configurations', data=mass) - created_wheel = post(client, '/configurations', data=wheel) - - configurations = get(client, '/configurations', - params={'config_type': 'aero'}) # read all aeros + created_aero = post(client, "/configurations", data=aero) # create an aero + created_aero2 = post(client, "/configurations", data=aero2) # create an aero + created_mass = post(client, "/configurations", data=mass) + created_wheel = post(client, "/configurations", data=wheel) + + configurations = get( + client, "/configurations", params={"config_type": "aero"} + ) # read all aeros print(configurations) - aero = get(client, "/configurations", - id=created_aero['id']) # get a particular aero configuration + aero = get( + client, "/configurations", id=created_aero["id"] + ) # get a particular aero configuration print(aero) ### Create Components - created_transmission = post(client, "/components", - data=transmission) # create transmission + created_transmission = post(client, "/components", data=transmission) # create transmission - created_motor = post_file(client, "/components", motor_file_name, - params=motor_params # create motor from file - ) + created_motor = post_file( + client, "/components", motor_file_name, params=motor_params # create motor from file + ) print(created_motor) client.timeout = 2000 # Needed as these calculations will take a long time. - motor_loss_map = post(client, '/components:calculate_loss_map',data = {}, - params={"component_id":created_motor['id']}) # get loss map from motor - - x = motor_loss_map['currents'] - y = motor_loss_map['phase_advances'] - z = motor_loss_map['losses_total'] + motor_loss_map = post( + client, + "/components:calculate_loss_map", + data={}, + params={"component_id": created_motor["id"]}, + ) # get loss map from motor + + x = motor_loss_map["currents"] + y = motor_loss_map["phase_advances"] + z = motor_loss_map["losses_total"] fig = go.Figure(data=go.Contour(x=x, y=y, z=z)) fig.show() - created_battery = post(client, "/components", - data=battery) # create battery + created_battery = post(client, "/components", data=battery) # create battery ### Architecture architecture = { "number_of_front_wheels": 1, "number_of_front_motors": 1, - "front_transmission_id": created_transmission['id'], - "front_motor_id": created_motor['id'], + "front_transmission_id": created_transmission["id"], + "front_motor_id": created_motor["id"], "number_of_rear_wheels": 0, "number_of_rear_motors": 0, - "battery_id": created_battery['id'], + "battery_id": created_battery["id"], } - created_arch = post(client, "/architectures", - data=architecture) # create arch + created_arch = post(client, "/architectures", data=architecture) # create arch # Requirements requirement = { "speed": 10, "acceleration": 1, - "aero_id": created_aero['id'], - "mass_id": created_mass['id'], - "wheel_id": created_wheel['id'], + "aero_id": created_aero["id"], + "mass_id": created_mass["id"], + "wheel_id": created_wheel["id"], "state_of_charge": 0.9, - "requirement_type":"static_acceleration", - "name":"Static Requirement 1", + "requirement_type": "static_acceleration", + "name": "Static Requirement 1", } created_requirement = post(client, "requirements", data=requirement) ### Submit job - concept = get(client, "/concepts", id=design_instance_id, - params={"populated": True}) + concept = get(client, "/concepts", id=design_instance_id, params={"populated": True}) job_info = create_submit_job(client, concept, account_id, hpc_id) ### Read results results = read_results(client, job_info) - x = results[0]['capability_curve']['speeds'] - y = results[0]['capability_curve']['torques'] + x = results[0]["capability_curve"]["speeds"] + y = results[0]["capability_curve"]["torques"] time.sleep(120) # Wait for the job to complete. fig = go.Figure(data=go.Scatter(x=x, y=y)) diff --git a/tests/test_main.py b/tests/test_main.py index 2465a6fa..25b7cb78 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,19 +1,20 @@ import os +import httpx import pytest +from pytest_httpx import HTTPXMock from ansys.conceptev.core import main -from pytest_httpx import HTTPXMock -import httpx + +conceptev_url = os.environ["CONCEPTEV_URL"] +ocm_url = os.environ["OCM_URL"] -conceptev_url = os.environ['CONCEPTEV_URL'] -ocm_url = os.environ['OCM_URL'] def test_get_token(httpx_mock: HTTPXMock): fake_token = "value1" - httpx_mock.add_response(url=f"{ocm_url}/auth/login/", - method="post", - json={"accessToken": fake_token}) + httpx_mock.add_response( + url=f"{ocm_url}/auth/login/", method="post", json={"accessToken": fake_token} + ) token = main.get_token() assert token == fake_token @@ -31,9 +32,9 @@ def test_get_http_client(): concept_id = "123" client = main.get_http_client(fake_token, concept_id=concept_id) assert isinstance(client, httpx.Client) - assert client.headers['authorization'] == fake_token - assert str(client.base_url).strip('/') == os.environ['CONCEPTEV_URL'].strip('/') - assert client.params['concept_id'] == concept_id + assert client.headers["authorization"] == fake_token + assert str(client.base_url).strip("/") == os.environ["CONCEPTEV_URL"].strip("/") + assert client.params["concept_id"] == concept_id def test_processed_response(): @@ -52,10 +53,8 @@ def test_processed_response(): def test_get(httpx_mock: HTTPXMock, client: httpx.Client): example_results = [{"name": "aero_mock_response"}, {"name": "aero_mock_response2"}] httpx_mock.add_response( - url=f"{conceptev_url}/configurations?concept_id=123", - method="get", - - json=example_results) + url=f"{conceptev_url}/configurations?concept_id=123", method="get", json=example_results + ) results = main.get(client, "/configurations") assert results == example_results @@ -67,7 +66,8 @@ def test_post(httpx_mock: HTTPXMock, client: httpx.Client): url=f"{conceptev_url}/configurations?concept_id=123", method="post", match_json=example_aero, - json=example_aero) + json=example_aero, + ) results = main.post(client, "/configurations", example_aero) assert results == example_aero @@ -94,78 +94,136 @@ def test_delete(httpx_mock: HTTPXMock, client: httpx.Client): def test_create_new_project(httpx_mock: HTTPXMock, client: httpx.Client): client.params = [] project_id = "project_id_123" + design_id = "design_id_123" design_instance_id = "design_instance_123" + account_id = "account_id_123" + hpc_id = "hpc_id_123" + user_id = "user_id_123" + title = "Testing Title" mocked_concept = {"name": "new_mocked_concept"} - httpx_mock.add_response(url=f"{ocm_url}/project/create", - json={"projectId": project_id}) + mocked_project = {"projectId": project_id} + mocked_design = { + "designId": design_id, + "designInstanceList": [{"designInstanceId": design_instance_id}], + "projectId": project_id, + } + mocked_user = {"userId": user_id} + project_data = { + "accountId": account_id, + "hpcId": hpc_id, + "projectTitle": title, + "projectGoal": "Created from the CLI", + } + + httpx_mock.add_response( + url=f"{ocm_url}/project/create", method="post", match_json=project_data, json=mocked_project + ) + + design_data = { + "projectId": project_id, + "productId": "ec987729-a125-4f9d-ae3f-c3a81ca75112", + "designTitle": "Branch 1", + } httpx_mock.add_response( - url=f"{ocm_url}/design/instance/create", - match_json={"projectId": project_id}, json={'id': design_instance_id}) + url=f"{ocm_url}/design/create", method="post", match_json=design_data, json=mocked_design + ) + httpx_mock.add_response(url=f"{ocm_url}/user/details", method="post", json=mocked_user) + + concept_data = { + "capabilities_ids": [], + "components_ids": [], + "configurations_ids": [], + "design_id": design_id, + "design_instance_id": design_instance_id, + "drive_cycles_ids": [], + "jobs_ids": [], + "name": "Branch 1", + "project_id": project_id, + "requirements_ids": [], + "user_id": user_id, + } httpx_mock.add_response( url=f"{conceptev_url}/concepts", - method="post", match_json={"design_instance_id": design_instance_id}, - json=mocked_concept) - value = main.create_new_project(client) + method="post", + match_json=concept_data, + json=mocked_concept, + ) + value = main.create_new_project(client, account_id, hpc_id, title) assert value == mocked_concept def test_get_concept_ids(httpx_mock: HTTPXMock, client: httpx.Client): client.params = [] - mocked_concepts = [{"name": "start", "id": "1"}, {"name": "pie", "id": "3.17"}, - {"name": "end", "id": "ragnorok"}] - httpx_mock.add_response( - url=f"{conceptev_url}/concepts", - method="get", json=mocked_concepts) + mocked_concepts = [ + {"name": "start", "id": "1"}, + {"name": "pie", "id": "3.17"}, + {"name": "end", "id": "ragnorok"}, + ] + httpx_mock.add_response(url=f"{conceptev_url}/concepts", method="get", json=mocked_concepts) returned_concepts = main.get_concept_ids(client) for concept in mocked_concepts: - assert returned_concepts[concept['name']] == concept['id'] + assert returned_concepts[concept["name"]] == concept["id"] def test_get_account_ids(httpx_mock: HTTPXMock): - token = '123' + token = "123" mocked_accounts = [ {"account": {"accountName": "account 1", "accountId": "al;kjasdf"}}, - {"account": {"accountName": "account 2", "accountId": "asdhalkjh"}}] + {"account": {"accountName": "account 2", "accountId": "asdhalkjh"}}, + ] httpx_mock.add_response( url=f"{ocm_url}/account/list", - method="post", headers={"authorization": token}, json=mocked_accounts,status_code=200) + method="post", + headers={"authorization": token}, + json=mocked_accounts, + status_code=200, + ) returned_account = main.get_account_ids(token) for account in mocked_accounts: - assert returned_account[account['account']['accountName']] == account['account']['accountId'] + assert ( + returned_account[account["account"]["accountName"]] == account["account"]["accountId"] + ) def test_get_default_hpc(httpx_mock: HTTPXMock): - mocked_account = {"accountId":"567"} - mocked_hpc = {"hpcId":"345"} + mocked_account = {"accountId": "567"} + mocked_hpc = {"hpcId": "345"} token = "123" httpx_mock.add_response( url=f"{ocm_url}/account/hpc/default", - method="post", headers={"authorization": token}, match_json=mocked_account,json=mocked_hpc,status_code=200) - hpc_id = main.get_default_hpc(token, mocked_account['accountId']) - assert hpc_id == mocked_hpc['hpcId'] - - -def test_create_submit_job(httpx_mock: HTTPXMock,client: httpx.Client): - account_id = '123' - hpc_id = '456' - job_name = '789' - concept = { 'requirements_ids':'abc', - 'architecture_id':'def', - 'id':'ghi', - 'design_instance_id':'jkl'} + method="post", + headers={"authorization": token}, + match_json=mocked_account, + json=mocked_hpc, + status_code=200, + ) + hpc_id = main.get_default_hpc(token, mocked_account["accountId"]) + assert hpc_id == mocked_hpc["hpcId"] + + +def test_create_submit_job(httpx_mock: HTTPXMock, client: httpx.Client): + account_id = "123" + hpc_id = "456" + job_name = "789" + concept = { + "requirements_ids": "abc", + "architecture_id": "def", + "id": "ghi", + "design_instance_id": "jkl", + } job_input = { "job_name": job_name, - "requirement_ids": concept['requirements_ids'], - "architecture_id": concept['architecture_id'], - "concept_id": concept['id'], - "design_instance_id": concept['design_instance_id'], + "requirement_ids": concept["requirements_ids"], + "architecture_id": concept["architecture_id"], + "concept_id": concept["id"], + "design_instance_id": concept["design_instance_id"], } - mocked_job = ({"job":"data"}, {"stuff":"in file"}) + mocked_job = ({"job": "data"}, {"stuff": "in file"}) httpx_mock.add_response( - url=f"{conceptev_url}/jobs?concept_id=123", - match_json = job_input, json=mocked_job) + url=f"{conceptev_url}/jobs?concept_id=123", match_json=job_input, json=mocked_job + ) mocked_info = "job info" - mocked_job_start = { + mocked_job_start = { "job": mocked_job[0], "uploaded_file": mocked_job[1], "account_id": account_id, @@ -173,55 +231,61 @@ def test_create_submit_job(httpx_mock: HTTPXMock,client: httpx.Client): } httpx_mock.add_response( url=f"{conceptev_url}/jobs:start?concept_id=123", - match_json = mocked_job_start, json=mocked_info) - job_info = main.create_submit_job(client,concept, account_id,hpc_id,job_name) + match_json=mocked_job_start, + json=mocked_info, + ) + job_info = main.create_submit_job(client, concept, account_id, hpc_id, job_name) assert job_info == mocked_info def test_put(httpx_mock: HTTPXMock, client: httpx.Client): example_aero = {"name": "aero_mock_response"} - mocked_id = '345' + mocked_id = "345" httpx_mock.add_response( - url = f"{conceptev_url}/configurations/{mocked_id}?concept_id=123", - method = "put", - match_json = example_aero, - json = example_aero) + url=f"{conceptev_url}/configurations/{mocked_id}?concept_id=123", + method="put", + match_json=example_aero, + json=example_aero, + ) - results = main.put(client, "/configurations",mocked_id, example_aero) + results = main.put(client, "/configurations", mocked_id, example_aero) assert results == example_aero def test_read_file(mocker): file_data = "Simple Data" mocked_file_data = mocker.mock_open(read_data=file_data) - mocker.patch("builtins.open",mocked_file_data) + mocker.patch("builtins.open", mocked_file_data) results = main.read_file("filename") assert results == file_data def test_read_results(httpx_mock: HTTPXMock, client: httpx.Client): example_job_info = {"job": "mocked_job"} - example_results = {"results":"returned"} + example_results = {"results": "returned"} httpx_mock.add_response( - url = f"{conceptev_url}/jobs:result?concept_id=123", - method = "post", - match_json = example_job_info, - json = example_results) - results = main.read_results(client,example_job_info) + url=f"{conceptev_url}/jobs:result?concept_id=123", + method="post", + match_json=example_job_info, + json=example_results, + ) + results = main.read_results(client, example_job_info) assert example_results == results def test_post_file(mocker, httpx_mock: HTTPXMock, client: httpx.Client): file_data = "Simple Data" - file_post_response_data = {"file":"read"} + file_post_response_data = {"file": "read"} mocked_file_data = mocker.mock_open(read_data=file_data) - mocker.patch("builtins.open",mocked_file_data) + mocker.patch("builtins.open", mocked_file_data) filename = "filename" - params = {"param1":"one"} - httpx_mock.add_response(url = f"{conceptev_url}/configurations:from_file?concept_id=123¶m1=one", - method="post", - json=file_post_response_data) + params = {"param1": "one"} + httpx_mock.add_response( + url=f"{conceptev_url}/configurations:from_file?concept_id=123¶m1=one", + method="post", + json=file_post_response_data, + ) - result = main.post_file(client,"/configurations",filename,params) + result = main.post_file(client, "/configurations", filename, params) assert result == file_post_response_data diff --git a/tox.ini b/tox.ini index ec501629..5da8de9d 100644 --- a/tox.ini +++ b/tox.ini @@ -15,7 +15,7 @@ basepython = py: python3 {style,reformat,doc}: python3 skip_install = true -whitelist_externals = +allowlist_externals = poetry setenv = PYTHONUNBUFFERED = yes @@ -35,8 +35,8 @@ commands = [testenv:doc] description = Check if documentation generates properly skip_install = true -whitelist_externals = +allowlist_externals = poetry commands = - poetry install + poetry install --with doc poetry run sphinx-build -d "{toxworkdir}/doc_doctree" doc/source "{toxinidir}/_build/html" --color -vW -bhtml