def argparser(): parser = argparse.ArgumentParser() parser.add_argument( '--control', default=get_config('global', 'control'), help='The remote control to control the stb (default: %(default)s)') parser.add_argument( '--source-pipeline', default=get_config('global', 'source_pipeline'), help='A gstreamer pipeline to use for A/V input (default: ' '%(default)s)') parser.add_argument('--sink-pipeline', default=get_config('global', 'sink_pipeline'), help='A gstreamer pipeline to use for video output ' '(default: %(default)s)') parser.add_argument( '--restart-source', action='store_true', default=get_config('global', 'restart_source', type_=bool), help='Restart the GStreamer source pipeline when video loss is ' 'detected') parser.add_argument('--save-video', help='Record video to the specified file', metavar='FILE', default=get_config('run', 'save_video')) logging.argparser_add_verbose_argument(parser) return parser
def press_until_match( self, key, image, interval_secs=None, max_presses=None, match_parameters=None, region=Region.ALL): from .match import MatchParameters, MatchTimeout, wait_for_match if interval_secs is None: # Should this be float? interval_secs = get_config( "press_until_match", "interval_secs", type_=int) if max_presses is None: max_presses = get_config( "press_until_match", "max_presses", type_=int) if match_parameters is None: match_parameters = MatchParameters() i = 0 while True: try: return wait_for_match(image, timeout_secs=interval_secs, match_parameters=match_parameters, region=region, frames=self.frames()) except MatchTimeout: if i < max_presses: self.press(key) i += 1 else: raise
def argparser(): parser = argparse.ArgumentParser() parser.add_argument( '--control', default=get_config('global', 'control'), help='The remote control to control the stb (default: %(default)s)') parser.add_argument( '--source-pipeline', default=get_config('global', 'source_pipeline'), help='A gstreamer pipeline to use for A/V input (default: ' '%(default)s)') parser.add_argument( '--sink-pipeline', default=get_config('global', 'sink_pipeline'), help='A gstreamer pipeline to use for video output ' '(default: %(default)s)') parser.add_argument( '--restart-source', action='store_true', default=get_config('global', 'restart_source', type_=bool), help='Restart the GStreamer source pipeline when video loss is ' 'detected') parser.add_argument( '--save-video', help='Record video to the specified file', metavar='FILE', default=get_config('run', 'save_video')) logging.argparser_add_verbose_argument(parser) return parser
def main(): parser = argparse.ArgumentParser() parser.prog = "stbt config" parser.description = """Prints the value of the specified key from the stbt configuration file. See 'configuration' in the stbt(1) man page.""" parser.epilog = """Returns non-zero exit status if the specified key or section isn't found.""" parser.add_argument("--bash-completion", action="store_true", help=argparse.SUPPRESS) parser.add_argument( "name", metavar="section.key", help="e.g. 'global.source_pipeline' or 'record.control_recorder'") args = parser.parse_args(sys.argv[1:]) if args.bash_completion: cfg = _config_init() for section in cfg.sections(): for option in cfg.options(section): print "%s.%s" % (section, option) sys.exit(0) if args.name.rfind(".") == -1: error("'name' parameter must contain the section and key " "separated by a dot") section, key = args.name.rsplit(".", 1) try: print get_config(section, key) except ConfigurationError as e: error(e.message)
def main(): parser = argparse.ArgumentParser() parser.prog = "stbt config" parser.description = """Prints the value of the specified key from the stbt configuration file. See 'configuration' in the stbt(1) man page.""" parser.epilog = """Returns non-zero exit status if the specified key or section isn't found.""" parser.add_argument( "--bash-completion", action="store_true", help=argparse.SUPPRESS) parser.add_argument( "name", metavar="section.key", help="e.g. 'global.source_pipeline' or 'record.control_recorder'") args = parser.parse_args(sys.argv[1:]) if args.bash_completion: cfg = _config_init() for section in cfg.sections(): for option in cfg.options(section): print "%s.%s" % (section, option) sys.exit(0) if args.name.rfind(".") == -1: error("'name' parameter must contain the section and key " "separated by a dot") section, key = args.name.rsplit(".", 1) try: print get_config(section, key) except ConfigurationError as e: error(e.message)
def argparser(): parser = argparse.ArgumentParser() parser.prog = "stbt control" parser.description = ("Send remote control signals using the PC keyboard " "or from the command line.") parser.add_argument( "--help-keymap", action='store_true', default=False, help="Show description of the keymap file format and exit.") parser.add_argument( "--keymap", default=default_keymap_file(), help="Load keymap from KEYMAP file; defaults to %(default)s. " "See `%(prog)s --help-keymap` for details.") parser.add_argument( "--control", default=get_config("global", "control"), help="Equivalent to the --control parameter of `stbt run`. " "See `man stbt` for available control types and configuration.") parser.add_argument( "remote_control_key", default=None, nargs='?', help=( "The name of a remote control key as in the control's config file " "(that is /etc/lirc/lircd.conf in case of a LIRC control device). " "Specifying this argument sends remote_control_key and exits. " "Omitting this argument brings up the printed keymap.")) return parser
def user_command(name, args, cwd): from _stbt.config import get_config script = get_config("batch", name) if script: return subprocess.call([script] + args, stdin=DEVNULL_R, cwd=cwd) else: return 0
def test_unicode_in_config_file_contents(): with temporary_config("""\ [global] unicodeinkey\xf8 = hi unicodeinvalue = \xf8 [unicodeinsection\xf8] key = bye """): assert get_config("global", "unicodeinkey\xf8") == "hi" assert get_config("global", "unicodeinvalue") == "\xf8" assert get_config("unicodeinsection\xf8", "key") == "bye" # This is `unicode` on python 2 and `str` (i.e. unicode) on python 3. assert isinstance(get_config("global", "unicodeinvalue"), text_type)
def new_device_under_test_from_config(parsed_args=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display(args.source_pipeline, sink_pipeline, args.restart_source, source_teardown_eos) return DeviceUnderTest(display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop)
def test_that_set_config_creates_directories_if_required(): with _directory_sandbox() as d: os.environ["XDG_CONFIG_HOME"] = d + "/.config" if "STBT_CONFIG_FILE" in os.environ: del os.environ["STBT_CONFIG_FILE"] set_config("global", "test", "hello2") assert os.path.isfile(d + "/.config/stbt/stbt.conf") _config_init(force=True) assert get_config("global", "test") == "hello2"
def add_argparse_argument(argparser): argparser.add_argument( "--tv-driver", help="Determines how to display videos on TV.\n\n" " manual - Prompt the user then wait for confirmation.\n" " assume - Assume the video is already playing (useful for " "scripting when passing a single test to be run).\n" " fake:pipe_name - Used for testing", default=get_config("camera", "tv_driver", "manual"))
def test_that_set_config_creates_directories_if_required(): with scoped_curdir() as d: os.environ['XDG_CONFIG_HOME'] = d + '/.config' if 'STBT_CONFIG_FILE' in os.environ: del os.environ['STBT_CONFIG_FILE'] set_config('global', 'test', 'hello2') assert os.path.isfile(d + '/.config/stbt/stbt.conf') _config_init(force=True) assert get_config('global', 'test') == 'hello2'
def new_device_under_test_from_config(parsed_args=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display( args.source_pipeline, sink_pipeline, args.restart_source, source_teardown_eos) return DeviceUnderTest( display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop)
def create_from_args(args, video_generator): desc = args.tv_driver video_server = _HTTPVideoServer( video_generator, video_format=get_config('camera', 'video_format')) if desc == 'assume': return _AssumeTvDriver() elif desc.startswith('fake:'): return _FakeTvDriver(desc[5:], video_server) elif desc == 'manual': return _ManualTvDriver(video_server) else: raise RuntimeError("Unknown video driver requested: %s" % desc)
def argparser(): parser = argparse.ArgumentParser() parser.add_argument( '--control', default=get_config('global', 'control'), help='The remote control to control the stb (default: %(default)s)') parser.add_argument( '--source-pipeline', default=get_config('global', 'source_pipeline'), help='A gstreamer pipeline to use for A/V input (default: ' '%(default)s)') parser.add_argument( '--sink-pipeline', default=get_config('global', 'sink_pipeline'), help='A gstreamer pipeline to use for video output ' '(default: %(default)s)') parser.add_argument( '--save-video', help='Record video to the specified file', metavar='FILE', default=get_config('run', 'save_video')) logging.argparser_add_verbose_argument(parser) return parser
def test_get_config_with_default_value(): with temporary_config("""\ [global] test=hello"""): assert get_config("global", "test", "my default") == "hello" assert get_config("global", "nosuchkey", "my default") == "my default" assert get_config("nosuchsection", "test", "my default") == "my default" assert get_config("nosuchsection", "test", None) is None with pytest.raises(ConfigurationError): get_config("nosuchsection", "test")
def main(argv): parser = argparse.ArgumentParser( description="Control and query a computer controllable power outlet", formatter_class=argparse.RawTextHelpFormatter) parser.add_argument("--power-outlet", metavar="URI", default=get_config("global", "power_outlet", ""), help=dedent("""\ Address of the power device and the outlet on the device. The format of <uri> is either: aten:<hostname>:<outlet> - For ATEN network controlled PDU ipp:<hostname>:<outlet> - For IP Power 9258 network controlled PDU pdu:<hostname>:<outlet> - For PDUeX KWX network controlled PDU rittal:<hostname>:<outlet>:<community> - For Rittal 7955.310 network controlled PDU aviosys-8800-pro[:<serial device>] - For Aviosys 8800 Pro USB controlled outlets where <hostname> The device's network address. <outlet> Address of the individual power outlet on the device. Allowed values depend on the specific device model. <serial device> The device name of the serial device that the 8800 Pro exposes. Defaults to /dev/ttyACM0 This URI defaults to from stbt.conf's "global.power_outlet" if not specified on the command line. """)) parser.add_argument("command", choices=["on", "off", "status"], metavar="command", help=dedent("""\ on|off: Turn power on or off status: Prints ON if the outlet is powered, otherwise prints OFF """)) args = parser.parse_args(argv[1:]) outlet = uri_to_power_outlet(args.power_outlet) if args.command == "on": outlet.set(True) elif args.command == "off": outlet.set(False) elif args.command == "status": sys.stdout.write("ON\n" if outlet.get() else "OFF\n") else: assert False
def main(argv): parser = argparse.ArgumentParser( description="Control and query a computer controllable power outlet", formatter_class=argparse.RawTextHelpFormatter) parser.add_argument( "--power-outlet", metavar="URI", default=get_config("global", "power_outlet", ""), help=dedent("""\ Address of the power device and the outlet on the device. The format of <uri> is either: aten:<hostname>:<outlet> - For ATEN network controlled PDU ipp:<hostname>:<outlet> - For IP Power 9258 network controlled PDU pdu:<hostname>:<outlet> - For PDUeX KWX network controlled PDU rittal:<hostname>:<outlet>:<community> - For Rittal 7955.310 network controlled PDU aviosys-8800-pro[:<serial device>] - For Aviosys 8800 Pro USB controlled outlets where <hostname> The device's network address. <outlet> Address of the individual power outlet on the device. Allowed values depend on the specific device model. <serial device> The device name of the serial device that the 8800 Pro exposes. Defaults to /dev/ttyACM0 This URI defaults to from stbt.conf's "global.power_outlet" if not specified on the command line. """)) parser.add_argument( "command", choices=["on", "off", "status"], metavar="command", help=dedent("""\ on|off: Turn power on or off status: Prints ON if the outlet is powered, otherwise prints OFF """)) args = parser.parse_args(argv[1:]) outlet = uri_to_power_outlet(args.power_outlet) if args.command == "on": outlet.set(True) elif args.command == "off": outlet.set(False) elif args.command == "status": sys.stdout.write("ON\n" if outlet.get() else "OFF\n") else: assert False
def is_screen_black(self, frame=None, mask=None, threshold=None, region=Region.ALL): if threshold is None: threshold = get_config('is_screen_black', 'threshold', type_=int) if frame is None: frame = self.get_frame() if mask is None: mask = _ImageFromUser(None, None, None) else: mask = _load_image(mask, cv2.IMREAD_GRAYSCALE) _region = Region.intersect(_image_region(frame), region) greyframe = cv2.cvtColor(crop(frame, _region), cv2.COLOR_BGR2GRAY) if mask.image is not None: cv2.bitwise_and(greyframe, mask.image, dst=greyframe) maxVal = greyframe.max() if logging.get_debug_level() > 1: imglog = logging.ImageLogger("is_screen_black") imglog.imwrite("source", frame) if mask.image is not None: imglog.imwrite('mask', mask.image) _, thresholded = cv2.threshold(greyframe, threshold, 255, cv2.THRESH_BINARY) imglog.imwrite('non-black-regions-after-masking', thresholded) result = _IsScreenBlackResult(bool(maxVal <= threshold), frame) debug("is_screen_black: {found} black screen using mask={mask}, " "threshold={threshold}, region={region}: " "{result}, maximum_intensity={maxVal}".format( found="Found" if result.black else "Didn't find", mask=mask.friendly_name, threshold=threshold, region=region, result=result, maxVal=maxVal)) return result
def _interpress_delay(self, interpress_delay_secs): if interpress_delay_secs is None: interpress_delay_secs = get_config( "press", "interpress_delay_secs", type_=float) if self._time_of_last_press is not None: # `sleep` is inside a `while` loop because the actual suspension # time of `sleep` may be less than that requested. while True: seconds_to_wait = ( self._time_of_last_press - datetime.datetime.now() + datetime.timedelta(seconds=interpress_delay_secs) ).total_seconds() if seconds_to_wait > 0: self._time.sleep(seconds_to_wait) else: break try: yield finally: self._time_of_last_press = datetime.datetime.now()
def main(argv): parser = argparse.ArgumentParser( description="Configure stb-tester to use a local X11 program as " "input/output.", epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) subparsers = parser.add_subparsers(dest='subcommand') run_parser = subparsers.add_parser('run') run_parser.add_argument('-b', '--background', action="store_true", help="Run virtual-stb in background") run_parser.add_argument('-v', '--verbose', action="store_true", help="Print xorg logs to console") run_parser.add_argument( '--x-keymap', help="Filename of file mapping key names to X keysyms") run_parser.add_argument('command', nargs=1) run_parser.add_argument('args', nargs=argparse.REMAINDER) stop_parser = subparsers.add_parser('stop') stop_parser.add_argument('-f', '--force', action="store_true", help="Ignore errors") args = parser.parse_args(argv[1:]) if args.subcommand == 'run': # Do run our `finally` teardown blocks on SIGTERM signal.signal(signal.SIGTERM, lambda _signo, _frame: sys.exit(0)) write_end = None if args.background: read_end, write_end = multiprocessing.Pipe(duplex=False) pid = os.fork() if pid: # Parent - wait for child to be ready write_end.close() read_end.recv() return 0 else: # Child read_end.close() with virtual_stb(args.command + args.args, verbose=args.verbose, x_keymap=args.x_keymap) as (child, config): for k, v in config.items(): set_config('global', k, v) try: if write_end is not None: write_end.send(True) write_end.close() child.wait() finally: for k in config.keys(): set_config('global', k, None) elif args.subcommand == 'stop': try: pid = get_config('global', 'vstb_pid', None) set_config('global', 'vstb_pid', None) os.kill(int(pid), signal.SIGTERM) while True: try: os.kill(int(pid), 0) time.sleep(0.1) except OSError as e: if e.errno == errno.ESRCH: return 0 else: raise except Exception: # pylint: disable=broad-except if not args.force: raise
def test_that_set_config_modifies_config_value(): with set_config_test(): set_config("global", "test", "goodbye") assert get_config("global", "test") == "goodbye" _config_init(force=True) assert get_config("global", "test") == "goodbye"
def test_that_set_config_modifies_config_value(): with set_config_test(): set_config('global', 'test', 'goodbye') assert get_config('global', 'test') == 'goodbye' _config_init(force=True) assert get_config('global', 'test') == 'goodbye'
def test_that_set_config_creates_new_sections_if_required(): with set_config_test(): set_config('non_existent_section', 'test', 'goodbye') assert get_config('non_existent_section', 'test') == 'goodbye' _config_init(force=True) assert get_config('non_existent_section', 'test') == 'goodbye'
def default_keymap_file(): config_dir = os.environ.get('XDG_CONFIG_HOME', '%s/.config' % os.environ['HOME']) return get_config("control", "keymap", "") or \ os.path.join(config_dir, "stbt", "control.conf")
def test_to_enum(): with temporary_config("""\ [global] bystrlc = name_1 bystruc = NAME_1 byvallc = value-1 byvaluc = VALUE-1 badstr = notakey byint = 5 byintname = NAME_5 badint = 7 """): assert get_config("global", "bystrlc", type_=MyEnum) == MyEnum.NAME_1 assert get_config("global", "bystruc", type_=MyEnum) == MyEnum.NAME_1 assert get_config("global", "byvallc", type_=MyEnum) == MyEnum.NAME_1 with pytest.raises(ConfigurationError) as excinfo: get_config("global", "byvaluc", type_=MyEnum) assert "Valid values are NAME_1, NAME_2" in str(excinfo.value) with pytest.raises(ConfigurationError): get_config("global", "badstr", type_=MyEnum) assert get_config("global", "notset", MyEnum.NAME_1, MyEnum) == \ MyEnum.NAME_1 assert get_config("global", "byint", type_=MyIntEnum) == \ MyIntEnum.NAME_5 assert get_config("global", "byintname", type_=MyIntEnum) == \ MyIntEnum.NAME_5 with pytest.raises(ConfigurationError) as excinfo: get_config("global", "badint", type_=MyIntEnum) assert "Valid values are NAME_5, NAME_6" in str(excinfo.value)
def test_unicode_in_STBT_CONFIG_FILE(): with temporary_config(test_config, prefix="\xf8"): assert get_config("global", "test") == "hello"
def make_video_server(): return _HTTPVideoServer( video_generator, video_format=get_config('camera', 'video_format'))
def new_device_under_test_from_config(parsed_args=None, transformation_pipeline=None): """ `parsed_args` if present should come from calling argparser().parse_args(). """ from _stbt.control import uri_to_control if parsed_args is None: args = argparser().parse_args([]) else: args = parsed_args if args.source_pipeline is None: args.source_pipeline = get_config('global', 'source_pipeline') if args.sink_pipeline is None: args.sink_pipeline = get_config('global', 'sink_pipeline') if args.control is None: args.control = get_config('global', 'control') if args.save_video is None: args.save_video = False if args.restart_source is None: args.restart_source = get_config('global', 'restart_source', type_=bool) if transformation_pipeline is None: transformation_pipeline = get_config('global', 'transformation_pipeline') source_teardown_eos = get_config('global', 'source_teardown_eos', type_=bool) use_old_threading_behaviour = get_config('global', 'use_old_threading_behaviour', type_=bool) if use_old_threading_behaviour: warn( dedent("""\ global.use_old_threading_behaviour is enabled. This is intended as a stop-gap measure to allow upgrading to stb-tester v28. We recommend porting functions that depend on stbt.get_frame() returning consecutive frames on each call to use stbt.frames() instead. This should make your functions usable from multiple threads. If porting to stbt.frames is not suitable please let us know on https://github.com/stb-tester/stb-tester/pull/449 otherwise this configuration option will be removed in a future release of stb-tester. """)) display = [None] def raise_in_user_thread(exception): display[0].tell_user_thread(exception) mainloop = _mainloop() if not args.sink_pipeline and not args.save_video: sink_pipeline = NoSinkPipeline() else: sink_pipeline = SinkPipeline( # pylint: disable=redefined-variable-type args.sink_pipeline, raise_in_user_thread, args.save_video) display[0] = Display(args.source_pipeline, sink_pipeline, args.restart_source, transformation_pipeline, source_teardown_eos) return DeviceUnderTest( display=display[0], control=uri_to_control(args.control, display[0]), sink_pipeline=sink_pipeline, mainloop=mainloop, use_old_threading_behaviour=use_old_threading_behaviour)
def test_that_set_config_creates_new_sections_if_required(): with set_config_test(): set_config("non_existent_section", "test", "goodbye") assert get_config("non_existent_section", "test") == "goodbye" _config_init(force=True) assert get_config("non_existent_section", "test") == "goodbye"
def make_video_server(): return _HTTPVideoServer(video_generator, video_format=get_config( 'camera', 'video_format'))