Skip to content

Commit 8898cee

Browse files
authored
Update python setup logic
Merge pull request #111 from mathworks/python-setup
2 parents 9efc959 + a04a72a commit 8898cee

File tree

4 files changed

+74
-42
lines changed

4 files changed

+74
-42
lines changed

Zarr.m

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,30 +17,43 @@
1717
isRemote
1818
end
1919

20-
2120
methods(Static)
2221
function pySetup
23-
% Load the Python library
22+
% Set up Python path
2423

2524
% Python module setup and bootstrapping to MATLAB
2625
fullPath = mfilename('fullpath');
2726
zarrDirectory = fileparts(fullPath);
28-
modpath = fullfile(zarrDirectory, 'PythonModule');
29-
% Add the current folder to the Python search path
30-
if count(py.sys.path,modpath) == 0
31-
insert(py.sys.path,int32(0),modpath);
32-
end
33-
34-
% Check if the ZarrPy module is loaded already. If not, load
35-
% it.
36-
sys = py.importlib.import_module('sys');
37-
loadedModules = dictionary(sys.modules);
38-
if ~loadedModules.isKey("ZarrPy")
39-
zarrModule = py.importlib.import_module('ZarrPy');
40-
py.importlib.reload(zarrModule);
27+
zarrPyPath = fullfile(zarrDirectory, 'PythonModule');
28+
% Add ZarrPy to the Python search path if it is not there
29+
% already
30+
if count(py.sys.path,zarrPyPath) == 0
31+
insert(py.sys.path,int32(0),zarrPyPath);
4132
end
4233
end
4334

35+
function zarrPy = ZarrPy()
36+
% Get ZarrPy Python module
37+
38+
% Python will compile and cache the module after the first call
39+
% to import_module, so there is no harm in making this call
40+
% multiple times.
41+
zarrPy = py.importlib.import_module('ZarrPy');
42+
end
43+
44+
function pyReloadInProcess()
45+
% Reload ZarrPy module after it has been modified (for
46+
% In-Process Python only). Need to do `clear classes` before
47+
% this call. For Out-of-Process Python, can just use
48+
% `terminate(pyenv)` instead.
49+
50+
% make sure the python module is on the path
51+
Zarr.pySetup()
52+
53+
% reload
54+
py.importlib.reload(Zarr.ZarrPy);
55+
end
56+
4457
function isZarray = isZarrArray(path)
4558
% Given a path, determine if it is a Zarr array
4659

@@ -262,7 +275,7 @@ function makeZarrGroups(existingParentPath, newGroupsPath)
262275
% Extract the S3 bucket name and path
263276
[bucketName, objectPath] = Zarr.extractS3BucketNameAndPath(obj.Path);
264277
% Create a Python dictionary for the KV store driver
265-
obj.KVStoreSchema = py.ZarrPy.createKVStore(obj.isRemote, objectPath, bucketName);
278+
obj.KVStoreSchema = Zarr.ZarrPy.createKVStore(obj.isRemote, objectPath, bucketName);
266279

267280
else % Local file
268281
% Use full path
@@ -272,7 +285,7 @@ function makeZarrGroups(existingParentPath, newGroupsPath)
272285
error("MATLAB:Zarr:invalidPath",...
273286
"Unable to access path ""%s"".", path)
274287
end
275-
obj.KVStoreSchema = py.ZarrPy.createKVStore(obj.isRemote, obj.Path);
288+
obj.KVStoreSchema = Zarr.ZarrPy.createKVStore(obj.isRemote, obj.Path);
276289
end
277290
end
278291

@@ -310,7 +323,7 @@ function makeZarrGroups(existingParentPath, newGroupsPath)
310323
endInds = start + stride.*count;
311324

312325
% Read the data
313-
ndArrayData = py.ZarrPy.readZarr(obj.KVStoreSchema,...
326+
ndArrayData = Zarr.ZarrPy.readZarr(obj.KVStoreSchema,...
314327
start, endInds, stride);
315328

316329
% Store the datatype
@@ -363,7 +376,7 @@ function create(obj, dtype, data_size, chunk_size, fillvalue, compression)
363376

364377
% The Python function returns the Tensorstore schema, but we
365378
% do not use it for anything at the moment.
366-
obj.TensorstoreSchema = py.ZarrPy.createZarr(obj.KVStoreSchema, py.numpy.array(obj.DsetSize),...
379+
obj.TensorstoreSchema = Zarr.ZarrPy.createZarr(obj.KVStoreSchema, py.numpy.array(obj.DsetSize),...
367380
py.numpy.array(obj.ChunkSize), obj.Datatype.TensorstoreType, ...
368381
obj.Datatype.ZarrType, obj.Compression, obj.FillValue);
369382
%py.ZarrPy.temp(py.numpy.array([1, 1]), py.numpy.array([2, 2]))
@@ -400,7 +413,7 @@ function write(obj, data)
400413
"Unable to write data. Size of the data to be written must match size of the array.");
401414
end
402415

403-
py.ZarrPy.writeZarr(obj.KVStoreSchema, data);
416+
Zarr.ZarrPy.writeZarr(obj.KVStoreSchema, data);
404417
end
405418

406419
end

test/tZarr.m

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
classdef tZarr < SharedZarrTestSetup
2+
% Tests for Zarr class methods
3+
4+
% Copyright 2025 The MathWorks, Inc.
5+
6+
methods(Test)
7+
8+
function verifySupportedCloudPatterns(testcase)
9+
% Verify that the bucket name and the array path can be
10+
% extracted successfully if a cloud path is used as an input.
11+
12+
% This list contains path pattern currently supported by Zarr
13+
% in MATLAB. Any invalid path not matching any of these
14+
% patterns will result in an error.
15+
inpPath = {'https://mybucket.s3.us-west-2.amazonaws.com/path/to/myZarrFile', ...
16+
'https://mybucket.s3.amazonaws.com/path/to/myZarrFile', ...
17+
'https://mybucket.s3.custom-endpoint.org/path/to/myZarrFile', ...
18+
'https://s3.amazonaws.com/mybucket/path/to/myZarrFile', ...
19+
'https://s3.eu-central-1.example.edu/mybucket/path/to/myZarrFile', ...
20+
's3://mybucket/path/to/myZarrFile'};
21+
22+
for i = 1:length(inpPath)
23+
[bucketName, objectPath] = Zarr.extractS3BucketNameAndPath(inpPath{i});
24+
testcase.verifyEqual(bucketName, 'mybucket', ['Bucket name extraction failed for ' inpPath{i}]);
25+
testcase.verifyEqual(objectPath, 'path/to/myZarrFile', ['Object path extraction failed for ' inpPath{i}]);
26+
end
27+
end
28+
29+
function verifyReload(testcase)
30+
% Verify that calling reload method does not cause any issues
31+
32+
Zarr.pyReloadInProcess()
33+
zarrPyModule = Zarr.ZarrPy;
34+
testcase.verifyTrue(isa(zarrPyModule, 'py.module'))
35+
36+
end
37+
38+
39+
end
40+
end

test/tZarrCreate.m

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,6 @@ function createArrayRelativePath(testcase)
6262
testcase.verifyEqual(arrInfo.node_type,'array','Unexpected Zarr array node type');
6363
end
6464

65-
function verifySupportedCloudPatterns(testcase)
66-
% Verify that the bucket name and the array path can be
67-
% extracted successfully if a cloud path is used as an input.
68-
69-
% This list contains path pattern currently supported by Zarr
70-
% in MATLAB. Any invalid path not matching any of these
71-
% patterns will result in an error.
72-
inpPath = {'https://mybucket.s3.us-west-2.amazonaws.com/path/to/myZarrFile', ...
73-
'https://mybucket.s3.amazonaws.com/path/to/myZarrFile', ...
74-
'https://mybucket.s3.custom-endpoint.org/path/to/myZarrFile', ...
75-
'https://s3.amazonaws.com/mybucket/path/to/myZarrFile', ...
76-
'https://s3.eu-central-1.example.edu/mybucket/path/to/myZarrFile', ...
77-
's3://mybucket/path/to/myZarrFile'};
78-
79-
for i = 1:length(inpPath)
80-
[bucketName, objectPath] = Zarr.extractS3BucketNameAndPath(inpPath{i});
81-
testcase.verifyEqual(bucketName, 'mybucket', ['Bucket name extraction failed for ' inpPath{i}]);
82-
testcase.verifyEqual(objectPath, 'path/to/myZarrFile', ['Object path extraction failed for ' inpPath{i}]);
83-
end
84-
end
85-
8665
function invalidFilePath(testcase)
8766
% Verify error when an invalid file path is used as an input to
8867
% zarrcreate function.

test/tZarrWrite.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ function invalidFilePath(testcase)
128128
function dataDatatypeMismatch(testcase)
129129
% Verify error for mismatch between datatype value and datatype
130130
% of data to be written with zarrwrite.
131-
errID = 'MATLAB:Python:PyExceptionWithNDArrayInfoAndMsg';
131+
errID = 'MATLAB:Python:PyException';
132132
zarrcreate(testcase.ArrPathWrite,testcase.ArrSize,"Datatype",'int8');
133133
data = ones(testcase.ArrSize);
134134
testcase.verifyError(@()zarrwrite(testcase.ArrPathWrite,data),errID);

0 commit comments

Comments
 (0)