def _input_reader_handler(self):
        """
        :param cparser.State state:
        :return: yields chars
        :rtype: typing.Generator[str]
        """
        state = self.state
        old_err_num = len(state._errors)
        old_content_list_num = len(state.contentlist)

        while True:
            try:
                line = input(">>> ")
            except EOFError:
                break
            for c in line + "\n":
                yield c
            for m in state._errors[old_err_num:]:
                print("Error:", m)
            old_err_num = len(state._errors)
            for m in state.contentlist[old_content_list_num:]:
                if self.debug:
                    print("Parsed:", m)
                if isinstance(m, (cparser.CStatement, cparser.CControlStructureBase)):
                    try:
                        res = self.interp.runSingleStatement(m, dump=self.debug)
                        print(res)
                    except Exception as exc:
                        print("Interpreter exception:", type(exc).__name__, ":", exc)
                        if self.debug:
                            better_exchook.better_exchook(*sys.exc_info())

            old_content_list_num = len(state.contentlist)
Example #2
0
  def excepthook(exc_type, exc_obj, exc_tb):
    """
    :param exc_type:
    :param exc_obj:
    :param exc_tb:
    """
    # noinspection PyBroadException
    try:
      # noinspection PyUnresolvedReferences,PyProtectedMember
      is_main_thread = isinstance(threading.currentThread(), threading._MainThread)
    except Exception:  # Can happen at a very late state while quitting.
      if exc_type is KeyboardInterrupt:
        return
    else:
      if is_main_thread:
        if exc_type is KeyboardInterrupt and getattr(sys, "exited", False):
          # Got SIGINT twice. Can happen.
          return
        # An unhandled exception in the main thread. This means that we are going to quit now.
        sys.exited = True
    print("Unhandled exception %s in thread %s, proc %i." % (exc_type, threading.currentThread(), os.getpid()))
    if exc_type is KeyboardInterrupt:
      return

    # noinspection PyUnresolvedReferences,PyProtectedMember
    if isinstance(threading.currentThread(), threading._MainThread):
      main_thread_id = thread.get_ident()
      if not isinstance(exc_type, Exception):
        # We are the main thread and we got an exit-exception. This is likely fatal.
        # This usually means an exit. (We ignore non-daemon threads and procs here.)
        # Print the stack of all other threads.
        dump_all_thread_tracebacks(exclude_thread_ids={main_thread_id})

    better_exchook.better_exchook(exc_type, exc_obj, exc_tb, file=sys.stdout)
Example #3
0
def log_exception(where, exctype, value, traceback):
    with lock:
        print("Exception at %s" % where)
        better_exchook.better_exchook(exctype,
                                      value,
                                      traceback,
                                      autodebugshell=False)
Example #4
0
	def __del__(self):
		try:
			if self._has_opened_file():
				self._close_file()
		except:
			print "SimpleStruct del error:", self, getattr(self, "_intern", None)
			better_exchook.better_exchook(*sys.exc_info())
Example #5
0
  def excepthook(exc_type, exc_obj, exc_tb):
    try:
      is_main_thread = isinstance(threading.currentThread(), threading._MainThread)
    except Exception:  # Can happen at a very late state while quitting.
      if exc_type is KeyboardInterrupt:
        return
    else:
      if is_main_thread:
        if exc_type is KeyboardInterrupt and getattr(sys, "exited", False):
          # Got SIGINT twice. Can happen.
          return
        # An unhandled exception in the main thread. This means that we are going to quit now.
        sys.exited = True
    print "Unhandled exception %s in thread %s, proc %i." % (exc_type, threading.currentThread(), os.getpid())
    if exc_type is KeyboardInterrupt:
      return

    if isinstance(threading.currentThread(), threading._MainThread):
      main_thread_id = thread.get_ident()
      if not isinstance(exc_type, Exception):
        # We are the main thread and we got an exit-exception. This is likely fatal.
        # This usually means an exit. (We ignore non-daemon threads and procs here.)
        # Print the stack of all other threads.
        dumpAllThreadTracebacks({main_thread_id})

    better_exchook.better_exchook(exc_type, exc_obj, exc_tb)
Example #6
0
    def excepthook(exc_type, exc_obj, exc_tb):
        try:
            is_main_thread = isinstance(threading.currentThread(),
                                        threading._MainThread)
        except Exception:  # Can happen at a very late state while quitting.
            if exc_type is KeyboardInterrupt:
                return
        else:
            if is_main_thread:
                if exc_type is KeyboardInterrupt and getattr(
                        sys, "exited", False):
                    # Got SIGINT twice. Can happen.
                    return
                # An unhandled exception in the main thread. This means that we are going to quit now.
                sys.exited = True
        print("Unhandled exception %s in thread %s, proc %i." %
              (exc_type, threading.currentThread(), os.getpid()))
        if exc_type is KeyboardInterrupt:
            return

        if isinstance(threading.currentThread(), threading._MainThread):
            main_thread_id = thread.get_ident()
            if not isinstance(exc_type, Exception):
                # We are the main thread and we got an exit-exception. This is likely fatal.
                # This usually means an exit. (We ignore non-daemon threads and procs here.)
                # Print the stack of all other threads.
                dumpAllThreadTracebacks({main_thread_id})

        better_exchook.better_exchook(exc_type, exc_obj, exc_tb)
Example #7
0
def log_except(*args, **kw):
    logger = kw.get('logger', None)
    better = kw.pop('_better', 0)
    if not logger:
        logger = logging.root

    if not len(args):
        msg = None
    elif len(args) == 1:
        msg = args[0]
        args = []
    else:
        msg = args[0]
        args = args[1:]
    lines = ['Traceback (most recent call last):\n']
    if better:
        import better_exchook
        better_exchook.better_exchook(
            *sys.exc_info(), output=lambda s: lines.append('%s\n' % s))
    else:
        ei = sys.exc_info()
        st = traceback.extract_stack(f=ei[2].tb_frame.f_back)
        et = traceback.extract_tb(ei[2])
        lines.extend(traceback.format_list(st))
        lines.append('  ****** Traceback ******  \n')
        lines.extend(traceback.format_list(et))
        lines.extend(traceback.format_exception_only(ei[0], ei[1]))
    exc = ''.join(lines)
    if msg:
        args = list(args)
        args.append(exc)
        logger.error(msg + ':\n%s', *args)
    else:
        logger.error(exc)
Example #8
0
def log_except(*args, **kw):
    logger = kw.get('logger', None)
    better = kw.pop('_better', 0)
    if not logger:
        logger = logging.root

    if not len(args):
        msg = None
    elif len(args) == 1:
        msg = args[0]
        args = []
    else:
        msg = args[0]
        args = args[1:]
    lines = ['Traceback (most recent call last):\n']
    if better:
        import better_exchook
        better_exchook.better_exchook(*sys.exc_info(),
                output=lambda s:lines.append('%s\n' % s))
    else:
        ei = sys.exc_info()
        st = traceback.extract_stack(f=ei[2].tb_frame.f_back)
        et = traceback.extract_tb(ei[2])
        lines.extend(traceback.format_list(st))
        lines.append('  ****** Traceback ******  \n')
        lines.extend(traceback.format_list(et))
        lines.extend(traceback.format_exception_only(ei[0], ei[1]))
    exc = ''.join(lines)
    if msg:
        args = list(args)
        args.append(exc)
        logger.error(msg + ':\n%s', *args)
    else:
        logger.error(exc)
Example #9
0
def exchook(exc_type, exc_obj, exc_tb):
  """
  Replacement for sys.excepthook.
  """
  if exc_type is KeyboardInterrupt:
    print("SprintExternInterface[pid %i]: KeyboardInterrupt" % (os.getpid(),))
    sys.exit(1)
  better_exchook.better_exchook(exc_type, exc_obj, exc_tb)
Example #10
0
		def extended_exc_hook(*args):
			better_exchook.better_exchook(*args)
			for t in threads:
				async_raise(t.ident, StopMe())
			# above doesn't seem to work (yet).
			# so to be sure:
			import os
			os._exit(0)
def exchook(exc_type, exc_obj, exc_tb):
    """
  Replacement for sys.excepthook.
  """
    if exc_type is KeyboardInterrupt:
        print("SprintExternInterface[pid %i]: KeyboardInterrupt" %
              (os.getpid(), ))
        sys.exit(1)
    better_exchook.better_exchook(exc_type, exc_obj, exc_tb)
Example #12
0
	def items(self):
		if not CacheEnabled: return
		from glob import glob
		for fn in glob(self._filename_pattern()):
			try:
				key, value = load(fn)
			except Exception:
				print "Exception on loading cache file %s" % fn
				better_exchook.better_exchook(*sys.exc_info())
				raise
			yield key, value
Example #13
0
 def run(self):
     with self.condition:
         if self.wait_time:
             self.condition.wait(self.wait_time)
     with self.db.lock:
         # noinspection PyBroadException
         try:
             self.do_task()
         except Exception:
             better_exchook.better_exchook(*sys.exc_info())
         finally:
             self.db.tasks.remove(self)
Example #14
0
	def __getitem__(self, key):
		if not CacheEnabled: raise KeyError
		try:
			cache_key, value = load(self._filename_for_key(key))
		except IOError:
			raise KeyError, "cache file not found"
		except Exception as exc:
			better_exchook.better_exchook(*sys.exc_info())
			if isinstance(exc, KeyError): raise Exception # no KeyError exception fall-through
			raise
		else:
			if cache_key == key: return value
			raise KeyError, "key repr collidation"
Example #15
0
def demo():
    """
    Some demo.
    """
    # some examples
    # this code produces this output: https://gist.github.com/922622

    try:
        x = {1: 2, "a": "b"}

        # noinspection PyMissingOrEmptyDocstring
        def f():
            y = "foo"
            # noinspection PyUnresolvedReferences,PyStatementEffect
            x, 42, sys.stdin.__class__, sys.exc_info, y, z

        f()
    except Exception:
        better_exchook(*sys.exc_info())

    try:
        # noinspection PyArgumentList
        (lambda _x: None)(__name__, 42)  # multiline
    except Exception:
        better_exchook(*sys.exc_info())

    try:

        class Obj:
            def __repr__(self):
                return ("<Obj multi-\n" + "     line repr>")

        obj = Obj()
        assert not obj
    except Exception:
        better_exchook(*sys.exc_info())

    # noinspection PyMissingOrEmptyDocstring
    def f1(a):
        f2(a + 1, 2)

    # noinspection PyMissingOrEmptyDocstring
    def f2(a, b):
        f3(a + b)

    # noinspection PyMissingOrEmptyDocstring
    def f3(a):
        b = ("abc" * 100) + "-interesting"  # some long demo str
        a(b)  # error, not callable

    try:
        f1(13)
    except Exception:
        better_exchook(*sys.exc_info())

    # use this to overwrite the global exception handler
    install()
    # and fail
    # noinspection PyUnresolvedReferences
    finalfail(sys)
  def excepthook(exc_type, exc_obj, exc_tb):
    print "Unhandled exception %s in thread %s, proc %s." % (exc_type, threading.currentThread(), os.getpid())
    better_exchook.better_exchook(exc_type, exc_obj, exc_tb)

    if main_thread_id == thread.get_ident():
      print "We are the main thread."
      if not isinstance(exc_type, Exception):
        # We are the main thread and we got an exit-exception. This is likely fatal.
        # This usually means an exit. (We ignore non-daemon threads and procs here.)
        # Print the stack of all other threads.
        if hasattr(sys, "_current_frames"):
          print ""
          threads = {t.ident: t for t in threading.enumerate()}
          for tid, stack in sys._current_frames().items():
            if tid != main_thread_id:
              print "Thread %s:" % threads.get(tid, "unnamed with id %i" % tid)
              better_exchook.print_traceback(stack)
              print ""
Example #17
0
def test_interpreter_helloworld():
    testcode = """
    #include <stdio.h>
    
    int main(int argc, char** argv) {
        printf("Hello %s\n", "world");
        printf("args: %i\n", argc);
        int i;
        for(i = 0; i < argc; ++i)
            printf("%s\n", argv[i]);
        fflush(stdout);
    }
    """

    state = helpers_test.parse(testcode, withGlobalIncludeWrappers=True)

    from cparser import interpreter
    interp = interpreter.Interpreter()
    interp.register(state)

    def dump():
        for f in state.contentlist:
            if not isinstance(f, cparser.CFunc): continue
            if not f.body: continue

            print()
            print("parsed content of " + str(f) + ":")
            for c in f.body.contentlist:
                print(c)

        print()
        print("PyAST of main:")
        interp.dumpFunc("main")

    #interpreter.runFunc("main", len(sys.argv), sys.argv + [None])

    import os
    # os.pipe() returns pipein,pipeout
    pipes = os.pipe(), os.pipe()  # for stdin/stdout+stderr
    if hasattr(os, "set_inheritable"):
        # Python 3 by default will close all fds in subprocesses. This will avoid that.
        os.set_inheritable(pipes[0][0], True)
        os.set_inheritable(pipes[0][1], True)
        os.set_inheritable(pipes[1][0], True)
        os.set_inheritable(pipes[1][1], True)

    pid = os.fork()
    if pid == 0:  # child
        os.close(pipes[0][1])
        os.close(pipes[1][0])
        os.dup2(pipes[0][0], sys.__stdin__.fileno())
        os.dup2(pipes[1][1], sys.__stdout__.fileno())
        os.dup2(pipes[1][1], sys.__stderr__.fileno())

        try:
            interp.runFunc("main", 2, ["./test", "abc", None])
        except SystemExit:
            raise
        except BaseException:
            better_exchook.better_exchook(*sys.exc_info())

        print("Normal exit.")
        os._exit(0)
        return

    # parent
    os.close(pipes[0][0])
    os.close(pipes[1][1])
    child_stdout = os.fdopen(pipes[1][0], "rb", 0)
    child_stdout = child_stdout.readlines()
    if PY3:
        child_stdout = [l.decode("utf8") for l in child_stdout]

    expected_out = [
        "Hello world\n",
        "args: 2\n",
        "./test\n",
        "abc\n",
        "Normal exit.\n",
    ]

    if expected_out != child_stdout:
        print("Got output:")
        print("".join(child_stdout))
        dump()

        print("run directly here now:")
        interp.runFunc("main", 2, ["./test", "abc", None])

        raise Exception("child stdout %r" % (child_stdout,))
Example #18
0
def _debug_shell_exception():
    # noinspection PyBroadException
    try:
        raise Exception("demo exception")
    except Exception:
        better_exchook(*sys.exc_info(), debugshell=True)
Example #19
0
				def handle_exc():
					print "Exception in thread", curthread.name
					better_exchook.better_exchook(*excinfo, autodebugshell=False)
def test_interpreter_helloworld():
    testcode = """
	#include <stdio.h>

	int main(int argc, char** argv) {
		printf("Hello %s\n", "world");
		printf("args: %i\n", argc);
		int i;
		for(i = 0; i < argc; ++i)
			printf("%s\n", argv[i]);
	}
	"""

    state = helpers_test.parse(testcode, withGlobalIncludeWrappers=True)

    import interpreter
    interp = interpreter.Interpreter()
    interp.register(state)

    def dump():
        for f in state.contentlist:
            if not isinstance(f, cparser.CFunc): continue
            if not f.body: continue

            print
            print "parsed content of " + str(f) + ":"
            for c in f.body.contentlist:
                print c

        print
        print "PyAST of main:"
        interp.dumpFunc("main")

    #interpreter.runFunc("main", len(sys.argv), sys.argv + [None])

    import os
    # os.pipe() returns pipein,pipeout
    pipes = os.pipe(), os.pipe() # for stdin/stdout+stderr

    if os.fork() == 0: # child
        os.close(pipes[0][1])
        os.close(pipes[1][0])
        os.dup2(pipes[0][0], sys.__stdin__.fileno())
        os.dup2(pipes[1][1], sys.__stdout__.fileno())
        os.dup2(pipes[1][1], sys.__stderr__.fileno())

        try:
            interp.runFunc("main", 2, ["./test", "abc", None])
        except BaseException:
            better_exchook.better_exchook(*sys.exc_info())

        os._exit(0)
        return

    # parent
    os.close(pipes[0][0])
    os.close(pipes[1][1])
    child_stdout = os.fdopen(pipes[1][0])
    child_stdout = child_stdout.readlines()

    expected_out = [
        "Hello world\n",
            "args: 2\n",
            "./test\n",
            "abc\n",
    ]

    if expected_out != child_stdout:
        print "Got output:"
        print "".join(child_stdout)
        dump()
        assert False
Example #21
0
    s1.extend(4, 5) == Stack(0, 1, 2, 3, 4, 5)

    return True


if __name__ == "__main__":
    # Try to display relevant current values upon any assertion failure.
    import os, subprocess
    try:
        # Use command-line 'pytest' if available to display
        # current values upon assertion failure.
        subprocess.call(["pytest", "-q", __file__])
    except:
        try:
            # See https://github.com/albertz/py_better_exchook
            import sys, traceback, better_exchook
            better_exchook.install()  # runs: sys.excepthook = better_exchook
        except:
            # Otherwise, use normal assertion output.
            try:
                test_stack()
                sys.exit()
            except:
                traceback.print_exc(file=sys.stdout)
                raise SystemExit
        # better_exchook module installed, use its current assertion values output.
        try:
            test_stack()
        except:
            better_exchook.better_exchook(*sys.exc_info())
Example #22
0
def test_interpreter_helloworld():
    testcode = """
	#include <stdio.h>

	int main(int argc, char** argv) {
		printf("Hello %s\n", "world");
		printf("args: %i\n", argc);
		int i;
		for(i = 0; i < argc; ++i)
			printf("%s\n", argv[i]);
	}
	"""

    state = helpers_test.parse(testcode, withGlobalIncludeWrappers=True)

    import interpreter
    interp = interpreter.Interpreter()
    interp.register(state)

    def dump():
        for f in state.contentlist:
            if not isinstance(f, cparser.CFunc): continue
            if not f.body: continue

            print
            print "parsed content of " + str(f) + ":"
            for c in f.body.contentlist:
                print c

        print
        print "PyAST of main:"
        interp.dumpFunc("main")

    #interpreter.runFunc("main", len(sys.argv), sys.argv + [None])

    import os
    # os.pipe() returns pipein,pipeout
    pipes = os.pipe(), os.pipe()  # for stdin/stdout+stderr

    if os.fork() == 0:  # child
        os.close(pipes[0][1])
        os.close(pipes[1][0])
        os.dup2(pipes[0][0], sys.__stdin__.fileno())
        os.dup2(pipes[1][1], sys.__stdout__.fileno())
        os.dup2(pipes[1][1], sys.__stderr__.fileno())

        try:
            interp.runFunc("main", 2, ["./test", "abc", None])
        except BaseException:
            better_exchook.better_exchook(*sys.exc_info())

        os._exit(0)
        return

    # parent
    os.close(pipes[0][0])
    os.close(pipes[1][1])
    child_stdout = os.fdopen(pipes[1][0])
    child_stdout = child_stdout.readlines()

    expected_out = [
        "Hello world\n",
        "args: 2\n",
        "./test\n",
        "abc\n",
    ]

    if expected_out != child_stdout:
        print "Got output:"
        print "".join(child_stdout)
        dump()
        assert False
def main():
    better_exchook.install()
    arg_parser = argparse.ArgumentParser()
    arg_parser.add_argument("--ogg")
    arg_parser.add_argument("--zip")
    arg_parser.add_argument("--ourexec")
    arg_parser.add_argument("--libvorbisexec")
    arg_parser.add_argument("--ourout")
    arg_parser.add_argument("--libvorbisout")
    arg_parser.add_argument("--dump_stdout", action="store_true")
    arg_parser.add_argument("--no_stderr", action="store_true")
    args = arg_parser.parse_args()

    if args.no_stderr:
        sys.stderr = sys.stdout

    if args.zip:
        assert not args.ogg and not args.ourout and not args.libvorbisout
        sub_cmd = [sys.argv[0]]
        if args.ourexec:
            sub_cmd += ["--ourexec", args.ourexec]
        if args.libvorbisexec:
            sub_cmd += ["--libvorbisexec", args.libvorbisexec]
        if args.dump_stdout:
            sub_cmd += ["--dump_stdout"]
        if args.no_stderr:
            sub_cmd += ["--no_stderr"]

        import zipfile
        ogg_count = 0
        with zipfile.ZipFile(args.zip) as zip_f:
            for fn in zip_f.namelist():
                print(fn)
                if fn.endswith(".ogg"):
                    ogg_count += 1
                    ogg_raw_bytes = zip_f.read(fn)
                    with tempfile.NamedTemporaryFile(
                            suffix=os.path.basename(fn)) as tmp_f:
                        tmp_f.write(ogg_raw_bytes)
                        tmp_f.flush()
                        call(sub_cmd + ["--ogg", tmp_f.name])
        print("Found %i OGG files." % ogg_count)
        return

    if args.ogg:
        assert not args.ourout, "--ogg xor --ourout.\n%s" % arg_parser.format_usage(
        )
        if args.ourexec is None:
            assert os.path.exists(
                default_ours_exec), "run `compile-libvorbis.py --mode ours`"
            args.ourexec = default_ours_exec
        args.ourout = create_debug_out(args.ourexec, args.ogg)
        if args.libvorbisexec is None:
            assert os.path.exists(
                default_libvorbis_exec
            ), "run `compile-libvorbis.py --mode standalone`"
            args.libvorbisexec = default_libvorbis_exec
        if args.libvorbisexec:
            assert not args.libvorbisout
            args.libvorbisout = create_debug_out(args.libvorbisexec, args.ogg)

    assert args.ourout, "need --ourout.\n%s" % arg_parser.format_usage()
    reader1 = Reader(args.ourout)
    print("Read our (ParseOggVorbis) debug out file:", reader1.filename)
    print("Our decoder name:", reader1.decoder_name)
    print("Our num channels:", reader1.decoder_num_channels)
    print("Our sample rate:", reader1.decoder_sample_rate)

    reader2 = None
    if args.libvorbisout:
        reader2 = Reader(args.libvorbisout)
        print("Read libvorbis debug out file:", reader2.filename)
        print("libvorbis decoder name:", reader2.decoder_name)
        print("libvorbis num channels:", reader2.decoder_num_channels)
        print("libvorbis sample rate:", reader2.decoder_sample_rate)
        print("Will check that both are the same.")
        assert reader2.decoder_sample_rate == reader1.decoder_sample_rate
        assert reader2.decoder_num_channels == reader1.decoder_num_channels

    reader1.read_setup(dump=args.dump_stdout)
    if reader2:
        reader2.read_setup(dump=args.dump_stdout)
        assert len(reader1.floors) == len(reader2.floors)
        for f1, f2 in zip(reader1.floors, reader2.floors):
            assert f1.multiplier == f2.multiplier
            assert len(f1.xs) == len(f2.xs)
            for x1, x2 in zip(f1.xs, f2.xs):
                assert x1 == x2

    num_packets = 0
    while True:
        packet1 = reader1.read_audio_packet(dump=args.dump_stdout)
        if reader2:
            packet2 = reader2.read_audio_packet(dump=args.dump_stdout)
            try:
                AudioPacket.assert_same(packet1, packet2)
                assert sorted(reader1.pcm_data.keys()) == sorted(
                    reader2.pcm_data.keys())
                for channel in sorted(reader1.pcm_data.keys()):
                    pcms1 = reader1.pcm_data[channel]
                    pcms2 = reader2.pcm_data[channel]
                    assert len(pcms1) == len(pcms2)
                    pcm1 = sum(pcms1, tuple())
                    pcm2 = sum(pcms2, tuple())
                    min_len = min(len(pcm1), len(pcm2))
                    assert_close_list(pcm1[:min_len], pcm2[:min_len])
                    pcms1.clear()
                    pcms2.clear()
                    if len(pcm1) > min_len:
                        pcms1.append(pcm1)
                    if len(pcm2) > min_len:
                        pcms2.append(pcm2)
                    if not pcms1:
                        del reader1.pcm_data[channel]
                    if not pcms2:
                        del reader2.pcm_data[channel]
            except Exception:
                print(
                    "Exception at packet %i, num samples1 %r, num samples2 %r (diff is valid here)."
                    % (num_packets, reader1.num_samples, reader2.num_samples))
                try:
                    num_remaining_packets1 = reader1.count_remaining_audio_packets(
                        dump=args.dump_stdout)
                    num_remaining_packets2 = reader2.count_remaining_audio_packets(
                        dump=args.dump_stdout)
                    print("Num remaining reader1: %i, reader2: %i" %
                          (num_remaining_packets1, num_remaining_packets2))
                except Exception:
                    print(
                        "During count_remaining_audio_packets, another exception occured:"
                    )
                    better_exchook.better_exchook(*sys.exc_info())
                print("Reraising original exception now.")
                raise
        if packet1.eof:
            print("EOF")
            if reader2:
                assert not reader1.pcm_data and not reader2.pcm_data
            break
        num_packets += 1
    print("Finished.")
    print("Num audio packets:", num_packets)
    print("Reader1 num samples:", reader1.num_samples)
    if reader2:
        print("Reader2 num samples:", reader2.num_samples)