def test_no_devices(self, get_driver): cfg = Mock() driver = Mock() driver.driver.match = Mock(return_value=False) usb_mock = Mock() plugin.usb.core.find = Mock(return_value=[usb_mock]) get_driver.return_value = driver plugin.get_driver = get_driver with pytest.raises(DeviceException) as excinfo: plugin.get_devices(cfg)
def test_no_devices(self): device_a = Mock() device_a.plugin.match = Mock(return_value=True) device_b = Mock() device_b.plugin.match = Mock(return_value=False) plugin.usb.core.find = Mock(return_value=[]) dm = Mock() dm.map = lambda x, y: [x(z, y) for z in [device_a, device_b]] plugin.get_devicemanager = Mock(return_value=dm) plugin.get_devices()
def test_get_devices(self, get_driver): cfg = Mock() cfg.keys.return_value = ["driver"] driver = Mock() usb_mock = Mock() plugin.usb.core.find = Mock(return_value=[usb_mock]) get_driver.return_value = driver plugin.get_driver = get_driver plugin.get_devices(cfg) assert call(cfg["device"], usb_mock) in driver.driver.call_args_list assert driver.driver.match.call_args_list == [call(usb_mock)]
def _set_device_target_page(config, target_page): """ Display dialog for setting the target page on a device. :param config: Currently active global configuration :type config: :py:class:`spreads.config.Configuration` :param target_page: Target page to set on the device :type target_page: One of 'odd' or 'even' """ print("Please connect and turn on the device labeled \'{0}\'".format( target_page)) print("Press any key when ready.") getch() devs = plugin.get_devices(config, force_reload=True) if len(devs) > 1: raise DeviceException("Please ensure that only one device is" " turned on!") if not devs: raise DeviceException("No device found!") devs[0].set_target_page(target_page) print( colorize("Configured \'{0}\' device.".format(target_page), colorama.Fore.GREEN)) print("Please turn off the device.") print("Press any key when ready.") getch()
def wizard(args, devices=None): # TODO: Think about how we can make this more dynamic, i.e. get list of # options for plugin with a description for each entry path = args.path if not devices: devices = get_devices() if any(not x.orientation for x in devices): print(colorama.Fore.YELLOW + "Devices not yet configured!") print(colorama.Fore.BLUE + "Please turn both devices off." " Press any key when ready.") while True: try: configure() break except DeviceException as e: print(e) print(colorama.Fore.GREEN + "==========================\n", "Starting capturing process\n", "==========================") capture(devices=devices) print(colorama.Fore.GREEN + "=========================\n", "Starting download process\n" "=========================") download(path=path) print(colorama.Fore.GREEN + "=======================\n" "Starting postprocessing\n" "=======================") postprocess(path=path) print(colorama.Fore.GREEN + "=================\n", "Generating output\n" "=================") output(path=path)
def set_orientation(self, target): """ Set target page on a device. Prompts the user to connect a device, prompts to retry or cancel on failure. If successful, updates the target page setting on the device. :param target: Target page to set on device :type target: unicode, one of "odd" or "even" """ rv = messagebox.askokcancel( message=("Please connect and turn on the camera for {0} pages". format(target)), title="Configure target page") if not rv: return devs = [] while True: try: devs = plugin.get_devices(self.spreads_config, force_reload=True) except plugin.DeviceException: devs = [] if not devs: errmsg = "No devices could be found." elif len(devs) > 1: errmsg = "Make sure only one device is turned on!" else: break rv = messagebox.askretrycancel(message=errmsg, title="Error") if not rv: return devs[0].set_target_page(target) messagebox.showinfo(message="Please turn off the device.")
def configure_focus(self): """ Acquire auto-focus value from devices and update the configuration with it. Prompts the user to connect a device, asks for cancel/retry on failure. On successful connection, acquires focus and writes the value to the configuration. """ # TODO: Handle independent focus for both devices rv = messagebox.askokcancel( message="Please connect and turn on one of your cameras.", title="Configure focus") if not rv: return while True: try: devs = plugin.get_devices(self.spreads_config, force_reload=True) focus = devs[0]._acquire_focus() self.spreads_config['device']['focus_distance'] = focus break except plugin.DeviceException: rv = messagebox.askretrycancel( message="No devices could be found.") if not rv: break else: continue
def configure_focus(self): """ Acquire auto-focus value from devices and update the configuration with it. Prompts the user to connect a device, asks for cancel/retry on failure. On successful connection, acquires focus and writes the value to the configuration. """ # TODO: Handle independent focus for both devices rv = messagebox.askokcancel( message="Please connect and turn on one of your cameras.", title="Configure focus") if not rv: return while True: try: devs = plugin.get_devices(self.spreads_config, force_reload=True) focus = devs[0]._acquire_focus() self.spreads_config['device']['focus_distance'] = focus break except plugin.DeviceException: rv = messagebox.askretrycancel( message="No devices could be found." ) if not rv: break else: continue
def set_orientation(self, target): """ Set target page on a device. Prompts the user to connect a device, prompts to retry or cancel on failure. If successful, updates the target page setting on the device. :param target: Target page to set on device :type target: unicode, one of "odd" or "even" """ rv = messagebox.askokcancel( message=("Please connect and turn on the camera for {0} pages" .format(target)), title="Configure target page") if not rv: return devs = [] while True: try: devs = plugin.get_devices(self.spreads_config, force_reload=True) except plugin.DeviceException: devs = [] if not devs: errmsg = "No devices could be found." elif len(devs) > 1: errmsg = "Make sure only one device is turned on!" else: break rv = messagebox.askretrycancel(message=errmsg, title="Error") if not rv: return devs[0].set_target_page(target) messagebox.showinfo(message="Please turn off the device.")
def set_orientation(self, target): rv = messagebox.askokcancel( message=("Please connect and turn on the camera for {0} pages" .format(target)), title="Configure target page") if not rv: return devs = [] while True: try: devs = plugin.get_devices(self.spreads_config, force_reload=True) except plugin.DeviceException: devs = [] if not devs: errmsg = "No devices could be found." elif len(devs) > 1: errmsg = "Make sure only one device is turned on!" else: break rv = messagebox.askretrycancel(message=errmsg, title="Error") if not rv: return devs[0].set_target_page(target) messagebox.showinfo(message="Please turn off the device.")
def run_server(config): setup_app(config) setup_logging(config) # Initialize huey task queue global task_queue db_location = os.path.join(config.config_dir(), 'queue.db') task_queue = SqliteHuey(location=db_location) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() in ['chdkcamera', 'a2200']): # Display the address of the web interface on the camera displays try: for cam in get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:5000".format(ip_address)) except: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() try: import waitress # NOTE: We spin up this obscene number of threads since we have # some long-polling going on, which will always block # one worker thread. waitress.serve(app, port=5000, threads=16) finally: consumer.shutdown() if app.config['DEBUG']: logger.info("Waiting for remaining connections to close...")
def download(args=None, path=None, devices=None): if args and args.path: path = args.path if not devices: devices = get_devices() status_str = "Downloading {0} images from devices" if config['download']['keep'].get(bool) or config['keep'].get(bool): status_str = status_str.format("and deleting ") else: status_str = status_str.format("") print(colorama.Fore.GREEN + status_str) workflow.download(devices, path)
def devices(self): if self._devices is None: self._devices = plugin.get_devices(self.config, force_reload=True) if any(not dev.connected() for dev in self._devices): self._logger.warning( "At least one of the devices has been disconnected." "Please make sure it has been re-enabled before taking another" "action.") self._devices = None if not self._devices: raise DeviceException("Could not find any compatible devices!") return self._devices
def display_ip(self): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(self.global_config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}" .format(self._ip_address, self._listening_port)) self._display_callback.stop() except plugin.DeviceException: # Try again next time... return
def configure(config): old_plugins = config["plugins"].get() driver_name = _select_driver(config["driver"].get() if 'driver' in config.keys() else None) if driver_name: config["driver"] = driver_name driver = plugin.get_driver(config["driver"].get()) else: driver = None # Save driver config.dump(filename=config.cfg_path) config["plugins"] = _select_plugins(old_plugins) _setup_processing_pipeline(config) # Load default configuration for newly added plugins new_plugins = [x for x in config["plugins"].get() if x not in old_plugins] for name in new_plugins: if not name in config.templates: continue config.set_from_template(name, config.templates[name]) # Save plugins config.dump(filename=config.cfg_path) # We only need to set the device target_page if the driver supports # shooting with two devices if driver and plugin.DeviceFeatures.IS_CAMERA in driver.features: answer = raw_input( "Do you want to configure the target_page of your devices?\n" "(Required for shooting with two devices) [y/N]: ") answer = True if answer.lower() == 'y' else False if answer: print("Setting target page on cameras") for target_page in ('odd', 'even'): _set_device_target_page(config, target_page) answer = raw_input("Do you want to setup the focus for your cameras? " "[y/N]: ") answer = True if answer.lower() == 'y' else False if answer: print("Please turn on one of your capture devices.\n" "Press any key to continue") getch() devs = plugin.get_devices(config, force_reload=True) print("Please put a book with as little whitespace as possible" "under your cameras.\nPress any button to continue") getch() focus = devs[0]._acquire_focus() config['device']['focus_distance'] = focus print("Configuration file written to '{0}'".format(config.cfg_path)) config.dump(filename=config.cfg_path)
def display_ip(self): """ Display external IP address on device displays. """ # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(self.global_config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}" .format(self._ip_address, self._listening_port)) self._display_callback.stop() except plugin.DeviceException: # Try again next time... return
def devices(self): if 'driver' not in self.config.keys(): raise util.DeviceException( "No driver has been configured\n" "Please run `spread configure` to select a driver.") if self._devices is None: self._devices = plugin.get_devices(self.config, force_reload=True) if any(not dev.connected() for dev in self._devices): self._logger.warning( "At least one of the devices has been disconnected." "Please make sure it has been re-enabled before taking another" "action.") self._devices = None return self._devices
def devices(self): if 'driver' not in self.config.keys(): raise util.DeviceException( "No driver has been configured\n" "Please run `spread configure` to select a driver.") if self._devices is None: self._devices = plugin.get_devices(self.config, force_reload=True) if any(not dev.connected() for dev in self._devices): self._logger.warning( "At least one of the devices has been disconnected. " "Please make sure it has been re-enabled before taking " "another action.") self._devices = None return self._devices
def test_get_devices(self): device_a = Mock() device_a.plugin.match = Mock(return_value=True) device_a.plugin.__name__ = "Mock" device_b = Mock() device_b.plugin.match = Mock(return_value=False) device_b.plugin.__name__ = "Mock" usb_mock = Mock() plugin.usb.core.find = Mock(return_value=[usb_mock]) dm = Mock() dm.map = lambda x, y: [x(z, y) for z in [device_a, device_b]] plugin.get_devicemanager = Mock(return_value=dm) ret = plugin.get_devices() assert ret == [device_a.plugin()] assert call(spreads.config, usb_mock) in device_a.plugin.call_args_list assert device_a.plugin.match.call_args_list == [call(usb_mock)] assert device_b.plugin.match.call_args_list == [call(usb_mock)]
def _set_device_target_page(config, target_page): print("Please connect and turn on the device labeled \'{0}\'" .format(target_page)) print("Press any key when ready.") getch() devs = plugin.get_devices(config, force_reload=True) if len(devs) > 1: raise DeviceException("Please ensure that only one device is" " turned on!") if not devs: raise DeviceException("No device found!") devs[0].set_target_page(target_page) print(colorize("Configured \'{0}\' device.".format(target_page), colorama.Fore.GREEN)) print("Please turn off the device.") print("Press any key when ready.") getch()
def _set_device_target_page(config, target_page): print("Please connect and turn on the device labeled \'{0}\'".format( target_page)) print("Press any key when ready.") getch() devs = plugin.get_devices(config, force_reload=True) if len(devs) > 1: raise DeviceException("Please ensure that only one device is" " turned on!") if not devs: raise DeviceException("No device found!") devs[0].set_target_page(target_page) print( colorize("Configured \'{0}\' device.".format(target_page), colorama.Fore.GREEN)) print("Please turn off the device.") print("Press any key when ready.") getch()
def configure(args=None): for orientation in ('left', 'right'): print("Please connect and turn on the device labeled \'{0}\'".format( orientation)) print(colorama.Fore.BLUE + "Press any key when ready.") getch() devs = get_devices() if len(devs) > 1: raise DeviceException("Please ensure that only one device is" " turned on!") if not devs: raise DeviceException("No device found!") devs[0].set_orientation(orientation) print(colorama.Fore.GREEN + "Configured \'{0}\' device.".format(orientation)) print("Please turn off the device.") print(colorama.Fore.BLUE + "Press any key when ready.") getch()
def configure(args=None): for orientation in ('left', 'right'): print("Please connect and turn on the device labeled \'{0}\'" .format(orientation)) print(colorama.Fore.BLUE + "Press any key when ready.") getch() devs = get_devices() if len(devs) > 1: raise DeviceException("Please ensure that only one device is" " turned on!") if not devs: raise DeviceException("No device found!") devs[0].set_orientation(orientation) print(colorama.Fore.GREEN + "Configured \'{0}\' device." .format(orientation)) print("Please turn off the device.") print(colorama.Fore.BLUE + "Press any key when ready.") getch()
def configure_focus(self): rv = messagebox.askokcancel( message="Please connect and turn on one of your cameras.", title="Configure focus") if not rv: return while True: try: devs = plugin.get_devices(self.spreads_config, force_reload=True) focus = devs[0]._acquire_focus() self.spreads_config['device']['focus_distance'] = focus except plugin.DeviceException: rv = messagebox.askretrycancel( message="No devices could be found." ) if not rv: break else: continue
def configure(config): config["driver"] = _select_driver() config["plugins"] = _select_plugins(config["plugins"].get()) # Set default plugin configuration plugin.set_default_config(config) _setup_processing_pipeline(config) cfg_path = os.path.join(config.config_dir(), confit.CONFIG_FILENAME) driver = plugin.get_driver(config["driver"].get()).driver # We only need to set the device target_page if the driver supports # shooting with two devices if plugin.DeviceFeatures.IS_CAMERA in driver.features: answer = raw_input( "Do you want to configure the target_page of your devices?\n" "(Required for shooting with two devices) [y/n]: ") answer = True if answer.lower() == 'y' else False if answer: print("Setting target page on cameras") for target_page in ('odd', 'even'): _set_device_target_page(config, target_page) answer = raw_input("Do you want to setup the focus for your cameras? " "[y/n]: ") answer = True if answer.lower() == 'y' else False if answer: print("Please turn on one of your capture devices.\n" "Press any key to continue") getch() devs = plugin.get_devices(config, force_reload=True) print("Please put a book with as little whitespace as possible" "under your cameras.\nPress any button to continue") getch() focus = devs[0]._acquire_focus() config['device']['focus_distance'] = focus print("Writing configuration file to '{0}'".format(cfg_path)) config.dump(filename=cfg_path)
def run_server(config): listening_port = config['web']['port'].get(int) ws_server = WebSocketServer(port=listening_port + 1) setup_app(config) setup_logging(config) setup_task_queue(config) setup_signals(ws_server) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() == 'chdkcamera'): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}".format( ip_address, listening_port)) except plugin.DeviceException: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() # Start websocket server ws_server.start() if app.config['mode'] in ('processor', 'full'): discovery_listener = DiscoveryListener(listening_port) discovery_listener.start() try: import waitress waitress.serve(app, port=listening_port) finally: consumer.shutdown() ws_server.stop() if app.config['mode'] in ('processor', 'full'): discovery_listener.stop()
def run_server(config): listening_port = config['web']['port'].get(int) ws_server = WebSocketServer(port=listening_port+1) setup_app(config) setup_logging(config) setup_task_queue(config) setup_signals(ws_server) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() == 'chdkcamera'): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:{1}" .format(ip_address, listening_port)) except plugin.DeviceException: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() # Start websocket server ws_server.start() if app.config['mode'] in ('processor', 'full'): discovery_listener = DiscoveryListener(listening_port) discovery_listener.start() try: import waitress waitress.serve(app, port=listening_port) finally: consumer.shutdown() ws_server.stop() if app.config['mode'] in ('processor', 'full'): discovery_listener.stop()
def run_server(config): ws_server = WebSocketServer(port=5001) setup_app(config) setup_logging(config) setup_signals(ws_server) # Initialize huey task queue global task_queue db_location = config.cfg_path.parent / 'queue.db' task_queue = SqliteHuey(location=unicode(db_location)) consumer = Consumer(task_queue) ip_address = get_ip_address() if (app.config['standalone'] and ip_address and config['driver'].get() == 'chdkcamera'): # Display the address of the web interface on the camera displays try: for cam in plugin.get_devices(config): cam.show_textbox( "\n You can now access the web interface at:" "\n\n\n http://{0}:5000".format(ip_address)) except plugin.DeviceException: logger.warn("No devices could be found at startup.") # Start task consumer consumer.start() # Start websocket server ws_server.start() try: import waitress # NOTE: We spin up this obscene number of threads since we have # some long-polling going on, which will always block # one worker thread. waitress.serve(app, port=5000, threads=16) finally: consumer.shutdown() ws_server.stop()
def capture(args=None, devices=None): if not devices: devices = get_devices() if len(devices) != 2: raise DeviceException("Please connect and turn on two" " pre-configured devices! ({0} were" " found)".format(len(devices))) print(colorama.Fore.GREEN + "Found {0} devices!".format(len(devices))) if any(not x.orientation for x in devices): raise DeviceException("At least one of the devices has not been" " properly configured, please re-run the" " program with the \'configure\' option!") # Set up for capturing print("Setting up devices for capturing.") workflow.prepare_capture(devices) # Start capture loop print(colorama.Fore.BLUE + "Press 'b' to capture.") shot_count = 0 start_time = time.time() pages_per_hour = 0 capture_keys = config['capture']['capture_keys'].as_str_seq() while True: if not getch().lower() in capture_keys: break workflow.capture(devices) shot_count += len(devices) pages_per_hour = (3600/(time.time() - start_time))*shot_count status = ("\rShot {0} pages [{1:.0f}/h]" .format(colorama.Fore.GREEN + unicode(shot_count), pages_per_hour)) sys.stdout.write(status) sys.stdout.flush() workflow.finish_capture(devices) sys.stdout.write("\rShot {0} pages in {1:.1f} minutes, average speed was" " {2:.0f} pages per hour" .format(colorama.Fore.GREEN + str(shot_count), (time.time() - start_time)/60, pages_per_hour)) sys.stdout.flush()
def _set_device_target_page(config, target_page): """ Display dialog for setting the target page on a device. :param config: Currently active global configuration :type config: :py:class:`spreads.config.Configuration` :param target_page: Target page to set on the device :type target_page: One of 'odd' or 'even' """ print("Please connect and turn on the device labeled \'{0}\'" .format(target_page)) print("Press any key when ready.") getch() devs = plugin.get_devices(config, force_reload=True) if len(devs) > 1: raise DeviceException("Please ensure that only one device is" " turned on!") if not devs: raise DeviceException("No device found!") devs[0].set_target_page(target_page) print(colorize("Configured \'{0}\' device.".format(target_page), colorama.Fore.GREEN)) print("Please turn off the device.") print("Press any key when ready.") getch()
def wizard(args): logger.debug("Starting GUI") app = QtGui.QApplication([]) wizard = gui.SpreadsWizard(spreads.config, get_devices()) wizard.show() app.exec_()
def test_get_devices(config): devices = plugin.get_devices(config) assert len(devices) == 2 assert devices[0].__name__ == 'testdriver' assert devices[0]._id != devices[1]._id
def configure(config): """ Configuration subcommand that runs through the various dialogs, builds a new configuration and writes it to disk. :param config: Currently active global configuration :type config: :py:class:`spreads.config.Configuration` """ old_plugins = config["plugins"].get() driver_name = _select_driver( config["driver"].get() if 'driver' in config.keys() else None) if driver_name: config["driver"] = driver_name driver = plugin.get_driver(config["driver"].get()) else: driver = None # Save driver config.dump(filename=config.cfg_path) config["plugins"] = _select_plugins(old_plugins) _setup_processing_pipeline(config) # Load default configuration for newly added plugins new_plugins = [x for x in config["plugins"].get() if x not in old_plugins] for name in new_plugins: if name not in config.templates: continue config.set_from_template(name, config.templates[name]) # Save plugins config.dump(filename=config.cfg_path) # We only need to set the device target_page if the driver supports # shooting with two devices if driver and plugin.DeviceFeatures.IS_CAMERA in driver.features: answer = raw_input( "Do you want to configure the target_page of your devices?\n" "(Required for shooting with two devices) [y/N]: ") answer = True if answer.lower() == 'y' else False if answer: print("Setting target page on cameras") for target_page in ('odd', 'even'): _set_device_target_page(config, target_page) answer = raw_input("Do you want to setup the focus for your cameras? " "[y/N]: ") answer = True if answer.lower() == 'y' else False if answer: # TODO: Set focus for both devices independently print("Please turn on one of your capture devices.\n" "Press any key to continue") getch() devs = plugin.get_devices(config, force_reload=True) print("Please put a book with as little whitespace as possible " "under your cameras.\nPress any button to continue") getch() focus = devs[0]._acquire_focus() config['device']['focus_mode'] = 'manual' config['device']['focus_distance'] = focus else: config['device']['focus_mode'] = 'autofocus_all' print("Configuration file written to '{0}'".format(config.cfg_path)) config.dump(filename=config.cfg_path)
def devices(self): if self._devices is None: self._devices = get_devices(self.config) if not self._devices: raise DeviceException("Could not find any compatible devices!") return self._devices
def _add_device_arguments(name, parser): try: for dev in get_devices(): dev.add_arguments(name, parser) except: return
def test_get_devices(config, mock_driver_mgr): devices = plugin.get_devices(config) assert len(devices) == 2 assert devices[0].__name__ == 'testdriver' assert devices[0]._id != devices[1]._id
def test_get_devices(config): devices = plugin.get_devices(config) assert len(devices) == 2 assert devices[0].__name__ == "testdriver" assert devices[0]._id != devices[1]._id
def configure(config): """ Configuration subcommand that runs through the various dialogs, builds a new configuration and writes it to disk. :param config: Currently active global configuration :type config: :py:class:`spreads.config.Configuration` """ old_plugins = config["plugins"].get() driver_name = _select_driver(config["driver"].get() if 'driver' in config.keys() else None) if driver_name: config["driver"] = driver_name driver = plugin.get_driver(config["driver"].get()) else: driver = None # Save driver config.dump(filename=config.cfg_path) config["plugins"] = _select_plugins(old_plugins) _setup_processing_pipeline(config) # Load default configuration for newly added plugins new_plugins = [x for x in config["plugins"].get() if x not in old_plugins] for name in new_plugins: if name not in config.templates: continue config.set_from_template(name, config.templates[name]) # Save plugins config.dump(filename=config.cfg_path) # We only need to set the device target_page if the driver supports # shooting with two devices if driver and plugin.DeviceFeatures.IS_CAMERA in driver.features: answer = raw_input( "Do you want to configure the target_page of your devices?\n" "(Required for shooting with two devices) [y/N]: ") answer = True if answer.lower() == 'y' else False if answer: print("Setting target page on cameras") for target_page in ('odd', 'even'): _set_device_target_page(config, target_page) answer = raw_input("Do you want to setup the focus for your cameras? " "[y/N]: ") answer = True if answer.lower() == 'y' else False if answer: # TODO: Set focus for both devices independently print("Please turn on one of your capture devices.\n" "Press any key to continue") getch() devs = plugin.get_devices(config, force_reload=True) print("Please put a book with as little whitespace as possible " "under your cameras.\nPress any button to continue") getch() focus = devs[0]._acquire_focus() config['device']['focus_mode'] = 'manual' config['device']['focus_distance'] = focus else: config['device']['focus_mode'] = 'autofocus_all' print("Configuration file written to '{0}'".format(config.cfg_path)) config.dump(filename=config.cfg_path)