Hi all, I’m currently trying to run a python script that grabs information from a RAM Concept model using its API. I’ve put this script in my lib folder and I refer to it in my PyRevit script using this line.
So far I’ve found that I cant use any external python libraries when running the script straight from PyRevit. I’ve found a way around most of my problems but I cant seem to avoid this one, and its pretty critical for what I’m trying to do. Is there a way to run this code or is there a workaround required?
Your problem is not with external libraries, but with python versions… __future__ imports are part of the standard library, and if you take a look at the table on that page you’ll see that the annotations feature is suported only from python 3.7.
In fact, typing annotations only work with recent python versions, so you either have to drop them altogether to make your script work with ironpython, or you need to run your script with the cpython engine.
My understanding is future imports is only in Python 3.7 and not other versions, I’m currently running Python 3.12.
I don’t think I have the option to run the script without this line since it’s from the RAM Concept API. Thing is when I use the RAM API in a python script outside the pyRevit environment it works fine, but when I run it from a pushbutton in pyRevit this error occurs.
PyRevit doesn’t use the python you installed in your system, but an interpreter (IronPython) that is embedded into pyrevit itself. This interpreter is not the same as the vanilla python, usually referred as cpython because it is written in C: it is written on c# to be able to run python scripts inside the .net runtime (used bt Revit).
There are different versions of the interpreter (pyRevit calls them engines) available, one of which allows you to run the cpython via a library called python.net, but the support is not that great at the moment.
Please take a look at the documentation to understand how pyRevit works and how to use the CPython engine
Thanks, this makes sense, and it looks like the RAM Concept API is now working in PyRevit, thanks!
But what I couldn’t find is how to install modules/python packages into the CPython site-packages folder. Is there any guidance on how to do this?
I ask because I tried to use an external library like easygui to open the file dialogue for a user to select a file path of a RAM model, since I cant use pyrevit forms with CPython.
Please search the forum, you’ll find that this is currently not possible.
What @Jean-Marc suggested is the current workaround for this:
you write an external cpython script with the libraries you want; this script would output the data to stdout (with print or other means) or save it to a file
the pyrevit script will launch the external script with
and process the output to get the data (or read the file saved by the external script of you went with that route).
Another option: this is not tested, but with the WIP (5.0) version could work since the CPython engine is better (and it is version 3.12): you could try to add at the beginning of your cpython script the instruction
This will add the libraries of your python environment to the one inside pyrevit.
Note that this can bring all sorts of incompatibility problems, but you can just give it a try
By the way, you can use MS winforms directly in pyrevit’s cpython (even the current stable 4.8 version), it’s the wpf framework (and by extension the pyrevit forms module) that cannot be used.
You’ll have to build your windows from scratch though… use Excel VBA editor if you want some visual help
I decided to try out subprocess with a regular IronPython script so I can still use pyrevit.forms etc.
Here is the code I added:
import json
import subprocess
ram_model_path = "model path goes here"
path_to_get_tendons = r"lib\get_ram_tendons.py" # path to get_tendons function
tendon_direction = 'direction'
cmd = ['python', path_to_get_tendons, ram_model_path, tendon_direction]
p = subprocess.run(cmd, capture_output=True) # run the subprocess
# Parse the JSON output back into a dictionary
if p.stdout:
try:
segments = json.loads(p.stdout.strip()) # Remove any extra whitespace/newlines
except json.JSONDecodeError as e:
print("Error decoding JSON:", e)
else:
print("No output from subprocess.")
print(segments)
and in my get_tendons script I put
import json
model_path = sys.argv[1]
tendon_direction = sys.argv[2]
def get_ram_tendons(model_path, tendon_direction):
"function here"
try:
segments = get_ram_tendons(model_path, tendon_direction)
# Print the dictionary as a JSON string
print(json.dumps(segments))
except:
"Error: Invalid path to RAM model"
I am getting this error once I try to run this in PyRevit
AttributeError: 'module' object has no attribute 'run'
Do you know what’s causing this? When I try to run this similar structure of code in a test script outside of pyrevit it works fine.
Ooops, sorry, I forgot that subprocess.run is a python 3.5+ thing!
For IronPython, that is version 2.7 (or 3.4, but not working very well in pyRevit), you can use subprocess.check_output
Also, if the "python" interpreter you want to call is not in the PATH environment variable, you may need to specify its full path.
This simply means that the command you launched returned an error.
Some tips:
As I mention before, check to see if python is in the PATH (just open a command prompt and launch python to see if it enters the python console);
since you specified a relative path for the script, you need to set the cwd parameter for check_output to os.path.dirname(__file__) (that is, the folder containing the pyrevit script)
as stated in the subprocess documentation, you can try to show the errors by using stderr=subprocess.STDOUT
As an alternative, is it possible to keep working using the CPython version of my script and obtain the file paths another way? If I create another button in my panel, can I use pyrevit.forms.pick_file to store the file path so it can be used by the CPython script (which is a different pushbutton)?
Unfortunately a cpython script cannot use the pyrevit.forms library, it was disabled because there were many problems with the old pythonnet (the library that lets you run cpython inside .net).
Now that we updated the library, we should be able to make it compatible, but the last time I tried I hit a wall pretty soon
As I mention earlier, you can still use winforms directly; this is the first result for a google search with the terms “winforms ironpython”:
The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. See the Replacing Older Functions with the subprocess Module section in the subprocess documentation for some helpful recipes.
Sorry for the misunderstanding, yes this could be a thing to try!
The thing that is missing is the run function, and as I already explained the check_output function is there and does more or less the same. In fact, they are all convenience functions over the Popen class.