Tuesday, July 7, 2015

The __file__ variable in RevitPythonShell

Today I’m going to talk about a special builtin variable __file__ as it is implemented in the RevitPythonShell. This feature is only available to external scripts
and RpsAddins. This is similar to how __file__ is normally defined for Python: It is not defined in the REPL.

Simply put: __file__ contains the path to the current file being run.

With external scripts, this is a path to a python script. With RpsAddins, it is the path to the addin’s DLL, a path separator, and the name of the script (e.g. C:\Program Files (x86)\MyAddin\MyAddin.dll\helloworld.py).

Suppose you have deployed some scripts to another computer. Suppose those scripts rely on other files - a database, maybe, or icons, pictures, anything really. If you keep referencing these files as C:\Users\Gareth\AwesomeScripts\all_my_data.sqlite you are going to run into difficulties on a computer that doesn’t belong to Gareth. Meg’s computer won’t know how to find the database! And she is going to complain to Meg and meg is going to complain to her boss and her boss is going to complain to your boss and your boss is going to go get coffee, lock himself up in his office and brood for a very long time. Then, he’s going to send someone to tell you to come to his office ASAP. Now!

You don’t want that to happen! That is why you’re going to make sure that all file references are relative to the installation of your external scripts / RpsAddins. And unless you have a priori knowledge of the folder name you’re installing to, well, I’ve got your back:

def get_folder():
    import os
    # assume external script
    folder = os.path.dirname(__file__)
    if folder.lower().endswith('.dll'):
        # nope - RpsAddin
        folder = os.path.dirname(folder)
    return folder

5 comments:

  1. Hello Daren,
    I tried to use this in one of my script without success. What I did wrong ?
    #script start
    import os
    import wpf
    def get_folder():
    # assume external script
    folder = os.path.dirname(__file__)
    if folder.lower().endswith('.dll'):
    # nope - RpsAddin
    folder = os.path.dirname(folder)
    return folder

    class MyWindow(Window):
    def __init__(self):
    folder = get_folder()
    gui_path = os.path.join(folder, 'outils_revit.xaml')
    wpf.LoadComponent(self, gui_path)

    Then I tried something simpler to display this path but I only got empty strings :
    def get_folder():
    # assume external script
    folder = os.path.dirname(__file__)
    if folder.lower().endswith('.dll'):
    # nope - RpsAddin
    folder = os.path.dirname(folder)
    return folder
    TaskDialog.Show('Test', get_folder())
    TaskDialog.Show('Test', os.path.dirname(__file__))

    Any idea ?

    P.S. Your book "Scripting Autodesk Revit with RevitPythonShell" helped me a lot in creating a full installer. Thanks.

    ReplyDelete
    Replies
    1. did you type this into the interactive shell? (`__file__` is empty for the interactive shell...)
      did you try to do `TaskDialog.Show('Test', __file__)`? This is the most simple test - or even: `print __file__`...

      Delete
    2. No, I typed this in external scripts.
      I tried `TaskDialog.Show('Test', __file__)` it return a empty dialog. I tried `print __file__`, it returns nothing.

      Delete
    3. is your version of RPS current? i've just tried it again in RPS 2016... and in RPS 2014... and in RPS 2015 - using a simple external script ("print __file__")

      Delete
    4. Sorry for late answer, irl issues. I installed RPS on Revit 2016 and it worked... I don't understand... Thanks

      Delete