How can I create the equivalent a python list without actually calling py.list?

9 views (last 30 days)
I am trying to call a RESTful API from within MATLAB using webwrite but am hung up on how to create the search query. If I force the input to be a python list using py.list, the search works OK using the py.requests module, but not if I pass the input as a MATLAB string that appears to be the same as the python list but is not being recognized as a list. Unless I use py.list to create the input, I get an error about "'PSScene' is not of type 'array'". I have tried different ways of formatting the string in question and can produce a json string that appears to be identical to that created using the python list but results in the array error.
I realize this is confusing, but I would appreciate any insight whatsoever. Here's the code I've been trying, with comments on what did and did not work:
%% Set up session for the search by logging in with Planet API key
BASE_URL = "https://api.planet.com/data/v1";
% % Authenticate with API_KEY defined as an environment variable
PLANET_API_KEY = getenv(apiKeyVar);
headerFields = {'Content-Type', 'application/json'};
options = weboptions('Username',PLANET_API_KEY,'Password','',...
'HeaderFields', headerFields);
response = webread(BASE_URL,options);
% response has a struct x_links with field x_self, which isn't very
% meaningful or specific, but at least we appear to be logged in this way
% Try again using one of the URL's returned by this initial request
assetUrl = response.x_links.asset_types;
assetResponse = webread(assetUrl,options); %#ok<*NASGU>
% This returns a struct with a field named asset_types that has information
% about all the different kinds of assets, for example
% assetResponse.asset_types.display_name
% If nothing else, this confirms that we're logged in to the Planet API OK
% using the webread options above to authenticate and specicy content type
%%
%% Try a simple search using the Python requests module
s = py.requests.session();
r = s.get(BASE_URL,pyargs('auth',{PLANET_API_KEY,''})) %#ok<*NOPTS>
% Returns 200, which is the code for OK
r.text
% Has the same output as the webread we did above, so so far so good
endPoint= "quick-search";
request = ['{"item_types":"' char(itemType) '","filter":' dateJson '}'];
result = s.post(BASE_URL+"/"+endPoint,pyargs('auth',{PLANET_API_KEY,''},...
'json',request))
% This returns status code 400 and the following error message in result.text:
% "A request body is required and must be an object"
%%
%% Repeat search attempt by explicitly forcing Python data types
% Another error we get is that PSScene is not of type array, and looking at the
% python variable explorer indicates that it should be a list, not a string
list = py.list(cellstr(itemType));
% Now use this python list to build the struct for our search request
searchRequest = struct("item_types",list,"filter",dateStruct);
% searchRequest = struct("item_types",cellstr("['" + itemType + "']"),"filter",dateStruct);
% Seems like this should work but we get error "'PSScene' is not of type 'array'"
endPoint = "quick-search";
% Note that passing the structure array directly works OK, so conversion from
% struct to dict must be handled automatically and correctly
searchResult = py.requests.post(BASE_URL+"/"+endPoint,pyargs('json',searchRequest,...
'auth',{PLANET_API_KEY,''}));
% Looks like this finally worked and we can extract the output of interest as a
% structure array containing search results by decoding the output json string
out = jsondecode(string(searchResult.text));
out.features(33) % Lots of info here but the only thing we need to download is id
% Note that various attempt to pass the request as a string withoug making a
% py.list all led to the error "'PSScene' is not of type 'array'"
% So the real question seems to be how to make a MATLAB string into a python
% list without calling py.list?
%%
%% Give it a shot with webwrite - nope
data = struct("item_types",cellstr("['" + itemType + "']"),"filter",dateStruct);
data = jsonencode(data);
tmp = webwrite(BASE_URL+"/"+endPoint,data,options);
% This yields an error from deep within readContentFromWebService.m:
% The server returned the status 400 with message "Bad Request" in response to the request to URL
% https://api.planet.com/data/v1/quick-search.
% I suspect this is just the result of the same issue we had with using the
% python code above, with the item type not being recognized as an array unless
% we force it to be a python list

Accepted Answer

Carl Legleiter
Carl Legleiter on 23 Aug 2022
I also submitted a technical support request and received a solution that works perfectly:
% The trick is to set up a structure array first, then force the value of the
% item_types field to be a cell array of strings rather than just a string
data = struct("item_types",itemType,"filter",dateStruct);
% The next line ensures that "item_types" is encoded as a cell array of strings
% ["PSScene"] rather than a string "PSScene"
data.item_types = cellstr(data.item_types);
data = jsonencode(data);
tmp = webwrite(BASE_URL+"/"+endPoint,data,options);
With this slight modification, I can now query the API entirely within MATLAB using webwrite, with no Python data type conversions or calls to Python functions required.
Thanks to Zack Taylor of MathWorks for this answer.

More Answers (0)

Products


Release

R2022a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!