Old 02-22-2019, 07:42 AM   #1
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default reapy: a pythonic wrapper around the ReaScript API

Hi everyone,

I know we are only a few Python ReaScripters here. But there are reasons for that:
  • the ReaScript API is a mess (almost no structure, inconsistent names, non-descriptive parameters names, no use of keyword optional arguments, buffer strings everywhere which makes no sense in Python),
  • its documentation is pretty bad (it's not just me saying it),
  • community libraries are one of Python's greatest strengths, yet importing them crashes REAPER (see complaints with Numpy, Scipy or Kivy),
  • no GUI programming is available since ReaScripts run in the main thread, even though GUI libraries exist for Python (see this thread to discover Tkinter's gorgeousness).

There have been several attempts to overcome these issues before:
  • The most estalished one is probably beyond.Reaper, which allows to call API functions from outside REAPER in a usual Python script. It's great, because:
    • it allows GUI programming,
    • it allows to import third-party libraries.
    It's not great, because:
    • it's been unmaintained since 2016,
    • though it has a (very thin) object-oriented layer around the ReaScript API, one can't say it provides a pythonic API,
    • there is almost no documentation (just a bunch of examples scripts),
    • the source code and the programming flow are very unusual (do we really need to override Python import process and have global variables jumping all over the place?), which makes it almost impossible for a standard Python user to read the source and figure out how it works.
  • ReaPyLib also implemented an object-oriented, human-readable model of the API. Yet the project has been unmaintained since the end of 2012 and doesn't cover much of the API.
  • The reaper-api project aims to replace bad parameters names by descriptive ones, and build documentation with a few docstrings. It is still alive, but doesn't help with the external libraries and GUI issues.

These projects weren't satisfying to me, so I wrote a new one. Its name is reapy, and it has the following features:
  • pip-installable (how convenient)
  • crazy simple to configure
  • can help with setting up Python in REAPER (if it's your first time)
  • sensible object-oriented interface to the ReaScript API
  • access to the whole native ReaScript API if you prefer it
  • can be imported inside REAPER and transparently act as a better API
  • can be imported outside REAPER and is faster than beyond.Reaper (see P.S. at the end)
  • a lot of well-formatted docstrings
  • PEP-compliant
  • Sphinx-generated online doc
  • nice GitHub with all explained on it so that people can improve it, request features, etc.

However, it is not a fully grown-up. Right now, only about a third of ReaScript API functions are wrapped in the reapy API. The other ones are still callable from reapy (inside and oustide REAPER), but without the pythonic feel. I think this project can become interesting only if other people in the community provide feedback and improvement, on the code itself as well as the documentation, structure, etc. So please don't hesitate to try it out and report bugs or missing features. And if you feel like coding yourself, feel free to fork the repository! As a Python ReaScripter, I know you dream like me of a well-established community-based REAPER API!


P.S. Performance comparison with beyond.Reaper

When you run a single API call with beyond.Reaper (e.g. path = Reaper.GetExePath()), it takes on average 0.15 s on my computer. With reapy (path = reapy.get_exe_dir()), it takes 0.03 s. However when performing several consecutive calls in the adapted context manager, the performance is asymptotically similar

Code:
>>> # beyond way
>>> import beyond.Reaper
>>> with Reaper as r:
...     # I hate the fact that the global variable `Reaper` appears without
...     # permission...
...     paths = [r.GetExePath() for _ in range(1000)]

>>> # reapy way
>>> import reapy
>>> with reapy.inside_reaper()
...     paths = [reapy.get_exe_path() for _ in range(1000)]

P.P.S. reapy should be cross-platform but since I have only tested it on Windows I couldn't swear. Yet I do think this is an important feature. We all love REAPER for Linux.

Last edited by romeo_despres; 02-26-2019 at 02:48 AM. Reason: added with reapy.inside_reaper() to the API
romeo_despres is offline   Reply With Quote
Old 02-22-2019, 09:54 AM   #2
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,123
Default

Nice work. I'm no Python-programmer at all, but this should make things better for those who do
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 02-22-2019, 06:16 PM   #3
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

Very very intersting ! Especially if it has more doc than beyong.reaper and GUI prpgramming. Ill have to test that !



I wonder, as it works as extension, it could be shared via reapack for more transparent updates ?
X-Raym is offline   Reply With Quote
Old 02-23-2019, 04:49 AM   #4
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

Thanks for the positive comments!

@mespotine
I found your ReaScript documentation categorization pretty nice so I edited the Translation Table to include it! I hope it's fine.

@X-Raym
The purpose of making it available on PyPI was already to allow for transparent updates via pip package manager, which is standard for Python. But it would definitely be nice to make it ReaPack-compatible as well. I am not familiar with the process for this so I'll have to learn more first.
romeo_despres is offline   Reply With Quote
Old 02-23-2019, 08:39 AM   #5
JerContact
Human being with feelings
 
Join Date: Feb 2017
Posts: 38
Default

Interesting!!! I do a bunch of python scripting with Reaper and was also sad about the GUI and other limitations. I’ll have to check this out!
JerContact is offline   Reply With Quote
Old 02-23-2019, 01:10 PM   #6
TonE
Human being with feelings
 
Join Date: Feb 2009
Location: Reaper HAS send control via midi !!!
Posts: 1,806
Default

What I am missing for Reaper mostly is something for this scenario:
-you have some old project, lots of track, fx, no or few mapped automation
-you want to add more automation
-and you have a concept of how the mapping should be over tracks, over fx, over parameters, all name based, something like;
PHP Code:
if track is x
   
if fx is y
      
if param is z
         map xyz to channel a
cc b     # for sliders
         
map xyz to channel anote b   # for toggle/switches 
Having a file like csv, with columns x,y,z,a,b to load such mapping would be good starting point. More columns could be added later in case Reaper would support min,max ranges for example.

Could reapy help implementing something like this? Now or in future? Name based mappings nothing is supported yet, afaik, ReaLearn is very cool, offering json import and export via clipboard, however it supports only numbered fx, parameters, not name based. I made a suggestion there, but nothing so far.

Then one could build such a csv file for their structure and import, easily, into any past or future project, and getting in one move a big set of mappings, ready to be used via their hardware set. In short, some tool, for converting software Reaper more into a hardware feeling Reaper. Open a project, hit a button, there you have your hardware feel. That would be top!

Then imagine users sharing those csv files here in the forum. It help file could be something like: mapping structure from Reason mode to following .RPP template. So anyone having a hardware set suppporting 'Reason mode', could immediately switch their device to Reason mode, open that .rpp template and all mappings would work, and be compatible to other csv structures for this combination, meaning reason mode > .rpp.

Last edited by TonE; 02-23-2019 at 01:50 PM.
TonE is offline   Reply With Quote
Old 02-24-2019, 02:28 PM   #7
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

I didn't succeed to run it, and I had quite some trouble,



If I run the Script: enable_dist_api.py from action list,


Code:
Script execution error

Traceback (most recent call last):
  File "enable_dist_api.py", line 13, in <module>
    reapy.config.enable_dist_api()
  File "C:\Program Files\Python372\lib\site-packages\reapy\config.py", line 108, in enable_dist_api
    create_new_web_interface(WEB_INTERFACE_PORT)
  File "C:\Program Files\Python372\lib\site-packages\reapy\config.py", line 38, in create_new_web_interface
    config = Config()
  File "C:\Program Files\Python372\lib\site-packages\reapy\config.py", line 19, in __init__
    self.read(reapy.get_ini_file())
  File "C:\Program Files\Python372\Lib\configparser.py", line 696, in read
    self._read(fp, filename)
  File "C:\Program Files\Python372\Lib\configparser.py", line 1091, in _read
    fpname, lineno)
configparser.DuplicateOptionError: While reading from 'C:\\Users\\USER\\AppData\\Roaming\\REAPER\\REAPER.ini' [line 1089]: option 'toolbar' in section 'reaper' already exists

and with the following code in Python IDLE



Code:
import reapy
reapy.print("Hello world!")



i got


Code:
Warning (from warnings module):
  File "C:\Program Files\Python372\lib\site-packages\reapy\tools\dist_program.py", line 14
    warnings.warn(DisabledDistAPIWarning())
DisabledDistAPIWarning: reapy distant API is disabled. Please call `reapy.config.enable_dist_api()` from inside REAPER.
Traceback (most recent call last):
  File "E:/Bureau/dfdf.py", line 2, in <module>
    reapy.print("Hello world!")
  File "C:\Program Files\Python372\lib\site-packages\reapy\core\reaper\reaper.py", line 281, in print
    show_console_message(*args, **kwargs)
  File "C:\Program Files\Python372\lib\site-packages\reapy\core\reaper\reaper.py", line 418, in show_console_message
    RPR.ShowConsoleMsg(txt)
AttributeError: module 'reapy.reascript_api' has no attribute 'ShowConsoleMsg'

Any idea ?



:S
X-Raym is offline   Reply With Quote
Old 02-24-2019, 03:48 PM   #8
cyrano
Human being with feelings
 
cyrano's Avatar
 
Join Date: Jun 2011
Location: Belgium
Posts: 4,042
Default

Tried on Macos El Capital:

Code:
...Collecting reapy
  Could not find a version that satisfies the requirement reapy (from versions: )
No matching distribution found for reapy
Python 3 only?
__________________
“It has become appallingly obvious that our technology has exceeded our humanity” Albert Einstein
cyrano is offline   Reply With Quote
Old 02-24-2019, 09:37 PM   #9
meta
Human being with feelings
 
Join Date: Sep 2018
Posts: 31
Default

Hey man, good stuff. I share your concerns regarding Python reascripting and have been working on a similar project for some time. I even considered using the name ReaPy too but you've beaten me to it! Serves me right for being a slowpoke. 😅

There's something you need to keep in mind regarding rpr_defer Python loops. As it stands, the embedded interpreter isn't in the best shape and unfortunately doesn't seem like it'll be improving any time soon. Every time a script is run, it redirects sys.stderr to a new temporary file. That also means for every single call to rpr_defer a new file is created. Aside from being ridiculously inefficient and bad for drives, this can result in crashes when running multiple instances of reaper with rpr_defer loops as there's a file access conflict when both scripts try to create/delete this file at the same time. You can read more about this in the bug report here: https://forum.cockos.com/showthread.php?t=211811 tl;dr is on the last post in the thread detailing the results of my investigation.

The way I've currently worked around it in my code is by using the following function first before initiating the loop:
Code:
def patch_stdout_stderr_open():
    global open, original_open, reaper_console

    class ReaperConsole:
        def write(self, output):
            RPR_ShowConsoleMsg(output)

        def flush(self):
            pass

        def close(self):
            pass

    reaper_console = ReaperConsole()

    sys.stdout = reaper_console
    sys.stderr = reaper_console

    original_open = open
    open = lambda *args, **kwargs: reaper_console
This way, every time the embedded interpreter tries to use 'open' to get a new file for stderr it'll just get the ReaperConsole instance instead. This function also replaces sys.stdout with ReaperConsole, which has the benefit that calls to Python's 'print' function will write directly to the reaper console instead.
meta is offline   Reply With Quote
Old 02-25-2019, 03:52 AM   #10
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

@TonE

You can access track, FX and parameter names as follows:

Code:
for track in reapy.Project().tracks:
    for fx in track.fxs:
        for param in fx.params:
            do_something(track.name, fx.name, param.name)
However access to MIDI notes and CC is not implemented yet in the reapy API, so you would have for now to use reascript API functions (available in reapy.reascript_api) in do_something.

Does this answer your question?

@X-Raym

Ok I wasn't expecting that... Although it's probably easy to fix, would you please post the content of your C:\Users\USER\AppData\Roaming\REAPER\REAPER.ini so that I'm sure to understand what's wrong?

@cyrano

As explained in the docs, you have to use "pip install python-reapy". The name "reapy" is currently squatted on pypi by an abandoned and empty project, whose author I haven't managed to contact yet.

@meta

I think many of us have been willing to do something similar... But if you want to take part so that this becomes your reapy too feel free

Thanks for your comment, it's quite interesting (and surprising!) to figure out this behavior. I guess normally one shouldn't have several instances of reaper open at the same time, since that's what tabs are for. But still it's a weird implementation and your little hack looks nice. It probably could be integrated in the main server defer loop. We could even implement a reapy.defer function that would allow people to safely use defer loop, that would be great!
romeo_despres is offline   Reply With Quote
Old 02-25-2019, 04:32 AM   #11
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

Here is my reaper.ini:
https://drive.google.com/file/d/1Iw3...ew?usp=sharing


Thx for your support !
X-Raym is offline   Reply With Quote
Old 02-25-2019, 05:19 AM   #12
cyrano
Human being with feelings
 
cyrano's Avatar
 
Join Date: Jun 2011
Location: Belgium
Posts: 4,042
Default

Tried "pip install python-reapy" (and even sudoed it).

Same result...
__________________
“It has become appallingly obvious that our technology has exceeded our humanity” Albert Einstein
cyrano is offline   Reply With Quote
Old 02-25-2019, 08:09 AM   #13
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Nice work!
Is there any way to insert a VST plugin into a reaper session using this module?
Is it even possible using the reaper API?
nir.arad is offline   Reply With Quote
Old 02-25-2019, 09:44 AM   #14
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

First, I have updated the PyPI package that now supports context manager syntax for efficient calls from outside REAPER:

Code:
>>> import reapy
>>> with reapy.inside_reaper():
...     do_something_in_reaper()
...     do_something_else_in_reaper()
...
which is strongly inspired by beyond.Reaper context manager.


@X-Raym

Thanks! I reproduced the bug on my computer and fixed it (at least for me). Could you please try to run "pip install python-reapy==0.1.0.dev5" (or just uninstall and reinstall reapy) and tell me if it works?

@cyrano

Oh sorry my mistake. Indeed there is no Python 2 support yet. This would be nice to have, but I am no expert in Python 2 so I would have to take some time to dig into it.

@nir.arad

There are ReaScript functions for that, you can access them via
Code:
>>> import reapy.reascript_api as RPR
>>> RPR.TrackFX_AddByName
but I'll try to add it soon to the reapy API, since it's obviously something needed.
romeo_despres is offline   Reply With Quote
Old 02-25-2019, 03:06 PM   #15
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

@romeo_depres
It works now, thx !


I manage to port my Tkinter code snippet you linked in first post, this is a demo with the code launched from Python IDLE:



On windows, if it is run by double click on the .py file, it also open a CMD window,




If this could be prevented it would be better but apart from that it seems pretty usable. It doesn't still keyboard focus like the usual way to run .py from REAPER !

I wonder how it perform with more advanced framework like Kivy :P
X-Raym is offline   Reply With Quote
Old 02-25-2019, 03:13 PM   #16
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

Quote:
On windows, if it is run by double click on the .py file, it also open a CMD window,

Just notice I can simply add the .py file in the action list and run from there, but in this case, tkinter still keyboard focus (I don't know if this is specific to tkinter or to the way this .py is run).
X-Raym is offline   Reply With Quote
Old 02-25-2019, 03:26 PM   #17
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

I think the doc should also provide an Uninstall process, cause we never know :P


Also, as far as I understood, Script: activate_reapy_server.py create a server. But this server isn't run if no reapy python script is run right ? Just be sure performance isn't affected by reapy install :P


Anyway, I like the clarity of the doc, with syntax colorization etc... :P
X-Raym is offline   Reply With Quote
Old 02-25-2019, 04:15 PM   #18
ChuckkH
Human being with feelings
 
Join Date: Feb 2019
Posts: 19
Default

Thank you!!
I am trying to adapt my Python sequencer program to interface with Reaper on a fairly deep level, and it's discouraging to find they haven't actually implemented Python scripting after all. I'm considering switching to Lua.
Are you saying I could include your library in my standalone Python program and use Reaper API calls on a running Reaper instance, without opening the script in Reaper? That would be phenomenal! I was looking into using __startup.lua to start the first Python script, and then to continually overwrite it from my program, before restarting it through OSC as needed.

But I can't get any Python defer to work at all (in the default Python API, not reapy). This gives invalid syntax:

<python code>
from reaper_python import *
def empty_function():
x = 1
y = 2
z = x
x = y
y = z

def empty_defer_function():
x = 1
y = 2
z = x
x = y
y = z
RPR_defer(empty_defer_function)

empty_function()
empty_defer_function()
</python code>

(The function lines are indented, but it doesn't show up here.)

And the invalid syntax error specifically points at the deferral, meaning the same function without defer runs fine:

<error message>
Deferred script execution error

Traceback (most recent call last):
File "defer", line 1
<function empty_defer_function at 0x00000000395D72E8>
^
SyntaxError: invalid syntax
</error message>

Is this what meta is referring to? Because, yeah, it won't even run, crashes immediately. Python 2.7.15, Reaper 5.965, both 64-bit on Win 7 64-bit.

-Chuckk

Last edited by ChuckkH; 02-25-2019 at 05:34 PM.
ChuckkH is offline   Reply With Quote
Old 02-25-2019, 04:23 PM   #19
ChuckkH
Human being with feelings
 
Join Date: Feb 2019
Posts: 19
Default

P.S. Does the ending "py" in "python-reapy" by any chance stand for "python reapy"?
ChuckkH is offline   Reply With Quote
Old 02-25-2019, 05:41 PM   #20
cyrano
Human being with feelings
 
cyrano's Avatar
 
Join Date: Jun 2011
Location: Belgium
Posts: 4,042
Default

Quote:
Originally Posted by romeo_despres View Post
@cyrano

Oh sorry my mistake. Indeed there is no Python 2 support yet. This would be nice to have, but I am no expert in Python 2 so I would have to take some time to dig into it.
Don't bother.

I have Python 3 installed, but I need to go chase the "path to it" problem again. Been there before. It's a pita. But it needs to be done...

EDIT

Had no idea I'd have to use "pip3" in stead of "pip". And that works.

python-reapy installed correctly on Macos El Capital, with python 3 installed.
__________________
“It has become appallingly obvious that our technology has exceeded our humanity” Albert Einstein

Last edited by cyrano; 02-25-2019 at 06:23 PM.
cyrano is offline   Reply With Quote
Old 02-26-2019, 02:13 AM   #21
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

@X-Raym

Great I'm glad it eventually worked! About your "command window" problem, I have found this which seems to answer your question (I wasn't aware of that technique and haven't tried it though).

And you are totally right about the Uninstall process which should be documented. This is on top of the todo-list. (I guess in my enthusiasm I couldn't imagine anyone would want to uninstall it...) And yes the "reapy server" is only activated when you import reapy from outside REAPER (which is why the import is pretty slow), so that it doesn't affect performance when you don't use reapy.

@ChuckkH

Indeed reapy can interact with a running instance of REAPER even when run outside REAPER (they communicate via the local network). However performance can be a problem when using reapy outside REAPER, which is the reason for the "with reapy.inside_reaper()" context manager (see doc for it here).

Your "defer" problem comes from the fact that "RPR_defer" takes as argument a string to execute, and not a callback. So you should use RPR_defer("empty_defer_function()"). In your case, RPR_defer first applies str to its argument (which outputs "<function empty_defer_function at 0x00000000395D72E8>") and then tries to execute it (which raises a SyntaxError).

Following this post I think I will soon try to implement a reapy.defer function, that would also accept callbacks as arguments in addition to strings (because I think that's what most people expect it to do).

@cyrano

Great to know it installs correctly on MacOS! I hope it also interacts well with REAPER.
romeo_despres is offline   Reply With Quote
Old 02-26-2019, 04:08 AM   #22
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

Quote:
(I guess in my enthusiasm I couldn't imagine anyone would want to uninstall it...)
We are enthusiast, it's just that sometimes I try things on someone else computer and I have to leave it clean ^^

(this is not what happen to me right now, but it could have been :P)
X-Raym is offline   Reply With Quote
Old 02-28-2019, 08:00 AM   #23
mespotine
Human being with feelings
 
mespotine's Avatar
 
Join Date: May 2017
Location: Leipzig, Germany
Posts: 1,123
Default

Quote:
Originally Posted by romeo_despres View Post
Thanks for the positive comments!

@mespotine
I found your ReaScript documentation categorization pretty nice so I edited the Translation Table to include it! I hope it's fine.
Sure. Just add a link to the docs so people can find the other docs as well and everything's fine
__________________
Ultraschall-API - a Lua-functions-library4Reaper: https://forum.cockos.com/showthread....98#post2067798
Reaper Internals - Developerdocs4Reaper: https://forum.cockos.com/showthread.php?t=207635
mespotine is offline   Reply With Quote
Old 02-28-2019, 09:50 AM   #24
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

Of course I did it
romeo_despres is offline   Reply With Quote
Old 03-19-2019, 01:38 AM   #25
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Hi @romeo_despres

I'm also having issue running reapy outside of Reaper (on Mac).
Inside Reaper the following code works.

Code:
import reapy
reapy.print("Hello world!")

Error
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/p4client/Automation/main_branch/Packages/apps/audio_apps/reaper.py", line 15, in test_reapy
    reapy.print("Hello world!")
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/core/reaper/reaper.py", line 281, in print
    show_console_message(*args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/core/reaper/reaper.py", line 418, in show_console_message
    RPR.ShowConsoleMsg(txt)
AttributeError: module 'reapy.reascript_api' has no attribute 'ShowConsoleMsg'
I've tried using other python libraries and getting similar errors.
Something's definitely not set up correctly on my system.

Code:
sys.path.append('/Applications/REAPER64.app/Contents/Plugins')
import reaper_python as rp
rp.RPR_ShowConsoleMsg("Hello world!")


Error
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py", line 605, in run
    testMethod()
  File "/p4client/Automation/main_branch/Packages/apps/audio_apps/reaper.py", line 11, in test_reaper_python
    rp.RPR_ShowConsoleMsg("Hello world!")
  File "/Applications/REAPER64.app/Contents/Plugins/reaper_python.py", line 3381, in RPR_ShowConsoleMsg
    a=_ft['ShowConsoleMsg']
KeyError: 'ShowConsoleMsg'
nir.arad is offline   Reply With Quote
Old 03-19-2019, 02:47 AM   #26
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

The second snippet is not supposed to work outside REAPER... We've all tried it I guess! The module "reaper_python.py" is dynamically built and, simply put, can only work inside REAPER.

About your first snippet, have you followed the installation instructions and especially the Enable reapy distant API part?
romeo_despres is offline   Reply With Quote
Old 03-19-2019, 03:57 AM   #27
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Thanks for the quick reply.
I tried running the commands according to the installation instructions but still no go:

Code:
python3.6 -m reapy
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/tools/dist_program.py:14: DisabledDistAPIWarning: Can't reach distant API. Please start REAPER, or call reapy.config.enable_dist_api() from inside REAPER to enable distant API.
  warnings.warn(DisabledDistAPIWarning())

======================
  reapy config infos
======================

Python DLL
----------
    Can't find python DLL...

Enable or disable reapy dist API
--------------------------------
Enable dist API
    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/reascripts/enable_dist_api.py

Disable dist API
    /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/reascripts/disable_dist_api.py
reapy can't seem to find the python interpreter, but Reaper does (see screenshot)

When running enable_dist_api.py from inside Reaper I get an exception:

Code:
Script execution error

Traceback (most recent call last):
  File "enable_dist_api.py", line 13, in <module>
    reapy.config.enable_dist_api()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/config.py", line 109, in enable_dist_api
    create_new_web_interface(WEB_INTERFACE_PORT)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/config.py", line 40, in create_new_web_interface
    csurf_count = int(config["reaper"]["csurf_cnt"])
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/configparser.py", line 959, in __getitem__
    raise KeyError(key)
KeyError: 'reaper'
Attached Images
File Type: png Screen Shot 2019-03-19 at 12.56.32 PM.png (57.3 KB, 13 views)
nir.arad is offline   Reply With Quote
Old 03-19-2019, 04:05 AM   #28
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

Thanks!

Would you please post the content of your "REAPER.ini" file so that I can try to understand better what is wrong? (you can get the path to it by running "reapy.get_ini_file()" inside REAPER)
romeo_despres is offline   Reply With Quote
Old 03-19-2019, 05:35 AM   #29
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

I've attached my reaper.ini file.
p.s. I've tried it also with 0.1.0dev5 but still got the same error
Attached Files
File Type: ini reaper.ini (1.9 KB, 10 views)
nir.arad is offline   Reply With Quote
Old 03-19-2019, 06:11 AM   #30
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

I've also tested on my Windows machine, but got a different error when running enable_dist_api from inside Reaper
Code:
Traceback (most recent call last):
  File "enable_dist_api.py", line 13, in <module>
    reapy.config.enable_dist_api()
  File "C:\Python36x64\lib\site-packages\reapy\config.py", line 109, in enable_dist_api
    create_new_web_interface(WEB_INTERFACE_PORT)
  File "C:\Python36x64\lib\site-packages\reapy\config.py", line 40, in create_new_web_interface
    csurf_count = int(config["reaper"]["csurf_cnt"])
  File "C:\Python36x64\Lib\configparser.py", line 1233, in __getitem__
    raise KeyError(key)
KeyError: 'csurf_cnt'
Attached Files
File Type: ini REAPER.ini (2.0 KB, 12 views)
nir.arad is offline   Reply With Quote
Old 03-23-2019, 05:33 AM   #31
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default Version 0.2.0

Hey everyone,

Over 50% of all ReaScript API functions now have a reapy counterpart. I thought this was a good reason to have a new release!

It includes:
  • the functions reapy.defer and reapy.at_exit that act as RPR_defer and RPR_atexit but take functions as input, and not code strings... Which in my opinion is way sounder. There is also special documentation for these functions here. I hope this can help newcomers to understand more easily how to use them.
  • a change log for details about all the new included functions.

@nir.arad
This release also (hopefully) fixes your installation bug. Please upgrade with pip install python-reapy --upgrade and let me know if it works!

@meta
I took your advice into account when coding reapy.defer. It prevents REAPER from writing to that reascripterr.txt file by adapting your solution (though I didn't exactly copy it, because a global override of the "open" function seemed a bit dangerous for someone who isn't aware of that behavior)
romeo_despres is offline   Reply With Quote
Old 03-23-2019, 02:52 PM   #32
X-Raym
Human being with feelings
 
X-Raym's Avatar
 
Join Date: Apr 2013
Location: France
Posts: 5,710
Default

thx !
X-Raym is offline   Reply With Quote
Old 03-25-2019, 01:17 AM   #33
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Thanks! The latest version indeed solved my problem and I can now run reapy outside Reaper (tested only on mac, not windows).
However, Everytime I run a script reaper displays an annoying error message.

Code:
reapy.print("Hello world!")
Code:
Deferred script execution error

Traceback (most recent call last):
  File "defer", line 1, in <module>
  File "activate_reapy_server.py", line 27, in main_loop
    SERVER.send_results(results)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/reascript_api/network/server.py", line 115, in send_results
    self._send_result(connection, result)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/reascript_api/network/server.py", line 82, in _send_result
    connection.send(result)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/reapy/reascript_api/network/socket.py", line 68, in send
    self._socket.sendall(length)
BrokenPipeError: [Errno 32] Broken pipe
nir.arad is offline   Reply With Quote
Old 03-26-2019, 04:18 AM   #34
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Hi @romeo_despres

I've done some testing and it seems that Reaper must be running before you import reapy and run your script.
This can be problematic in my case since I always launch the Reaper application as part of the script and the imports happen before that.

Is there any chance you can wrap the code in dist_program.py in a function so it can be called after the script launches the Reaper app?
Or simply put in inside Program class so it will be called only when calling Program.run()

Code:
if not reapy.is_inside_reaper():
    try:
        from reapy.reascript_api.network import Client, WebInterface
        WEB_INTERFACE = WebInterface(reapy.config.WEB_INTERFACE_PORT)
        CLIENT = Client(WEB_INTERFACE.get_reapy_server_port())
    except DisabledDistAPIError:
        import warnings
        warnings.warn(DisabledDistAPIWarning())
nir.arad is offline   Reply With Quote
Old 04-01-2019, 05:33 AM   #35
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

Hi nir.arad,

Sorry for the delay, I've been quite busy recently. I understand your issue, and it would definitely make sense to have a function to retry connecting to REAPER after importing reapy. I guess it would be slightly more complicated than just wrapping the code inside a function, but I'll try to work on it as soon as possible.

Thanks for your feedback!
romeo_despres is offline   Reply With Quote
Old 04-01-2019, 05:34 AM   #36
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Thanks! What about the deferred script execution error?

Do you have any clues why this happens?
nir.arad is offline   Reply With Quote
Old 04-01-2019, 06:01 AM   #37
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

Oh I thought both were linked... Are you saying that when you run reapy.print('Hello world') from the terminal, you get the 'hello world' message AND the deferred error?
romeo_despres is offline   Reply With Quote
Old 04-01-2019, 06:03 AM   #38
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Quote:
Originally Posted by romeo_despres View Post
Oh I thought both were linked... Are you saying that when you run reapy.print('Hello world') from the terminal, you get the 'hello world' message AND the deferred error?
Yes, it is unrelated.
nir.arad is offline   Reply With Quote
Old 04-01-2019, 06:14 AM   #39
romeo_despres
Human being with feelings
 
Join Date: Jan 2019
Posts: 20
Default

Oh ok... You're the one getting all the bugs sorry! Just to be sure, you can't call anything from reapy anymore after that, can you? I guess you have something like the following:

Code:
>>> reapy.print('Hello world')
>>> reapy.print('Hello world twice')
Nasty error message and no 'Hello world twice' inside REAPER
And when you call a function that, unlike "reapy.print", has to return something, for instance "reapy.Project()", I suppose you get an error too right?
romeo_despres is offline   Reply With Quote
Old 04-02-2019, 12:00 AM   #40
nir.arad
Human being with feelings
 
Join Date: Dec 2018
Posts: 15
Default

Quote:
Originally Posted by romeo_despres View Post
Oh ok... You're the one getting all the bugs sorry! Just to be sure, you can't call anything from reapy anymore after that, can you? I guess you have something like the following:

Code:
>>> reapy.print('Hello world')
>>> reapy.print('Hello world twice')
Nasty error message and no 'Hello world twice' inside REAPER
This works as expected, but still displays the message.

Quote:
Originally Posted by romeo_despres View Post
And when you call a function that, unlike "reapy.print", has to return something, for instance "reapy.Project()", I suppose you get an error too right?
Also works (despite the error message), See attached screenshot
Attached Images
File Type: png Screen Shot 2019-04-02 at 10.04.37 AM.png (26.6 KB, 9 views)
nir.arad is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -7. The time now is 10:03 PM.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.