c2pa-python 0.37.3__tar.gz → 0.37.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.
- {c2pa_python-0.37.3/src/c2pa_python.egg-info → c2pa_python-0.37.4}/PKG-INFO +4 -4
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/README.md +3 -3
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/pyproject.toml +1 -1
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa/c2pa.py +42 -42
- {c2pa_python-0.37.3 → c2pa_python-0.37.4/src/c2pa_python.egg-info}/PKG-INFO +4 -4
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/tests/test_unit_tests.py +12 -12
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/LICENSE-APACHE +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/LICENSE-MIT +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/MANIFEST.in +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/requirements.txt +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/scripts/download_artifacts.py +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/setup.cfg +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/setup.py +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa/__init__.py +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa/build.py +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa/lib.py +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa_python.egg-info/SOURCES.txt +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa_python.egg-info/dependency_links.txt +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa_python.egg-info/entry_points.txt +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa_python.egg-info/requires.txt +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/src/c2pa_python.egg-info/top_level.txt +0 -0
- {c2pa_python-0.37.3 → c2pa_python-0.37.4}/tests/test_unit_tests_threaded.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c2pa-python
|
|
3
|
-
Version: 0.37.
|
|
3
|
+
Version: 0.37.4
|
|
4
4
|
Summary: Python bindings for the C2PA Content Authenticity Initiative (CAI) library
|
|
5
5
|
Author-email: Gavin Peacock <gvnpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
|
|
6
6
|
Maintainer-email: Gavin Peacock <gpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
|
|
@@ -35,7 +35,7 @@ Features:
|
|
|
35
35
|
- Add assertions and ingredients to assets.
|
|
36
36
|
- Examples and unit tests to demonstrate usage.
|
|
37
37
|
|
|
38
|
-
<div
|
|
38
|
+
<div class="github-only">
|
|
39
39
|
|
|
40
40
|
For the best experience, read the docs on the [CAI Open Source SDK documentation website](https://opensource.contentauthenticity.org/docs/c2pa-c).
|
|
41
41
|
|
|
@@ -44,7 +44,7 @@ If you want to view the documentation in GitHub, see:
|
|
|
44
44
|
- [Supported formats](https://github.com/contentauth/c2pa-rs/blob/main/docs/supported-formats.md)
|
|
45
45
|
- [Configuring the SDK using `Context` and `Settings`](docs/context-settings.md)
|
|
46
46
|
- [Using Builder intents](docs/intents.md) to ensure spec-compliant manifests
|
|
47
|
-
- Using [working stores and
|
|
47
|
+
- Using [working stores and archives](docs/working-stores.md)
|
|
48
48
|
- Selectively constructing manifests by [filtering actions and ingredients](docs/selective-manifests.md)
|
|
49
49
|
- [Diagram of public classes in the Python library and their relationships](docs/class-diagram.md)
|
|
50
50
|
- [Release notes](docs/release-notes.md)
|
|
@@ -95,7 +95,7 @@ export C2PA_RS_PATH=/path/to/c2pa-rs
|
|
|
95
95
|
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`.
|
|
98
|
+
This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`. By default, the build uses the release profile; to build the debug profile instead, pass `EXTRA_BUILD_ARGS="--debug"`:
|
|
99
99
|
|
|
100
100
|
```sh
|
|
101
101
|
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH EXTRA_BUILD_ARGS="--debug"
|
|
@@ -12,7 +12,7 @@ Features:
|
|
|
12
12
|
- Add assertions and ingredients to assets.
|
|
13
13
|
- Examples and unit tests to demonstrate usage.
|
|
14
14
|
|
|
15
|
-
<div
|
|
15
|
+
<div class="github-only">
|
|
16
16
|
|
|
17
17
|
For the best experience, read the docs on the [CAI Open Source SDK documentation website](https://opensource.contentauthenticity.org/docs/c2pa-c).
|
|
18
18
|
|
|
@@ -21,7 +21,7 @@ If you want to view the documentation in GitHub, see:
|
|
|
21
21
|
- [Supported formats](https://github.com/contentauth/c2pa-rs/blob/main/docs/supported-formats.md)
|
|
22
22
|
- [Configuring the SDK using `Context` and `Settings`](docs/context-settings.md)
|
|
23
23
|
- [Using Builder intents](docs/intents.md) to ensure spec-compliant manifests
|
|
24
|
-
- Using [working stores and
|
|
24
|
+
- Using [working stores and archives](docs/working-stores.md)
|
|
25
25
|
- Selectively constructing manifests by [filtering actions and ingredients](docs/selective-manifests.md)
|
|
26
26
|
- [Diagram of public classes in the Python library and their relationships](docs/class-diagram.md)
|
|
27
27
|
- [Release notes](docs/release-notes.md)
|
|
@@ -72,7 +72,7 @@ export C2PA_RS_PATH=/path/to/c2pa-rs
|
|
|
72
72
|
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
-
This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`.
|
|
75
|
+
This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`. By default, the build uses the release profile; to build the debug profile instead, pass `EXTRA_BUILD_ARGS="--debug"`:
|
|
76
76
|
|
|
77
77
|
```sh
|
|
78
78
|
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH EXTRA_BUILD_ARGS="--debug"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "c2pa-python"
|
|
7
|
-
version = "0.37.
|
|
7
|
+
version = "0.37.4"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
description = "Python bindings for the C2PA Content Authenticity Initiative (CAI) library"
|
|
10
10
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# specific language governing permissions and limitations under
|
|
12
12
|
# each license.
|
|
13
13
|
|
|
14
|
-
# Version: 0.37.
|
|
14
|
+
# Version: 0.37.4
|
|
15
15
|
|
|
16
16
|
import ctypes
|
|
17
17
|
import enum
|
|
@@ -1464,36 +1464,6 @@ def load_settings(settings: Union[str, dict], format: str = "json") -> None:
|
|
|
1464
1464
|
check=lambda r: r != 0)
|
|
1465
1465
|
|
|
1466
1466
|
|
|
1467
|
-
def _get_mime_type_from_path(path: Union[str, Path]) -> str:
|
|
1468
|
-
"""Attempt to guess the MIME type from a file path's extension.
|
|
1469
|
-
When the extension is missing or unrecognized, this returns an empty
|
|
1470
|
-
string so the caller hands it to the lib for auto-detection.
|
|
1471
|
-
A recognized-but-wrong extension still returns a mimetype:
|
|
1472
|
-
the native layer will attempt to correct it from the bytes when
|
|
1473
|
-
reading (the real type still needs to be supported by the lib),
|
|
1474
|
-
and if it can't, an error will happen then.
|
|
1475
|
-
|
|
1476
|
-
Args:
|
|
1477
|
-
path: File path as string or Path object
|
|
1478
|
-
|
|
1479
|
-
Returns:
|
|
1480
|
-
MIME type string, or an empty string
|
|
1481
|
-
(when it cannot be determined from the extension).
|
|
1482
|
-
An empty string here means the native lib should attempt auto-detect.
|
|
1483
|
-
"""
|
|
1484
|
-
path_obj = Path(path)
|
|
1485
|
-
file_extension = path_obj.suffix.lower() if path_obj.suffix else ""
|
|
1486
|
-
|
|
1487
|
-
if file_extension == ".dng":
|
|
1488
|
-
# mimetypes guesses the wrong type for dng,
|
|
1489
|
-
# so we bypass it and set the correct type
|
|
1490
|
-
return "image/dng"
|
|
1491
|
-
else:
|
|
1492
|
-
# Fall back to an empty string for extensionless or unknown files.
|
|
1493
|
-
# Empty string flags this as a guess-type attempt.
|
|
1494
|
-
return mimetypes.guess_type(str(path))[0] or ""
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
1467
|
class ContextProvider(ABC):
|
|
1498
1468
|
"""Abstract base class for types that provide a C2PA context.
|
|
1499
1469
|
|
|
@@ -2154,6 +2124,46 @@ class Stream:
|
|
|
2154
2124
|
"""
|
|
2155
2125
|
return self._initialized
|
|
2156
2126
|
|
|
2127
|
+
@staticmethod
|
|
2128
|
+
def is_read_stream(obj) -> bool:
|
|
2129
|
+
"""Return True if obj is a stream-like object this SDK can use.
|
|
2130
|
+
Note: only method presence to identify streams are checked,
|
|
2131
|
+
not that they work (a broken stream can fail later).
|
|
2132
|
+
"""
|
|
2133
|
+
if obj is None or isinstance(obj, (str, Path)):
|
|
2134
|
+
return False
|
|
2135
|
+
return all(hasattr(obj, method) for method in Stream._REQUIRED_STREAM_METHODS)
|
|
2136
|
+
|
|
2137
|
+
|
|
2138
|
+
def _get_mime_type_from_path(path: Union[str, Path]) -> str:
|
|
2139
|
+
"""Attempt to guess the MIME type from a file path's extension.
|
|
2140
|
+
When the extension is missing or unrecognized, this returns an empty
|
|
2141
|
+
string so the caller hands it to the lib for auto-detection.
|
|
2142
|
+
A recognized-but-wrong extension still returns a mimetype:
|
|
2143
|
+
the native layer will attempt to correct it from the bytes when
|
|
2144
|
+
reading (the real type still needs to be supported by the lib),
|
|
2145
|
+
and if it can't, an error will happen then.
|
|
2146
|
+
|
|
2147
|
+
Args:
|
|
2148
|
+
path: File path as string or Path object
|
|
2149
|
+
|
|
2150
|
+
Returns:
|
|
2151
|
+
MIME type string, or an empty string
|
|
2152
|
+
(when it cannot be determined from the extension).
|
|
2153
|
+
An empty string here means the native lib should attempt auto-detect.
|
|
2154
|
+
"""
|
|
2155
|
+
path_obj = Path(path)
|
|
2156
|
+
file_extension = path_obj.suffix.lower() if path_obj.suffix else ""
|
|
2157
|
+
|
|
2158
|
+
if file_extension == ".dng":
|
|
2159
|
+
# mimetypes guesses the wrong type for dng,
|
|
2160
|
+
# so we bypass it and set the correct type
|
|
2161
|
+
return "image/dng"
|
|
2162
|
+
else:
|
|
2163
|
+
# Fall back to an empty string for extensionless or unknown files.
|
|
2164
|
+
# Empty string flags this as a guess-type attempt.
|
|
2165
|
+
return mimetypes.guess_type(str(path))[0] or ""
|
|
2166
|
+
|
|
2157
2167
|
|
|
2158
2168
|
def _get_supported_mime_types(ffi_func, cache):
|
|
2159
2169
|
"""Shared helper to retrieve supported MIME types from the native library.
|
|
@@ -2269,16 +2279,6 @@ def _format_ffi_arg(fmt: Optional[bytes]) -> bytes:
|
|
|
2269
2279
|
return fmt if fmt is not None else b""
|
|
2270
2280
|
|
|
2271
2281
|
|
|
2272
|
-
def _is_read_stream(obj) -> bool:
|
|
2273
|
-
"""Return True if obj is a stream-like object this SDK can use.
|
|
2274
|
-
Note: only method presence to identify streams are checked,
|
|
2275
|
-
not that they work (a broken stream can fail later).
|
|
2276
|
-
"""
|
|
2277
|
-
if obj is None or isinstance(obj, (str, Path)):
|
|
2278
|
-
return False
|
|
2279
|
-
return all(hasattr(obj, method) for method in Stream._REQUIRED_STREAM_METHODS)
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
2282
|
class Reader(ManagedResource):
|
|
2283
2283
|
"""High-level wrapper for C2PA Reader operations.
|
|
2284
2284
|
|
|
@@ -2478,7 +2478,7 @@ class Reader(ManagedResource):
|
|
|
2478
2478
|
self._context = context
|
|
2479
2479
|
|
|
2480
2480
|
# Only stream, no format: Reader(fh) must auto-detect on the stream.
|
|
2481
|
-
if stream is None and
|
|
2481
|
+
if stream is None and Stream.is_read_stream(format_or_path):
|
|
2482
2482
|
stream = format_or_path
|
|
2483
2483
|
format_or_path = None
|
|
2484
2484
|
# A context supplies settings, not the asset, so a path or stream is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c2pa-python
|
|
3
|
-
Version: 0.37.
|
|
3
|
+
Version: 0.37.4
|
|
4
4
|
Summary: Python bindings for the C2PA Content Authenticity Initiative (CAI) library
|
|
5
5
|
Author-email: Gavin Peacock <gvnpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
|
|
6
6
|
Maintainer-email: Gavin Peacock <gpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
|
|
@@ -35,7 +35,7 @@ Features:
|
|
|
35
35
|
- Add assertions and ingredients to assets.
|
|
36
36
|
- Examples and unit tests to demonstrate usage.
|
|
37
37
|
|
|
38
|
-
<div
|
|
38
|
+
<div class="github-only">
|
|
39
39
|
|
|
40
40
|
For the best experience, read the docs on the [CAI Open Source SDK documentation website](https://opensource.contentauthenticity.org/docs/c2pa-c).
|
|
41
41
|
|
|
@@ -44,7 +44,7 @@ If you want to view the documentation in GitHub, see:
|
|
|
44
44
|
- [Supported formats](https://github.com/contentauth/c2pa-rs/blob/main/docs/supported-formats.md)
|
|
45
45
|
- [Configuring the SDK using `Context` and `Settings`](docs/context-settings.md)
|
|
46
46
|
- [Using Builder intents](docs/intents.md) to ensure spec-compliant manifests
|
|
47
|
-
- Using [working stores and
|
|
47
|
+
- Using [working stores and archives](docs/working-stores.md)
|
|
48
48
|
- Selectively constructing manifests by [filtering actions and ingredients](docs/selective-manifests.md)
|
|
49
49
|
- [Diagram of public classes in the Python library and their relationships](docs/class-diagram.md)
|
|
50
50
|
- [Release notes](docs/release-notes.md)
|
|
@@ -95,7 +95,7 @@ export C2PA_RS_PATH=/path/to/c2pa-rs
|
|
|
95
95
|
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH
|
|
96
96
|
```
|
|
97
97
|
|
|
98
|
-
This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`.
|
|
98
|
+
This does a clean build of the `c2pa-c-ffi` crate (with the `file_io` feature, which the Python wrapper requires), stages the resulting library under both `artifacts/` and `src/c2pa/libs/`, and installs the package in editable mode, replacing any prebuilt artifacts from `make download-native-artifacts`. By default, the build uses the release profile; to build the debug profile instead, pass `EXTRA_BUILD_ARGS="--debug"`:
|
|
99
99
|
|
|
100
100
|
```sh
|
|
101
101
|
make build-from-source C2PA_RS_PATH=$C2PA_RS_PATH EXTRA_BUILD_ARGS="--debug"
|
|
@@ -36,7 +36,7 @@ warnings.simplefilter("ignore", category=DeprecationWarning)
|
|
|
36
36
|
|
|
37
37
|
from c2pa import Builder, C2paError as Error, Reader, C2paSigningAlg as SigningAlg, C2paSignerInfo, Signer, sdk_version, C2paBuilderIntent, C2paDigitalSourceType
|
|
38
38
|
from c2pa import Settings, Context, ContextBuilder, ContextProvider
|
|
39
|
-
from c2pa.c2pa import Stream, LifecycleState, ManagedResource, load_settings, create_signer, create_signer_from_info, ed25519_sign, format_embeddable, _get_mime_type_from_path, _encode_format, _format_ffi_arg
|
|
39
|
+
from c2pa.c2pa import Stream, LifecycleState, ManagedResource, load_settings, create_signer, create_signer_from_info, ed25519_sign, format_embeddable, _get_mime_type_from_path, _encode_format, _format_ffi_arg
|
|
40
40
|
import c2pa.c2pa as c2pa_module
|
|
41
41
|
from pathlib import Path
|
|
42
42
|
|
|
@@ -105,17 +105,17 @@ class TestIsReadableStream(unittest.TestCase):
|
|
|
105
105
|
def test_paths_and_formats_are_not_streams(self):
|
|
106
106
|
for value in (None, "", "image/jpeg", "path/to/file.jpg",
|
|
107
107
|
Path("x.jpg")):
|
|
108
|
-
self.assertFalse(
|
|
108
|
+
self.assertFalse(Stream.is_read_stream(value), repr(value))
|
|
109
109
|
|
|
110
110
|
def test_non_stream_objects_are_not_streams(self):
|
|
111
111
|
for value in (b"bytes", bytearray(b"x"), 42, object()):
|
|
112
|
-
self.assertFalse(
|
|
112
|
+
self.assertFalse(Stream.is_read_stream(value), repr(value))
|
|
113
113
|
|
|
114
114
|
def test_object_missing_methods_is_not_a_stream(self):
|
|
115
115
|
class OnlyRead:
|
|
116
116
|
def read(self):
|
|
117
117
|
return b""
|
|
118
|
-
self.assertFalse(
|
|
118
|
+
self.assertFalse(Stream.is_read_stream(OnlyRead()))
|
|
119
119
|
|
|
120
120
|
def test_read_only_object_is_not_a_stream(self):
|
|
121
121
|
# Has read/seek/tell but no write/flush, so not a Stream for us.
|
|
@@ -128,11 +128,11 @@ class TestIsReadableStream(unittest.TestCase):
|
|
|
128
128
|
|
|
129
129
|
def tell(self):
|
|
130
130
|
return 0
|
|
131
|
-
self.assertFalse(
|
|
131
|
+
self.assertFalse(Stream.is_read_stream(ReadOnly()))
|
|
132
132
|
|
|
133
133
|
def test_in_memory_streams_are_streams(self):
|
|
134
|
-
self.assertTrue(
|
|
135
|
-
self.assertTrue(
|
|
134
|
+
self.assertTrue(Stream.is_read_stream(io.BytesIO(b"x")))
|
|
135
|
+
self.assertTrue(Stream.is_read_stream(io.StringIO("x")))
|
|
136
136
|
|
|
137
137
|
def test_file_handles_are_streams(self):
|
|
138
138
|
path = self._tmp_path()
|
|
@@ -145,13 +145,13 @@ class TestIsReadableStream(unittest.TestCase):
|
|
|
145
145
|
):
|
|
146
146
|
fh = opener()
|
|
147
147
|
try:
|
|
148
|
-
self.assertTrue(
|
|
148
|
+
self.assertTrue(Stream.is_read_stream(fh), type(fh).__name__)
|
|
149
149
|
finally:
|
|
150
150
|
fh.close()
|
|
151
151
|
|
|
152
152
|
def test_spooled_temporary_file_is_a_stream(self):
|
|
153
153
|
with tempfile.SpooledTemporaryFile() as fh:
|
|
154
|
-
self.assertTrue(
|
|
154
|
+
self.assertTrue(Stream.is_read_stream(fh))
|
|
155
155
|
|
|
156
156
|
def test_compressed_file_objects_are_streams(self):
|
|
157
157
|
with tempfile.TemporaryDirectory() as tmp:
|
|
@@ -164,7 +164,7 @@ class TestIsReadableStream(unittest.TestCase):
|
|
|
164
164
|
with opener(p, "wb") as fh:
|
|
165
165
|
fh.write(b"data")
|
|
166
166
|
with opener(p, "rb") as fh:
|
|
167
|
-
self.assertTrue(
|
|
167
|
+
self.assertTrue(Stream.is_read_stream(fh), ext)
|
|
168
168
|
|
|
169
169
|
def test_placeholder_typed_object_with_all_methods_is_a_stream(self):
|
|
170
170
|
class Duck:
|
|
@@ -182,7 +182,7 @@ class TestIsReadableStream(unittest.TestCase):
|
|
|
182
182
|
|
|
183
183
|
def flush(self):
|
|
184
184
|
pass
|
|
185
|
-
self.assertTrue(
|
|
185
|
+
self.assertTrue(Stream.is_read_stream(Duck()))
|
|
186
186
|
|
|
187
187
|
|
|
188
188
|
class TestFormatValidation(unittest.TestCase):
|
|
@@ -562,7 +562,7 @@ class TestReader(unittest.TestCase):
|
|
|
562
562
|
reader.close()
|
|
563
563
|
|
|
564
564
|
def test_bare_stream_closed_handle_raises(self):
|
|
565
|
-
#
|
|
565
|
+
# Stream.is_read_stream only checks method presence
|
|
566
566
|
# so a closed handle is accepted as a stream and fails at read time.
|
|
567
567
|
file = open(self.testPath, "rb")
|
|
568
568
|
file.close()
|
|
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
|