oscar-python 1.3.1__tar.gz → 1.3.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.
Files changed (43) hide show
  1. oscar_python-1.3.3/.github/workflows/release-build.yaml +76 -0
  2. oscar_python-1.3.3/.github/workflows/tests.yaml +27 -0
  3. oscar_python-1.3.3/.gitignore +160 -0
  4. {oscar_python-1.3.1/oscar_python.egg-info → oscar_python-1.3.3}/PKG-INFO +25 -15
  5. {oscar_python-1.3.1 → oscar_python-1.3.3}/README.md +6 -3
  6. oscar_python-1.3.3/jupyter_example/oscar_notebook.ipynb +143 -0
  7. oscar_python-1.3.3/jupyter_example/services/cowsay_example/cowsay.yaml +12 -0
  8. oscar_python-1.3.3/jupyter_example/services/cowsay_example/script.sh +8 -0
  9. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_oidc.py +2 -2
  10. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/client.py +14 -5
  11. {oscar_python-1.3.1 → oscar_python-1.3.3/oscar_python.egg-info}/PKG-INFO +26 -16
  12. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python.egg-info/SOURCES.txt +7 -2
  13. oscar_python-1.3.3/oscar_python.egg-info/requires.txt +10 -0
  14. oscar_python-1.3.3/oscar_python.egg-info/top_level.txt +1 -0
  15. oscar_python-1.3.3/pyproject.toml +38 -0
  16. oscar_python-1.3.3/setup.py +21 -0
  17. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_oidc.py +2 -1
  18. oscar_python-1.3.1/oscar_python/test_v2.py +0 -206
  19. oscar_python-1.3.1/oscar_python.egg-info/not-zip-safe +0 -1
  20. oscar_python-1.3.1/oscar_python.egg-info/requires.txt +0 -7
  21. oscar_python-1.3.1/oscar_python.egg-info/top_level.txt +0 -5
  22. oscar_python-1.3.1/setup.py +0 -49
  23. {oscar_python-1.3.1 → oscar_python-1.3.3}/LICENSE +0 -0
  24. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/__init__.py +0 -0
  25. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_providers/_minio.py +0 -0
  26. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_providers/_onedata.py +0 -0
  27. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_providers/_providers_base.py +0 -0
  28. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_providers/_s3.py +0 -0
  29. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_providers/_webdav.py +0 -0
  30. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/_utils.py +0 -0
  31. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/client_anon.py +0 -0
  32. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/default_client.py +0 -0
  33. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/local_test.py +0 -0
  34. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python/storage.py +0 -0
  35. {oscar_python-1.3.1 → oscar_python-1.3.3}/oscar_python.egg-info/dependency_links.txt +0 -0
  36. {oscar_python-1.3.1 → oscar_python-1.3.3}/setup.cfg +0 -0
  37. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_client.py +0 -0
  38. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_default_client.py +0 -0
  39. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_onedata.py +0 -0
  40. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_s3.py +0 -0
  41. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_storage.py +0 -0
  42. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_utils.py +0 -0
  43. {oscar_python-1.3.1 → oscar_python-1.3.3}/tests/test_webdav.py +0 -0
@@ -0,0 +1,76 @@
1
+ # This workflow will upload a Python Package to PyPI when a release is created
2
+ # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries
3
+
4
+ name: Upload Python Package
5
+
6
+ on:
7
+ release:
8
+ types: [published]
9
+
10
+ permissions:
11
+ contents: read
12
+
13
+ jobs:
14
+ release-build:
15
+ runs-on: ubuntu-latest
16
+ outputs:
17
+ version: ${{ steps.get_version.outputs.version }}
18
+
19
+ steps:
20
+ - name: Checkout
21
+ uses: actions/checkout@v4
22
+ with:
23
+ # Fetch sufficient history for setuptools-scm to find tags
24
+ # Using 50 commits should cover most scenarios while being faster than full history
25
+ fetch-depth: 50
26
+
27
+ - name: Set up Python
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.12"
31
+
32
+ - name: Get version from setuptools-scm
33
+ id: get_version
34
+ run: |
35
+ python -m pip install setuptools-scm
36
+ version=$(python -m setuptools_scm)
37
+ echo "version=$version" >> $GITHUB_OUTPUT
38
+ echo "Package version: $version"
39
+
40
+ - name: Build release distributions
41
+ run: |
42
+ python -m pip install build
43
+ python -m build
44
+
45
+ - name: Upload distributions
46
+ uses: actions/upload-artifact@v4
47
+ with:
48
+ name: release-dists
49
+ path: dist/
50
+
51
+ pypi-publish:
52
+ runs-on: ubuntu-latest
53
+ needs:
54
+ - release-build
55
+ permissions:
56
+ # IMPORTANT: this permission is mandatory for trusted publishing
57
+ id-token: write
58
+
59
+ # Dedicated environments with protections for publishing are strongly recommended.
60
+ # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
61
+ environment:
62
+ name: pypi
63
+ # PyPI project URL with the exact version (e.g., 1.3.3 or 1.3.3b3)
64
+ url: https://pypi.org/project/oscar-python/${{ needs.release-build.outputs.version }}/
65
+
66
+ steps:
67
+ - name: Retrieve release distributions
68
+ uses: actions/download-artifact@v4
69
+ with:
70
+ name: release-dists
71
+ path: dist/
72
+
73
+ - name: Publish release distributions to PyPI
74
+ uses: pypa/gh-action-pypi-publish@release/v1
75
+ with:
76
+ packages-dir: dist/
@@ -0,0 +1,27 @@
1
+ name: tests
2
+
3
+ on:
4
+ push:
5
+ branches: ["main", "devel"]
6
+ pull_request:
7
+ branches: ["main", "devel"]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v4
15
+
16
+ - name: Set up Python 3.
17
+ uses: actions/setup-python@v5
18
+ with:
19
+ python-version: '3.12'
20
+
21
+ - name: Install dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ python -m pip install -e .[dev]
25
+
26
+ - name: Run tests
27
+ run: python -m pytest tests --cov=oscar_python
@@ -0,0 +1,160 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # poetry
98
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
+ #poetry.lock
103
+
104
+ # pdm
105
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
+ #pdm.lock
107
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
+ # in version control.
109
+ # https://pdm.fming.dev/#use-with-ide
110
+ .pdm.toml
111
+
112
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
+ __pypackages__/
114
+
115
+ # Celery stuff
116
+ celerybeat-schedule
117
+ celerybeat.pid
118
+
119
+ # SageMath parsed files
120
+ *.sage.py
121
+
122
+ # Environments
123
+ .env
124
+ .venv
125
+ env/
126
+ venv/
127
+ ENV/
128
+ env.bak/
129
+ venv.bak/
130
+
131
+ # Spyder project settings
132
+ .spyderproject
133
+ .spyproject
134
+
135
+ # Rope project settings
136
+ .ropeproject
137
+
138
+ # mkdocs documentation
139
+ /site
140
+
141
+ # mypy
142
+ .mypy_cache/
143
+ .dmypy.json
144
+ dmypy.json
145
+
146
+ # Pyre type checker
147
+ .pyre/
148
+
149
+ # pytype static type analyzer
150
+ .pytype/
151
+
152
+ # Cython debug symbols
153
+ cython_debug/
154
+
155
+ # PyCharm
156
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
159
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
+ #.idea/
@@ -1,21 +1,30 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: oscar-python
3
- Version: 1.3.1
4
- Summary: OSCAR API for python
5
- Home-page: https://github.com/grycap/oscar_python
6
- Author: GRyCAP - Universitat Politecnica de Valencia
7
- Author-email: calarcon@i3m.upv.es
8
- License: Apache 2.0
9
- Platform: UNKNOWN
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: License :: OSI Approved :: Apache Software License
3
+ Version: 1.3.3
4
+ Summary: Python client for OSCAR clusters
5
+ Author: GRyCAP - I3M - UPV
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/grycap/oscar-python
8
+ Project-URL: Repository, https://github.com/grycap/oscar-python
9
+ Keywords: oscar,faas,serverless
10
+ Requires-Python: >=3.8
12
11
  Description-Content-Type: text/markdown
13
12
  License-File: LICENSE
13
+ Requires-Dist: requests
14
+ Requires-Dist: webdavclient3>=3.14.6
15
+ Requires-Dist: boto3
16
+ Requires-Dist: pyyaml
17
+ Requires-Dist: aiohttp
18
+ Requires-Dist: liboidcagent
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: pytest-cov; extra == "dev"
22
+ Dynamic: license-file
14
23
 
15
24
  ## Python OSCAR client
16
25
 
17
- [![Build](https://github.com/grycap/oscar_python/actions/workflows/release.yaml/badge.svg)](https://github.com/grycap/oscar_python/actions/workflows/main.yaml)
18
- ![PyPI](https://img.shields.io/pypi/v/oscar_python)
26
+ [![Tests](https://github.com/grycap/oscar_python/actions/workflows/tests.yaml/badge.svg?branch=main)](https://github.com/grycap/oscar_python/actions/workflows/tests.yaml)
27
+ [![PyPI](https://img.shields.io/pypi/v/oscar-python)](https://pypi.org/project/oscar-python/)
19
28
 
20
29
  This package provides a client to interact with OSCAR (https://oscar.grycap.net) clusters and services. It is available on Pypi with the name [oscar-python](https://pypi.org/project/oscar-python/).
21
30
 
@@ -91,6 +100,7 @@ and `scopes`:
91
100
  'refresh_token':'token',
92
101
  'scopes': ["openid", "profile", "email"],
93
102
  'token_endpoint': "http://issuer.com/token",
103
+ 'client_id': "your_client_id"
94
104
  'ssl':'True'}
95
105
 
96
106
  client = Client(options = options_oidc_auth)
@@ -215,6 +225,8 @@ logs = client.get_job_logs("service_name", "job_id") # returns an http response
215
225
  ``` python
216
226
  # get a list of jobs in a service
217
227
  log_list = client.list_jobs("service_name") # returns an http response
228
+ # to get more jobs use the page parameter
229
+ log_list = client.list_jobs("service_name",page="token_to_next_page") # returns an http response
218
230
  ```
219
231
 
220
232
  **remove_job**
@@ -252,7 +264,7 @@ This method returns a JSON with the info except for OneData, which returns an HT
252
264
 
253
265
  ``` python
254
266
  # get a list of the files of one of the service storage provider
255
- files = storage_service.list_files_from_path("storage_provider") # returns json
267
+ files = storage_service.list_files_from_path("storage_provider", "remote_path") # returns json
256
268
  ```
257
269
 
258
270
  **upload_file**
@@ -266,5 +278,3 @@ response = storage_service.upload_file("storage_provider", "local_path", "remote
266
278
  # download a file from a remote path to a local path
267
279
  response = storage_service.download_file("storage_provider", "local_path", "remote_path")
268
280
  ```
269
-
270
-
@@ -1,7 +1,7 @@
1
1
  ## Python OSCAR client
2
2
 
3
- [![Build](https://github.com/grycap/oscar_python/actions/workflows/release.yaml/badge.svg)](https://github.com/grycap/oscar_python/actions/workflows/main.yaml)
4
- ![PyPI](https://img.shields.io/pypi/v/oscar_python)
3
+ [![Tests](https://github.com/grycap/oscar_python/actions/workflows/tests.yaml/badge.svg?branch=main)](https://github.com/grycap/oscar_python/actions/workflows/tests.yaml)
4
+ [![PyPI](https://img.shields.io/pypi/v/oscar-python)](https://pypi.org/project/oscar-python/)
5
5
 
6
6
  This package provides a client to interact with OSCAR (https://oscar.grycap.net) clusters and services. It is available on Pypi with the name [oscar-python](https://pypi.org/project/oscar-python/).
7
7
 
@@ -77,6 +77,7 @@ and `scopes`:
77
77
  'refresh_token':'token',
78
78
  'scopes': ["openid", "profile", "email"],
79
79
  'token_endpoint': "http://issuer.com/token",
80
+ 'client_id': "your_client_id"
80
81
  'ssl':'True'}
81
82
 
82
83
  client = Client(options = options_oidc_auth)
@@ -201,6 +202,8 @@ logs = client.get_job_logs("service_name", "job_id") # returns an http response
201
202
  ``` python
202
203
  # get a list of jobs in a service
203
204
  log_list = client.list_jobs("service_name") # returns an http response
205
+ # to get more jobs use the page parameter
206
+ log_list = client.list_jobs("service_name",page="token_to_next_page") # returns an http response
204
207
  ```
205
208
 
206
209
  **remove_job**
@@ -238,7 +241,7 @@ This method returns a JSON with the info except for OneData, which returns an HT
238
241
 
239
242
  ``` python
240
243
  # get a list of the files of one of the service storage provider
241
- files = storage_service.list_files_from_path("storage_provider") # returns json
244
+ files = storage_service.list_files_from_path("storage_provider", "remote_path") # returns json
242
245
  ```
243
246
 
244
247
  **upload_file**
@@ -0,0 +1,143 @@
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "### OSCAR API notebook example"
8
+ ]
9
+ },
10
+ {
11
+ "cell_type": "markdown",
12
+ "metadata": {},
13
+ "source": [
14
+ "This notebook is a sample of the usage of the python API with jupyter notebooks step by step. You can modify the parameters in the code and the service to test it with your own OSCAR cluster.\n",
15
+ "\n",
16
+ "The first step is to install the package from Pypi."
17
+ ]
18
+ },
19
+ {
20
+ "cell_type": "code",
21
+ "execution_count": null,
22
+ "metadata": {
23
+ "collapsed": true,
24
+ "jupyter": {
25
+ "outputs_hidden": true
26
+ },
27
+ "tags": []
28
+ },
29
+ "outputs": [],
30
+ "source": [
31
+ "# Install oscar-python package in the current Jupyter kernel\n",
32
+ "import sys\n",
33
+ "!{sys.executable} -m pip install oscar-python"
34
+ ]
35
+ },
36
+ {
37
+ "cell_type": "markdown",
38
+ "metadata": {},
39
+ "source": [
40
+ "With the package installed you can now create the client with your cluster credentials, enpoint and ID or cluster name."
41
+ ]
42
+ },
43
+ {
44
+ "cell_type": "code",
45
+ "execution_count": null,
46
+ "metadata": {},
47
+ "outputs": [],
48
+ "source": [
49
+ "# Import oscar_python library\n",
50
+ "from oscar_python.client import Client\n",
51
+ "client = Client(\"cluster-id\",\"https://your-cluster-endpoint.net\", \"user\", \"password\", True)"
52
+ ]
53
+ },
54
+ {
55
+ "cell_type": "markdown",
56
+ "metadata": {},
57
+ "source": [
58
+ "Once the client is created, you can call the function `create_service` with the path to the FDL file wich contains the function definition. To make it easier we recommend to have a folder for each service with their respective fdl and script within the path of the jupyter notebook. \n",
59
+ "\n",
60
+ "Also, the cluster ID on the FDL file has to match the one provided on the client definition, otherwise the function will throw an exception."
61
+ ]
62
+ },
63
+ {
64
+ "cell_type": "code",
65
+ "execution_count": null,
66
+ "metadata": {
67
+ "collapsed": true,
68
+ "jupyter": {
69
+ "outputs_hidden": true
70
+ },
71
+ "tags": []
72
+ },
73
+ "outputs": [],
74
+ "source": [
75
+ "# Create a service with the function create_service, which returns an error if something goes wrong or nothing if the service is created correctly\n",
76
+ "try:\n",
77
+ " client.create_service(\"services/cowsay_example/cowsay.yaml\")\n",
78
+ " print(\"Service created\")\n",
79
+ "except Exception as ex:\n",
80
+ " print(\"Error creating service: \", ex)"
81
+ ]
82
+ },
83
+ {
84
+ "cell_type": "markdown",
85
+ "metadata": {},
86
+ "source": [
87
+ "Then, you can run a synchronous invocation with the function `run_service` and the input parameters that the function requires."
88
+ ]
89
+ },
90
+ {
91
+ "cell_type": "code",
92
+ "execution_count": null,
93
+ "metadata": {
94
+ "collapsed": true,
95
+ "jupyter": {
96
+ "outputs_hidden": true
97
+ },
98
+ "tags": []
99
+ },
100
+ "outputs": [],
101
+ "source": [
102
+ "# Test the synchronous invocation of the service\n",
103
+ "try:\n",
104
+ " res = client.run_service(\"cowsay\", input = '{\"message\": \"Hi there\"}')\n",
105
+ " if res.status_code == 200:\n",
106
+ " print(res.text)\n",
107
+ "except Exception as ex:\n",
108
+ " print(\"Error running service: \", ex)"
109
+ ]
110
+ },
111
+ {
112
+ "cell_type": "code",
113
+ "execution_count": null,
114
+ "metadata": {},
115
+ "outputs": [],
116
+ "source": []
117
+ }
118
+ ],
119
+ "metadata": {
120
+ "interpreter": {
121
+ "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6"
122
+ },
123
+ "kernelspec": {
124
+ "display_name": "Python 3 (ipykernel)",
125
+ "language": "python",
126
+ "name": "python3"
127
+ },
128
+ "language_info": {
129
+ "codemirror_mode": {
130
+ "name": "ipython",
131
+ "version": 3
132
+ },
133
+ "file_extension": ".py",
134
+ "mimetype": "text/x-python",
135
+ "name": "python",
136
+ "nbconvert_exporter": "python",
137
+ "pygments_lexer": "ipython3",
138
+ "version": "3.9.7"
139
+ }
140
+ },
141
+ "nbformat": 4,
142
+ "nbformat_minor": 4
143
+ }
@@ -0,0 +1,12 @@
1
+ functions:
2
+ oscar:
3
+ - oscar-gpu-cluster:
4
+ name: cowsay
5
+ cpu: 1.0
6
+ memory: 1Gi
7
+ image: ghcr.io/grycap/cowsay
8
+ script: services/cowsay_example/script.sh
9
+ log_level: CRITICAL # To avoid supervisor logs in response
10
+ environment:
11
+ Variables:
12
+ INPUT_TYPE: json # Comment to set input string encoded in base64
@@ -0,0 +1,8 @@
1
+ #!/bin/sh
2
+
3
+ if [ "$INPUT_TYPE" = "json" ]
4
+ then
5
+ jq '.message' "$INPUT_FILE_PATH" -r | /usr/games/cowsay
6
+ else
7
+ cat "$INPUT_FILE_PATH" | /usr/games/cowsay
8
+ fi
@@ -77,14 +77,14 @@ class OIDC(object):
77
77
  return True
78
78
 
79
79
  @staticmethod
80
- def refresh_access_token(refresh_token, scopes, token_endpoint):
80
+ def refresh_access_token(refresh_token, scopes, token_endpoint, client_id="token-portal"):
81
81
  """
82
82
  Refresh the access token using the refresh token
83
83
  """
84
84
  data = {
85
85
  'grant_type': 'refresh_token',
86
86
  'refresh_token': refresh_token,
87
- 'client_id': 'token-portal',
87
+ 'client_id': client_id,
88
88
  'scope': ' '.join(scopes)
89
89
  }
90
90
 
@@ -41,6 +41,7 @@ _DELETE = "delete"
41
41
  # Default values for OIDC refresh token using EGI CheckIn
42
42
  _DEFAULT_SCOPES = ['openid', 'email', 'profile', 'voperson_id', 'eduperson_entitlement']
43
43
  _DEFAULT_TOKEN_ENDPOINT = 'https://aai.egi.eu/auth/realms/egi/protocol/openid-connect/token'
44
+ _DEFAULT_CLIENT_ID = 'token-portal'
44
45
 
45
46
 
46
47
  class Client(DefaultClient):
@@ -72,6 +73,8 @@ class Client(DefaultClient):
72
73
  self.token_endpoint = options.get('token_endpoint',
73
74
  _DEFAULT_TOKEN_ENDPOINT)
74
75
  self.ssl = bool(options['ssl'])
76
+ self.client_id = options.get('client_id',
77
+ _DEFAULT_CLIENT_ID)
75
78
 
76
79
  def set_auth_type(self, options):
77
80
  if 'user' in options:
@@ -91,7 +94,8 @@ class Client(DefaultClient):
91
94
  if self.refresh_token and OIDC.is_access_token_expired(self.oidc_token):
92
95
  self.oidc_token = OIDC.refresh_access_token(self.refresh_token,
93
96
  self.scopes,
94
- self.token_endpoint)
97
+ self.token_endpoint,
98
+ self.client_id)
95
99
  return self.oidc_token
96
100
 
97
101
  """ Creates a generic storage client to interact with the storage providers
@@ -132,9 +136,14 @@ class Client(DefaultClient):
132
136
  except KeyError as err:
133
137
  raise Exception("FDL clusterID does not match current clusterID: {0}".format(err))
134
138
  try:
135
- with open(svc["script"]) as s:
139
+ if os.path.isabs(svc["script"]):
140
+ script_path = svc["script"]
141
+ else:
142
+ fdl_directory = os.path.dirname(fdl_path)
143
+ script_path = os.path.join(fdl_directory, svc['script'])
144
+ with open(script_path) as s:
136
145
  svc["script"] = s.read()
137
- except IOError:
146
+ except IOError as e:
138
147
  raise Exception("Couldn't read script")
139
148
 
140
149
  # cpu parameter has to be string on the request
@@ -205,8 +214,8 @@ class Client(DefaultClient):
205
214
  return utils.make_request(self, _LOGS_PATH+"/"+svc+"/"+job, _GET)
206
215
 
207
216
  """ List a service jobs """
208
- def list_jobs(self, svc):
209
- return utils.make_request(self, _LOGS_PATH+"/"+svc, _GET)
217
+ def list_jobs(self, svc, page=""):
218
+ return utils.make_request(self, _LOGS_PATH+"/"+svc+"?page="+page, _GET)
210
219
 
211
220
  """ Remove a service job """
212
221
  def remove_job(self, svc, job):
@@ -1,21 +1,30 @@
1
- Metadata-Version: 2.1
2
- Name: oscar_python
3
- Version: 1.3.1
4
- Summary: OSCAR API for python
5
- Home-page: https://github.com/grycap/oscar_python
6
- Author: GRyCAP - Universitat Politecnica de Valencia
7
- Author-email: calarcon@i3m.upv.es
8
- License: Apache 2.0
9
- Platform: UNKNOWN
10
- Classifier: Programming Language :: Python :: 3
11
- Classifier: License :: OSI Approved :: Apache Software License
1
+ Metadata-Version: 2.4
2
+ Name: oscar-python
3
+ Version: 1.3.3
4
+ Summary: Python client for OSCAR clusters
5
+ Author: GRyCAP - I3M - UPV
6
+ License: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/grycap/oscar-python
8
+ Project-URL: Repository, https://github.com/grycap/oscar-python
9
+ Keywords: oscar,faas,serverless
10
+ Requires-Python: >=3.8
12
11
  Description-Content-Type: text/markdown
13
12
  License-File: LICENSE
13
+ Requires-Dist: requests
14
+ Requires-Dist: webdavclient3>=3.14.6
15
+ Requires-Dist: boto3
16
+ Requires-Dist: pyyaml
17
+ Requires-Dist: aiohttp
18
+ Requires-Dist: liboidcagent
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest; extra == "dev"
21
+ Requires-Dist: pytest-cov; extra == "dev"
22
+ Dynamic: license-file
14
23
 
15
24
  ## Python OSCAR client
16
25
 
17
- [![Build](https://github.com/grycap/oscar_python/actions/workflows/release.yaml/badge.svg)](https://github.com/grycap/oscar_python/actions/workflows/main.yaml)
18
- ![PyPI](https://img.shields.io/pypi/v/oscar_python)
26
+ [![Tests](https://github.com/grycap/oscar_python/actions/workflows/tests.yaml/badge.svg?branch=main)](https://github.com/grycap/oscar_python/actions/workflows/tests.yaml)
27
+ [![PyPI](https://img.shields.io/pypi/v/oscar-python)](https://pypi.org/project/oscar-python/)
19
28
 
20
29
  This package provides a client to interact with OSCAR (https://oscar.grycap.net) clusters and services. It is available on Pypi with the name [oscar-python](https://pypi.org/project/oscar-python/).
21
30
 
@@ -91,6 +100,7 @@ and `scopes`:
91
100
  'refresh_token':'token',
92
101
  'scopes': ["openid", "profile", "email"],
93
102
  'token_endpoint': "http://issuer.com/token",
103
+ 'client_id': "your_client_id"
94
104
  'ssl':'True'}
95
105
 
96
106
  client = Client(options = options_oidc_auth)
@@ -215,6 +225,8 @@ logs = client.get_job_logs("service_name", "job_id") # returns an http response
215
225
  ``` python
216
226
  # get a list of jobs in a service
217
227
  log_list = client.list_jobs("service_name") # returns an http response
228
+ # to get more jobs use the page parameter
229
+ log_list = client.list_jobs("service_name",page="token_to_next_page") # returns an http response
218
230
  ```
219
231
 
220
232
  **remove_job**
@@ -252,7 +264,7 @@ This method returns a JSON with the info except for OneData, which returns an HT
252
264
 
253
265
  ``` python
254
266
  # get a list of the files of one of the service storage provider
255
- files = storage_service.list_files_from_path("storage_provider") # returns json
267
+ files = storage_service.list_files_from_path("storage_provider", "remote_path") # returns json
256
268
  ```
257
269
 
258
270
  **upload_file**
@@ -266,5 +278,3 @@ response = storage_service.upload_file("storage_provider", "local_path", "remote
266
278
  # download a file from a remote path to a local path
267
279
  response = storage_service.download_file("storage_provider", "local_path", "remote_path")
268
280
  ```
269
-
270
-
@@ -1,6 +1,13 @@
1
+ .gitignore
1
2
  LICENSE
2
3
  README.md
4
+ pyproject.toml
3
5
  setup.py
6
+ .github/workflows/release-build.yaml
7
+ .github/workflows/tests.yaml
8
+ jupyter_example/oscar_notebook.ipynb
9
+ jupyter_example/services/cowsay_example/cowsay.yaml
10
+ jupyter_example/services/cowsay_example/script.sh
4
11
  oscar_python/__init__.py
5
12
  oscar_python/_oidc.py
6
13
  oscar_python/_utils.py
@@ -9,11 +16,9 @@ oscar_python/client_anon.py
9
16
  oscar_python/default_client.py
10
17
  oscar_python/local_test.py
11
18
  oscar_python/storage.py
12
- oscar_python/test_v2.py
13
19
  oscar_python.egg-info/PKG-INFO
14
20
  oscar_python.egg-info/SOURCES.txt
15
21
  oscar_python.egg-info/dependency_links.txt
16
- oscar_python.egg-info/not-zip-safe
17
22
  oscar_python.egg-info/requires.txt
18
23
  oscar_python.egg-info/top_level.txt
19
24
  oscar_python/_providers/_minio.py
@@ -0,0 +1,10 @@
1
+ requests
2
+ webdavclient3>=3.14.6
3
+ boto3
4
+ pyyaml
5
+ aiohttp
6
+ liboidcagent
7
+
8
+ [dev]
9
+ pytest
10
+ pytest-cov
@@ -0,0 +1 @@
1
+ oscar_python
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "setuptools-scm>=8"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "oscar-python"
7
+ dynamic = ["version"]
8
+ description = "Python client for OSCAR clusters"
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+ license = {text = "Apache-2.0"}
12
+ authors = [{name = "GRyCAP - I3M - UPV"}]
13
+ keywords = ["oscar", "faas", "serverless"]
14
+
15
+ dependencies = [
16
+ "requests",
17
+ "webdavclient3>=3.14.6",
18
+ "boto3",
19
+ "pyyaml",
20
+ "aiohttp",
21
+ "liboidcagent",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ dev = [
26
+ "pytest",
27
+ "pytest-cov",
28
+ ]
29
+
30
+ [project.urls]
31
+ Homepage = "https://github.com/grycap/oscar-python"
32
+ Repository = "https://github.com/grycap/oscar-python"
33
+
34
+ [tool.setuptools]
35
+ packages = ["oscar_python"]
36
+
37
+ [tool.setuptools_scm]
38
+ # Automatically get version from git tags
@@ -0,0 +1,21 @@
1
+ # Copyright (C) GRyCAP - I3M - UPV
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Minimal setup.py for backward compatibility.
16
+ All configuration is now in pyproject.toml.
17
+ """
18
+
19
+ from setuptools import setup
20
+
21
+ setup()
@@ -24,7 +24,8 @@ def test_refresh_access_token():
24
24
  mock_post.return_value = mock_response
25
25
  access_token = OIDC.refresh_access_token("old_refresh_token",
26
26
  ["openid", "profile", "email"],
27
- "http://test.com/token")
27
+ "http://test.com/token",
28
+ "token-portal")
28
29
 
29
30
  assert access_token == "new_access_token"
30
31
  mock_post.assert_called_once_with(
@@ -1,206 +0,0 @@
1
- import json
2
- import base64
3
- from client import Client
4
- #from client import Client
5
- from storage import Storage
6
- from client_anon import AnonymousClient
7
-
8
-
9
- def get_svc_test(client):
10
- response = client.get_service("cowsay")
11
- print(response)
12
-
13
- def cowsay_test_anon(client):
14
- text = {"message": "blyat"}
15
- tk = '38919156059e55805f66b81f74e8f6b59e0ba9e1f987900ed0a6eb0eb0aed82e'
16
- response = client.run_service("cowsay", token=tk, input=json.dumps(text))
17
- print(response.text)
18
-
19
- def cowsay_test_text(client):
20
- text = "blyat"
21
- response = client.run_service("cowsay", input=text)
22
- print(response.text)
23
-
24
- def plants_test_anon(client):
25
- tk = "201d9c9c252a47d70e61dacbf02353074921ddd4a39aaef16440949b604c2e26"
26
- image_in = "/home/calarcon/Pictures/plant2.jpg"
27
- response = client.run_service("ai4eosc-service", token= tk, input=image_in, timeout=400)
28
- print(response)
29
-
30
- def text_to_speech_test(client):
31
- file_in = "/home/caterina/Documentos/text-to-speech-coqui/text.txt"
32
- file_out = "/home/caterina/Documentos/text-to-speech-coqui/test-python-run-out.mp3"
33
- response = client.run_service("text-to-speech-coqui", input="si vose volve a desir uwu", output="test-tes-test.mp3", timeout=100)
34
- #print(response.text)
35
-
36
- def plants_sync_test(client):
37
- image_in = "/home/caterina/Documentos/egi_conference_2023/plants_example/images/cerezos.jpg"
38
- response = client.run_service("plant-classification", input=image_in, timeout=400)
39
-
40
-
41
- def grayify_test(client):
42
- response = client.run_service("grayify", input="/home/caterina/Documentos/imagemagick_example/images")
43
-
44
- def create_service_test(client):
45
- path = "/home/caterina/Documentos/imagemagick_example/imagemagick.yaml"
46
- return client.create_service(path)
47
-
48
- def json_definition_example():
49
- return {
50
- "name": "grayify",
51
- "memory": "1Gi",
52
- "cpu": "1.0",
53
- "total_memory": "1Gi",
54
- "total_cpu": "1.0",
55
- "log_level": "CRITICAL",
56
- "image": "ghcr.io/grycap/imagemagick",
57
- "alpine": True,
58
- "script": "#!/bin/bash \necho \'SCRIPT: Invoked Image Grayifier. File available in $INPUT_FILE_PATH\' \nFILE_NAME=`basename \'$INPUT_FILE_PATH\'` \nOUTPUT_FILE=\'$TMP_OUTPUT_DIR/$FILE_NAME\' \necho \'SCRIPT: Converting input image file $INPUT_FILE_PATH to grayscale to output file $OUTPUT_FILE\' \nconvert \'$INPUT_FILE_PATH\' -type Grayscale \'$OUTPUT_FILE\'",
59
- "image_pull_secrets": [
60
- ],
61
- "input": [
62
- {
63
- "storage_provider": "minio.default",
64
- "path": "grayify/input",
65
- "suffix": [
66
- ""
67
- ],
68
- "prefix": [
69
- ""
70
- ]
71
- }
72
- ],
73
- "output": [
74
- {
75
- "storage_provider": "minio.default",
76
- "path": "grayify/output",
77
- "suffix": [
78
- ""
79
- ],
80
- "prefix": [
81
- ""
82
- ]
83
- },
84
- {
85
- "storage_provider": "webdav.dcache",
86
- "path": "/Users/calarcon/grayify",
87
- "suffix": [
88
- ""
89
- ],
90
- "prefix": [
91
- ""
92
- ]
93
- }
94
- ],
95
- "storage_providers": {
96
- "minio": {
97
- "default": {
98
- "endpoint": "http://console.minio.wizardly-lamport0.im.grycap.net",
99
- "region": "us-west-1",
100
- "secret_key": "a1b2c3d4",
101
- "access_key": "minio",
102
- "verify": True
103
- }
104
- },
105
- "webdav": {
106
- "dcache": {
107
- "hostname": "prometheus.desy.de",
108
- "login": "calarcon",
109
- "password": "v5vsYhd2"
110
- }
111
- }
112
- }
113
- }
114
-
115
- def ai4eosc_test(client):
116
- service = {
117
- "log_level": "CRITICAL",
118
- "memory": "1Gi",
119
- "cluster_id": "oscar-cluster",
120
- "name": "test2",
121
- "cpu": "1.0",
122
- "vo": "vo.ai4eosc.eu",
123
- "image": "deephdc/deep-oc-plants-classification-tf",
124
- "alpine": False,
125
- "script": "#!/bin/bash",
126
- "allowed_users" : []
127
- }
128
- res = client.create_service(service)
129
- print(res.text)
130
-
131
- def get_service_base_definition():
132
- """
133
- Base parameters of an OSCAR service
134
-
135
- """
136
- return {
137
-
138
- "log_level": "CRITICAL",
139
- "alpine": False,
140
- "script": "#!/bin/bash \nFILE_NAME=`basename $INPUT_FILE_PATH` \
141
- \nOUTPUT_FILE=\"$TMP_OUTPUT_DIR/$FILE_NAME\"\
142
- \necho \"SCRIPT: Invoked deepaas-predict command. File available in $INPUT_FILE_PATH.\" \
143
- \deepaas-predict -i $INPUT_FILE_PATH -o $OUTPUT_FILE"
144
- }
145
-
146
- def main():
147
-
148
- #client.remove_service(svc_name)
149
- #local_client = Client("oscar-test","http://localhost", "oscar", "MTY5Yjc0", False)
150
-
151
- # Options for basic auth login
152
- options_basic_auth = {'cluster_id':'oscar-egi-cluster',
153
- 'endpoint':'https://funny-kalam8.im.grycap.net',
154
- 'user':'oscar',
155
- 'password':'oscar123',
156
- 'ssl':'True'}
157
-
158
- options_egi = {'cluster_id':'oscar-cluster',
159
- 'endpoint':'https://oscar.test.fedcloud.eu/',
160
- 'shortname':'calarcon',
161
- 'ssl':'True'}
162
-
163
- SERVICE_NAME = "grayify"
164
- token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJQVVlPaXJBM1ktZF9kR3BkajRpSkRIdzR6SGE4SVktYmhaZGFFajByamJVIn0.eyJleHAiOjE3MTY4MDMwMDksImlhdCI6MTcxNjc5OTQwOSwiYXV0aF90aW1lIjoxNzE2Nzk1NDgzLCJqdGkiOiI0OTBmNDdlNy00NTc2LTRjODYtYWUyMy00ZjIxNDUzZDEzMjMiLCJpc3MiOiJodHRwczovL2FhaS5lZ2kuZXUvYXV0aC9yZWFsbXMvZWdpIiwic3ViIjoiNjJiYjExYjQwMzk4ZjczNzc4YjY2ZjM0NGQyODIyNDJkZWJiOGVlM2ViYjEwNjcxN2ExMjNjYTIxMzE2MjkyNkBlZ2kuZXUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJpbS1kYXNoYm9hcmQiLCJzZXNzaW9uX3N0YXRlIjoiMjhiMjU5OGUtYmQ2YS00Y2UzLWI4MDUtNDgyNWRmNGQ2ZjM0Iiwic2NvcGUiOiJvcGVuaWQgb2ZmbGluZV9hY2Nlc3MgZWR1cGVyc29uX2VudGl0bGVtZW50IHByb2ZpbGUgZW1haWwiLCJzaWQiOiIyOGIyNTk4ZS1iZDZhLTRjZTMtYjgwNS00ODI1ZGY0ZDZmMzQiLCJhdXRoZW50aWNhdGluZ19hdXRob3JpdHkiOiJodHRwczovL3d3dy5yZWRpcmlzLmVzL3Npci91cHZpZHAifQ.aZib2Rypqy-XGjPn4ycmEA4u1nlNUb45zz4ry8yZevAdna3lNzEIvxsfwYpjgAvmiDEzrJMYRNAm2652EgvCPUK4bnn9qJuzPhEfSpRbam_jDxmG9MiX6XlKSIO-UqlJQLuDxAAAGuxhdvfqffaT9rZ10042w6-0qTvSiXtNOvFkusc4iVHp8eBcr469txMFvEcWoV8uPXtTL6bl8rbEQMEo2KT1p9twzVpL1WQNIa0XrVa4pfIS3V_IDCKjcDl8PmV3N7KKKkIiQEFg13FS6TSLEs2peszi8eqSAXX2Lq27eSxl0pPH3ZTcrA7vI5dyTKSi7qoK7lsKtHZJOvOCvw"
165
- options_egi_oidc = {'cluster_id':'oscar-egi-oidc',
166
- 'endpoint':'https://inference.cloud.ai4eosc.eu',
167
- 'oidc_token': token,
168
- 'ssl':'True'}
169
-
170
- #client = Client("oscar-cluster","https://sleepy-brown8.im.grycap.net", "oscar", "oscar123", True)
171
- anon_client = AnonymousClient({
172
- 'cluster_id':'oscar-cluster',
173
- 'endpoint':'https://funny-kalam8.im.grycap.net',
174
- 'ssl':'true'
175
- })
176
-
177
- #get_svc_test(anon_client)
178
-
179
- try:
180
- client = Client(options = options_egi)
181
- print("Client created!!")
182
- except:
183
- print("Error creating OSCAR client!!!!11")
184
-
185
- # res = client.run_service(SERVICE_NAME, input="/home/calarcon/Pictures/cat.jpg", output=".")
186
- # print(res)
187
- storage = client.create_storage_client()
188
- print(storage.storage_providers)
189
- print("------------------------")
190
- storage = client.create_storage_client("grayify")
191
- print(storage.storage_providers)
192
- #cowsay_test_text(client)
193
- #get_svc_test(client)
194
- #grayify_storage = client.create_storage_client(svc_name)
195
- #stablediff_storage = client.create_storage_client("stable-diffusion")
196
-
197
- # Download files test
198
- #res = stablediff_storage.download_file("minio.default", "/home/caterina/Documentos/oscar_python_package", "stable-diffusion/out/text1.zip")
199
- #res = grayify_storage.download_file("minio.default", "/home/caterina/Documentos/oscar_python_package", "gray/output/image1.jpg")
200
-
201
- # Upload files test
202
- #res = stablediff_storage.upload_file("minio.default", "/home/caterina/Documentos/txt_to_img/text1.txt", "stable-diffusion/in")
203
- #res = grayify_storage.upload_file("minio.default", "/home/caterina/Documentos/imagemagick_example/images/image2.jpeg", "gray/input")
204
-
205
- if __name__ == "__main__":
206
- main()
@@ -1,7 +0,0 @@
1
- aiohttp
2
- boto3
3
- liboidcagent
4
- pyyaml
5
- requests
6
- setuptools>=40.8.0
7
- webdavclient3==3.14.6
@@ -1,5 +0,0 @@
1
- build
2
- dist
3
- jupyter_example
4
- oscar_python
5
- tests
@@ -1,49 +0,0 @@
1
- # Copyright (C) GRyCAP - I3M - UPV
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- from setuptools import setup, find_namespace_packages
16
-
17
- # Load readme
18
- with open('README.md', mode='r', encoding='utf-8') as f:
19
- readme = f.read()
20
-
21
- # Load version
22
- with open('version.py', mode='r', encoding='utf-8') as f:
23
- exec(f.read())
24
-
25
-
26
- setup(name='oscar_python',
27
- version=__version__,
28
- description='OSCAR API for python',
29
- long_description=readme,
30
- long_description_content_type='text/markdown',
31
- url='https://github.com/grycap/oscar_python',
32
- author='GRyCAP - Universitat Politecnica de Valencia',
33
- author_email='calarcon@i3m.upv.es',
34
- license='Apache 2.0',
35
- packages=find_namespace_packages(),
36
- install_requires=[
37
- 'webdavclient3 == 3.14.6',
38
- 'requests',
39
- 'boto3',
40
- 'setuptools >= 40.8.0',
41
- 'pyyaml',
42
- 'aiohttp',
43
- 'liboidcagent',
44
- ],
45
- classifiers=[
46
- 'Programming Language :: Python :: 3',
47
- 'License :: OSI Approved :: Apache Software License'
48
- ],
49
- zip_safe=False)
File without changes
File without changes