evo-files 0.1.0__tar.gz → 0.2.0__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.
- evo_files-0.2.0/.gitignore +24 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/PKG-INFO +28 -8
- evo_files-0.2.0/pyproject.toml +73 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/io.py +1 -1
- evo_files-0.2.0/src/evo/files/py.typed +0 -0
- evo_files-0.1.0/README.md +0 -42
- evo_files-0.1.0/pyproject.toml +0 -65
- evo_files-0.1.0/setup.cfg +0 -4
- evo_files-0.1.0/src/evo_files.egg-info/PKG-INFO +0 -58
- evo_files-0.1.0/src/evo_files.egg-info/SOURCES.txt +0 -20
- evo_files-0.1.0/src/evo_files.egg-info/dependency_links.txt +0 -1
- evo_files-0.1.0/src/evo_files.egg-info/requires.txt +0 -8
- evo_files-0.1.0/src/evo_files.egg-info/top_level.txt +0 -1
- evo_files-0.1.0/tests/test_file_api_client.py +0 -534
- evo_files-0.1.0/tests/test_file_io.py +0 -152
- evo_files-0.1.0/tests/test_make_name_safe.py +0 -54
- {evo_files-0.1.0 → evo_files-0.2.0}/LICENSE.md +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/__init__.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/_model_config.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/client.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/data.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/endpoints/__init__.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/endpoints/api/__init__.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/endpoints/api/file_v2_api.py +0 -0
- {evo_files-0.1.0 → evo_files-0.2.0}/src/evo/files/endpoints/models.py +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# IDE Settings
|
|
2
|
+
.idea/
|
|
3
|
+
.project
|
|
4
|
+
.pydevproject
|
|
5
|
+
.vscode/
|
|
6
|
+
|
|
7
|
+
# Distribution / Packaging
|
|
8
|
+
*.egg*
|
|
9
|
+
*.whl
|
|
10
|
+
__pycache__/
|
|
11
|
+
site/
|
|
12
|
+
build/
|
|
13
|
+
|
|
14
|
+
# Reporting
|
|
15
|
+
.coverage
|
|
16
|
+
|
|
17
|
+
# Environmnents
|
|
18
|
+
venv/
|
|
19
|
+
venv*/
|
|
20
|
+
.venv/
|
|
21
|
+
.env
|
|
22
|
+
.tox/
|
|
23
|
+
|
|
24
|
+
.DS_store
|
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: evo-files
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Python SDK for using the Seequent Evo File API
|
|
5
|
+
Project-URL: Source, https://github.com/SeequentEvo/evo-python-sdk
|
|
6
|
+
Project-URL: Tracker, https://github.com/SeequentEvo/evo-python-sdk/issues
|
|
7
|
+
Project-URL: Homepage, https://www.seequent.com/
|
|
8
|
+
Project-URL: Documentation, https://developer.seequent.com/
|
|
5
9
|
Author-email: Seequent <support@seequent.com>
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
10
|
License-File: LICENSE.md
|
|
11
|
+
Requires-Python: >=3.10
|
|
9
12
|
Requires-Dist: evo-sdk-common>=0.1.0
|
|
10
13
|
Requires-Dist: pydantic<3,>=2
|
|
11
14
|
Provides-Extra: aiohttp
|
|
12
|
-
Requires-Dist: evo-sdk-common[aiohttp]>=0.1.0; extra ==
|
|
15
|
+
Requires-Dist: evo-sdk-common[aiohttp]>=0.1.0; extra == 'aiohttp'
|
|
13
16
|
Provides-Extra: notebooks
|
|
14
|
-
Requires-Dist: evo-sdk-common[notebooks]>=0.1.0; extra ==
|
|
15
|
-
|
|
17
|
+
Requires-Dist: evo-sdk-common[notebooks]>=0.1.0; extra == 'notebooks'
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
16
19
|
|
|
17
20
|
<p align="center"><a href="https://seequent.com" target="_blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://developer.seequent.com/img/seequent-logo-dark.svg" alt="Seequent logo" width="400" /><img src="https://developer.seequent.com/img/seequent-logo.svg" alt="Seequent logo" width="400" /></picture></a></p>
|
|
18
21
|
<p align="center">
|
|
22
|
+
<a href="https://pypi.org/project/evo-files/"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/evo-files" /></a>
|
|
19
23
|
<a href="https://github.com/SeequentEvo/evo-python-sdk/actions/workflows/on-push.yaml"><img src="https://github.com/SeequentEvo/evo-python-sdk/actions/workflows/on-push.yaml/badge.svg" alt="" /></a>
|
|
20
24
|
</p>
|
|
21
25
|
<p align="center">
|
|
22
26
|
<a href="https://developer.seequent.com/" target="_blank">Seequent Developer Portal</a>
|
|
23
|
-
• <a href="https://community.seequent.com/" target="_blank">Seequent Community</a>
|
|
27
|
+
• <a href="https://community.seequent.com/group/19-evo" target="_blank">Seequent Community</a>
|
|
24
28
|
• <a href="https://seequent.com" target="_blank">Seequent website</a>
|
|
25
29
|
</p>
|
|
26
30
|
|
|
@@ -36,12 +40,28 @@ formats and sizes are accepted.
|
|
|
36
40
|
pip install evo-files
|
|
37
41
|
```
|
|
38
42
|
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
To get up and running quickly with the Evo File SDK, start by configuring your
|
|
46
|
+
[environment and API connector](https://github.com/SeequentEvo/evo-python-sdk/blob/main/packages/evo-sdk-common/docs/quickstart.md).
|
|
47
|
+
|
|
48
|
+
You can then use the `FileAPIClient` to perform operations, for example:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from evo.files import FileAPIClient
|
|
52
|
+
|
|
53
|
+
file_client = FileAPIClient(environment, connector)
|
|
54
|
+
files = await file_client.list_files()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
For some interactive Jupyter notebook examples, see the [examples folder](https://github.com/SeequentEvo/evo-python-sdk/tree/main/packages/evo-files/docs/examples).
|
|
58
|
+
|
|
39
59
|
## Developing the library
|
|
40
60
|
|
|
41
61
|
For instructions on contributing to the development of this library, please refer to the [evo-python-sdk documentation](https://github.com/seequentevo/evo-python-sdk).
|
|
42
62
|
|
|
43
63
|
## License
|
|
44
|
-
The Python SDK for Evo is open source and licensed under the [Apache 2.0 license.](
|
|
64
|
+
The Python SDK for Evo is open source and licensed under the [Apache 2.0 license.](https://github.com/SeequentEvo/evo-python-sdk/tree/main/packages/evo-files/./LICENSE.md).
|
|
45
65
|
|
|
46
66
|
Copyright © 2025 Bentley Systems, Incorporated.
|
|
47
67
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "evo-files"
|
|
3
|
+
description = "Python SDK for using the Seequent Evo File API"
|
|
4
|
+
version = "0.2.0"
|
|
5
|
+
requires-python = ">=3.10"
|
|
6
|
+
license-files = ["LICENSE.md"]
|
|
7
|
+
dynamic = ["readme"]
|
|
8
|
+
authors = [
|
|
9
|
+
{ name = "Seequent", email = "support@seequent.com" }
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
dependencies = [
|
|
13
|
+
"evo-sdk-common>=0.1.0",
|
|
14
|
+
"pydantic>=2,<3",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Source = "https://github.com/SeequentEvo/evo-python-sdk"
|
|
19
|
+
Tracker = "https://github.com/SeequentEvo/evo-python-sdk/issues"
|
|
20
|
+
Homepage = "https://www.seequent.com/"
|
|
21
|
+
Documentation = "https://developer.seequent.com/"
|
|
22
|
+
|
|
23
|
+
[project.optional-dependencies]
|
|
24
|
+
aiohttp = ["evo-sdk-common[aiohttp]>=0.1.0"]
|
|
25
|
+
notebooks = ["evo-sdk-common[notebooks]>=0.1.0"]
|
|
26
|
+
|
|
27
|
+
[dependency-groups]
|
|
28
|
+
# Dev dependencies. The version is left unspecified so the latest is installed.
|
|
29
|
+
test = [
|
|
30
|
+
"evo-files[aiohttp]",
|
|
31
|
+
"parameterized==0.9.0",
|
|
32
|
+
"pytest",
|
|
33
|
+
]
|
|
34
|
+
dev = [
|
|
35
|
+
"evo-files[aiohttp]",
|
|
36
|
+
"bumpver",
|
|
37
|
+
"coverage[toml]",
|
|
38
|
+
"ruff",
|
|
39
|
+
{include-group="test"},
|
|
40
|
+
]
|
|
41
|
+
notebooks = [
|
|
42
|
+
"evo-files[aiohttp,notebooks]",
|
|
43
|
+
"jupyter",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.ruff]
|
|
47
|
+
src = ["src", "tests"]
|
|
48
|
+
line-length = 120
|
|
49
|
+
|
|
50
|
+
[tool.ruff.lint]
|
|
51
|
+
extend-select = ["I", "RUF022"]
|
|
52
|
+
|
|
53
|
+
[build-system]
|
|
54
|
+
requires = ["hatchling", "hatch-fancy-pypi-readme"]
|
|
55
|
+
build-backend = "hatchling.build"
|
|
56
|
+
|
|
57
|
+
[tool.hatch.build.targets.sdist]
|
|
58
|
+
include = ["src"]
|
|
59
|
+
|
|
60
|
+
[tool.hatch.build.targets.wheel]
|
|
61
|
+
packages = ["src/evo"]
|
|
62
|
+
|
|
63
|
+
[tool.hatch.metadata.hooks.fancy-pypi-readme]
|
|
64
|
+
content-type = "text/markdown"
|
|
65
|
+
|
|
66
|
+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
|
|
67
|
+
path = "README.md"
|
|
68
|
+
|
|
69
|
+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
|
70
|
+
# Literal TOML strings (single quotes) need no escaping of backslashes.
|
|
71
|
+
# Converts relative links to absolute links in PyPI
|
|
72
|
+
pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)'
|
|
73
|
+
replacement = '[\1](https://github.com/SeequentEvo/evo-python-sdk/tree/main/packages/$HFPR_PACKAGE_NAME/\g<2>)'
|
|
@@ -144,7 +144,7 @@ class FileAPIDownload(Download[FileMetadata], _FileIOMixin):
|
|
|
144
144
|
def __init__(self, connector: APIConnector, metadata: FileMetadata, initial_url: str) -> None:
|
|
145
145
|
"""
|
|
146
146
|
:param connector: The connector to use for the API calls.
|
|
147
|
-
:param metadata: The metadata of the file that
|
|
147
|
+
:param metadata: The metadata of the file that will be downloaded.
|
|
148
148
|
:param initial_url: The initial URL to use for the download.
|
|
149
149
|
"""
|
|
150
150
|
super().__init__(connector, initial_url)
|
|
File without changes
|
evo_files-0.1.0/README.md
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
<p align="center"><a href="https://seequent.com" target="_blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://developer.seequent.com/img/seequent-logo-dark.svg" alt="Seequent logo" width="400" /><img src="https://developer.seequent.com/img/seequent-logo.svg" alt="Seequent logo" width="400" /></picture></a></p>
|
|
2
|
-
<p align="center">
|
|
3
|
-
<a href="https://github.com/SeequentEvo/evo-python-sdk/actions/workflows/on-push.yaml"><img src="https://github.com/SeequentEvo/evo-python-sdk/actions/workflows/on-push.yaml/badge.svg" alt="" /></a>
|
|
4
|
-
</p>
|
|
5
|
-
<p align="center">
|
|
6
|
-
<a href="https://developer.seequent.com/" target="_blank">Seequent Developer Portal</a>
|
|
7
|
-
• <a href="https://community.seequent.com/" target="_blank">Seequent Community</a>
|
|
8
|
-
• <a href="https://seequent.com" target="_blank">Seequent website</a>
|
|
9
|
-
</p>
|
|
10
|
-
|
|
11
|
-
# Evo File API Client
|
|
12
|
-
|
|
13
|
-
The File API provides the ability to manage files of any type or size, associated with your Evo workspace.
|
|
14
|
-
Enable your product with Evo connected workflows by integrating with the Seequent Evo File API. Most file
|
|
15
|
-
formats and sizes are accepted.
|
|
16
|
-
|
|
17
|
-
## Installation
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
pip install evo-files
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
## Developing the library
|
|
24
|
-
|
|
25
|
-
For instructions on contributing to the development of this library, please refer to the [evo-python-sdk documentation](https://github.com/seequentevo/evo-python-sdk).
|
|
26
|
-
|
|
27
|
-
## License
|
|
28
|
-
The Python SDK for Evo is open source and licensed under the [Apache 2.0 license.](./LICENSE.md).
|
|
29
|
-
|
|
30
|
-
Copyright © 2025 Bentley Systems, Incorporated.
|
|
31
|
-
|
|
32
|
-
Licensed under the Apache License, Version 2.0 (the "License").
|
|
33
|
-
You may obtain a copy of the License at
|
|
34
|
-
|
|
35
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
36
|
-
|
|
37
|
-
Unless required by applicable law or agreed to in writing, software
|
|
38
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
39
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
40
|
-
See the License for the specific language governing permissions and
|
|
41
|
-
limitations under the License.
|
|
42
|
-
|
evo_files-0.1.0/pyproject.toml
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools >= 61.0.0"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "evo-files"
|
|
7
|
-
description = "Python SDK for using the Seequent Evo File API"
|
|
8
|
-
version = "0.1.0"
|
|
9
|
-
requires-python = ">=3.10"
|
|
10
|
-
license-files = ["LICENSE.md"]
|
|
11
|
-
readme = "README.md"
|
|
12
|
-
authors = [
|
|
13
|
-
{ name = "Seequent", email = "support@seequent.com" }
|
|
14
|
-
]
|
|
15
|
-
dependencies = [
|
|
16
|
-
"evo-sdk-common>=0.1.0",
|
|
17
|
-
"pydantic>=2,<3",
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
[project.optional-dependencies]
|
|
21
|
-
aiohttp = ["evo-sdk-common[aiohttp]>=0.1.0"]
|
|
22
|
-
notebooks = ["evo-sdk-common[notebooks]>=0.1.0"]
|
|
23
|
-
|
|
24
|
-
[dependency-groups]
|
|
25
|
-
# Dev dependencies. The version is left unspecified so the latest is installed.
|
|
26
|
-
test = [
|
|
27
|
-
"evo-files[aiohttp]",
|
|
28
|
-
"parameterized==0.9.0",
|
|
29
|
-
"pytest",
|
|
30
|
-
]
|
|
31
|
-
dev = [
|
|
32
|
-
"evo-files[aiohttp]",
|
|
33
|
-
"bumpver",
|
|
34
|
-
"coverage[toml]",
|
|
35
|
-
"ruff",
|
|
36
|
-
{include-group="test"},
|
|
37
|
-
]
|
|
38
|
-
notebooks = [
|
|
39
|
-
"evo-files[aiohttp,notebooks]",
|
|
40
|
-
"jupyter",
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
[tool.setuptools.packages.find]
|
|
44
|
-
where = ["src"]
|
|
45
|
-
namespaces = true
|
|
46
|
-
|
|
47
|
-
[tool.ruff]
|
|
48
|
-
src = ["src", "tests"]
|
|
49
|
-
line-length = 120
|
|
50
|
-
|
|
51
|
-
[tool.ruff.lint]
|
|
52
|
-
extend-select = ["I", "RUF022"]
|
|
53
|
-
|
|
54
|
-
[tool.bumpver]
|
|
55
|
-
current_version = "v0.1.0"
|
|
56
|
-
version_pattern = "vMAJOR.MINOR.PATCH[.PYTAGNUM]"
|
|
57
|
-
commit = true
|
|
58
|
-
tag = true
|
|
59
|
-
commit_message = "Bump version from {old_version} to {new_version}"
|
|
60
|
-
|
|
61
|
-
[tool.bumpver.file_patterns]
|
|
62
|
-
"pyproject.toml" = [
|
|
63
|
-
'version = "{pep440_version}"',
|
|
64
|
-
'current_version = "{version}"',
|
|
65
|
-
]
|
evo_files-0.1.0/setup.cfg
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: evo-files
|
|
3
|
-
Version: 0.1.0
|
|
4
|
-
Summary: Python SDK for using the Seequent Evo File API
|
|
5
|
-
Author-email: Seequent <support@seequent.com>
|
|
6
|
-
Requires-Python: >=3.10
|
|
7
|
-
Description-Content-Type: text/markdown
|
|
8
|
-
License-File: LICENSE.md
|
|
9
|
-
Requires-Dist: evo-sdk-common>=0.1.0
|
|
10
|
-
Requires-Dist: pydantic<3,>=2
|
|
11
|
-
Provides-Extra: aiohttp
|
|
12
|
-
Requires-Dist: evo-sdk-common[aiohttp]>=0.1.0; extra == "aiohttp"
|
|
13
|
-
Provides-Extra: notebooks
|
|
14
|
-
Requires-Dist: evo-sdk-common[notebooks]>=0.1.0; extra == "notebooks"
|
|
15
|
-
Dynamic: license-file
|
|
16
|
-
|
|
17
|
-
<p align="center"><a href="https://seequent.com" target="_blank"><picture><source media="(prefers-color-scheme: dark)" srcset="https://developer.seequent.com/img/seequent-logo-dark.svg" alt="Seequent logo" width="400" /><img src="https://developer.seequent.com/img/seequent-logo.svg" alt="Seequent logo" width="400" /></picture></a></p>
|
|
18
|
-
<p align="center">
|
|
19
|
-
<a href="https://github.com/SeequentEvo/evo-python-sdk/actions/workflows/on-push.yaml"><img src="https://github.com/SeequentEvo/evo-python-sdk/actions/workflows/on-push.yaml/badge.svg" alt="" /></a>
|
|
20
|
-
</p>
|
|
21
|
-
<p align="center">
|
|
22
|
-
<a href="https://developer.seequent.com/" target="_blank">Seequent Developer Portal</a>
|
|
23
|
-
• <a href="https://community.seequent.com/" target="_blank">Seequent Community</a>
|
|
24
|
-
• <a href="https://seequent.com" target="_blank">Seequent website</a>
|
|
25
|
-
</p>
|
|
26
|
-
|
|
27
|
-
# Evo File API Client
|
|
28
|
-
|
|
29
|
-
The File API provides the ability to manage files of any type or size, associated with your Evo workspace.
|
|
30
|
-
Enable your product with Evo connected workflows by integrating with the Seequent Evo File API. Most file
|
|
31
|
-
formats and sizes are accepted.
|
|
32
|
-
|
|
33
|
-
## Installation
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
pip install evo-files
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
## Developing the library
|
|
40
|
-
|
|
41
|
-
For instructions on contributing to the development of this library, please refer to the [evo-python-sdk documentation](https://github.com/seequentevo/evo-python-sdk).
|
|
42
|
-
|
|
43
|
-
## License
|
|
44
|
-
The Python SDK for Evo is open source and licensed under the [Apache 2.0 license.](./LICENSE.md).
|
|
45
|
-
|
|
46
|
-
Copyright © 2025 Bentley Systems, Incorporated.
|
|
47
|
-
|
|
48
|
-
Licensed under the Apache License, Version 2.0 (the "License").
|
|
49
|
-
You may obtain a copy of the License at
|
|
50
|
-
|
|
51
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
52
|
-
|
|
53
|
-
Unless required by applicable law or agreed to in writing, software
|
|
54
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
55
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
56
|
-
See the License for the specific language governing permissions and
|
|
57
|
-
limitations under the License.
|
|
58
|
-
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
LICENSE.md
|
|
2
|
-
README.md
|
|
3
|
-
pyproject.toml
|
|
4
|
-
src/evo/files/__init__.py
|
|
5
|
-
src/evo/files/_model_config.py
|
|
6
|
-
src/evo/files/client.py
|
|
7
|
-
src/evo/files/data.py
|
|
8
|
-
src/evo/files/io.py
|
|
9
|
-
src/evo/files/endpoints/__init__.py
|
|
10
|
-
src/evo/files/endpoints/models.py
|
|
11
|
-
src/evo/files/endpoints/api/__init__.py
|
|
12
|
-
src/evo/files/endpoints/api/file_v2_api.py
|
|
13
|
-
src/evo_files.egg-info/PKG-INFO
|
|
14
|
-
src/evo_files.egg-info/SOURCES.txt
|
|
15
|
-
src/evo_files.egg-info/dependency_links.txt
|
|
16
|
-
src/evo_files.egg-info/requires.txt
|
|
17
|
-
src/evo_files.egg-info/top_level.txt
|
|
18
|
-
tests/test_file_api_client.py
|
|
19
|
-
tests/test_file_io.py
|
|
20
|
-
tests/test_make_name_safe.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
evo
|
|
@@ -1,534 +0,0 @@
|
|
|
1
|
-
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
-
# you may not use this file except in compliance with the License.
|
|
4
|
-
# You may obtain a copy of the License at
|
|
5
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
-
# See the License for the specific language governing permissions and
|
|
10
|
-
# limitations under the License.
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
from unittest import mock
|
|
14
|
-
from uuid import UUID
|
|
15
|
-
|
|
16
|
-
from data import load_test_data
|
|
17
|
-
from evo.common import Environment, HealthCheckType, Page, RequestMethod, ServiceUser
|
|
18
|
-
from evo.common.test_tools import BASE_URL, ORG, WORKSPACE_ID, MockResponse, TestWithConnector, utc_datetime
|
|
19
|
-
from evo.files import FileAPIClient, FileAPIDownload, FileAPIUpload, FileMetadata, FileVersion
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class TestFileApiClient(TestWithConnector):
|
|
23
|
-
def setUp(self) -> None:
|
|
24
|
-
TestWithConnector.setUp(self)
|
|
25
|
-
self.environment = Environment(hub_url=BASE_URL, org_id=ORG.id, workspace_id=WORKSPACE_ID)
|
|
26
|
-
self.file_api_client = FileAPIClient(connector=self.connector, environment=self.environment)
|
|
27
|
-
|
|
28
|
-
@property
|
|
29
|
-
def base_path(self) -> str:
|
|
30
|
-
return f"file/v2/orgs/{self.environment.org_id}/workspaces/{self.environment.workspace_id}"
|
|
31
|
-
|
|
32
|
-
async def test_check_service_health(self) -> None:
|
|
33
|
-
"""Test service health check implementation"""
|
|
34
|
-
with mock.patch("evo.files.client.get_service_health", spec_set=True) as mock_get_service_health:
|
|
35
|
-
await self.file_api_client.get_service_health()
|
|
36
|
-
mock_get_service_health.assert_called_once_with(self.connector, "file", check_type=HealthCheckType.FULL)
|
|
37
|
-
|
|
38
|
-
async def test_list_files_default_args(self) -> None:
|
|
39
|
-
empty_content = load_test_data("list_files_empty.json")
|
|
40
|
-
with self.transport.set_http_response(
|
|
41
|
-
200, json.dumps(empty_content), headers={"Content-Type": "application/json"}
|
|
42
|
-
):
|
|
43
|
-
page = await self.file_api_client.list_files()
|
|
44
|
-
self.assertIsInstance(page, Page)
|
|
45
|
-
self.assertEqual([], page.items())
|
|
46
|
-
self.assert_request_made(
|
|
47
|
-
method=RequestMethod.GET,
|
|
48
|
-
path=f"{self.base_path}/files?limit=5000&offset=0",
|
|
49
|
-
headers={"Accept": "application/json"},
|
|
50
|
-
)
|
|
51
|
-
|
|
52
|
-
async def test_list_files_all_args(self) -> None:
|
|
53
|
-
empty_content = load_test_data("list_files_empty.json")
|
|
54
|
-
with self.transport.set_http_response(
|
|
55
|
-
200, json.dumps(empty_content), headers={"Content-Type": "application/json"}
|
|
56
|
-
):
|
|
57
|
-
page = await self.file_api_client.list_files(limit=20, offset=10, name="x.csv")
|
|
58
|
-
self.assertIsInstance(page, Page)
|
|
59
|
-
self.assertEqual([], page.items())
|
|
60
|
-
self.assert_request_made(
|
|
61
|
-
method=RequestMethod.GET,
|
|
62
|
-
path=f"{self.base_path}/files?limit=20&offset=10&file_name=x.csv",
|
|
63
|
-
headers={"Accept": "application/json"},
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
async def test_list_files(self) -> None:
|
|
67
|
-
content_0 = load_test_data("list_files_0.json")
|
|
68
|
-
content_1 = load_test_data("list_files_1.json")
|
|
69
|
-
responses = [
|
|
70
|
-
MockResponse(status_code=200, content=json.dumps(content_0), headers={"Content-Type": "application/json"}),
|
|
71
|
-
MockResponse(status_code=200, content=json.dumps(content_1), headers={"Content-Type": "application/json"}),
|
|
72
|
-
]
|
|
73
|
-
self.transport.request.side_effect = responses
|
|
74
|
-
page_one = await self.file_api_client.list_files(limit=2)
|
|
75
|
-
expected_files_page_one = [
|
|
76
|
-
FileMetadata(
|
|
77
|
-
environment=self.environment,
|
|
78
|
-
id=UUID(int=2),
|
|
79
|
-
name="x.csv",
|
|
80
|
-
created_by=ServiceUser(
|
|
81
|
-
id=UUID(int=16),
|
|
82
|
-
name="x y",
|
|
83
|
-
email="test@example.com",
|
|
84
|
-
),
|
|
85
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
86
|
-
modified_by=ServiceUser(
|
|
87
|
-
id=UUID(int=16),
|
|
88
|
-
name="x y",
|
|
89
|
-
email="test@example.com",
|
|
90
|
-
),
|
|
91
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
92
|
-
parent="/A/",
|
|
93
|
-
size=11,
|
|
94
|
-
version_id="2",
|
|
95
|
-
),
|
|
96
|
-
FileMetadata(
|
|
97
|
-
environment=self.environment,
|
|
98
|
-
id=UUID(int=3),
|
|
99
|
-
name="y.csv",
|
|
100
|
-
created_by=ServiceUser(
|
|
101
|
-
id=UUID(int=17),
|
|
102
|
-
name=None,
|
|
103
|
-
email=None,
|
|
104
|
-
),
|
|
105
|
-
created_at=utc_datetime(2020, 1, 2, 1, 30),
|
|
106
|
-
modified_by=ServiceUser(
|
|
107
|
-
id=UUID(int=17),
|
|
108
|
-
name=None,
|
|
109
|
-
email=None,
|
|
110
|
-
),
|
|
111
|
-
modified_at=utc_datetime(2020, 1, 2, 1, 30),
|
|
112
|
-
parent="/A/",
|
|
113
|
-
size=12,
|
|
114
|
-
version_id="1",
|
|
115
|
-
),
|
|
116
|
-
]
|
|
117
|
-
self.assertIsInstance(page_one, Page)
|
|
118
|
-
self.assertEqual(expected_files_page_one, page_one.items())
|
|
119
|
-
self.assertEqual(0, page_one.offset)
|
|
120
|
-
self.assertEqual(2, page_one.limit)
|
|
121
|
-
self.assertFalse(page_one.is_last)
|
|
122
|
-
self.assert_request_made(
|
|
123
|
-
method=RequestMethod.GET,
|
|
124
|
-
path=f"{self.base_path}/files?limit=2&offset=0",
|
|
125
|
-
headers={"Accept": "application/json"},
|
|
126
|
-
)
|
|
127
|
-
self.transport.request.reset_mock()
|
|
128
|
-
|
|
129
|
-
page_two = await self.file_api_client.list_files(offset=page_one.next_offset, limit=page_one.limit)
|
|
130
|
-
expected_files_page_two = [
|
|
131
|
-
FileMetadata(
|
|
132
|
-
environment=self.environment,
|
|
133
|
-
id=UUID(int=4),
|
|
134
|
-
name="z.csv",
|
|
135
|
-
created_by=ServiceUser(
|
|
136
|
-
id=UUID(int=16),
|
|
137
|
-
name="x y",
|
|
138
|
-
email="test@example.com",
|
|
139
|
-
),
|
|
140
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
141
|
-
modified_by=ServiceUser(
|
|
142
|
-
id=UUID(int=16),
|
|
143
|
-
name="x y",
|
|
144
|
-
email="test@example.com",
|
|
145
|
-
),
|
|
146
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
147
|
-
parent="/B/",
|
|
148
|
-
size=13,
|
|
149
|
-
version_id="3",
|
|
150
|
-
),
|
|
151
|
-
]
|
|
152
|
-
self.assertIsInstance(page_two, Page)
|
|
153
|
-
self.assertEqual(expected_files_page_two, page_two.items())
|
|
154
|
-
self.assertEqual(2, page_two.offset)
|
|
155
|
-
self.assertEqual(2, page_two.limit)
|
|
156
|
-
self.assertTrue(page_two.is_last)
|
|
157
|
-
self.assert_request_made(
|
|
158
|
-
method=RequestMethod.GET,
|
|
159
|
-
path=f"{self.base_path}/files?limit=2&offset=2",
|
|
160
|
-
headers={"Accept": "application/json"},
|
|
161
|
-
)
|
|
162
|
-
|
|
163
|
-
async def test_list_all_files(self) -> None:
|
|
164
|
-
content_0 = load_test_data("list_files_0.json")
|
|
165
|
-
content_1 = load_test_data("list_files_1.json")
|
|
166
|
-
responses = [
|
|
167
|
-
MockResponse(status_code=200, content=json.dumps(content_0), headers={"Content-Type": "application/json"}),
|
|
168
|
-
MockResponse(status_code=200, content=json.dumps(content_1), headers={"Content-Type": "application/json"}),
|
|
169
|
-
]
|
|
170
|
-
self.transport.request.side_effect = responses
|
|
171
|
-
file_list = await self.file_api_client.list_all_files(limit_per_request=2)
|
|
172
|
-
expected_files = [
|
|
173
|
-
FileMetadata(
|
|
174
|
-
environment=self.environment,
|
|
175
|
-
id=UUID(int=2),
|
|
176
|
-
name="x.csv",
|
|
177
|
-
created_by=ServiceUser(
|
|
178
|
-
id=UUID(int=16),
|
|
179
|
-
name="x y",
|
|
180
|
-
email="test@example.com",
|
|
181
|
-
),
|
|
182
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
183
|
-
modified_by=ServiceUser(
|
|
184
|
-
id=UUID(int=16),
|
|
185
|
-
name="x y",
|
|
186
|
-
email="test@example.com",
|
|
187
|
-
),
|
|
188
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
189
|
-
parent="/A/",
|
|
190
|
-
size=11,
|
|
191
|
-
version_id="2",
|
|
192
|
-
),
|
|
193
|
-
FileMetadata(
|
|
194
|
-
environment=self.environment,
|
|
195
|
-
id=UUID(int=3),
|
|
196
|
-
name="y.csv",
|
|
197
|
-
created_by=ServiceUser(
|
|
198
|
-
id=UUID(int=17),
|
|
199
|
-
name=None,
|
|
200
|
-
email=None,
|
|
201
|
-
),
|
|
202
|
-
created_at=utc_datetime(2020, 1, 2, 1, 30),
|
|
203
|
-
modified_by=ServiceUser(
|
|
204
|
-
id=UUID(int=17),
|
|
205
|
-
name=None,
|
|
206
|
-
email=None,
|
|
207
|
-
),
|
|
208
|
-
modified_at=utc_datetime(2020, 1, 2, 1, 30),
|
|
209
|
-
parent="/A/",
|
|
210
|
-
size=12,
|
|
211
|
-
version_id="1",
|
|
212
|
-
),
|
|
213
|
-
FileMetadata(
|
|
214
|
-
environment=self.environment,
|
|
215
|
-
id=UUID(int=4),
|
|
216
|
-
name="z.csv",
|
|
217
|
-
created_by=ServiceUser(
|
|
218
|
-
id=UUID(int=16),
|
|
219
|
-
name="x y",
|
|
220
|
-
email="test@example.com",
|
|
221
|
-
),
|
|
222
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
223
|
-
modified_by=ServiceUser(
|
|
224
|
-
id=UUID(int=16),
|
|
225
|
-
name="x y",
|
|
226
|
-
email="test@example.com",
|
|
227
|
-
),
|
|
228
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
229
|
-
parent="/B/",
|
|
230
|
-
size=13,
|
|
231
|
-
version_id="3",
|
|
232
|
-
),
|
|
233
|
-
]
|
|
234
|
-
|
|
235
|
-
self.assertEqual(expected_files, file_list)
|
|
236
|
-
self.assert_any_request_made(
|
|
237
|
-
method=RequestMethod.GET,
|
|
238
|
-
path=f"{self.base_path}/files?limit=2&offset=0",
|
|
239
|
-
headers={"Accept": "application/json"},
|
|
240
|
-
)
|
|
241
|
-
self.assert_any_request_made(
|
|
242
|
-
method=RequestMethod.GET,
|
|
243
|
-
path=f"{self.base_path}/files?limit=2&offset=2",
|
|
244
|
-
headers={"Accept": "application/json"},
|
|
245
|
-
)
|
|
246
|
-
|
|
247
|
-
async def test_get_file_by_path(self) -> None:
|
|
248
|
-
get_file_response = load_test_data("get_file.json")
|
|
249
|
-
path = "points.csv"
|
|
250
|
-
expected_metadata = FileMetadata(
|
|
251
|
-
environment=self.environment,
|
|
252
|
-
id=UUID(int=6),
|
|
253
|
-
name="points.csv",
|
|
254
|
-
created_by=ServiceUser(
|
|
255
|
-
id=UUID(int=16),
|
|
256
|
-
name="x y",
|
|
257
|
-
email="test@example.com",
|
|
258
|
-
),
|
|
259
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
260
|
-
modified_by=ServiceUser(
|
|
261
|
-
id=UUID(int=16),
|
|
262
|
-
name="x y",
|
|
263
|
-
email="test@example.com",
|
|
264
|
-
),
|
|
265
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
266
|
-
parent="/",
|
|
267
|
-
size=10,
|
|
268
|
-
version_id="1",
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
with self.transport.set_http_response(
|
|
272
|
-
status_code=200, content=json.dumps(get_file_response), headers={"Content-Type": "application/json"}
|
|
273
|
-
):
|
|
274
|
-
actual_metadata = await self.file_api_client.get_file_by_path(path)
|
|
275
|
-
|
|
276
|
-
self.assert_request_made(
|
|
277
|
-
method=RequestMethod.GET,
|
|
278
|
-
path=f"{self.base_path}/files/path/{path}",
|
|
279
|
-
headers={"Accept": "application/json"},
|
|
280
|
-
)
|
|
281
|
-
self.assertEqual(expected_metadata, actual_metadata)
|
|
282
|
-
|
|
283
|
-
async def test_prepare_download_by_path(self) -> None:
|
|
284
|
-
get_file_response = load_test_data("get_file.json")
|
|
285
|
-
path = "points.csv"
|
|
286
|
-
expected_metadata = FileMetadata(
|
|
287
|
-
environment=self.environment,
|
|
288
|
-
id=UUID(int=6),
|
|
289
|
-
name="points.csv",
|
|
290
|
-
created_by=ServiceUser(
|
|
291
|
-
id=UUID(int=16),
|
|
292
|
-
name="x y",
|
|
293
|
-
email="test@example.com",
|
|
294
|
-
),
|
|
295
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
296
|
-
modified_by=ServiceUser(
|
|
297
|
-
id=UUID(int=16),
|
|
298
|
-
name="x y",
|
|
299
|
-
email="test@example.com",
|
|
300
|
-
),
|
|
301
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
302
|
-
parent="/",
|
|
303
|
-
size=10,
|
|
304
|
-
version_id="1",
|
|
305
|
-
)
|
|
306
|
-
|
|
307
|
-
with self.transport.set_http_response(
|
|
308
|
-
status_code=200, content=json.dumps(get_file_response), headers={"Content-Type": "application/json"}
|
|
309
|
-
):
|
|
310
|
-
download = await self.file_api_client.prepare_download_by_path(path)
|
|
311
|
-
|
|
312
|
-
self.assertIsInstance(download, FileAPIDownload)
|
|
313
|
-
self.assertEqual(expected_metadata, download.metadata)
|
|
314
|
-
self.assert_request_made(
|
|
315
|
-
method=RequestMethod.GET,
|
|
316
|
-
path=f"{self.base_path}/files/path/{path}",
|
|
317
|
-
headers={"Accept": "application/json"},
|
|
318
|
-
)
|
|
319
|
-
|
|
320
|
-
async def test_get_file_by_id(self) -> None:
|
|
321
|
-
get_file_response = load_test_data("get_file.json")
|
|
322
|
-
file_id = UUID(int=6)
|
|
323
|
-
expected_metadata = FileMetadata(
|
|
324
|
-
environment=self.environment,
|
|
325
|
-
id=file_id,
|
|
326
|
-
name="points.csv",
|
|
327
|
-
created_by=ServiceUser(
|
|
328
|
-
id=UUID(int=16),
|
|
329
|
-
name="x y",
|
|
330
|
-
email="test@example.com",
|
|
331
|
-
),
|
|
332
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
333
|
-
modified_by=ServiceUser(
|
|
334
|
-
id=UUID(int=16),
|
|
335
|
-
name="x y",
|
|
336
|
-
email="test@example.com",
|
|
337
|
-
),
|
|
338
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
339
|
-
parent="/",
|
|
340
|
-
size=10,
|
|
341
|
-
version_id="1",
|
|
342
|
-
)
|
|
343
|
-
|
|
344
|
-
with self.transport.set_http_response(
|
|
345
|
-
status_code=200, content=json.dumps(get_file_response), headers={"Content-Type": "application/json"}
|
|
346
|
-
):
|
|
347
|
-
actual_metadata = await self.file_api_client.get_file_by_id(file_id)
|
|
348
|
-
|
|
349
|
-
self.assert_request_made(
|
|
350
|
-
method=RequestMethod.GET,
|
|
351
|
-
path=f"{self.base_path}/files/{file_id}",
|
|
352
|
-
headers={"Accept": "application/json"},
|
|
353
|
-
)
|
|
354
|
-
self.assertEqual(expected_metadata, actual_metadata)
|
|
355
|
-
|
|
356
|
-
async def test_prepare_download_by_id(self) -> None:
|
|
357
|
-
get_file_response = load_test_data("get_file.json")
|
|
358
|
-
file_id = UUID(int=6)
|
|
359
|
-
expected_metadata = FileMetadata(
|
|
360
|
-
environment=self.environment,
|
|
361
|
-
id=file_id,
|
|
362
|
-
name="points.csv",
|
|
363
|
-
created_by=ServiceUser(
|
|
364
|
-
id=UUID(int=16),
|
|
365
|
-
name="x y",
|
|
366
|
-
email="test@example.com",
|
|
367
|
-
),
|
|
368
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
369
|
-
modified_by=ServiceUser(
|
|
370
|
-
id=UUID(int=16),
|
|
371
|
-
name="x y",
|
|
372
|
-
email="test@example.com",
|
|
373
|
-
),
|
|
374
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
375
|
-
parent="/",
|
|
376
|
-
size=10,
|
|
377
|
-
version_id="1",
|
|
378
|
-
)
|
|
379
|
-
|
|
380
|
-
with self.transport.set_http_response(
|
|
381
|
-
status_code=200, content=json.dumps(get_file_response), headers={"Content-Type": "application/json"}
|
|
382
|
-
):
|
|
383
|
-
download = await self.file_api_client.prepare_download_by_id(file_id)
|
|
384
|
-
|
|
385
|
-
self.assertIsInstance(download, FileAPIDownload)
|
|
386
|
-
self.assertEqual(expected_metadata, download.metadata)
|
|
387
|
-
self.assert_request_made(
|
|
388
|
-
method=RequestMethod.GET,
|
|
389
|
-
path=f"{self.base_path}/files/{file_id}",
|
|
390
|
-
headers={"Accept": "application/json"},
|
|
391
|
-
)
|
|
392
|
-
|
|
393
|
-
async def test_list_versions_by_path(self) -> None:
|
|
394
|
-
file_path = "points.csv"
|
|
395
|
-
list_versions_response = load_test_data("list_versions.json")
|
|
396
|
-
with self.transport.set_http_response(
|
|
397
|
-
200, json.dumps(list_versions_response), headers={"Content-Type": "application/json"}
|
|
398
|
-
):
|
|
399
|
-
versions = await self.file_api_client.list_versions_by_path(file_path)
|
|
400
|
-
expected_versions = [
|
|
401
|
-
FileVersion(
|
|
402
|
-
version_id="3",
|
|
403
|
-
created_at=utc_datetime(2020, 1, 3, 1, 30),
|
|
404
|
-
created_by=ServiceUser(
|
|
405
|
-
id=UUID(int=16),
|
|
406
|
-
name="x y",
|
|
407
|
-
email="test@example.com",
|
|
408
|
-
),
|
|
409
|
-
),
|
|
410
|
-
FileVersion(
|
|
411
|
-
version_id="2",
|
|
412
|
-
created_at=utc_datetime(2020, 1, 2, 1, 30),
|
|
413
|
-
created_by=ServiceUser(
|
|
414
|
-
id=UUID(int=17),
|
|
415
|
-
name="x z",
|
|
416
|
-
email="test@example.com",
|
|
417
|
-
),
|
|
418
|
-
),
|
|
419
|
-
FileVersion(
|
|
420
|
-
version_id="1",
|
|
421
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
422
|
-
created_by=ServiceUser(
|
|
423
|
-
id=UUID("00000000-0000-0000-0000-000000000012"),
|
|
424
|
-
name="x w",
|
|
425
|
-
email="test@example.com",
|
|
426
|
-
),
|
|
427
|
-
),
|
|
428
|
-
]
|
|
429
|
-
|
|
430
|
-
self.assertEqual(versions, expected_versions)
|
|
431
|
-
self.assert_request_made(
|
|
432
|
-
method=RequestMethod.GET,
|
|
433
|
-
path=f"{self.base_path}/files/path/points.csv?include_versions=True",
|
|
434
|
-
headers={"Accept": "application/json"},
|
|
435
|
-
)
|
|
436
|
-
|
|
437
|
-
async def test_list_versions_by_id(self) -> None:
|
|
438
|
-
file_id = UUID(int=6)
|
|
439
|
-
list_versions_response = load_test_data("list_versions.json")
|
|
440
|
-
with self.transport.set_http_response(
|
|
441
|
-
200, json.dumps(list_versions_response), headers={"Content-Type": "application/json"}
|
|
442
|
-
):
|
|
443
|
-
versions = await self.file_api_client.list_versions_by_id(file_id)
|
|
444
|
-
expected_versions = [
|
|
445
|
-
FileVersion(
|
|
446
|
-
version_id="3",
|
|
447
|
-
created_at=utc_datetime(2020, 1, 3, 1, 30),
|
|
448
|
-
created_by=ServiceUser(
|
|
449
|
-
id=UUID(int=16),
|
|
450
|
-
name="x y",
|
|
451
|
-
email="test@example.com",
|
|
452
|
-
),
|
|
453
|
-
),
|
|
454
|
-
FileVersion(
|
|
455
|
-
version_id="2",
|
|
456
|
-
created_at=utc_datetime(2020, 1, 2, 1, 30),
|
|
457
|
-
created_by=ServiceUser(
|
|
458
|
-
id=UUID(int=17),
|
|
459
|
-
name="x z",
|
|
460
|
-
email="test@example.com",
|
|
461
|
-
),
|
|
462
|
-
),
|
|
463
|
-
FileVersion(
|
|
464
|
-
version_id="1",
|
|
465
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
466
|
-
created_by=ServiceUser(
|
|
467
|
-
id=UUID("00000000-0000-0000-0000-000000000012"),
|
|
468
|
-
name="x w",
|
|
469
|
-
email="test@example.com",
|
|
470
|
-
),
|
|
471
|
-
),
|
|
472
|
-
]
|
|
473
|
-
|
|
474
|
-
self.assertEqual(versions, expected_versions)
|
|
475
|
-
self.assert_request_made(
|
|
476
|
-
method=RequestMethod.GET,
|
|
477
|
-
path=f"{self.base_path}/files/{file_id}?include_versions=True",
|
|
478
|
-
headers={"Accept": "application/json"},
|
|
479
|
-
)
|
|
480
|
-
|
|
481
|
-
async def test_prepare_upload_by_path(self) -> None:
|
|
482
|
-
upsert_file_response = load_test_data("upsert_file.json")
|
|
483
|
-
with self.transport.set_http_response(
|
|
484
|
-
status_code=200, content=json.dumps(upsert_file_response), headers={"Content-Type": "application/json"}
|
|
485
|
-
):
|
|
486
|
-
upload = await self.file_api_client.prepare_upload_by_path("points.csv")
|
|
487
|
-
|
|
488
|
-
self.assertIsInstance(upload, FileAPIUpload)
|
|
489
|
-
self.assertEqual(upsert_file_response["file_id"], str(upload._id))
|
|
490
|
-
self.assertEqual(upsert_file_response["version_id"], upload._version_id)
|
|
491
|
-
self.assert_request_made(
|
|
492
|
-
method=RequestMethod.PUT,
|
|
493
|
-
path=f"{self.base_path}/files/path/points.csv",
|
|
494
|
-
headers={"Accept": "application/json"},
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
async def test_update_file_by_id(self) -> None:
|
|
498
|
-
update_file_response = load_test_data("update_file.json")
|
|
499
|
-
file_id = UUID(int=5)
|
|
500
|
-
with self.transport.set_http_response(
|
|
501
|
-
status_code=200, content=json.dumps(update_file_response), headers={"Content-Type": "application/json"}
|
|
502
|
-
):
|
|
503
|
-
upload = await self.file_api_client.prepare_upload_by_id(file_id)
|
|
504
|
-
|
|
505
|
-
self.assertIsInstance(upload, FileAPIUpload)
|
|
506
|
-
self.assertEqual(update_file_response["file_id"], str(upload._id))
|
|
507
|
-
self.assertEqual(update_file_response["version_id"], upload._version_id)
|
|
508
|
-
self.assert_request_made(
|
|
509
|
-
method=RequestMethod.PUT,
|
|
510
|
-
path=f"{self.base_path}/files/{file_id}",
|
|
511
|
-
headers={"Accept": "application/json"},
|
|
512
|
-
)
|
|
513
|
-
|
|
514
|
-
async def test_delete_file_by_path(self) -> None:
|
|
515
|
-
path = "points.csv"
|
|
516
|
-
with self.transport.set_http_response(
|
|
517
|
-
status_code=204, content="", headers={"Content-Type": "application/json"}
|
|
518
|
-
):
|
|
519
|
-
await self.file_api_client.delete_file_by_path(path)
|
|
520
|
-
self.assert_request_made(
|
|
521
|
-
method=RequestMethod.DELETE,
|
|
522
|
-
path=f"{self.base_path}/files/path/{path}",
|
|
523
|
-
)
|
|
524
|
-
|
|
525
|
-
async def test_delete_file_by_id(self) -> None:
|
|
526
|
-
file_id = UUID(int=6)
|
|
527
|
-
with self.transport.set_http_response(
|
|
528
|
-
status_code=204, content="", headers={"Content-Type": "application/json"}
|
|
529
|
-
):
|
|
530
|
-
await self.file_api_client.delete_file_by_id(file_id)
|
|
531
|
-
self.assert_request_made(
|
|
532
|
-
method=RequestMethod.DELETE,
|
|
533
|
-
path=f"{self.base_path}/files/{file_id}",
|
|
534
|
-
)
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
-
# you may not use this file except in compliance with the License.
|
|
4
|
-
# You may obtain a copy of the License at
|
|
5
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
-
# See the License for the specific language governing permissions and
|
|
10
|
-
# limitations under the License.
|
|
11
|
-
|
|
12
|
-
import json
|
|
13
|
-
from uuid import UUID
|
|
14
|
-
|
|
15
|
-
from data import load_test_data
|
|
16
|
-
from evo.common import ServiceUser
|
|
17
|
-
from evo.common.test_tools import TestWithConnector, TestWithDownloadHandler, TestWithUploadHandler, utc_datetime
|
|
18
|
-
from evo.files import FileAPIDownload, FileAPIUpload, FileMetadata
|
|
19
|
-
|
|
20
|
-
TEST_DATA = """
|
|
21
|
-
x,y,z
|
|
22
|
-
10689.54607,100813.2874,442.172449
|
|
23
|
-
10690.87819,100812.6204,437.399555
|
|
24
|
-
10692.21062,100811.9502,432.627182
|
|
25
|
-
10693.54337,100811.277,427.85533
|
|
26
|
-
10694.87638,100810.6009,423.083966
|
|
27
|
-
10696.06353,100809.9976,418.831067
|
|
28
|
-
10725.47983,100777.2912,448.471682
|
|
29
|
-
10727.51038,100775.9784,444.022761
|
|
30
|
-
10729.54666,100774.6657,439.576449
|
|
31
|
-
10731.58199,100773.3566,435.128615
|
|
32
|
-
""".lstrip().encode("utf-8")
|
|
33
|
-
|
|
34
|
-
FILE_ID = UUID(int=5)
|
|
35
|
-
VERSION_ID = "123456"
|
|
36
|
-
INITIAL_URL = "https://unit.test/initial/url"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
class TestFileAPIDownload(TestWithConnector, TestWithDownloadHandler):
|
|
40
|
-
def setUp(self) -> None:
|
|
41
|
-
TestWithConnector.setUp(self)
|
|
42
|
-
TestWithDownloadHandler.setUp(self)
|
|
43
|
-
self.setup_download_handler(TEST_DATA)
|
|
44
|
-
self.metadata = FileMetadata(
|
|
45
|
-
environment=self.environment,
|
|
46
|
-
id=FILE_ID,
|
|
47
|
-
name="file.csv",
|
|
48
|
-
created_by=ServiceUser(
|
|
49
|
-
id=UUID(int=16),
|
|
50
|
-
name="x y",
|
|
51
|
-
email="test@example.com",
|
|
52
|
-
),
|
|
53
|
-
created_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
54
|
-
modified_by=ServiceUser(
|
|
55
|
-
id=UUID(int=16),
|
|
56
|
-
name="x y",
|
|
57
|
-
email="test@example.com",
|
|
58
|
-
),
|
|
59
|
-
modified_at=utc_datetime(2020, 1, 1, 1, 30),
|
|
60
|
-
parent="/some/path",
|
|
61
|
-
version_id=VERSION_ID,
|
|
62
|
-
size=len(TEST_DATA),
|
|
63
|
-
)
|
|
64
|
-
self.download = FileAPIDownload(connector=self.connector, metadata=self.metadata, initial_url=INITIAL_URL)
|
|
65
|
-
|
|
66
|
-
def test_label(self) -> None:
|
|
67
|
-
expected = f"{self.metadata.id}?version_id={self.metadata.version_id}"
|
|
68
|
-
self.assertEqual(expected, self.download.label)
|
|
69
|
-
|
|
70
|
-
def test_metadata(self) -> None:
|
|
71
|
-
self.assertEqual(self.metadata, self.download.metadata)
|
|
72
|
-
|
|
73
|
-
def test_get_cache_location(self) -> None:
|
|
74
|
-
expected = self.cache.get_location(self.environment, "filev2") / str(FILE_ID) / VERSION_ID / self.metadata.name
|
|
75
|
-
self.assertEqual(expected, self.download._get_cache_location(self.cache))
|
|
76
|
-
|
|
77
|
-
async def test_get_download_url(self) -> None:
|
|
78
|
-
# Test the initial URL is used first.
|
|
79
|
-
first = await self.download.get_download_url()
|
|
80
|
-
self.assertEqual(INITIAL_URL, first)
|
|
81
|
-
|
|
82
|
-
# No requests should be made when using the initial URL.
|
|
83
|
-
self.transport.assert_no_requests()
|
|
84
|
-
|
|
85
|
-
# Test that a new URL is generated when the initial URL is used up.
|
|
86
|
-
get_file_response = load_test_data("get_file.json")
|
|
87
|
-
with self.transport.set_http_response(
|
|
88
|
-
status_code=200, content=json.dumps(get_file_response), headers={"Content-Type": "application/json"}
|
|
89
|
-
):
|
|
90
|
-
second = await self.download.get_download_url()
|
|
91
|
-
self.assertEqual(get_file_response["download"], second)
|
|
92
|
-
|
|
93
|
-
async def test_download_to_path(self) -> None:
|
|
94
|
-
dest = self.cache.root / "test_download_to_path.csv"
|
|
95
|
-
await self.download.download_to_path(dest, self.transport)
|
|
96
|
-
|
|
97
|
-
# Check the file was downloaded correctly.
|
|
98
|
-
self.assertEqual(TEST_DATA, dest.read_bytes())
|
|
99
|
-
self.assert_download_requests(INITIAL_URL)
|
|
100
|
-
|
|
101
|
-
async def test_download_to_cache(self) -> None:
|
|
102
|
-
dest = await self.download.download_to_cache(self.cache, self.transport)
|
|
103
|
-
|
|
104
|
-
# Check the download location is correct.
|
|
105
|
-
expected = self.cache.get_location(self.environment, "filev2") / str(FILE_ID) / VERSION_ID / self.metadata.name
|
|
106
|
-
self.assertEqual(expected, dest)
|
|
107
|
-
|
|
108
|
-
# Check the file was downloaded correctly.
|
|
109
|
-
self.assertEqual(TEST_DATA, dest.read_bytes())
|
|
110
|
-
self.assert_download_requests(INITIAL_URL)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
class TestFileAPIUpload(TestWithConnector, TestWithUploadHandler):
|
|
114
|
-
def setUp(self) -> None:
|
|
115
|
-
TestWithConnector.setUp(self)
|
|
116
|
-
TestWithUploadHandler.setUp(self)
|
|
117
|
-
self.upload = FileAPIUpload(
|
|
118
|
-
connector=self.connector,
|
|
119
|
-
environment=self.environment,
|
|
120
|
-
file_id=FILE_ID,
|
|
121
|
-
version_id=VERSION_ID,
|
|
122
|
-
initial_url=INITIAL_URL,
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
def test_label(self) -> None:
|
|
126
|
-
expected = f"{FILE_ID}?version_id={VERSION_ID}"
|
|
127
|
-
self.assertEqual(expected, self.upload.label)
|
|
128
|
-
|
|
129
|
-
async def test_get_upload_url(self) -> None:
|
|
130
|
-
# Test the initial URL is used first.
|
|
131
|
-
first = await self.upload.get_upload_url()
|
|
132
|
-
self.assertEqual(INITIAL_URL, first)
|
|
133
|
-
|
|
134
|
-
# No requests should be made when using the initial URL.
|
|
135
|
-
self.transport.assert_no_requests()
|
|
136
|
-
|
|
137
|
-
# Test that a new URL is generated when the initial URL is used up.
|
|
138
|
-
update_file_response = load_test_data("update_file.json")
|
|
139
|
-
with self.transport.set_http_response(
|
|
140
|
-
status_code=200, content=json.dumps(update_file_response), headers={"Content-Type": "application/json"}
|
|
141
|
-
):
|
|
142
|
-
second = await self.upload.get_upload_url()
|
|
143
|
-
self.assertEqual(update_file_response["upload"], second)
|
|
144
|
-
|
|
145
|
-
async def test_upload_from_path(self) -> None:
|
|
146
|
-
source = self.cache.root / "test_upload_from_path.csv"
|
|
147
|
-
source.write_bytes(TEST_DATA)
|
|
148
|
-
await self.upload.upload_from_path(source, self.transport)
|
|
149
|
-
|
|
150
|
-
# Check the file was uploaded correctly.
|
|
151
|
-
uploaded = await self.handler.get_committed()
|
|
152
|
-
self.assertEqual(TEST_DATA, uploaded)
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Copyright © 2025 Bentley Systems, Incorporated
|
|
2
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
3
|
-
# you may not use this file except in compliance with the License.
|
|
4
|
-
# You may obtain a copy of the License at
|
|
5
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
6
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
7
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
8
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
9
|
-
# See the License for the specific language governing permissions and
|
|
10
|
-
# limitations under the License.
|
|
11
|
-
|
|
12
|
-
import unittest
|
|
13
|
-
|
|
14
|
-
from evo.files.io import _INVALID_NAMES, _make_name_safe
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class TestMakeNameSafe(unittest.TestCase):
|
|
18
|
-
def test_invalid_characters(self):
|
|
19
|
-
self.assertEqual(_make_name_safe("test<name>"), "test%3Cname%3E")
|
|
20
|
-
self.assertEqual(_make_name_safe("test:name"), "test%3Aname")
|
|
21
|
-
self.assertEqual(_make_name_safe("test/name"), "test%2Fname")
|
|
22
|
-
self.assertEqual(_make_name_safe("test\\name"), "test%5Cname")
|
|
23
|
-
self.assertEqual(_make_name_safe("test|name"), "test%7Cname")
|
|
24
|
-
self.assertEqual(_make_name_safe("test?name"), "test%3Fname")
|
|
25
|
-
self.assertEqual(_make_name_safe("test*name"), "test%2Aname")
|
|
26
|
-
|
|
27
|
-
def test_invalid_trailing_characters(self):
|
|
28
|
-
self.assertEqual(_make_name_safe("test "), "test%20")
|
|
29
|
-
self.assertEqual(_make_name_safe("test."), "test%2E")
|
|
30
|
-
|
|
31
|
-
def test_reserved_names(self):
|
|
32
|
-
for name in _INVALID_NAMES:
|
|
33
|
-
self.assertEqual(_make_name_safe(name), name + "_")
|
|
34
|
-
self.assertEqual(_make_name_safe(name + ".txt"), name + "_.txt")
|
|
35
|
-
|
|
36
|
-
def test_valid_names(self):
|
|
37
|
-
self.assertEqual(_make_name_safe("test"), "test")
|
|
38
|
-
self.assertEqual(_make_name_safe("test123"), "test123")
|
|
39
|
-
self.assertEqual(_make_name_safe("test_name"), "test_name")
|
|
40
|
-
|
|
41
|
-
def test_leading_trailing_special_characters(self):
|
|
42
|
-
self.assertEqual(_make_name_safe("<test>"), "%3Ctest%3E")
|
|
43
|
-
|
|
44
|
-
def test_leading_trailing_reserved_names(self):
|
|
45
|
-
self.assertEqual(_make_name_safe("CONtestCON"), "CONtestCON")
|
|
46
|
-
|
|
47
|
-
def test_mixed_valid_invalid_characters(self):
|
|
48
|
-
self.assertEqual(_make_name_safe("te<st>na:me"), "te%3Cst%3Ena%3Ame")
|
|
49
|
-
|
|
50
|
-
def test_empty_string(self):
|
|
51
|
-
self.assertEqual(_make_name_safe(""), "")
|
|
52
|
-
|
|
53
|
-
def test_only_special_characters(self):
|
|
54
|
-
self.assertEqual(_make_name_safe('<>:"/\\|?*'), "%3C%3E%3A%22%2F%5C%7C%3F%2A")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|