change matlab path from python - python

So I have the following problem: I have a folder at a location known from a config.py file, in my case externals/bct. Now this needs to be added to matlab's path. Now I've searched for some examples to edit matlab path but from what I can see let's say here: matlab path the changes are done from matlab. My question would then be: is there any way I could change the matlab path from python?
Best regards,
Bogdan

Thanks for the inputs. The project already has an adapter that allows runnig matlab code from python using from scipy.io import loadmat, savemat. The problem was that we are using BCT and that need to be added to matlab path dinamically at startup. The solution that worked for me was to use the method already defined to execute matlab code and just send at startup:
addpath(PATH_TO_BCT); savepath;

Your source says:
path displays the MATLAB search path, which is stored in pathdef.m
I believe your best bet is to find this pathdef.m file in the Matlab install folder, then open and change it from python.
On my Windows Machine with Matlab 2008a, it's in C:\MATLAB\R2008a\toolbox\local\pathdef.m. There are two emptied-out versions of the same file at \local\ja and \local\template, but that first one seems to be the one that counts.
There's a big warning in it saying not to edit, but it's plain text Matlab language, really easy to reverse-engineer, you should be fine. Just don't forget the semicolon at the end of each path string (unless they changed synthax in the new version you might have... just take a look at your file.)

Related

Python : .p file with MATLAB function

I have a .p file (for the example named EX1.p) that contains a MATLAB function that I need in my python code and I tried to import the file/the function but with no success.
Hope someone can help
I think there is at least two options: oct2py (only valid if your code may be run in Octave) and Matlab Engine. You can find an explanation of both options here.

Can Python subprocess lose track of what is in my PATH after I import pygmsh module?

Lately I have wanted to use pygmsh to help with resampling 3d geometry. Ideally I would like to understand what I'm doing by routinely drawing the output of pygmsh calls using itikz. However something in pygmsh seams to be altering the operating system PATH after I call code of the form:
import pygmsh
with pygmsh.geo.Geometry() as geom:
geom.add_circle([0.0, 0.0], 1.0, mesh_size=0.2)
mesh = geom.generate_mesh()
If I run the following code before the pygmsh cell above I get typical pdflatex output, and a pdf:
from subprocess import check_output
subprocess.check_output(['pdflatex', 'src.tex'])
If I run that same cell after the pygmsh cell, I get a FileNotFoundError.
After playing around with this last night I made the following observations:
The PATH returned by the ipython shell command !PATH is being shortened. I have my full path available before calling the pygmsh cell, but after it has been substantially reduced.
However the output of os.environ['PATH'] seams not to change.
I am trying to use itikz to draw a diagram of a 3d mesh, generated by pygmsh in a jupyter-lab notebook. Ordinarily I can use itikz in my notebooks with out issues.
Under the hood the itikz cell magic simply saves the contents of a cell to a .tex file (ie 'src'tex'), then calls pdflatex on the file using subprocess.check_output(['pdflatex', 'src.tex']). After this it converts the resulting src.pdf to an .svg image and renders that as the cells output. It seams that the important point though is that itikz calls an external program found on the operating system PATH.
This generally works well enough, on it's own.
So I guess I have two questions.
What is the best way to find the offending code in the pygmsh repository to stamp this bug?
Why am I getting different results from the ipython shell command and from os.environ['PATH']?
I'm running python version 3.8.6 64bit, on windows 64bit 10.
Additionally
Scanning the repository for pygmsh hasn't yielded any footholds yet.
https://github.com/nschloe/pygmsh/search?q=path
If they modify the path maybe they do it by accident. Or they just don't use convenient names.
I have narrowed down the culprit to the with statement. Removing that idiom doesn't seam to mess with my path. Not a fix, seams I need to __enter__() the geom object and __exit__() for it to function, and somewhere between these two calls is my culprit!
found it... it's a known issue with gmsh [https://gitlab.onelab.info/gmsh/gmsh/-/issues/1142]
The environment of you current process can be modified by a statement in the imported module causing executable resolution relying on search PATH to fail, e.g.:
subprocess.run("ls")
os.environ["PATH"] = "bogus"
subprocess.run("ls")
This will run the first ls and fail on the second one.
Manipulating environment of running process is a problematic action and can lead to confusion. But you could also in this case isolate yourself form it by using absolute paths.
But to your edit, to find the offending location, be on a lookout for os.environ or os.putenv.
So it turns out I was encountering a known issue in gmsh which is what is doing the grunt work under the hood of pygmsh.
Unfortunatly there isn't really a work around because the fix for this involves passing arguments to a function that pygmsh does not fully expose.
In the short term I have submitted a pull request to that repo trying to expose the fix.

How can the root directory in python chunk be specified?

Setting the root directory in a python-chunk with the following code line results in an error while for an ordinary r-chunk it works just fine
knitr::opts_knit$set(root.dir ="..")
knitr::opts_knit$set(root.dir ="..")
Optimally there should exist the following options for each knitr-chunk:
- directory to find code to be imported / executed
- directory to find files / dependencies that are needed for code execution
- directory to save any code output
Does something similar exist?
What it looks like here is that you have told it that it is to look for python code:
```{python}
knitr::opts_knit$set(root.dir ="..")
```
When you run this in R studio it will give you an error:
Error: invalid syntax (, line 1)
You fed it python code instead. This makes sense as the call knit::opt_knit$set means to look in the knitr package for the opts_knit$set and set it to…. This doesn’t exist in python… yet. The python compiler does not recognize it as python code and returns a syntax error. Whereas when you run it as an R chunk, it knows to look into the knitr package. Error handling can be huge issue to deal with. It makes more sense to handle error categories than to account for every type of error. If you want to control the settings for a code chunk, you would do so in the parenthesis ie:
```{python, args }
codeHere
```
I have not seen args for any other language than R, but that does not mean it doesn’t exist. I have just not seen them. I also do not believe that this will fix your issue. You could try some of the following ideas:
Writing your python in a separate file and link to it. This would allow for you to take advantage of the language and utilize things like the OS import. This may be something you want to consider as even python has its ways of navigating around the various operating systems. This may be helpful if you are just running quick scripts and not loading or running python programs.
# OS module
import os
# Your os name
print(os.name)
# Gets PWD or present working directory
os.getcwd()
# change your directory
os.chdir("path")
You could try using the reticulate library within an R chunk and load your python that way
Another thought is that you could try
library(reticulate)
use_python(“path”)
Knitr looks in the same directory as your markdown file to find other files if needed. This is just like about any other IDE
At one point in time knitr would not accept R’s setwd() command. Trying to call setwd() may not do you any good.
It may not the best idea to compute paths relative to what's being executed. If possible they should be determined relative to where the user calls the code from.
This site may help.
The author of the knitr package is very active and involved. Good luck with what you are doing!

Creating Executable Zip Archives With Packages in the Project

I feel this question needs a better title and I will amend it if someone suggests something better. The problem is I'm not sure of the terminology of the feature that I'm using here.
The best way to describe my problem is to show what I've done. The project is here: https://github.com/jeffnyman/quendor
This project is setup so it can be executed as a module. For example, from the project root someone could do this:
python3 -m quendor
I also have a build script to generate an in-memory zip (if I'm using that terminology correctly):
https://github.com/jeffnyman/quendor/blob/master/build.py
That works in that if you run build.py it will generate a quendor.py file that executes the entire project. That worked fine up until I included other directories (like my utilities and zinterface).
With the project as it is in the repo right now, if you run the build (.\build.py) and then run the generated file:
./quendor.py
You get the following error:
File "./quendor.py/quendor/__main__.py", line 6, in <module>
ModuleNotFoundError: No module named 'quendor.zinterface'
So a key point: if all of my files are in the same directory (i.e., in quendor) this build script works fine in terms of producing an executable script file.
But once I include the subdirectories and files in those directories, things go south on me with the above error.
I'm sure all the files are being gathered. I handle that starting on line 18 (https://github.com/jeffnyman/quendor/blob/master/build.py#L18). And if you were to add to line 24 this statement:
print(f"* {file_path}")
You would see it outputs the following:
* quendor/__init__.py
* quendor/__version__.py
* quendor/zinterface/fileio.py
* quendor/utilities/messages.py
* quendor/__main__.py
So I'm suspecting it might have to do with the code where I write the string at line 28 (https://github.com/jeffnyman/quendor/blob/master/build.py#L28). I feel I have to do more to let the executable zipped script file know about the modules.
But I'm not sure if (1) I'm accurate and (2) even if I'm accurate, if that's possible. I'm finding I'm in a bit over my head here.
Any thoughts would be appreciated and I'm happy to update with any necessarily clarifications or terminology.
So it won't let me comment unless I have more reputation but I can post an answer. Even though I don't have an answer, but rather a comment. I think the above comment was not meant for your actual __main__.py file but rather the one that is getting generated in your quendor.py file. You might want to try adding the import statements to your packed string that you write.
For example, see what happens if on line 32 you add this: import quendor.zinterface.fileio as zio. (Don't replace the line that's there. Just put my line and then keep your others.) I'm not sure how the zip process works but if it tries to mirror the module process that should work. However, if it doesn't, that won't work. You might also just want to try doing import quendor.zinterface. By itself that won't work but it would be interesting to see if it gave you a different error.
Actually, it turns out I found a way to do this! It required using os.walk rather than os.listdir. This required taking a few ideas that people here discussed. Here is the script that does the trick:
https://github.com/jeffnyman/quendor/blob/master/build.py
You can compare that with my previous commit that was trying to handle this a different way.
Eldritch was right that I couldn't just flatten the directory nor could I just add imports to the string I was writing to the final zip file. Jean-François was correct that I had to focus on the __main__.py that was being generated. My contribution was figuring out os.walk() and then parameterizing the written string to handle the different directories.
Finally, this solution does require, as per HTF's suggestion, that I put an empty __init__.py file in each package.
With my solution in place, you can run build.py which then generates the quendor.py script. That script then executes correctly, in terms of recognizing the imports to various packages.
Playing around with just about every variation of import and file gathering that I can think of with your repo, there's a good news / bad news thing.
The bad news is that the answer is this: it isn't possible.
The good news is this: you do have a working implementation if you just keep all files in the quendor directory rather than having subdirectories.
The other good news is you stumbled on something, and posed a problem, that Python gurus aren't able to answer. And there's a certain pleasure to be found in that! I guarantee you will not get an answer to this that works (except for the "all files in one directory" solution).
A refinement to the answer is that if you're setting up the program to run as a module anyway, just use a pip configuration. That basically does the same thing that you want but without having to go through the contortions. (Unless there's a reason you were doing the build the way you were rather than using pip.)

Why doesn't matlab find this function call?

So I downloaded some compiled matlab files. I see the following files in a folder.
makemesh.mexmaci64
makemesh.mexw32
makemesh.mexw64
I added this folder to userpath, and now the path variable shows that this folder exists in it.
I try to run a test script that came with these files, and I get this error message.
Undefined function 'makemesh' for input arguments of type 'struct'.
Now to trouble shoot, I need to find,
Does it find the function, but the data type is wrong.
It doesn't even find the function.
And if it is case 1.
1a. How do I find out what is the proper data structure that function expects.
I am good with python, but new to matlab, so any tips you can add regarding how to query the help string of a function, how to print out the function signature given a function name (like ?function_name in ipython interface) would be super useful.
thank you,
computer('arch') returns glnxa64 which stands for GnuLiNuX 64bit. You have downloaded binaries for Win32bit (mexw32), Win64bit (mexw64) and IOS on Intel (mexmaci64). Either get the source files to compile it yourself or the binaries for linux.
You can find the location of a file on your path by using the which command. For example:
which makemesh.mexw64
should print the location of that file to the terminal. If you get
'makemesh.mexmaci64' not found.
then it means that the file does not exist on your path.
As for finding out what the function wants, I'd start with "help"
help makemesh.mexw64
and see if that gives you anything useful.
I suspect that somehow or other, your matlab is not recognizing the mex file as a function, so I'd start looking there.
You can use the command which <functionName> to see if Matlab is seeing your function.
Have you tried help <functionName> to see if there are any useful comments on what your function is expecting?

Categories