3

I'm using a module called pywaves for interacting with waves.exchange API. The problem is sometimes when I try to place an order, it gets rejected with an error message:

[ERROR] Order Rejected...

The problem is how to capture this error message in my script. The code that generates the error is: myOrder = myAddress.sell(assetPair = PRO_WAVES, amount = 1491999999, price = proprice1, matcherFee = 700000, maxLifetime = 3600) The error does not throw an exception, and is not captured into myOrder. How do I get the data from this error into a variable so I can work with it?

martineau
  • 119,623
  • 25
  • 170
  • 301
  • this looks like a log message which does not necessarily raise the actual error, can you show the full error? –  May 16 '20 at 15:13
  • [ERROR] Order Rejected - The asset's script of 6GQkwHGyd769EghKQ6qXhAHG55JyaFjK7VGWEKSSg4Z8 returned the error: Sell price must be >= 1637850000 wavelets in Cycle # 338. My script needs access to the error message to pull the minimum price from it. – Marc Greene May 17 '20 at 00:08

2 Answers2

3

The error inside the library is probably written to the standard error output sys.stderr. You could thus redirect the error output and check if the library is writing to it. See for instance this question on logging error output.

Once you have a logger (or in your case a class that records and parses any errors), use it like this:

import sys
_stderr = sys.stderr
sys.stderr = MyErrorCheckLogger()
try:
    myOrder = myAddress.sell(...)
finally:
    sys.stderr = _stderr

Of course, you can do the same thing with sys.stdout—the standard output channel.


Edit: Here is a full example where we catch any error messages directly printed to the standard output (stdout).

import sys

class ErrorChecker:
    def __init__(self, output):
        self.output = output               # Save the original `stdout` (or `stderr`)
        self.buffer = ""                   # The buffer for the message printed

    def write(self, message):
        self.buffer += message             # Add any message to our buffer
        self.output.write(message)         # Print it as original intended

    def flush(self):
        self.output.flush()

def throwError(f, *args, **kwargs):
    sys.stdout = ErrorChecker(sys.stdout)  # Create a new output-stream with buffer
    try:
        result = f(*args, **kwargs)        # Execute the code that might cause an error
    finally:
        buffer = sys.stdout.buffer         # Get the output buffer
        sys.stdout = sys.stdout.output     # Restore the original 'stdout'
    if buffer.startswith("[ERROR]"):       # If the output is an error message, raise
        raise Exception(buffer)            # it as an actual exception
    return result

myOrder = throwError(myAddress.sell, assetPair = PRO_WAVES, amount = 1491999999, price = proprice1, matcherFee = 700000, maxLifetime = 3600)
Tobias
  • 1,321
  • 6
  • 11
  • I added this code, and the output is the same... what variable would I use to access the error message say to pull the minimum sell price from it: [ERROR] Order Rejected - The asset's script of 6GQkwHGyd769EghKQ6qXhAHG55JyaFjK7VGWEKSSg4Z8 returned the error: Sell price must be >= 1637850000 wavelets in Cycle # 338. – Marc Greene May 17 '20 at 00:11
3

After reading through the actual code, it appears that you can use pywaves.setThrowOnError() to cause exceptions to be raised whenever errors are logged, such as in the situation you describe. However, for whatever reason that doesn't appear to be documented, so use at your own risk. You can use the issue tracking system to communicate with the developers about this.

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
  • 1
    The documentation looks pretty sketchy. It's hard to see why there would be a `setThrowOnError` function unless it was meant as a public API. (It doesn't seem to be used internally by any other modules). – ekhumoro May 16 '20 at 15:49