Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions ansys/rep/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,24 +37,28 @@ class Client(object):
Refresh Token
access_token : str, optional
Access Token
all_fields: bool, optional
If True, the query parameter ``fields="all"`` is applied by default
to all requests, so that all available fields are returned for
the requested resources.

Examples
--------

>>> from ansys.rep.client import Client
>>> # Create client object and connect to REP with username & password
>>> cl = Client(
rep_url="https://localhost:8443/rep", username="repadmin", password="repadmin"
)
... rep_url="https://localhost:8443/rep", username="repuser", password="repuser"
... )
>>> # Extract refresh token to eventually store it
>>> refresh_token = cl.refresh_token
>>> # Alternative: Create client object and connect to REP with refresh token
>>> cl = Client(
rep_url="https://localhost:8443/rep",
username="repadmin",
refresh_token=refresh_token,
grant_type="refresh_token"
)
... rep_url="https://localhost:8443/rep",
... username="repuser",
... refresh_token=refresh_token,
... grant_type="refresh_token"
>>> )

"""

Expand All @@ -72,6 +76,7 @@ def __init__(
access_token: str = None,
refresh_token: str = None,
auth_url: str = None,
all_fields=True,
):

self.rep_url = rep_url
Expand Down Expand Up @@ -103,6 +108,9 @@ def __init__(
self.refresh_token = tokens["refresh_token"]

self.session = create_session(self.access_token)
if all_fields:
self.session.params = {"fields": "all"}

# register hook to handle expiring of the refresh token
self.session.hooks["response"] = [self._auto_refresh_token, raise_for_status]
self._unauthorized_num_retry = 0
Expand Down
2 changes: 1 addition & 1 deletion ansys/rep/client/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def create_session(access_token: str = None) -> requests.Session:
if access_token:
session.headers.update({"Authorization": "Bearer %s" % access_token})

retries = Retry(total=10, backoff_factor=1, status_forcelist=[503])
retries = Retry(total=5, backoff_factor=0.5, status_forcelist=[502, 503, 504])
session.mount("http://", HTTPAdapter(max_retries=retries))
session.mount("https://", HTTPAdapter(max_retries=retries))
return session
Expand Down
4 changes: 0 additions & 4 deletions ansys/rep/client/jms/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ def get_objects(

rest_name = obj_type.Meta.rest_name
url = f"{url}/{rest_name}"
query_params.setdefault("fields", "all")
r = session.get(url, params=query_params)

if query_params.get("count"):
Expand All @@ -36,7 +35,6 @@ def get_object(

rest_name = obj_type.Meta.rest_name
url = f"{url}/{rest_name}/{id}"
query_params.setdefault("fields", "all")
r = session.get(url, params=query_params)

data = r.json()[rest_name]
Expand Down Expand Up @@ -68,7 +66,6 @@ def create_objects(
rest_name = obj_type.Meta.rest_name

url = f"{url}/{rest_name}"
query_params.setdefault("fields", "all")
schema = obj_type.Meta.schema(many=True)
serialized_data = schema.dump(objects)
json_data = json.dumps({rest_name: serialized_data})
Expand Down Expand Up @@ -100,7 +97,6 @@ def update_objects(
rest_name = obj_type.Meta.rest_name

url = f"{url}/{rest_name}"
query_params.setdefault("fields", "all")
schema = obj_type.Meta.schema(many=True)
serialized_data = schema.dump(objects)
json_data = json.dumps({rest_name: serialized_data})
Expand Down
2 changes: 0 additions & 2 deletions ansys/rep/client/jms/api/project_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,8 +549,6 @@ def copy_jobs(project_api: ProjectApi, jobs: List[Job], as_objects=True, **query

url = f"{project_api.url}/jobs"

query_params.setdefault("fields", "all")

json_data = json.dumps({"source_ids": [obj.id for obj in jobs]})
r = project_api.client.session.post(f"{url}", data=json_data, params=query_params)

Expand Down
94 changes: 61 additions & 33 deletions doc/source/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,49 +62,26 @@ of a tubular steel trellis motorbike-frame.
See :ref:`example_mapdl_motorbike_frame` for a detailed description of this example.

Query parameters
-----------------------------------
----------------

Most ``get`` functions support filtering by query parameters.

Properties
^^^^^^^^^^

You can query resources by the value of their properties.

.. code-block:: python

project = jms_api.get_project_by_name(name="Mapdl Motorbike Frame")
project_api = ProjectApi(client, project.id)

# Get all jobs with all fields
# Get all jobs
jobs = project_api.get_jobs()

# Get id and parameter values for all evaluated jobs
jobs = project_api.get_jobs(fields=["id", "values"], eval_status="evaluated")

# Get name and elapsed time of max 5 evaluated jobs
jobs = project_api.get_jobs(fields=["name", "elapsed_time"],
eval_status="evaluated", limit=5)
for job in jobs:
print(job)
# {
# "id": "02qoqedl8QCjkuLcqCi10Q",
# "name": "Job.0",
# "priority": 0,
# "elapsed_time": 35.275044
# }
# {
# "id": "02qoqedlDMO1LrSGoHQqnT",
# "name": "Job.1",
# "priority": 0,
# "elapsed_time": 34.840801
# }
# ...

# Get all jobs sorted by fitness value in ascending order
jobs = project_api.get_jobs(sort="fitness")
# Get all evaluated jobs
jobs = project_api.get_jobs(eval_status="evaluated")

# Get all jobs sorted by fitness value in descending order
jobs = project_api.get_jobs(sort="-fitness")

# Get all jobs sorted by the parameters tube1 and weight
jobs = project_api.get_jobs(sort=["values.tube1", "values.weight"])
print([(job.values["tube1"], job.values["weight"]) for job in jobs])

In general, query parameters support the following operators: ``lt`` (less than), ``le`` (less or equal),
``=`` (equal), ``ne`` (not equal), ``ge`` (greater or equal), ``gt`` (greater than), ``in`` (value found in list) and
Expand All @@ -126,6 +103,57 @@ In general, query parameters support the following operators: ``lt`` (less than)
query_params = {"fitness.lt": 1.8}
jobs = project_api.get_jobs(**query_params)


Fields
^^^^^^

When you query a resource, the REST API returns a set of fields by default. You can specify which fields
you want returned by using the ``fields`` query parameter (this returns only the fields you specify,
and the ID of the resource, which is always returned).
Moreover, you can request all fields to be returned by specifying ``fields="all"``.

.. code-block:: python

# Get all jobs with all fields
jobs = project_api.get_jobs(fields="all")

# Get id and parameter values for all evaluated jobs
jobs = project_api.get_jobs(fields=["id", "values"], eval_status="evaluated")

Sorting
^^^^^^^

You can sort resource collections by their properties.
Prefixing with ``-`` (minus) denotes descending order.

.. code-block:: python

# Get all jobs sorted by fitness value in ascending order
jobs = project_api.get_jobs(sort="fitness")

# Get all jobs sorted by fitness value in descending order
jobs = project_api.get_jobs(sort="-fitness")

# Get all jobs sorted by the parameters tube1 and weight
jobs = project_api.get_jobs(sort=["values.tube1", "values.weight"])
print([(job.values["tube1"], job.values["weight"]) for job in jobs])

Pagination
^^^^^^^^^^

You can use the ``offset`` and ``limit`` query parameters to paginate items in a collection.

.. code-block:: python

# Get name and elapsed time of max 5 evaluated jobs, sorted by creation time
jobs = project_api.get_jobs(fields=["name", "elapsed_time"], sort="-creation_time",
eval_status="evaluated", limit=5)

# Query the next 10 jobs
jobs = project_api.get_jobs(fields=["name", "elapsed_time"], sort="-creation_time",
eval_status="evaluated", limit=10, offset=5)


Objects vs dictionaries
-----------------------------------

Expand Down
4 changes: 2 additions & 2 deletions examples/lsdyna_cylinder_plate/lsdyna_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ def submit_job() -> REPJob:
max_execution_time=3600.0,
resource_requirements=ResourceRequirements(
cpu_core_usage=6,
memory=6000,
disk_space=4000,
memory=6000 * 1024 * 1024,
disk_space=4000 * 1024 * 1024,
),
execution_level=0,
num_trials=1,
Expand Down
5 changes: 3 additions & 2 deletions examples/mapdl_tyre_performance/project_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,9 @@ def main(client: Client, name: str, num_jobs: int, version: str) -> Project:
execution_command="%executable% -b -i %file:mac% -o file.out -np %resource:num_cores%",
resource_requirements=ResourceRequirements(
cpu_core_usage=4,
memory=4000,
disk_space=500,
memory=4000 * 1024 * 1024,
disk_space=500 * 1024 * 1024,
distributed=True,
),
max_execution_time=1800.0,
execution_level=0,
Expand Down
45 changes: 45 additions & 0 deletions tests/jms/test_jms_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
import unittest

from examples.mapdl_motorbike_frame.project_setup import create_project
from marshmallow.utils import missing

from ansys.rep.client import Client
from ansys.rep.client.jms import JmsApi, ProjectApi
from ansys.rep.client.jms.resource import Job, Project
from tests.rep_test import REPTestCase
Expand Down Expand Up @@ -75,6 +77,49 @@ def test_jms_api(self):
# Delete Jobs again
project_api.delete_jobs(created_jobs)

def test_fields_query_parameter(self):

client1 = Client(self.rep_url, self.username, self.password, all_fields=False)

proj_name = "test_fields_query_parameter"
project = create_project(client1, proj_name, num_jobs=2, use_exec_script=False)

project_api1 = ProjectApi(client1, project.id)

jobs = project_api1.get_jobs()
self.assertEqual(len(jobs), 2)
self.assertNotEqual(jobs[0].id, missing)
self.assertNotEqual(jobs[0].eval_status, missing)
self.assertEqual(jobs[0].values, missing)
self.assertEqual(jobs[0].host_ids, missing)

jobs = project_api1.get_jobs(fields=["id", "eval_status", "host_ids"])
self.assertEqual(len(jobs), 2)
self.assertNotEqual(jobs[0].id, missing)
self.assertNotEqual(jobs[0].eval_status, missing)
self.assertNotEqual(jobs[0].host_ids, missing)
self.assertEqual(jobs[0].values, missing)

client2 = Client(self.rep_url, self.username, self.password, all_fields=True)
project_api2 = ProjectApi(client2, project.id)

jobs = project_api2.get_jobs()
self.assertEqual(len(jobs), 2)
self.assertNotEqual(jobs[0].id, missing)
self.assertNotEqual(jobs[0].eval_status, missing)
self.assertNotEqual(jobs[0].values, missing)
self.assertNotEqual(jobs[0].host_ids, missing)

jobs = project_api2.get_jobs(fields=["id", "eval_status"])
self.assertEqual(len(jobs), 2)
self.assertNotEqual(jobs[0].id, missing)
self.assertNotEqual(jobs[0].eval_status, missing)
self.assertEqual(jobs[0].host_ids, missing)
self.assertEqual(jobs[0].values, missing)

# Delete project
JmsApi(client1).delete_project(project)


if __name__ == "__main__":
unittest.main()
10 changes: 1 addition & 9 deletions tests/jms/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,10 @@ def test_task_deserialization(self):

def test_task_integration(self):

# This test assumes that the project mapdl_motorbike_frame
# already exists on the REP server.
# In case, you can create such project running the script
# examples/mapdl_motorbike_frame/project_setup.py

client = self.client()
proj_name = "Mapdl Motorbike Frame"

jms_api = JmsApi(client)
project = jms_api.get_project_by_name(name=proj_name)
if not project:
project = create_project(client, proj_name, num_jobs=5, use_exec_script=False)
project = create_project(client, proj_name, num_jobs=5, use_exec_script=False)

project_api = ProjectApi(client, project.id)
tasks = project_api.get_tasks(limit=5)
Expand Down