ansys-conceptev-core 0.1.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ # This is the list of Pyconceptev Core's significant contributors.
2
+ #
3
+ # This file does not necessarily list everyone who has contributed code.
4
+ #
5
+ # For contributions made under a Corporate CLA, the organization is
6
+ # added to this file.
7
+ #
8
+ # If you have contributed to the repository and wish to be added to this file
9
+ # please submit a request.
10
+ #
11
+ #
12
+ ANSYS, Inc.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,120 @@
1
+ Metadata-Version: 2.1
2
+ Name: ansys-conceptev-core
3
+ Version: 0.1.3
4
+ Summary: A Python wrapper for Ansys Conceptev core
5
+ Home-page: https://github.com/ansys/pyconceptev
6
+ License: MIT
7
+ Keywords: Ansys,Concept EV,Electric Powertrain
8
+ Author: ANSYS, Inc.
9
+ Author-email: pyansys.core@ansys.com
10
+ Maintainer: ANSYS, Inc.
11
+ Maintainer-email: pyansys.core@ansys.com
12
+ Requires-Python: >=3.9,<4.0
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Requires-Dist: httpx (>=0.26.0,<0.27.0)
23
+ Requires-Dist: importlib-metadata (>=7.0,<8.0) ; python_version < "3.8"
24
+ Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
25
+ Project-URL: Documentation, https://conceptev.core.docs.pyansys.com
26
+ Project-URL: Repository, https://github.com/ansys/pyconceptev
27
+ Description-Content-Type: text/x-rst
28
+
29
+ PyConceptEV
30
+ ===========
31
+ |pyansys| |python| |MIT|
32
+
33
+ .. |pyansys| image:: https://img.shields.io/badge/Py-Ansys-ffc107.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABDklEQVQ4jWNgoDfg5mD8vE7q/3bpVyskbW0sMRUwofHD7Dh5OBkZGBgW7/3W2tZpa2tLQEOyOzeEsfumlK2tbVpaGj4N6jIs1lpsDAwMJ278sveMY2BgCA0NFRISwqkhyQ1q/Nyd3zg4OBgYGNjZ2ePi4rB5loGBhZnhxTLJ/9ulv26Q4uVk1NXV/f///////69du4Zdg78lx//t0v+3S88rFISInD59GqIH2esIJ8G9O2/XVwhjzpw5EAam1xkkBJn/bJX+v1365hxxuCAfH9+3b9/+////48cPuNehNsS7cDEzMTAwMMzb+Q2u4dOnT2vWrMHu9ZtzxP9vl/69RVpCkBlZ3N7enoDXBwEAAA+YYitOilMVAAAAAElFTkSuQmCC
34
+ :target: https://docs.pyansys.com/
35
+ :alt: PyAnsys
36
+
37
+ .. |python| image:: https://img.shields.io/badge/python-3.9+-blue.svg
38
+ :target: https://www.python.org/downloads/
39
+ :alt: Python
40
+
41
+ .. .. |pypi| image:: https://img.shields.io/pypi/v/ansys-conceptev-core.svg?logo=python&logoColor=white
42
+ .. :target: https://pypi.org/project/ansys-conceptev-core
43
+ .. :alt: PyPI
44
+
45
+ .. .. |downloads| image:: https://img.shields.io/pypi/dm/ansys-conceptev-core.svg
46
+ .. :target: https://pypi.org/project/ansys-conceptev-core/
47
+ .. :alt: PyPI Downloads
48
+
49
+ .. .. |codecov| image:: https://codecov.io/gh/ansys/pyconceptev/graph/badge.svg?token=UZIC7XT5WE
50
+ .. :target: https://codecov.io/gh/ansys/pyconceptev
51
+ .. :alt: Codecov
52
+
53
+ .. .. |GH-CI| image:: https://github.com/ansys/pyconceptev/actions/workflows/ci_cd.yml/badge.svg
54
+ .. :target: https://github.com/ansys/pyconceptev/actions/workflows/ci_cd.yml
55
+ .. :alt: GH-CI
56
+
57
+ .. |MIT| image:: https://img.shields.io/badge/License-MIT-yellow.svg
58
+ :target: https://opensource.org/licenses/MIT
59
+ :alt: MIT
60
+
61
+ .. .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=flat
62
+ .. :target: https://github.com/psf/black
63
+ .. :alt: Black
64
+
65
+ .. .. |pre-commit| image:: https://results.pre-commit.ci/badge/github/ansys/pyconceptev/main.svg
66
+ .. :target: https://results.pre-commit.ci/latest/github/ansys/pyconceptev/main
67
+ .. :alt: pre-commit.ci
68
+
69
+
70
+ Overview
71
+ --------
72
+
73
+ PyConceptEV is a Python client library for the `Ansys ConceptEV <https://www.ansys.com/products/electronics/ansys-concept-ev>`_
74
+ service, which provides a cloud-based design and simulation platform for the concept design
75
+ of EV powertrains.
76
+
77
+ Documentation and issues
78
+ ------------------------
79
+
80
+ Documentation for the latest stable release of PyConceptEV is hosted
81
+ at `PyConceptEV documentation <https://conceptev.core.docs.pyansys.com/>`_.
82
+
83
+ The documentation has these sections:
84
+
85
+ - `Getting started <https://conceptev.core.docs.pyansys.com/version/stable/getting_started/index.html>`_: Learn
86
+ how to install PyConceptEV in user mode and quickly begin using it.
87
+ - `User guide <https://conceptev.core.docs.pyansys.com/version/stable/user_guide/index.html>`_: Learn how to
88
+ configure a PyConceptEV session, get a token, and create a client.
89
+ - `API reference <conceptev.core.docs.pyansys.com/version/stable/api/index.html>`_: Understand how the
90
+ `Ansys ConceptEV API documentation <https://conceptev.ansys.com/api/docs>`_ provides for interacting
91
+ programmatically with PyConcept EV.
92
+ - `Examples <https://conceptev.core.docs.pyansys.com/version/stable/examples/index.html>`_: Explore examples
93
+ that show how to use PyConceptEV.
94
+ - `Contribute <conceptev.core.docs.pyansys.com/version/stable/contributing.html>`_: Learn how to
95
+ contribute to the PyConceptEV codebase or documentation.
96
+
97
+ In the upper right corner of the documentation's title bar, there is an option
98
+ for switching from viewing the documentation for the latest stable release
99
+ to viewing the documentation for the development version or previously
100
+ released versions.
101
+
102
+ On the `PyConceptEV Issues <https://github.com/ansys/pyconceptev/issues>`_
103
+ page, you can create issues to report bugs and request new features. On the
104
+ `Discussions <https://discuss.ansys.com/>`_ page on the Ansys Developer portal,
105
+ you can post questions, share ideas, and get community feedback.
106
+
107
+ If you have general questions about the PyAnsys ecosystem, email
108
+ `pyansys.core@ansys.com <pyansys.core@ansys.com>`_. If your
109
+ question is specific to PyConceptEV, ask your question in an issue
110
+ as described in the previous paragraph.
111
+
112
+ License
113
+ -------
114
+
115
+ PyConceptEV is licensed under the `MIT License <https://github.com/ansys/pyconceptev/blob/main/LICENSE>`_.
116
+
117
+ PyConceptEV makes no commercial claim over Ansys whatsoever. This library adds a
118
+ Python interface for `Ansys ConceptEV <https://www.ansys.com/products/electronics/ansys-concept-ev>`_
119
+ without changing the core behavior or license of the original Ansys software.
120
+
@@ -0,0 +1,91 @@
1
+ PyConceptEV
2
+ ===========
3
+ |pyansys| |python| |MIT|
4
+
5
+ .. |pyansys| image:: https://img.shields.io/badge/Py-Ansys-ffc107.svg?logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABDklEQVQ4jWNgoDfg5mD8vE7q/3bpVyskbW0sMRUwofHD7Dh5OBkZGBgW7/3W2tZpa2tLQEOyOzeEsfumlK2tbVpaGj4N6jIs1lpsDAwMJ278sveMY2BgCA0NFRISwqkhyQ1q/Nyd3zg4OBgYGNjZ2ePi4rB5loGBhZnhxTLJ/9ulv26Q4uVk1NXV/f///////69du4Zdg78lx//t0v+3S88rFISInD59GqIH2esIJ8G9O2/XVwhjzpw5EAam1xkkBJn/bJX+v1365hxxuCAfH9+3b9/+////48cPuNehNsS7cDEzMTAwMMzb+Q2u4dOnT2vWrMHu9ZtzxP9vl/69RVpCkBlZ3N7enoDXBwEAAA+YYitOilMVAAAAAElFTkSuQmCC
6
+ :target: https://docs.pyansys.com/
7
+ :alt: PyAnsys
8
+
9
+ .. |python| image:: https://img.shields.io/badge/python-3.9+-blue.svg
10
+ :target: https://www.python.org/downloads/
11
+ :alt: Python
12
+
13
+ .. .. |pypi| image:: https://img.shields.io/pypi/v/ansys-conceptev-core.svg?logo=python&logoColor=white
14
+ .. :target: https://pypi.org/project/ansys-conceptev-core
15
+ .. :alt: PyPI
16
+
17
+ .. .. |downloads| image:: https://img.shields.io/pypi/dm/ansys-conceptev-core.svg
18
+ .. :target: https://pypi.org/project/ansys-conceptev-core/
19
+ .. :alt: PyPI Downloads
20
+
21
+ .. .. |codecov| image:: https://codecov.io/gh/ansys/pyconceptev/graph/badge.svg?token=UZIC7XT5WE
22
+ .. :target: https://codecov.io/gh/ansys/pyconceptev
23
+ .. :alt: Codecov
24
+
25
+ .. .. |GH-CI| image:: https://github.com/ansys/pyconceptev/actions/workflows/ci_cd.yml/badge.svg
26
+ .. :target: https://github.com/ansys/pyconceptev/actions/workflows/ci_cd.yml
27
+ .. :alt: GH-CI
28
+
29
+ .. |MIT| image:: https://img.shields.io/badge/License-MIT-yellow.svg
30
+ :target: https://opensource.org/licenses/MIT
31
+ :alt: MIT
32
+
33
+ .. .. |black| image:: https://img.shields.io/badge/code%20style-black-000000.svg?style=flat
34
+ .. :target: https://github.com/psf/black
35
+ .. :alt: Black
36
+
37
+ .. .. |pre-commit| image:: https://results.pre-commit.ci/badge/github/ansys/pyconceptev/main.svg
38
+ .. :target: https://results.pre-commit.ci/latest/github/ansys/pyconceptev/main
39
+ .. :alt: pre-commit.ci
40
+
41
+
42
+ Overview
43
+ --------
44
+
45
+ PyConceptEV is a Python client library for the `Ansys ConceptEV <https://www.ansys.com/products/electronics/ansys-concept-ev>`_
46
+ service, which provides a cloud-based design and simulation platform for the concept design
47
+ of EV powertrains.
48
+
49
+ Documentation and issues
50
+ ------------------------
51
+
52
+ Documentation for the latest stable release of PyConceptEV is hosted
53
+ at `PyConceptEV documentation <https://conceptev.core.docs.pyansys.com/>`_.
54
+
55
+ The documentation has these sections:
56
+
57
+ - `Getting started <https://conceptev.core.docs.pyansys.com/version/stable/getting_started/index.html>`_: Learn
58
+ how to install PyConceptEV in user mode and quickly begin using it.
59
+ - `User guide <https://conceptev.core.docs.pyansys.com/version/stable/user_guide/index.html>`_: Learn how to
60
+ configure a PyConceptEV session, get a token, and create a client.
61
+ - `API reference <conceptev.core.docs.pyansys.com/version/stable/api/index.html>`_: Understand how the
62
+ `Ansys ConceptEV API documentation <https://conceptev.ansys.com/api/docs>`_ provides for interacting
63
+ programmatically with PyConcept EV.
64
+ - `Examples <https://conceptev.core.docs.pyansys.com/version/stable/examples/index.html>`_: Explore examples
65
+ that show how to use PyConceptEV.
66
+ - `Contribute <conceptev.core.docs.pyansys.com/version/stable/contributing.html>`_: Learn how to
67
+ contribute to the PyConceptEV codebase or documentation.
68
+
69
+ In the upper right corner of the documentation's title bar, there is an option
70
+ for switching from viewing the documentation for the latest stable release
71
+ to viewing the documentation for the development version or previously
72
+ released versions.
73
+
74
+ On the `PyConceptEV Issues <https://github.com/ansys/pyconceptev/issues>`_
75
+ page, you can create issues to report bugs and request new features. On the
76
+ `Discussions <https://discuss.ansys.com/>`_ page on the Ansys Developer portal,
77
+ you can post questions, share ideas, and get community feedback.
78
+
79
+ If you have general questions about the PyAnsys ecosystem, email
80
+ `pyansys.core@ansys.com <pyansys.core@ansys.com>`_. If your
81
+ question is specific to PyConceptEV, ask your question in an issue
82
+ as described in the previous paragraph.
83
+
84
+ License
85
+ -------
86
+
87
+ PyConceptEV is licensed under the `MIT License <https://github.com/ansys/pyconceptev/blob/main/LICENSE>`_.
88
+
89
+ PyConceptEV makes no commercial claim over Ansys whatsoever. This library adds a
90
+ Python interface for `Ansys ConceptEV <https://www.ansys.com/products/electronics/ansys-concept-ev>`_
91
+ without changing the core behavior or license of the original Ansys software.
@@ -0,0 +1,136 @@
1
+ [build-system]
2
+ requires = ["poetry-core>=1.0.0"]
3
+ build-backend = "poetry.core.masonry.api"
4
+
5
+ [tool.poetry]
6
+ # Check https://python-poetry.org/docs/pyproject/ for all available sections
7
+ name = "ansys-conceptev-core"
8
+ description = "A Python wrapper for Ansys Conceptev core"
9
+ version = "0.1.3"
10
+ license = "MIT"
11
+ authors = ["ANSYS, Inc. <pyansys.core@ansys.com>"]
12
+ maintainers = ["ANSYS, Inc. <pyansys.core@ansys.com>"]
13
+ repository = "https://github.com/ansys/pyconceptev"
14
+ documentation = "https://conceptev.core.docs.pyansys.com"
15
+ readme = "README.rst"
16
+ keywords = [
17
+ "Ansys",
18
+ "Concept EV",
19
+ "Electric Powertrain",
20
+ ]
21
+ classifiers = [
22
+ "License :: OSI Approved :: MIT License",
23
+ "Development Status :: 4 - Beta",
24
+ "Intended Audience :: Science/Research",
25
+ "Operating System :: OS Independent",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.9",
28
+ "Programming Language :: Python :: 3.10",
29
+ "Programming Language :: Python :: 3.11",
30
+ ]
31
+ packages = [
32
+ { include = "ansys", from = "src" },
33
+ ]
34
+
35
+ [tool.poetry.dependencies]
36
+ python = ">=3.9,<4.0"
37
+ importlib-metadata = {version = "^7.0", python = "<3.8"}
38
+ python-dotenv = "^1.0.0"
39
+ httpx = "^0.26.0"
40
+
41
+ # Common packages for test and examples
42
+ [tool.poetry.group.dev.dependencies]
43
+ plotly = "^5.18.0"
44
+ tox = "^4.15.1"
45
+ pytest-cov = "^5.0.0"
46
+ pre-commit = "^3.7.1"
47
+
48
+ # Optional documentation dependencies
49
+ [tool.poetry.group.doc]
50
+ optional = true
51
+
52
+ [tool.poetry.group.doc.dependencies]
53
+ ansys-sphinx-theme = "^0.16.5"
54
+ ipython = "^8.1"
55
+ ipywidgets = "^8.1.3"
56
+ jupyterlab = "^4.2.2"
57
+ jupytext = "^1.15"
58
+ nbconvert = "^7.16.4"
59
+ nbsphinx = "^0.9.3"
60
+ numpydoc = "^1.5.0"
61
+ pypandoc = "^1.13"
62
+ recommonmark = "^0.7.1"
63
+ Sphinx = "^7.2.6"
64
+ sphinx-autobuild = "^2024.4.16"
65
+ sphinx-autodoc-typehints = "^2.1.1"
66
+ sphinx-copybutton = "^0.5.1"
67
+ sphinx-design = "^0.6.0"
68
+
69
+ # Optional testing dependencies
70
+ [tool.poetry.group.tests]
71
+ optional = true
72
+
73
+ [tool.poetry.group.tests.dependencies]
74
+ pytest = "^8.2.2"
75
+ pytest-cov = "^5.0.0"
76
+ pytest-httpx = "^0.29.0"
77
+ pytest-mock = "^3.12.0"
78
+
79
+ # Optional build requirements
80
+ [tool.poetry.group.build]
81
+ optional = true
82
+
83
+ [tool.poetry.group.build.dependencies]
84
+ build = "^1.0.3"
85
+ twine = "^5.0.0"
86
+
87
+ [tool.black]
88
+ line-length = 100
89
+
90
+ [tool.isort]
91
+ profile = "black"
92
+ force_sort_within_sections = true
93
+ line_length = 100
94
+ default_section = "THIRDPARTY"
95
+ src_paths = ["doc", "src", "tests"]
96
+ skip_gitignore = true
97
+
98
+ [tool.coverage.run]
99
+ source = ["ansys.conceptev.core"]
100
+
101
+ [tool.coverage.report]
102
+ show_missing = true
103
+
104
+ [tool.towncrier]
105
+ package = "ansys.conceptev.core"
106
+ directory = "doc/changelog.d"
107
+ filename = "doc/source/changelog.rst"
108
+ start_string = ".. towncrier release notes start\n"
109
+ template = "doc/changelog.d/changelog_template.jinja"
110
+ title_format = "`{version} <https://github.com/ansys/pyconceptev/releases/tag/v{version}>`_ - {project_date}"
111
+ issue_format = "`#{issue} <https://github.com/ansys/pyconceptev/pull/{issue}>`_"
112
+
113
+ [[tool.towncrier.type]]
114
+ directory = "added"
115
+ name = "Added"
116
+ showcontent = true
117
+
118
+ [[tool.towncrier.type]]
119
+ directory = "changed"
120
+ name = "Changed"
121
+ showcontent = true
122
+
123
+ [[tool.towncrier.type]]
124
+ directory = "fixed"
125
+ name = "Fixed"
126
+ showcontent = true
127
+
128
+ [[tool.towncrier.type]]
129
+ directory = "dependencies"
130
+ name = "Dependencies"
131
+ showcontent = true
132
+
133
+ [[tool.towncrier.type]]
134
+ directory = "miscellaneous"
135
+ name = "Miscellaneous"
136
+ showcontent = true
@@ -0,0 +1,29 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+ """Python wrapper for the Ansys ConceptEV service."""
23
+
24
+ try:
25
+ import importlib.metadata as importlib_metadata
26
+ except ModuleNotFoundError:
27
+ import importlib_metadata
28
+
29
+ __version__ = importlib_metadata.version(__name__.replace(".", "-"))
@@ -0,0 +1,319 @@
1
+ # Copyright (C) 2023 - 2024 ANSYS, Inc. and/or its affiliates.
2
+ # SPDX-License-Identifier: MIT
3
+ #
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ """Simple API client for the Ansys ConceptEV service."""
24
+
25
+ import datetime
26
+ from json import JSONDecodeError
27
+ import os
28
+ import time
29
+ from typing import Literal
30
+
31
+ import dotenv
32
+ import httpx
33
+
34
+ dotenv.load_dotenv()
35
+
36
+ Router = Literal[
37
+ "/architectures",
38
+ "/components",
39
+ "/components:from_file",
40
+ "/components:calculate_loss_map",
41
+ "/configurations",
42
+ "/configurations:calculate_forces",
43
+ "/requirements",
44
+ "/requirements:calculate_examples",
45
+ "/jobs",
46
+ "/jobs:start",
47
+ "/jobs:status",
48
+ "/jobs:result",
49
+ "/concepts",
50
+ "/drive_cycles",
51
+ "/drive_cycles:from_file",
52
+ "/health",
53
+ "/utilities:data_format_version",
54
+ ]
55
+
56
+
57
+ def get_token() -> str:
58
+ """Get token from OCM."""
59
+ username = os.environ["CONCEPTEV_USERNAME"]
60
+ password = os.environ["CONCEPTEV_PASSWORD"]
61
+ ocm_url = os.environ["OCM_URL"]
62
+ response = httpx.post(
63
+ url=ocm_url + "/auth/login/", json={"emailAddress": username, "password": password}
64
+ )
65
+ if response.status_code != 200:
66
+ raise Exception(f"Failed to get token {response.content}")
67
+ return response.json()["accessToken"]
68
+
69
+
70
+ def get_http_client(token: str, design_instance_id: str | None = None) -> httpx.Client:
71
+ """Get an HTTP client.
72
+
73
+ The HTTP client creates and maintains the connection, which is more performant than
74
+ re-creating this connection for each call.
75
+ """
76
+ base_url = os.environ["CONCEPTEV_URL"]
77
+ params = None
78
+ if design_instance_id:
79
+ params = {"design_instance_id": design_instance_id}
80
+ return httpx.Client(headers={"Authorization": token}, params=params, base_url=base_url)
81
+
82
+
83
+ def process_response(response) -> dict:
84
+ """Process a response.
85
+
86
+ Check the value returned from the API and raise an error if the process is not successful.
87
+ """
88
+ if response.status_code == 200 or response.status_code == 201: # Success
89
+ try:
90
+ return response.json()
91
+ except JSONDecodeError:
92
+ return response.content
93
+ raise Exception(f"Response Failed:{response.content}")
94
+
95
+
96
+ def get(
97
+ client: httpx.Client, router: Router, id: str | None = None, params: dict | None = None
98
+ ) -> dict:
99
+ """Send a GET request to the base client.
100
+
101
+ This HTTP verb performs the ``GET`` request and adds the route to the base client.
102
+ """
103
+ if id:
104
+ path = "/".join([router, id])
105
+ else:
106
+ path = router
107
+ response = client.get(url=path, params=params)
108
+ return process_response(response)
109
+
110
+
111
+ def post(client: httpx.Client, router: Router, data: dict, params: dict = {}) -> dict:
112
+ """Send a POST request to the base client.
113
+
114
+ This HTTP verb performs the ``POST`` request and adds the route to the base client.
115
+ """
116
+ response = client.post(url=router, json=data, params=params)
117
+ return process_response(response)
118
+
119
+
120
+ def delete(client: httpx.Client, router: Router, id: str) -> dict:
121
+ """Send a DELETE request to the base client.
122
+
123
+ This HTTP verb performs the ``DELETE`` request and adds the route to the base client.
124
+ """
125
+ path = "/".join([router, id])
126
+ response = client.delete(url=path)
127
+ if response.status_code != 204:
128
+ raise Exception(f"Failed to delete from {router} with ID:{id}.")
129
+
130
+
131
+ def put(client: httpx.Client, router: Router, id: str, data: dict) -> dict:
132
+ """Put/update from the client at the specific route.
133
+
134
+ An HTTP verb that performs the ``PUT`` request and adds the route to the base client.
135
+ """
136
+ path = "/".join([router, id])
137
+ response = client.put(url=path, json=data)
138
+ return process_response(response)
139
+
140
+
141
+ def create_new_project(
142
+ client: httpx.Client,
143
+ account_id: str,
144
+ hpc_id: str,
145
+ title: str,
146
+ project_goal: str = "Created from the CLI",
147
+ ):
148
+ """Create a project."""
149
+ osm_url = os.environ["OCM_URL"]
150
+ token = client.headers["Authorization"]
151
+ project_data = {
152
+ "accountId": account_id,
153
+ "hpcId": hpc_id,
154
+ "projectTitle": title,
155
+ "projectGoal": project_goal,
156
+ }
157
+ created_project = httpx.post(
158
+ osm_url + "/project/create", headers={"Authorization": token}, json=project_data
159
+ )
160
+ if created_project.status_code != 200 and created_project.status_code != 204:
161
+ raise Exception(f"Failed to create a project {created_project}.")
162
+
163
+ product_ids = httpx.get(osm_url + "/product/list", headers={"Authorization": token})
164
+ product_id = [
165
+ product["productId"]
166
+ for product in product_ids.json()
167
+ if product["productName"] == "CONCEPTEV"
168
+ ][0]
169
+
170
+ design_data = {
171
+ "projectId": created_project.json()["projectId"],
172
+ "productId": product_id,
173
+ "designTitle": "Branch 1",
174
+ }
175
+ created_design = httpx.post(
176
+ osm_url + "/design/create", headers={"Authorization": token}, json=design_data
177
+ )
178
+
179
+ if created_design.status_code not in (200, 204):
180
+ raise Exception(f"Failed to create a design on OCM {created_design.content}.")
181
+
182
+ user_details = httpx.post(osm_url + "/user/details", headers={"Authorization": token})
183
+ if user_details.status_code not in (200, 204):
184
+ raise Exception(f"Failed to get a user details on OCM {user_details}.")
185
+
186
+ concept_data = {
187
+ "capabilities_ids": [],
188
+ "components_ids": [],
189
+ "configurations_ids": [],
190
+ "design_id": created_design.json()["designId"],
191
+ "design_instance_id": created_design.json()["designInstanceList"][0]["designInstanceId"],
192
+ "drive_cycles_ids": [],
193
+ "jobs_ids": [],
194
+ "name": "Branch 1",
195
+ "project_id": created_project.json()["projectId"],
196
+ "requirements_ids": [],
197
+ "user_id": user_details.json()["userId"],
198
+ }
199
+
200
+ created_concept = post(client, "/concepts", data=concept_data)
201
+ return created_concept
202
+
203
+
204
+ def get_concept_ids(client: httpx.Client):
205
+ """Get concept IDs."""
206
+ concepts = get(client, "/concepts")
207
+ return {concept["name"]: concept["id"] for concept in concepts}
208
+
209
+
210
+ def get_account_ids(token: str) -> dict:
211
+ """Get account IDs."""
212
+ ocm_url = os.environ["OCM_URL"]
213
+ response = httpx.post(url=ocm_url + "/account/list", headers={"authorization": token})
214
+ if response.status_code != 200:
215
+ raise Exception(f"Failed to get accounts {response}.")
216
+ accounts = {
217
+ account["account"]["accountName"]: account["account"]["accountId"]
218
+ for account in response.json()
219
+ }
220
+ return accounts
221
+
222
+
223
+ def get_default_hpc(token: str, account_id: str):
224
+ """Get the default HPC ID."""
225
+ ocm_url = os.environ["OCM_URL"]
226
+ response = httpx.post(
227
+ url=ocm_url + "/account/hpc/default",
228
+ json={"accountId": account_id},
229
+ headers={"authorization": token},
230
+ )
231
+ if response.status_code != 200:
232
+ raise Exception(f"Failed to get accounts {response}.")
233
+ return response.json()["hpcId"]
234
+
235
+
236
+ def create_submit_job(
237
+ client,
238
+ concept: dict,
239
+ account_id: str,
240
+ hpc_id: str,
241
+ job_name: str = "cli_job: " + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
242
+ ):
243
+ """Create and then submit a job."""
244
+ job_input = {
245
+ "job_name": job_name,
246
+ "requirement_ids": concept["requirements_ids"],
247
+ "architecture_id": concept["architecture_id"],
248
+ "concept_id": concept["id"],
249
+ "design_instance_id": concept["design_instance_id"],
250
+ }
251
+ job, uploaded_file = post(client, "/jobs", data=job_input)
252
+ job_start = {
253
+ "job": job,
254
+ "uploaded_file": uploaded_file,
255
+ "account_id": account_id,
256
+ "hpc_id": hpc_id,
257
+ }
258
+ job_info = post(client, "/jobs:start", data=job_start)
259
+ return job_info
260
+
261
+
262
+ def read_file(filename: str) -> str:
263
+ """Read a given file."""
264
+ with open(filename) as f:
265
+ content = f.read()
266
+ return content
267
+
268
+
269
+ def read_results(
270
+ client,
271
+ job_info: dict,
272
+ calculate_units: bool = True,
273
+ no_of_tries: int = 200,
274
+ rate_limit: float = 0.3,
275
+ ) -> dict:
276
+ """Read job results.
277
+
278
+ Continuously request job results until a valid response is received or a limit of tries is
279
+ reached.
280
+ """
281
+ version_number = get(client, "/utilities:data_format_version")
282
+ for _ in range(0, no_of_tries):
283
+ response = client.post(
284
+ url="/jobs:result",
285
+ json=job_info,
286
+ params={
287
+ "results_file_name": f"output_file_v{version_number}.json",
288
+ "calculate_units": calculate_units,
289
+ },
290
+ )
291
+ time.sleep(rate_limit)
292
+ if response.status_code == 200:
293
+ return response.json()
294
+
295
+ raise Exception(f"There are too many requests: {response}.")
296
+
297
+
298
+ def post_component_file(client: httpx.Client, filename: str, component_file_type: str) -> dict:
299
+ """Send a POST request to the base client with a file.
300
+
301
+ An HTTP verb that performs the ``POST`` request, adds the route to the base client,
302
+ and then adds the file as a multipart form request.
303
+ """
304
+ path = "/components:upload"
305
+ file_contents = read_file(filename)
306
+ response = client.post(
307
+ url=path, files={"file": file_contents}, params={"component_file_type": component_file_type}
308
+ )
309
+ return process_response(response)
310
+
311
+
312
+ if __name__ == "__main__":
313
+ token = get_token()
314
+
315
+ with get_http_client(token) as client: # Create a client to talk to the API
316
+ health = get(client, "/health") # Check that the API is healthy
317
+ print(health)
318
+ concepts = get(client, "/concepts") # Get a list of concepts
319
+ print(concepts)