- Use a dummy import statement like import('STUB') where needed, and replace these with import('my_movable_package.*') using an init.m script.
- Place this script in the package's root folder to recursively update all files with the correct fully qualified paths.
Future-proofness of my relative import solution?
25 views (last 30 days)
Show older comments
I am trying to solve the "relative-import" problem (import statements need to be absolute which makes using packages as subpackages in other packages hard).
I am solving this with a helper function located in the private-folder that is called `get_import_str`
function [import_str,parent_dir] = get_import_str()
% Returns the import string needed to import all sub-packages
%
% Usage: Place in the top of a package function to provide a relative import
%
% function out = functionA(arg1,arg2)
% % Package function located in <some_path>/+<some_package1>/+<some_package2>/
% % Import subpackages
% import_str = get_import_str();
% import(import_str);
%
% arg3 = functionB(arg1); % Sibling function
% out = arg1+arg2+arg3;
% end
%
stack_info = dbstack('-completenames');
if length(stack_info) <= 1, error('This function must be called from a m-file.'); end
caller_fn = stack_info(2).file;
[parent_dir,fname,~] = fileparts(fileparts(caller_fn));
while true
if ~strcmp(fname(1),'+')
parent_dir = fullfile(parent_dir,fname);
import_str = fileparts(caller_fn);
import_str = [replace(import_str(length(parent_dir)+3:end),[filesep,'+'],'.'),'.*'];
return
end
[parent_dir,fname,~] = fileparts(parent_dir);
end
end
To call a sibling package function you use the
function out = functionA(arg1,arg2)
import_str = get_import_str();
import(import_str);
arg3 = functionB(arg1); % Sibling function: Returns arg1*10
arg4 = sub_package.functionC(arg2); % Child-package-function: Returns arg2*pi
out = arg1+arg2+arg3+arg4;
end
This seems to work fine (please inform me if you se any issues) but now to my question:
Question: How future-proof is this? I get a warning saying
"In a future release, IMPORT will not accept variable names, function calls, or operators. Use literal char vectors instead."
At my company we run a old version of matlab (R2018b) but I don't want my stuff to break when we upgrade.
Details
<some-path>
+my_movable_package
private/
get_import_str.m
functionA.m
functionB.m
+sub_package
functionC.m
0 Comments
Answers (1)
Arnav
on 7 Nov 2024 at 11:02
To avoid deprecation warnings when using import function dynamically, switch to using fully qualified path names in the import statement. Alternatively, you can replace import statements statically before any function execution.
You can refer to the below:
To recursively find all .m files in a package you can use the code snippet shown:
function INIT()
script_full_path = mfilename('fullpath');
[package_root, ~, ~] = fileparts(script_full_path);
files = dir(fullfile(package_root, '**', '*.m'));
for k = 1:length(files)
file_path = fullfile(files(k).folder, files(k).name);
if strcmp(files(k).name, 'init.m')
continue;
end
replace_stub(file_path, package_root);
end
end
function replace_stub(file_path, package_root)
fid = fopen(file_path, 'r');
file_content = fread(fid, '*char')';
fclose(fid);
relative_path = strrep(file_path, [fileparts(package_root), filesep], '');
relative_path = fileparts(relative_path);
package_path = strrep(relative_path, ['+', filesep], '');
package_path = strrep(package_path, '+', '');
package_path = strrep(package_path, filesep, '.');
import_statement = sprintf("import('%s.*')", package_path);
new_content = strrep(file_content, "import('STUB')", import_statement);
fid = fopen(file_path, 'w');
fwrite(fid, new_content);
fclose(fid);
end
INIT();
This package can then be imported and used as shown below:
>> import my_movable_package.*
>> init
>> functionA(10, 12)
>> functionB(10)
0 Comments
See Also
Categories
Find more on Historical Contests in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!