ayon-python-api 1.2.3__tar.gz → 1.2.4__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.
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/PKG-INFO +1 -1
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/__init__.py +4 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api.py +52 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/base.py +11 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/thumbnails.py +70 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/constants.py +4 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/graphql_queries.py +17 -1
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/operations.py +68 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/typing.py +15 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/version.py +1 -1
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/PKG-INFO +1 -1
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/pyproject.toml +1 -1
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/LICENSE +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/README.md +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/__init__.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/actions.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/activities.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/attributes.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/bundles_addons.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/dependency_packages.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/events.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/folders.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/installers.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/links.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/lists.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/products.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/projects.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/representations.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/secrets.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/tasks.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/versions.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/workfiles.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/entity_hub.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/events.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/exceptions.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/graphql.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/server_api.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/utils.py +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/SOURCES.txt +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/dependency_links.txt +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/requires.txt +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/top_level.txt +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/setup.cfg +0 -0
- {ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/setup.py +0 -0
|
@@ -271,7 +271,9 @@ from ._api import (
|
|
|
271
271
|
get_version_thumbnail,
|
|
272
272
|
get_workfile_thumbnail,
|
|
273
273
|
create_thumbnail,
|
|
274
|
+
create_thumbnail_with_stream,
|
|
274
275
|
update_thumbnail,
|
|
276
|
+
update_thumbnail_from_stream,
|
|
275
277
|
)
|
|
276
278
|
|
|
277
279
|
|
|
@@ -546,5 +548,7 @@ __all__ = (
|
|
|
546
548
|
"get_version_thumbnail",
|
|
547
549
|
"get_workfile_thumbnail",
|
|
548
550
|
"create_thumbnail",
|
|
551
|
+
"create_thumbnail_with_stream",
|
|
549
552
|
"update_thumbnail",
|
|
553
|
+
"update_thumbnail_from_stream",
|
|
550
554
|
)
|
|
@@ -7726,6 +7726,34 @@ def create_thumbnail(
|
|
|
7726
7726
|
)
|
|
7727
7727
|
|
|
7728
7728
|
|
|
7729
|
+
def create_thumbnail_with_stream(
|
|
7730
|
+
project_name: str,
|
|
7731
|
+
stream: StreamType,
|
|
7732
|
+
thumbnail_id: Optional[str] = None,
|
|
7733
|
+
) -> str:
|
|
7734
|
+
"""Create new thumbnail on server from byte stream.
|
|
7735
|
+
|
|
7736
|
+
Args:
|
|
7737
|
+
project_name (str): Project where the thumbnail will be created
|
|
7738
|
+
and can be used.
|
|
7739
|
+
stream (StreamType): Thumbnail content stream.
|
|
7740
|
+
thumbnail_id (Optional[str]): Prepared if of thumbnail.
|
|
7741
|
+
|
|
7742
|
+
Returns:
|
|
7743
|
+
str: Created thumbnail id.
|
|
7744
|
+
|
|
7745
|
+
Raises:
|
|
7746
|
+
ValueError: When a thumbnail source cannot be processed.
|
|
7747
|
+
|
|
7748
|
+
"""
|
|
7749
|
+
con = get_server_api_connection()
|
|
7750
|
+
return con.create_thumbnail_with_stream(
|
|
7751
|
+
project_name=project_name,
|
|
7752
|
+
stream=stream,
|
|
7753
|
+
thumbnail_id=thumbnail_id,
|
|
7754
|
+
)
|
|
7755
|
+
|
|
7756
|
+
|
|
7729
7757
|
def update_thumbnail(
|
|
7730
7758
|
project_name: str,
|
|
7731
7759
|
thumbnail_id: str,
|
|
@@ -7751,3 +7779,27 @@ def update_thumbnail(
|
|
|
7751
7779
|
thumbnail_id=thumbnail_id,
|
|
7752
7780
|
src_filepath=src_filepath,
|
|
7753
7781
|
)
|
|
7782
|
+
|
|
7783
|
+
|
|
7784
|
+
def update_thumbnail_from_stream(
|
|
7785
|
+
project_name: str,
|
|
7786
|
+
thumbnail_id: str,
|
|
7787
|
+
stream: StreamType,
|
|
7788
|
+
) -> None:
|
|
7789
|
+
"""Change thumbnail content by id.
|
|
7790
|
+
|
|
7791
|
+
Update can be also used to create new thumbnail.
|
|
7792
|
+
|
|
7793
|
+
Args:
|
|
7794
|
+
project_name (str): Project where the thumbnail will be created
|
|
7795
|
+
and can be used.
|
|
7796
|
+
thumbnail_id (str): Thumbnail id to update.
|
|
7797
|
+
stream (StreamType): Thumbnail content stream.
|
|
7798
|
+
|
|
7799
|
+
"""
|
|
7800
|
+
con = get_server_api_connection()
|
|
7801
|
+
return con.update_thumbnail_from_stream(
|
|
7802
|
+
project_name=project_name,
|
|
7803
|
+
thumbnail_id=thumbnail_id,
|
|
7804
|
+
stream=stream,
|
|
7805
|
+
)
|
|
@@ -13,6 +13,7 @@ if typing.TYPE_CHECKING:
|
|
|
13
13
|
AnyEntityDict,
|
|
14
14
|
ServerVersion,
|
|
15
15
|
ProjectDict,
|
|
16
|
+
StreamType,
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
_PLACEHOLDER = object()
|
|
@@ -84,6 +85,16 @@ class BaseServerAPI:
|
|
|
84
85
|
) -> requests.Response:
|
|
85
86
|
raise NotImplementedError()
|
|
86
87
|
|
|
88
|
+
def upload_file_from_stream(
|
|
89
|
+
self,
|
|
90
|
+
endpoint: str,
|
|
91
|
+
stream: StreamType,
|
|
92
|
+
progress: Optional[TransferProgress] = None,
|
|
93
|
+
request_type: Optional[RequestType] = None,
|
|
94
|
+
**kwargs
|
|
95
|
+
) -> requests.Response:
|
|
96
|
+
raise NotImplementedError()
|
|
97
|
+
|
|
87
98
|
def download_file(
|
|
88
99
|
self,
|
|
89
100
|
endpoint: str,
|
|
@@ -2,9 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
4
|
import warnings
|
|
5
|
+
import typing
|
|
5
6
|
from typing import Optional
|
|
6
7
|
|
|
7
8
|
from ayon_api.utils import (
|
|
9
|
+
get_media_mime_type_for_stream,
|
|
8
10
|
get_media_mime_type,
|
|
9
11
|
ThumbnailContent,
|
|
10
12
|
RequestTypes,
|
|
@@ -13,6 +15,9 @@ from ayon_api.utils import (
|
|
|
13
15
|
|
|
14
16
|
from .base import BaseServerAPI
|
|
15
17
|
|
|
18
|
+
if typing.TYPE_CHECKING:
|
|
19
|
+
from .typing import StreamType
|
|
20
|
+
|
|
16
21
|
|
|
17
22
|
class ThumbnailsAPI(BaseServerAPI):
|
|
18
23
|
def get_thumbnail_by_id(
|
|
@@ -259,6 +264,45 @@ class ThumbnailsAPI(BaseServerAPI):
|
|
|
259
264
|
response.raise_for_status()
|
|
260
265
|
return response.json()["id"]
|
|
261
266
|
|
|
267
|
+
def create_thumbnail_with_stream(
|
|
268
|
+
self,
|
|
269
|
+
project_name: str,
|
|
270
|
+
stream: StreamType,
|
|
271
|
+
thumbnail_id: Optional[str] = None,
|
|
272
|
+
) -> str:
|
|
273
|
+
"""Create new thumbnail on server from byte stream.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
project_name (str): Project where the thumbnail will be created
|
|
277
|
+
and can be used.
|
|
278
|
+
stream (StreamType): Thumbnail content stream.
|
|
279
|
+
thumbnail_id (Optional[str]): Prepared if of thumbnail.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
str: Created thumbnail id.
|
|
283
|
+
|
|
284
|
+
Raises:
|
|
285
|
+
ValueError: When a thumbnail source cannot be processed.
|
|
286
|
+
|
|
287
|
+
"""
|
|
288
|
+
if thumbnail_id:
|
|
289
|
+
self.update_thumbnail_from_stream(
|
|
290
|
+
project_name,
|
|
291
|
+
thumbnail_id,
|
|
292
|
+
stream
|
|
293
|
+
)
|
|
294
|
+
return thumbnail_id
|
|
295
|
+
|
|
296
|
+
mime_type = get_media_mime_type_for_stream(stream)
|
|
297
|
+
response = self.upload_file_from_stream(
|
|
298
|
+
f"projects/{project_name}/thumbnails",
|
|
299
|
+
stream,
|
|
300
|
+
request_type=RequestTypes.post,
|
|
301
|
+
headers={"Content-Type": mime_type},
|
|
302
|
+
)
|
|
303
|
+
response.raise_for_status()
|
|
304
|
+
return response.json()["id"]
|
|
305
|
+
|
|
262
306
|
def update_thumbnail(
|
|
263
307
|
self, project_name: str, thumbnail_id: str, src_filepath: str
|
|
264
308
|
) -> None:
|
|
@@ -288,6 +332,32 @@ class ThumbnailsAPI(BaseServerAPI):
|
|
|
288
332
|
)
|
|
289
333
|
response.raise_for_status()
|
|
290
334
|
|
|
335
|
+
def update_thumbnail_from_stream(
|
|
336
|
+
self,
|
|
337
|
+
project_name: str,
|
|
338
|
+
thumbnail_id: str,
|
|
339
|
+
stream: StreamType,
|
|
340
|
+
) -> None:
|
|
341
|
+
"""Change thumbnail content by id.
|
|
342
|
+
|
|
343
|
+
Update can be also used to create new thumbnail.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
project_name (str): Project where the thumbnail will be created
|
|
347
|
+
and can be used.
|
|
348
|
+
thumbnail_id (str): Thumbnail id to update.
|
|
349
|
+
stream (StreamType): Thumbnail content stream.
|
|
350
|
+
|
|
351
|
+
"""
|
|
352
|
+
mime_type = get_media_mime_type_for_stream(stream)
|
|
353
|
+
response = self.upload_file_from_stream(
|
|
354
|
+
f"projects/{project_name}/thumbnails/{thumbnail_id}",
|
|
355
|
+
stream,
|
|
356
|
+
request_type=RequestTypes.put,
|
|
357
|
+
headers={"Content-Type": mime_type},
|
|
358
|
+
)
|
|
359
|
+
response.raise_for_status()
|
|
360
|
+
|
|
291
361
|
def _prepare_thumbnail_content(
|
|
292
362
|
self,
|
|
293
363
|
project_name: str,
|
|
@@ -680,9 +680,25 @@ def entity_lists_graphql_query(fields):
|
|
|
680
680
|
entity_lists_field = project_field.add_field_with_edges("entityLists")
|
|
681
681
|
entity_lists_field.set_filter("ids", entity_list_ids)
|
|
682
682
|
|
|
683
|
-
|
|
683
|
+
fields = set(fields)
|
|
684
|
+
items_field_names = set()
|
|
685
|
+
for field_name in set(fields):
|
|
686
|
+
field_name.removeprefix("items")
|
|
687
|
+
if not field_name.startswith("items"):
|
|
688
|
+
continue
|
|
689
|
+
|
|
690
|
+
fields.discard(field_name)
|
|
691
|
+
field_name = field_name.removeprefix("items").lstrip(".")
|
|
692
|
+
if field_name:
|
|
693
|
+
items_field_names.add(field_name)
|
|
684
694
|
|
|
685
695
|
query_queue = collections.deque()
|
|
696
|
+
if items_field_names:
|
|
697
|
+
items_field = entity_lists_field.add_field_with_edges("items")
|
|
698
|
+
for field_name in items_field_names:
|
|
699
|
+
items_field.add_edge_field(field_name)
|
|
700
|
+
|
|
701
|
+
nested_fields = fields_to_dict(set(fields))
|
|
686
702
|
for key, value in nested_fields.items():
|
|
687
703
|
query_queue.append((key, value, entity_lists_field))
|
|
688
704
|
|
|
@@ -15,6 +15,7 @@ if typing.TYPE_CHECKING:
|
|
|
15
15
|
from .server_api import ServerAPI
|
|
16
16
|
from .typing import (
|
|
17
17
|
NewFolderDict,
|
|
18
|
+
NewTaskDict,
|
|
18
19
|
NewProductDict,
|
|
19
20
|
NewVersionDict,
|
|
20
21
|
NewRepresentationDict,
|
|
@@ -76,6 +77,7 @@ def new_folder_entity(
|
|
|
76
77
|
folder_type: str,
|
|
77
78
|
parent_id: Optional[str] = None,
|
|
78
79
|
status: Optional[str] = None,
|
|
80
|
+
active: Optional[bool] = None,
|
|
79
81
|
tags: Optional[list[str]] = None,
|
|
80
82
|
attribs: Optional[dict[str, Any]] = None,
|
|
81
83
|
data: Optional[dict[str, Any]] = None,
|
|
@@ -89,6 +91,7 @@ def new_folder_entity(
|
|
|
89
91
|
folder_type (str): Type of folder.
|
|
90
92
|
parent_id (Optional[str]): Parent folder id.
|
|
91
93
|
status (Optional[str]): Product status.
|
|
94
|
+
active (Optional[bool]): Active status..
|
|
92
95
|
tags (Optional[list[str]]): List of tags.
|
|
93
96
|
attribs (Optional[dict[str, Any]]): Explicitly set attributes
|
|
94
97
|
of folder.
|
|
@@ -125,6 +128,67 @@ def new_folder_entity(
|
|
|
125
128
|
output["status"] = status
|
|
126
129
|
if tags:
|
|
127
130
|
output["tags"] = tags
|
|
131
|
+
if active is not None:
|
|
132
|
+
output["active"] = active
|
|
133
|
+
return output
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def new_task_entity(
|
|
137
|
+
name: str,
|
|
138
|
+
task_type: str,
|
|
139
|
+
folder_id: str,
|
|
140
|
+
*,
|
|
141
|
+
label: Optional[str] = None,
|
|
142
|
+
assignees: Optional[list[str]] = None,
|
|
143
|
+
attrib: Optional[dict[str, Any]] = None,
|
|
144
|
+
data: Optional[dict[str, Any]] = None,
|
|
145
|
+
tags: Optional[list[str]] = None,
|
|
146
|
+
status: Optional[str] = None,
|
|
147
|
+
active: Optional[bool] = None,
|
|
148
|
+
thumbnail_id: Optional[str] = None,
|
|
149
|
+
task_id: Optional[str] = None,
|
|
150
|
+
) -> NewTaskDict:
|
|
151
|
+
"""Create skeleton data of task entity.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
name (str): Folder name.
|
|
155
|
+
task_type (str): Task type.
|
|
156
|
+
folder_id (str): Parent folder id.
|
|
157
|
+
label (Optional[str]): Label of folder.
|
|
158
|
+
assignees (Optional[list[str]]): Task assignees.
|
|
159
|
+
attrib (Optional[dict[str, Any]]): Task attributes.
|
|
160
|
+
data (Optional[dict[str, Any]]): Task data.
|
|
161
|
+
tags (Optional[list[str]]): Task tags.
|
|
162
|
+
status (Optional[str]): Task status.
|
|
163
|
+
active (Optional[bool]): Task active state.
|
|
164
|
+
thumbnail_id (Optional[str]): Task thumbnail id.
|
|
165
|
+
task_id (Optional[str]): Task id. If not passed new id is
|
|
166
|
+
generated.
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
NewTaskDict: Skeleton of task entity.
|
|
170
|
+
|
|
171
|
+
"""
|
|
172
|
+
if not task_id:
|
|
173
|
+
task_id = create_entity_id()
|
|
174
|
+
output = {
|
|
175
|
+
"id": task_id,
|
|
176
|
+
"name": name,
|
|
177
|
+
"taskType": task_type,
|
|
178
|
+
"folderId": folder_id,
|
|
179
|
+
}
|
|
180
|
+
for key, value in (
|
|
181
|
+
("label", label),
|
|
182
|
+
("attrib", attrib),
|
|
183
|
+
("data", data),
|
|
184
|
+
("tags", tags),
|
|
185
|
+
("status", status),
|
|
186
|
+
("assignees", assignees),
|
|
187
|
+
("active", active),
|
|
188
|
+
("thumbnailId", thumbnail_id),
|
|
189
|
+
):
|
|
190
|
+
if value is not None:
|
|
191
|
+
output[key] = value
|
|
128
192
|
return output
|
|
129
193
|
|
|
130
194
|
|
|
@@ -1046,6 +1110,10 @@ class OperationsSession(object):
|
|
|
1046
1110
|
"taskType": task_type,
|
|
1047
1111
|
"folderId": folder_id,
|
|
1048
1112
|
}
|
|
1113
|
+
if tags is not None:
|
|
1114
|
+
tags = list(tags)
|
|
1115
|
+
if assignees is not None:
|
|
1116
|
+
assignees = list(assignees)
|
|
1049
1117
|
for key, value in (
|
|
1050
1118
|
("label", label),
|
|
1051
1119
|
("attrib", attrib),
|
|
@@ -362,6 +362,21 @@ class NewFolderDict(TypedDict):
|
|
|
362
362
|
tags: NotRequired[list[str]]
|
|
363
363
|
|
|
364
364
|
|
|
365
|
+
class NewTaskDict(TypedDict):
|
|
366
|
+
id: str
|
|
367
|
+
name: str
|
|
368
|
+
task_type: str
|
|
369
|
+
folder_id: str
|
|
370
|
+
label: NotRequired[str]
|
|
371
|
+
assignees: NotRequired[list[str]]
|
|
372
|
+
attrib: NotRequired[dict[str, Any]]
|
|
373
|
+
data: NotRequired[dict[str, Any]]
|
|
374
|
+
thumbnailId: NotRequired[str]
|
|
375
|
+
active: NotRequired[bool]
|
|
376
|
+
status: NotRequired[str]
|
|
377
|
+
tags: NotRequired[list[str]]
|
|
378
|
+
|
|
379
|
+
|
|
365
380
|
class NewProductDict(TypedDict):
|
|
366
381
|
id: str
|
|
367
382
|
name: str
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Package declaring Python API for AYON server."""
|
|
2
|
-
__version__ = "1.2.
|
|
2
|
+
__version__ = "1.2.4"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_api/_api_helpers/dependency_packages.py
RENAMED
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
{ayon_python_api-1.2.3 → ayon_python_api-1.2.4}/ayon_python_api.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|