array-split 0.6.4__py2.py3-none-any.whl → 0.7.0__py2.py3-none-any.whl
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.
- array_split/__init__.py +7 -5
- array_split/_version.py +3 -3
- array_split/license.py +5 -5
- array_split/logging.py +6 -84
- array_split/split.py +71 -84
- array_split/split_plot.py +3 -5
- array_split/split_test.py +17 -11
- array_split/tests.py +6 -11
- array_split/unittest.py +5 -173
- {array_split-0.6.4.dist-info → array_split-0.7.0.dist-info}/METADATA +4 -3
- array_split-0.7.0.dist-info/RECORD +16 -0
- {array_split-0.6.4.dist-info → array_split-0.7.0.dist-info}/WHEEL +1 -1
- array_split-0.6.4.dist-info/RECORD +0 -16
- {array_split-0.6.4.dist-info → array_split-0.7.0.dist-info/licenses}/LICENSE.txt +0 -0
- {array_split-0.6.4.dist-info → array_split-0.7.0.dist-info}/top_level.txt +0 -0
array_split/__init__.py
CHANGED
|
@@ -60,11 +60,13 @@ Attributes
|
|
|
60
60
|
|
|
61
61
|
|
|
62
62
|
"""
|
|
63
|
-
|
|
64
|
-
from .
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
63
|
+
|
|
64
|
+
from . import (
|
|
65
|
+
_version,
|
|
66
|
+
split,
|
|
67
|
+
)
|
|
68
|
+
from .license import copyright as _copyright, license as _license
|
|
69
|
+
from .split import ShapeSplitter, array_split, shape_split # noqa: F401
|
|
68
70
|
|
|
69
71
|
__author__ = "Shane J. Latham"
|
|
70
72
|
__license__ = _license()
|
array_split/_version.py
CHANGED
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "
|
|
11
|
+
"date": "2026-10-10T18:38:18+1100",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "0.
|
|
14
|
+
"full-revisionid": "5b616e6ba38686a13e353e572fc5b9f21f034bfe",
|
|
15
|
+
"version": "0.7.0"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
array_split/license.py
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
To be replaced.
|
|
3
3
|
"""
|
|
4
4
|
# pylint: disable=redefined-builtin
|
|
5
|
-
from
|
|
6
|
-
|
|
5
|
+
from importlib.resources import files
|
|
6
|
+
|
|
7
7
|
from . import _version
|
|
8
8
|
|
|
9
|
-
__copyright__ =
|
|
9
|
+
__copyright__ = files("array_split").joinpath("copyright.txt").read_bytes().decode()
|
|
10
10
|
__license__ = (
|
|
11
11
|
__copyright__
|
|
12
12
|
+
|
|
13
13
|
"\n\n"
|
|
14
14
|
+
|
|
15
|
-
|
|
15
|
+
files("array_split").joinpath("license.txt").read_bytes().decode()
|
|
16
16
|
)
|
|
17
17
|
__author__ = "Shane J. Latham"
|
|
18
18
|
__version__ = _version.get_versions()['version']
|
|
@@ -78,6 +78,6 @@ Functions
|
|
|
78
78
|
copyright - Returns :mod:`array_split` copyright string.
|
|
79
79
|
version - Returns :mod:`array_split` version string.
|
|
80
80
|
|
|
81
|
-
""" % (license(), copyright())
|
|
81
|
+
""" % (license(), copyright()) # noqa: UP031
|
|
82
82
|
|
|
83
83
|
__all__ = [s for s in dir() if not s.startswith('_')]
|
array_split/logging.py
CHANGED
|
@@ -26,12 +26,11 @@ Classes and Functions
|
|
|
26
26
|
# pylint: disable=wildcard-import
|
|
27
27
|
# pylint: disable=invalid-name
|
|
28
28
|
|
|
29
|
-
from __future__ import absolute_import
|
|
30
|
-
|
|
31
|
-
import sys
|
|
32
29
|
import logging as _builtin_logging
|
|
33
|
-
|
|
34
|
-
from
|
|
30
|
+
import sys
|
|
31
|
+
from logging import *
|
|
32
|
+
|
|
33
|
+
from .license import copyright as _copyright, license as _license, version as _version
|
|
35
34
|
|
|
36
35
|
__author__ = "Shane J. Latham"
|
|
37
36
|
__license__ = _license()
|
|
@@ -39,66 +38,7 @@ __copyright__ = _copyright()
|
|
|
39
38
|
__version__ = _version()
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
class
|
|
43
|
-
|
|
44
|
-
"""
|
|
45
|
-
A python :obj:`logging.handlers` :samp:`Handler` class for
|
|
46
|
-
splitting logging messages to different streams depending on
|
|
47
|
-
the logging-level.
|
|
48
|
-
"""
|
|
49
|
-
|
|
50
|
-
def __init__(self, outstr=sys.stdout, errstr=sys.stderr, splitlevel=_builtin_logging.WARNING):
|
|
51
|
-
"""
|
|
52
|
-
Initialise with a pair of streams and a threshold level which determines
|
|
53
|
-
the stream where the messages are writting.
|
|
54
|
-
|
|
55
|
-
:type outstr: file-like
|
|
56
|
-
:param outstr: Logging messages are written to this stream if
|
|
57
|
-
the message level is less than :samp:`self.splitLevel`.
|
|
58
|
-
:type errstr: stream
|
|
59
|
-
:param errstr: Logging messages are written to this stream if
|
|
60
|
-
the message level is greater-than-or-equal-to :samp:`self.splitLevel`.
|
|
61
|
-
:type splitlevel: int
|
|
62
|
-
:param splitlevel: Logging level threshold determining split streams for log messages.
|
|
63
|
-
"""
|
|
64
|
-
self.outStream = outstr
|
|
65
|
-
self.errStream = errstr
|
|
66
|
-
self.splitLevel = splitlevel
|
|
67
|
-
_builtin_logging.Handler.__init__(self)
|
|
68
|
-
|
|
69
|
-
def emit(self, record):
|
|
70
|
-
"""
|
|
71
|
-
Mostly copy-paste from :obj:`logging.StreamHandler`.
|
|
72
|
-
"""
|
|
73
|
-
try:
|
|
74
|
-
msg = self.format(record)
|
|
75
|
-
if record.levelno < self.splitLevel:
|
|
76
|
-
stream = self.outStream
|
|
77
|
-
else:
|
|
78
|
-
stream = self.errStream
|
|
79
|
-
fs = "%s\n"
|
|
80
|
-
|
|
81
|
-
try:
|
|
82
|
-
if (isinstance(msg, unicode) and # noqa: F405
|
|
83
|
-
getattr(stream, 'encoding', None)):
|
|
84
|
-
ufs = fs.decode(stream.encoding)
|
|
85
|
-
try:
|
|
86
|
-
stream.write(ufs % msg)
|
|
87
|
-
except UnicodeEncodeError:
|
|
88
|
-
stream.write((ufs % msg).encode(stream.encoding))
|
|
89
|
-
else:
|
|
90
|
-
stream.write(fs % msg)
|
|
91
|
-
except UnicodeError:
|
|
92
|
-
stream.write(fs % msg.encode("UTF-8"))
|
|
93
|
-
|
|
94
|
-
stream.flush()
|
|
95
|
-
except (KeyboardInterrupt, SystemExit):
|
|
96
|
-
raise
|
|
97
|
-
except Exception:
|
|
98
|
-
self.handleError(record)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class _Python3SplitStreamHandler(_builtin_logging.Handler):
|
|
41
|
+
class SplitStreamHandler(_builtin_logging.Handler):
|
|
102
42
|
|
|
103
43
|
"""
|
|
104
44
|
A python :obj:`logging.handlers` :samp:`Handler` class for
|
|
@@ -162,28 +102,10 @@ class _Python3SplitStreamHandler(_builtin_logging.Handler):
|
|
|
162
102
|
self.flush()
|
|
163
103
|
except (KeyboardInterrupt, SystemExit): # pragma: no cover
|
|
164
104
|
raise
|
|
165
|
-
except Exception:
|
|
105
|
+
except Exception: # noqa: BLE001
|
|
166
106
|
self.handleError(record)
|
|
167
107
|
|
|
168
108
|
|
|
169
|
-
if sys.version_info[0] <= 2:
|
|
170
|
-
class SplitStreamHandler(_Python2SplitStreamHandler):
|
|
171
|
-
|
|
172
|
-
"""
|
|
173
|
-
To be replaced.
|
|
174
|
-
"""
|
|
175
|
-
|
|
176
|
-
__doc__ = _Python2SplitStreamHandler.__doc__
|
|
177
|
-
else:
|
|
178
|
-
class SplitStreamHandler(_Python3SplitStreamHandler):
|
|
179
|
-
|
|
180
|
-
"""
|
|
181
|
-
To be replaced.
|
|
182
|
-
"""
|
|
183
|
-
|
|
184
|
-
__doc__ = _Python3SplitStreamHandler.__doc__
|
|
185
|
-
|
|
186
|
-
|
|
187
109
|
def get_formatter(prefix_string="ARRSPLT| "):
|
|
188
110
|
"""
|
|
189
111
|
Returns :obj:`logging.Formatter` object which produces messages
|
array_split/split.py
CHANGED
|
@@ -40,10 +40,10 @@ Utilities
|
|
|
40
40
|
pad_with_none - End pads a sequence with :samp:`None` elements.
|
|
41
41
|
|
|
42
42
|
"""
|
|
43
|
-
from __future__ import absolute_import
|
|
44
43
|
import numpy as _np
|
|
45
|
-
|
|
44
|
+
|
|
46
45
|
from . import logging as _logging
|
|
46
|
+
from .license import copyright as _copyright, license as _license, version as _version
|
|
47
47
|
|
|
48
48
|
__copyright__ = _copyright()
|
|
49
49
|
__version__ = _version()
|
|
@@ -151,9 +151,7 @@ def pad_with_object(sequence, new_length, obj=None):
|
|
|
151
151
|
list(sequence) + [obj, ] * (new_length - len(sequence))
|
|
152
152
|
elif len(sequence) > new_length:
|
|
153
153
|
raise ValueError(
|
|
154
|
-
"Got len(sequence)
|
|
155
|
-
%
|
|
156
|
-
(len(sequence), new_length)
|
|
154
|
+
f"Got len(sequence)={len(sequence)} which exceeds new_length={new_length}"
|
|
157
155
|
)
|
|
158
156
|
|
|
159
157
|
return sequence
|
|
@@ -302,12 +300,8 @@ def calculate_tile_shape_for_max_bytes(
|
|
|
302
300
|
|
|
303
301
|
if _np.any(array_shape < sub_tile_shape):
|
|
304
302
|
raise ValueError(
|
|
305
|
-
"Got array_shape
|
|
306
|
-
|
|
307
|
-
(
|
|
308
|
-
array_shape,
|
|
309
|
-
sub_tile_shape
|
|
310
|
-
)
|
|
303
|
+
f"Got array_shape={array_shape} element less than corresponding"
|
|
304
|
+
f" sub_tile_shape={sub_tile_shape} element."
|
|
311
305
|
)
|
|
312
306
|
|
|
313
307
|
logger.debug("max_tile_shape=%s", max_tile_shape)
|
|
@@ -448,19 +442,15 @@ def calculate_num_slices_per_axis(num_slices_per_axis, num_slices, max_slices_pe
|
|
|
448
442
|
max_slices_per_axis = _np.array(max_slices_per_axis)
|
|
449
443
|
|
|
450
444
|
if _np.any(max_slices_per_axis <= 0):
|
|
451
|
-
raise ValueError("Got non-positive value in max_slices_per_axis
|
|
445
|
+
raise ValueError(f"Got non-positive value in max_slices_per_axis={max_slices_per_axis}")
|
|
452
446
|
|
|
453
447
|
while _np.any(ret_array <= 0):
|
|
454
448
|
prd = _np.prod(ret_array[_np.where(ret_array > 0)]) # returns 1 for zero-length array
|
|
455
449
|
if (num_slices < prd) or ((num_slices % prd) > 0):
|
|
456
450
|
raise ValueError(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
"num_slices_per_axis=%s (with max_slices_per_axis=%s)"
|
|
461
|
-
)
|
|
462
|
-
%
|
|
463
|
-
(num_slices, num_slices_per_axis, max_slices_per_axis)
|
|
451
|
+
f"Unable to construct grid of num_slices={num_slices} elements from "
|
|
452
|
+
f"num_slices_per_axis={num_slices_per_axis}"
|
|
453
|
+
f" (with max_slices_per_axis={max_slices_per_axis})"
|
|
464
454
|
)
|
|
465
455
|
ridx = _np.where(ret_array <= 0)
|
|
466
456
|
f = shape_factors(num_slices // prd, ridx[0].shape[0])[::-1]
|
|
@@ -634,15 +624,13 @@ def convert_halo_to_array_form(halo, ndim):
|
|
|
634
624
|
|
|
635
625
|
if halo.shape[0] != ndim:
|
|
636
626
|
raise ValueError(
|
|
637
|
-
"Got halo.shape
|
|
638
|
-
%
|
|
639
|
-
(halo.shape, ndim)
|
|
627
|
+
f"Got halo.shape={halo.shape}, expecting halo.shape=({ndim}, 2)"
|
|
640
628
|
)
|
|
641
629
|
|
|
642
630
|
return halo
|
|
643
631
|
|
|
644
632
|
|
|
645
|
-
class ShapeSplitter
|
|
633
|
+
class ShapeSplitter:
|
|
646
634
|
|
|
647
635
|
"""
|
|
648
636
|
Implements array shape splitting. There are three main (top-level) methods:
|
|
@@ -687,7 +675,7 @@ class ShapeSplitter(object):
|
|
|
687
675
|
|
|
688
676
|
#: Class attribute indicating list of valid values for :attr:`tile_bound_policy`.
|
|
689
677
|
#: See :data:`ARRAY_BOUNDS` and :data:`NO_BOUNDS`.
|
|
690
|
-
valid_tile_bounds_policies =
|
|
678
|
+
valid_tile_bounds_policies = (ARRAY_BOUNDS, NO_BOUNDS)
|
|
691
679
|
|
|
692
680
|
def __init__(
|
|
693
681
|
self,
|
|
@@ -1026,9 +1014,8 @@ class ShapeSplitter(object):
|
|
|
1026
1014
|
"""
|
|
1027
1015
|
if self.tile_bounds_policy not in self.valid_tile_bounds_policies:
|
|
1028
1016
|
raise ValueError(
|
|
1029
|
-
"Got self.tile_bounds_policy
|
|
1030
|
-
|
|
1031
|
-
(self.tile_bounds_policy, self.valid_tile_bounds_policies)
|
|
1017
|
+
f"Got self.tile_bounds_policy={self.tile_bounds_policy},"
|
|
1018
|
+
f" which is not in {self.valid_tile_bounds_policies}."
|
|
1032
1019
|
)
|
|
1033
1020
|
|
|
1034
1021
|
def check_consistent_parameter_dimensions(self):
|
|
@@ -1038,55 +1025,55 @@ class ShapeSplitter(object):
|
|
|
1038
1025
|
|
|
1039
1026
|
:raises ValueError: For inconsistent parameter dimensions.
|
|
1040
1027
|
"""
|
|
1041
|
-
if
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
)
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
if self.tile_shape is not None:
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
(len(self.tile_shape), len(self.array_shape))
|
|
1065
|
-
)
|
|
1028
|
+
if (
|
|
1029
|
+
(self.indices_per_axis is not None)
|
|
1030
|
+
and
|
|
1031
|
+
(len(self.indices_per_axis) > len(self.array_shape))
|
|
1032
|
+
):
|
|
1033
|
+
raise ValueError(
|
|
1034
|
+
f"Got len(self.indices_per_axis)={len(self.indices_per_axis)}"
|
|
1035
|
+
f" > len(self.array_shape)={len(self.array_shape)}, should be equal."
|
|
1036
|
+
)
|
|
1037
|
+
if (
|
|
1038
|
+
(self.split_num_slices_per_axis is not None)
|
|
1039
|
+
and
|
|
1040
|
+
(len(self.split_num_slices_per_axis) > len(self.array_shape))
|
|
1041
|
+
):
|
|
1042
|
+
raise ValueError(
|
|
1043
|
+
f"Got len(self.split_num_slices_per_axis)={len(self.split_num_slices_per_axis)}"
|
|
1044
|
+
f" > len(self.array_shape)={len(self.array_shape)}, should be equal."
|
|
1045
|
+
)
|
|
1046
|
+
if (self.tile_shape is not None) and (len(self.tile_shape) != len(self.array_shape)):
|
|
1047
|
+
raise ValueError(
|
|
1048
|
+
f"Got len(self.tile_shape)={len(self.tile_shape)}"
|
|
1049
|
+
f" > len(self.array_shape)={len(self.array_shape)}, should be equal."
|
|
1050
|
+
)
|
|
1066
1051
|
|
|
1067
|
-
if
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
)
|
|
1052
|
+
if (
|
|
1053
|
+
(self.sub_tile_shape is not None)
|
|
1054
|
+
and
|
|
1055
|
+
(len(self.sub_tile_shape) != len(self.array_shape))
|
|
1056
|
+
):
|
|
1057
|
+
raise ValueError(
|
|
1058
|
+
f"Got len(self.sub_tile_shape)={len(self.sub_tile_shape)}"
|
|
1059
|
+
f" > len(self.array_shape)={len(self.array_shape)}, should be equal."
|
|
1060
|
+
)
|
|
1074
1061
|
|
|
1075
|
-
if
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
)
|
|
1062
|
+
if (
|
|
1063
|
+
(self.max_tile_shape is not None)
|
|
1064
|
+
and
|
|
1065
|
+
(len(self.max_tile_shape) != len(self.array_shape))
|
|
1066
|
+
):
|
|
1067
|
+
raise ValueError(
|
|
1068
|
+
f"Got len(self.max_tile_shape)={len(self.max_tile_shape)}"
|
|
1069
|
+
f" > len(self.array_shape)={len(self.array_shape)}, should be equal."
|
|
1070
|
+
)
|
|
1082
1071
|
|
|
1083
|
-
if self.array_start is not None:
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
(len(self.array_start), len(self.array_shape))
|
|
1089
|
-
)
|
|
1072
|
+
if (self.array_start is not None) and (len(self.array_start) != len(self.array_shape)):
|
|
1073
|
+
raise ValueError(
|
|
1074
|
+
f"Got len(self.array_start)={len(self.array_start)}"
|
|
1075
|
+
f" > len(self.array_shape)={len(self.array_shape)}, should be equal."
|
|
1076
|
+
)
|
|
1090
1077
|
|
|
1091
1078
|
def check_consistent_parameter_grouping(self):
|
|
1092
1079
|
"""
|
|
@@ -1111,11 +1098,11 @@ class ShapeSplitter(object):
|
|
|
1111
1098
|
parameter_groups["max_tile_bytes"] = \
|
|
1112
1099
|
{"self.max_tile_bytes": self.max_tile_bytes}
|
|
1113
1100
|
if self.max_tile_shape is not None:
|
|
1114
|
-
if "max_tile_bytes" not in parameter_groups
|
|
1101
|
+
if "max_tile_bytes" not in parameter_groups:
|
|
1115
1102
|
parameter_groups["max_tile_bytes"] = {}
|
|
1116
1103
|
parameter_groups["max_tile_bytes"]["self.max_tile_shape"] = self.max_tile_shape
|
|
1117
1104
|
if self.sub_tile_shape is not None:
|
|
1118
|
-
if "max_tile_bytes" not in parameter_groups
|
|
1105
|
+
if "max_tile_bytes" not in parameter_groups:
|
|
1119
1106
|
parameter_groups["max_tile_bytes"] = {}
|
|
1120
1107
|
parameter_groups["max_tile_bytes"]["self.sub_tile_shape"] = self.sub_tile_shape
|
|
1121
1108
|
|
|
@@ -1132,7 +1119,7 @@ class ShapeSplitter(object):
|
|
|
1132
1119
|
"\n".join(
|
|
1133
1120
|
[
|
|
1134
1121
|
(
|
|
1135
|
-
|
|
1122
|
+
f"Group {group_key!r:>18}: "
|
|
1136
1123
|
+
|
|
1137
1124
|
str(parameter_groups[group_key])
|
|
1138
1125
|
)
|
|
@@ -1251,11 +1238,11 @@ class ShapeSplitter(object):
|
|
|
1251
1238
|
_np.array(
|
|
1252
1239
|
_np.unravel_index(
|
|
1253
1240
|
_np.arange(0, _np.prod(self.split_shape)),
|
|
1254
|
-
self.split_shape if self.split_shape is not None else
|
|
1241
|
+
self.split_shape if self.split_shape is not None else ()
|
|
1255
1242
|
)
|
|
1256
1243
|
).T
|
|
1257
1244
|
],
|
|
1258
|
-
dtype=[("
|
|
1245
|
+
dtype=[(f"{d:d}", "object") for d in range(len(self.split_shape))]
|
|
1259
1246
|
).reshape(self.split_shape)
|
|
1260
1247
|
|
|
1261
1248
|
return ret
|
|
@@ -1303,11 +1290,11 @@ class ShapeSplitter(object):
|
|
|
1303
1290
|
_np.array(
|
|
1304
1291
|
_np.unravel_index(
|
|
1305
1292
|
_np.arange(0, _np.prod(self.split_shape)),
|
|
1306
|
-
self.split_shape if self.split_shape is not None else
|
|
1293
|
+
self.split_shape if self.split_shape is not None else ()
|
|
1307
1294
|
)
|
|
1308
1295
|
).T
|
|
1309
1296
|
],
|
|
1310
|
-
dtype=[("
|
|
1297
|
+
dtype=[(f"{d:d}", "2int64") for d in range(len(self.split_shape))]
|
|
1311
1298
|
).reshape(self.split_shape)
|
|
1312
1299
|
|
|
1313
1300
|
return ret
|
|
@@ -1533,7 +1520,7 @@ Initialises parameters which define a split.
|
|
|
1533
1520
|
|
|
1534
1521
|
.. seealso:: :ref:`array_split-examples`
|
|
1535
1522
|
|
|
1536
|
-
""" % (
|
|
1523
|
+
""" % ( # noqa: UP031
|
|
1537
1524
|
_array_shape_param_doc,
|
|
1538
1525
|
(
|
|
1539
1526
|
_ShapeSplitter__init__params_doc
|
|
@@ -1573,7 +1560,7 @@ Splits specified :samp:`{array_shape}` in tiles, returns array of :obj:`slice` t
|
|
|
1573
1560
|
:ref:`array_split-examples`
|
|
1574
1561
|
|
|
1575
1562
|
|
|
1576
|
-
""" % (
|
|
1563
|
+
""" % ( # noqa: UP031
|
|
1577
1564
|
_array_shape_param_doc,
|
|
1578
1565
|
(
|
|
1579
1566
|
_ShapeSplitter__init__params_doc
|
|
@@ -1599,7 +1586,7 @@ def array_split(
|
|
|
1599
1586
|
halo=None
|
|
1600
1587
|
):
|
|
1601
1588
|
"To be replaced."
|
|
1602
|
-
return
|
|
1589
|
+
return [
|
|
1603
1590
|
ary[slyce]
|
|
1604
1591
|
for slyce in
|
|
1605
1592
|
shape_split(
|
|
@@ -1615,7 +1602,7 @@ def array_split(
|
|
|
1615
1602
|
halo=halo,
|
|
1616
1603
|
tile_bounds_policy=ARRAY_BOUNDS
|
|
1617
1604
|
).flatten().tolist()
|
|
1618
|
-
|
|
1605
|
+
]
|
|
1619
1606
|
|
|
1620
1607
|
|
|
1621
1608
|
array_split.__doc__ =\
|
array_split/split_plot.py
CHANGED
|
@@ -16,9 +16,7 @@ Classes and Functions
|
|
|
16
16
|
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
-
from
|
|
20
|
-
|
|
21
|
-
from .license import license as _license, copyright as _copyright, version as _version
|
|
19
|
+
from .license import copyright as _copyright, license as _license, version as _version
|
|
22
20
|
|
|
23
21
|
__author__ = "Shane J. Latham"
|
|
24
22
|
__license__ = _license()
|
|
@@ -26,15 +24,15 @@ __copyright__ = _copyright()
|
|
|
26
24
|
__version__ = _version()
|
|
27
25
|
|
|
28
26
|
|
|
29
|
-
class SplitPlotter
|
|
27
|
+
class SplitPlotter:
|
|
30
28
|
"""
|
|
31
29
|
Plots a split.
|
|
32
30
|
"""
|
|
33
31
|
|
|
34
32
|
def __init__(self):
|
|
35
33
|
"""
|
|
34
|
+
Initialise.
|
|
36
35
|
"""
|
|
37
|
-
pass
|
|
38
36
|
|
|
39
37
|
|
|
40
38
|
def plot(split):
|
array_split/split_test.py
CHANGED
|
@@ -23,18 +23,24 @@ Classes
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
"""
|
|
26
|
-
from __future__ import absolute_import
|
|
27
|
-
import array_split as _array_split
|
|
28
26
|
import numpy as _np
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
from . import unittest as _unittest
|
|
32
|
-
from . import logging as _logging
|
|
28
|
+
import array_split as _array_split
|
|
33
29
|
|
|
34
|
-
from .
|
|
35
|
-
from .
|
|
36
|
-
from .split import
|
|
37
|
-
|
|
30
|
+
from . import logging as _logging, unittest as _unittest
|
|
31
|
+
from .license import copyright as _copyright, license as _license, version as _version
|
|
32
|
+
from .split import (
|
|
33
|
+
ARRAY_BOUNDS,
|
|
34
|
+
NO_BOUNDS,
|
|
35
|
+
ShapeSplitter,
|
|
36
|
+
array_split,
|
|
37
|
+
calculate_num_slices_per_axis,
|
|
38
|
+
calculate_tile_shape_for_max_bytes,
|
|
39
|
+
convert_halo_to_array_form,
|
|
40
|
+
pad_with_object,
|
|
41
|
+
shape_factors,
|
|
42
|
+
shape_split,
|
|
43
|
+
)
|
|
38
44
|
|
|
39
45
|
__author__ = "Shane J. Latham"
|
|
40
46
|
__license__ = _license()
|
|
@@ -1424,7 +1430,7 @@ class SplitTest(_unittest.TestCase):
|
|
|
1424
1430
|
split[4, 0].tolist()
|
|
1425
1431
|
)
|
|
1426
1432
|
for i in range(5, 8):
|
|
1427
|
-
for j in range(
|
|
1433
|
+
for j in range(12):
|
|
1428
1434
|
self.assertEqual(
|
|
1429
1435
|
slice(5, 5, None),
|
|
1430
1436
|
split[i, j].tolist()[0]
|
|
@@ -1437,7 +1443,7 @@ class SplitTest(_unittest.TestCase):
|
|
|
1437
1443
|
),
|
|
1438
1444
|
split[i, j].tolist()
|
|
1439
1445
|
)
|
|
1440
|
-
for i in range(
|
|
1446
|
+
for i in range(5):
|
|
1441
1447
|
for j in range(12, 15):
|
|
1442
1448
|
self.assertEqual(
|
|
1443
1449
|
slice(12, 12, None),
|
array_split/tests.py
CHANGED
|
@@ -24,17 +24,16 @@ Classes and Functions
|
|
|
24
24
|
|
|
25
25
|
"""
|
|
26
26
|
# pylint: disable=unused-import
|
|
27
|
-
from __future__ import absolute_import
|
|
28
|
-
import sys as _sys
|
|
29
|
-
import re as _re
|
|
30
|
-
import unittest as _unittest
|
|
31
27
|
import doctest as _doctest
|
|
32
28
|
import os.path
|
|
29
|
+
import re as _re
|
|
30
|
+
import unittest as _unittest
|
|
31
|
+
|
|
33
32
|
import array_split as _array_split
|
|
34
33
|
from array_split import split as _split
|
|
35
34
|
|
|
36
|
-
from .license import
|
|
37
|
-
from .split_test import SplitTest # noqa: F401
|
|
35
|
+
from .license import copyright as _copyright, license as _license, version as _version
|
|
36
|
+
from .split_test import SplitTest # noqa: F401
|
|
38
37
|
|
|
39
38
|
__author__ = "Shane J. Latham"
|
|
40
39
|
__license__ = _license()
|
|
@@ -53,15 +52,11 @@ class MultiPlatformAnd23Checker(_doctest_OuputChecker):
|
|
|
53
52
|
|
|
54
53
|
def check_output(self, want, got, optionflags):
|
|
55
54
|
"""
|
|
56
|
-
|
|
57
|
-
replaces :samp:`", dtype=int64)"` with :samp:`")"`.
|
|
55
|
+
Replaces :samp:`", dtype=int64)"` with :samp:`")"`.
|
|
58
56
|
|
|
59
57
|
See :meth:`doctest.OutputChecker.check_output`.
|
|
60
58
|
|
|
61
59
|
"""
|
|
62
|
-
if _sys.version_info[0] <= 2:
|
|
63
|
-
got = _re.sub("([0-9]+)L", "\\1", got)
|
|
64
|
-
|
|
65
60
|
got = _re.sub(", dtype=int64\\)", ")", got)
|
|
66
61
|
|
|
67
62
|
return _doctest_OuputChecker.check_output(self, want, got, optionflags)
|
array_split/unittest.py
CHANGED
|
@@ -18,12 +18,13 @@ Classes and Functions
|
|
|
18
18
|
TestCase - Extends :obj:`unittest.TestCase` with :obj:`TestCase.assertArraySplitEqual`.
|
|
19
19
|
|
|
20
20
|
"""
|
|
21
|
-
from __future__ import absolute_import
|
|
22
21
|
|
|
23
22
|
import unittest as _builtin_unittest
|
|
23
|
+
|
|
24
24
|
import numpy as _np
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
from . import logging as _logging
|
|
27
|
+
from .license import copyright as _copyright, license as _license, version as _version
|
|
27
28
|
|
|
28
29
|
__author__ = "Shane J. Latham"
|
|
29
30
|
__license__ = _license()
|
|
@@ -126,9 +127,8 @@ class TestCase(_builtin_unittest.TestCase):
|
|
|
126
127
|
((_np.array(splt1[i]).size == 0) and (_np.array(splt2[i]).size == 0))
|
|
127
128
|
),
|
|
128
129
|
msg=(
|
|
129
|
-
"element
|
|
130
|
-
|
|
131
|
-
(i, _np.array(splt1[i]), _np.array(splt2[i]))
|
|
130
|
+
f"element {i:d} of split is not equal"
|
|
131
|
+
f" {_np.array(splt1[i])} != {_np.array(splt2[i])}"
|
|
132
132
|
)
|
|
133
133
|
)
|
|
134
134
|
|
|
@@ -177,176 +177,8 @@ class TestCase(_builtin_unittest.TestCase):
|
|
|
177
177
|
"""
|
|
178
178
|
_builtin_unittest.TestCase.assertWarnsRegex(self, *args, **kwargs)
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
if not hasattr(TestCase, "assertSequenceEqual"):
|
|
182
|
-
# code from python-2.7 unitest.case.TestCase
|
|
183
|
-
_MAX_LENGTH = 80
|
|
184
|
-
|
|
185
|
-
def safe_repr(obj, short=False):
|
|
186
|
-
"""
|
|
187
|
-
Returns :func:`repr` string for :samp:`{obj}`.
|
|
188
|
-
"""
|
|
189
|
-
try:
|
|
190
|
-
result = repr(obj)
|
|
191
|
-
except Exception:
|
|
192
|
-
result = object.__repr__(obj)
|
|
193
|
-
if not short or len(result) < _MAX_LENGTH:
|
|
194
|
-
return result
|
|
195
|
-
return result[:_MAX_LENGTH] + ' [truncated]...'
|
|
196
|
-
|
|
197
|
-
def strclass(cls):
|
|
198
|
-
"""
|
|
199
|
-
Returns name string of :samp:`{cls}` as `<modulename>.<classname>`.
|
|
200
|
-
"""
|
|
201
|
-
return "%s.%s" % (cls.__module__, cls.__name__)
|
|
202
|
-
|
|
203
|
-
def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None):
|
|
204
|
-
"""An equality assertion for ordered sequences (like lists and tuples).
|
|
205
|
-
|
|
206
|
-
For the purposes of this function, a valid ordered sequence type is one
|
|
207
|
-
which can be indexed, has a length, and has an equality operator.
|
|
208
|
-
|
|
209
|
-
:param seq1: The first sequence to compare.
|
|
210
|
-
:param seq2: The second sequence to compare.
|
|
211
|
-
:param seq_type: The expected datatype of the sequences, or None if no
|
|
212
|
-
datatype should be enforced.
|
|
213
|
-
:param msg: Optional message to use on failure instead of a list of
|
|
214
|
-
differences.
|
|
215
|
-
"""
|
|
216
|
-
|
|
217
|
-
import pprint
|
|
218
|
-
import difflib
|
|
219
|
-
if seq_type is not None:
|
|
220
|
-
seq_type_name = seq_type.__name__
|
|
221
|
-
if not isinstance(seq1, seq_type):
|
|
222
|
-
raise self.failureException('First sequence is not a %s: %s'
|
|
223
|
-
% (seq_type_name, safe_repr(seq1)))
|
|
224
|
-
if not isinstance(seq2, seq_type):
|
|
225
|
-
raise self.failureException('Second sequence is not a %s: %s'
|
|
226
|
-
% (seq_type_name, safe_repr(seq2)))
|
|
227
|
-
else:
|
|
228
|
-
seq_type_name = "sequence"
|
|
229
|
-
|
|
230
|
-
differing = None
|
|
231
|
-
try:
|
|
232
|
-
len1 = len(seq1)
|
|
233
|
-
except (TypeError, NotImplementedError):
|
|
234
|
-
differing = 'First %s has no length. Non-sequence?' % (
|
|
235
|
-
seq_type_name)
|
|
236
|
-
|
|
237
|
-
if differing is None:
|
|
238
|
-
try:
|
|
239
|
-
len2 = len(seq2)
|
|
240
|
-
except (TypeError, NotImplementedError):
|
|
241
|
-
differing = 'Second %s has no length. Non-sequence?' % (
|
|
242
|
-
seq_type_name)
|
|
243
|
-
|
|
244
|
-
if differing is None:
|
|
245
|
-
if seq1 == seq2:
|
|
246
|
-
return
|
|
247
|
-
|
|
248
|
-
seq1_repr = safe_repr(seq1)
|
|
249
|
-
seq2_repr = safe_repr(seq2)
|
|
250
|
-
|
|
251
|
-
if len(seq1_repr) > 30:
|
|
252
|
-
seq1_repr = seq1_repr[:30] + '...'
|
|
253
|
-
if len(seq2_repr) > 30:
|
|
254
|
-
seq2_repr = seq2_repr[:30] + '...'
|
|
255
|
-
elements = (seq_type_name.capitalize(), seq1_repr, seq2_repr)
|
|
256
|
-
differing = '%ss differ: %s != %s\n' % elements
|
|
257
|
-
|
|
258
|
-
for i in range(min(len1, len2)):
|
|
259
|
-
try:
|
|
260
|
-
item1 = seq1[i]
|
|
261
|
-
except (TypeError, IndexError, NotImplementedError):
|
|
262
|
-
differing += ('\nUnable to index element %d of first %s\n' %
|
|
263
|
-
(i, seq_type_name))
|
|
264
|
-
break
|
|
265
|
-
|
|
266
|
-
try:
|
|
267
|
-
item2 = seq2[i]
|
|
268
|
-
except (TypeError, IndexError, NotImplementedError):
|
|
269
|
-
differing += ('\nUnable to index element %d of second %s\n' %
|
|
270
|
-
(i, seq_type_name))
|
|
271
|
-
break
|
|
272
|
-
|
|
273
|
-
if item1 != item2:
|
|
274
|
-
differing += ('\nFirst differing element %d:\n%s\n%s\n' %
|
|
275
|
-
(i, item1, item2))
|
|
276
|
-
break
|
|
277
|
-
else:
|
|
278
|
-
if (len1 == len2 and seq_type is None and
|
|
279
|
-
not isinstance(seq1, type(seq2))):
|
|
280
|
-
# The sequences are the same, but have differing types.
|
|
281
|
-
return
|
|
282
|
-
|
|
283
|
-
if len1 > len2:
|
|
284
|
-
differing += ('\nFirst %s contains %d additional '
|
|
285
|
-
'elements.\n' % (seq_type_name, len1 - len2))
|
|
286
|
-
try:
|
|
287
|
-
differing += ('First extra element %d:\n%s\n' %
|
|
288
|
-
(len2, seq1[len2]))
|
|
289
|
-
except (TypeError, IndexError, NotImplementedError):
|
|
290
|
-
differing += ('Unable to index element %d '
|
|
291
|
-
'of first %s\n' % (len2, seq_type_name))
|
|
292
|
-
elif len1 < len2:
|
|
293
|
-
differing += ('\nSecond %s contains %d additional '
|
|
294
|
-
'elements.\n' % (seq_type_name, len2 - len1))
|
|
295
|
-
try:
|
|
296
|
-
differing += ('First extra element %d:\n%s\n' %
|
|
297
|
-
(len1, seq2[len1]))
|
|
298
|
-
except (TypeError, IndexError, NotImplementedError):
|
|
299
|
-
differing += ('Unable to index element %d '
|
|
300
|
-
'of second %s\n' % (len1, seq_type_name))
|
|
301
|
-
standardMsg = differing
|
|
302
|
-
diffMsg = '\n' + '\n'.join(
|
|
303
|
-
difflib.ndiff(pprint.pformat(seq1).splitlines(),
|
|
304
|
-
pprint.pformat(seq2).splitlines()))
|
|
305
|
-
standardMsg = self._truncateMessage(standardMsg, diffMsg)
|
|
306
|
-
msg = self._formatMessage(msg, standardMsg)
|
|
307
|
-
self.fail(msg)
|
|
308
|
-
|
|
309
|
-
def _formatMessage(self, msg, standardMsg):
|
|
310
|
-
"""Honour the longMessage attribute when generating failure messages.
|
|
311
|
-
If longMessage is False this means:
|
|
312
|
-
* Use only an explicit message if it is provided
|
|
313
|
-
* Otherwise use the standard message for the assert
|
|
314
|
-
|
|
315
|
-
If longMessage is True:
|
|
316
|
-
* Use the standard message
|
|
317
|
-
* If an explicit message is provided, plus ' : ' and the explicit message
|
|
318
|
-
"""
|
|
319
|
-
if not self.longMessage:
|
|
320
|
-
return msg or standardMsg
|
|
321
|
-
if msg is None:
|
|
322
|
-
return standardMsg
|
|
323
|
-
try:
|
|
324
|
-
# don't switch to '{}' formatting in Python 2.X
|
|
325
|
-
# it changes the way unicode input is handled
|
|
326
|
-
return '%s : %s' % (standardMsg, msg)
|
|
327
|
-
except UnicodeDecodeError:
|
|
328
|
-
return '%s : %s' % (safe_repr(standardMsg), safe_repr(msg))
|
|
329
|
-
|
|
330
|
-
def _truncateMessage(self, message, diff):
|
|
331
|
-
DIFF_OMITTED = ('\nDiff is %s characters long. '
|
|
332
|
-
'Set self.maxDiff to None to see it.')
|
|
333
|
-
|
|
334
|
-
max_diff = self.maxDiff
|
|
335
|
-
if max_diff is None or len(diff) <= max_diff:
|
|
336
|
-
return message + diff
|
|
337
|
-
return message + (DIFF_OMITTED % len(diff))
|
|
338
|
-
|
|
339
|
-
_maxDiff = 80 * 8
|
|
340
|
-
setattr(TestCase, "maxDiff", _maxDiff)
|
|
341
|
-
setattr(TestCase, "_truncateMessage", _truncateMessage)
|
|
342
|
-
setattr(TestCase, "_formatMessage", _formatMessage)
|
|
343
|
-
setattr(TestCase, "assertSequenceEqual", assertSequenceEqual)
|
|
344
|
-
else:
|
|
345
|
-
|
|
346
180
|
def assertSequenceEqual(self, *args, **kwargs):
|
|
347
181
|
"""
|
|
348
182
|
See :obj:`unittest.TestCase.assertSequenceEqual`.
|
|
349
183
|
"""
|
|
350
184
|
_builtin_unittest.TestCase.assertSequenceEqual(self, *args, **kwargs)
|
|
351
|
-
|
|
352
|
-
setattr(TestCase, "assertSequenceEqual", assertSequenceEqual)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: array_split
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: The array_split python package is an enhancement to existing numpy.ndarray functions (such as numpy.array_split) which sub-divide a multi-dimensional array into a number of multi-dimensional sub-arrays (slices)
|
|
5
5
|
Author-email: Shane-J-Latham <array.split@gmail.com>, array-split <array.split@gmail.com>
|
|
6
6
|
License: Copyright (C) 2017 The Australian National University.
|
|
@@ -31,7 +31,8 @@ Classifier: Operating System :: OS Independent
|
|
|
31
31
|
Requires-Python: >=3.8
|
|
32
32
|
Description-Content-Type: text/x-rst
|
|
33
33
|
License-File: LICENSE.txt
|
|
34
|
-
Requires-Dist: numpy
|
|
34
|
+
Requires-Dist: numpy>=1.6
|
|
35
|
+
Dynamic: license-file
|
|
35
36
|
|
|
36
37
|
|
|
37
38
|
=============
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
array_split/__init__.py,sha256=y6bfgsztfoFp7BYPeKd47aacmuGErOU1Opf2NXhhV_k,2593
|
|
2
|
+
array_split/_version.py,sha256=WXLm9rJd0DCoORZ3dx3UvfuISQNobXkNOaq6KptNas4,497
|
|
3
|
+
array_split/copyright.txt,sha256=Kn1cZDiLPzgR9O6e-_OT2q_BELBKeFLEyMja8X3YOpU,55
|
|
4
|
+
array_split/license.py,sha256=E835AMFAGxWGAb4SX-nSEU3lSvjjPzVYRIJrVXL5elY,1491
|
|
5
|
+
array_split/license.txt,sha256=voJkgFtk2zV9dBOftdZ7NW3a_aXOLYErZcWZAK812-A,1022
|
|
6
|
+
array_split/logging.py,sha256=6YGQUFcPjTCWgeQHP-XEiPQfwk38J8YPvIgNLTuly9A,5462
|
|
7
|
+
array_split/split.py,sha256=kFOqiQLLI7LGDuUIApEJ6ePNvF85DPlrwsks3XvquW4,59533
|
|
8
|
+
array_split/split_plot.py,sha256=vgNDifvqTU59L91rBTUKg1zY52DRaezhF9GRSktoMz4,703
|
|
9
|
+
array_split/split_test.py,sha256=l2Gf7TqwEMZCc8p_5Qijl8P3QmsLhJoTjLbUh8RJczw,54544
|
|
10
|
+
array_split/tests.py,sha256=8en7bwXrr9ZbQvyVh3LW1sXBRqlj4EhVbV6gUTGSvOw,4030
|
|
11
|
+
array_split/unittest.py,sha256=Y-PWbRrBxCJ9MPTRw2pmaEHb4UoToveFaZTJJXQyRA8,6162
|
|
12
|
+
array_split-0.7.0.dist-info/licenses/LICENSE.txt,sha256=IyUbQpVqCKhPOzm6BVhZ2fJ_Uj7xr6NBhvlBq7rN3wQ,1079
|
|
13
|
+
array_split-0.7.0.dist-info/METADATA,sha256=tziSHKqtfwRmdMqP41cYqlVc7eGFeTKGhucKmuS9Jx4,10167
|
|
14
|
+
array_split-0.7.0.dist-info/WHEEL,sha256=4YBfCYNH4wlLpv3pzq1hbEuIlXA4WJabKLFurZ7eTL0,109
|
|
15
|
+
array_split-0.7.0.dist-info/top_level.txt,sha256=exjaJ5xH8Dhtj-gpoxxGnXIn4gga7_gnAmF7y3v0PBs,12
|
|
16
|
+
array_split-0.7.0.dist-info/RECORD,,
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
array_split/__init__.py,sha256=MhUT1vAjdCj_7TanAParWfHu8KmIEYEV5XqmeGorcoI,2655
|
|
2
|
-
array_split/_version.py,sha256=89zuw6m__XlOJrBK-nmTfqTRi6pBEVV4ZDUvP622Evo,497
|
|
3
|
-
array_split/copyright.txt,sha256=Kn1cZDiLPzgR9O6e-_OT2q_BELBKeFLEyMja8X3YOpU,55
|
|
4
|
-
array_split/license.py,sha256=p09v3AawXDoucFQ0vfZm7fYPtA6v48ssP0iR1Y8eU4c,1521
|
|
5
|
-
array_split/license.txt,sha256=voJkgFtk2zV9dBOftdZ7NW3a_aXOLYErZcWZAK812-A,1022
|
|
6
|
-
array_split/logging.py,sha256=siuVTYdxAmRxdwjhrxnSZA4AimNmlOlCHC3Ns9hZ4Sc,8017
|
|
7
|
-
array_split/split.py,sha256=diCJ2Ob_oPhj8khWhqspeuTBhY1MA1vmTUBTbsONNPI,59998
|
|
8
|
-
array_split/split_plot.py,sha256=kQb-j080rtNoIJn9HT-gRdjDnrmfaqcWtwJlXAOmp68,744
|
|
9
|
-
array_split/split_test.py,sha256=oeI5dtGZ-8mm9lvJj-I6ErZRMZu3Nio2xWL7hKrqeOI,54611
|
|
10
|
-
array_split/tests.py,sha256=-T6yGN9NOGHbfxVyYW2y_QrCWskG3m8rZtTeVfay39I,4251
|
|
11
|
-
array_split/unittest.py,sha256=3kf8oFLX-CikKnv2gswfp4tutn-FV773-L6alnvPmiM,13031
|
|
12
|
-
array_split-0.6.4.dist-info/LICENSE.txt,sha256=IyUbQpVqCKhPOzm6BVhZ2fJ_Uj7xr6NBhvlBq7rN3wQ,1079
|
|
13
|
-
array_split-0.6.4.dist-info/METADATA,sha256=Gz_jLyZ2KHR0QnrjGN_EaZJNBkjZkNACjeJ3O5YJIVk,10146
|
|
14
|
-
array_split-0.6.4.dist-info/WHEEL,sha256=XRxW4r1PNiVhMpP4bT9oWtu3HyndxpJ84SkubFgzp_Y,109
|
|
15
|
-
array_split-0.6.4.dist-info/top_level.txt,sha256=exjaJ5xH8Dhtj-gpoxxGnXIn4gga7_gnAmF7y3v0PBs,12
|
|
16
|
-
array_split-0.6.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|