r-barnes / richdem

High-performance Terrain and Hydrology Analysis
GNU General Public License v3.0
264 stars 67 forks source link

Option to silent function TerrainAttribute #57

Open adehecq opened 2 years ago

adehecq commented 2 years ago

The function TerrainAttribute prints references to the screen when run. E.g. for the slope:

A Slope calculation (degrees) C Horn, B.K.P., 1981. Hill shading and the reflectance map. Proceedings of the IEEE 69, 14–47. doi:10.1109/PROC.1981.11918

I understand the idea behind it, but it can become annoying when looping over many items, and trying to add a progress bar. I could not find any option to silent that print. Please let me know if there is a way, otherwise would it be possible to include this as an option?

Since the print is called from the C++ function, it does not seem possible to catch the stdout in Python directly. I tried for example this option and this option, without success. It works with a pure Python function though. So I don't think there is any way on my end to capture that output that comes from the C++ function.

FraserParlane commented 10 months ago

Agreed—this reduces the usability of the library. It'd be great to have a fix to silence the printing!

FraserParlane commented 10 months ago

Here's a solution that I found:

import os

class Silence:
    """A context manager that prevents shared C libraries from printing to
    console. Specifically, this was built to silence richdem."""
    def __init__(self):
        self.stderr_fd = sys.stderr.fileno()
        self.orig_fd = os.dup(self.stderr_fd)
        self.null_fd = os.open(os.devnull, os.O_WRONLY)

    def __enter__(self):
        os.dup2(self.null_fd, self.stderr_fd)

    def __exit__(self, type, value, traceback):
        os.dup2(self.orig_fd, self.stderr_fd)

# Instantiating this once helps with performance.
silence = Silence()

with silence:
    rd.TerrainAttribute()