def test_later(self): from worker import current, later, sleep a = 0 b = None def add(value): nonlocal a nonlocal b b = current() a += value current().later(add, 10, timeout=2) with self.subTest("not yet"): sleep(1) self.assertEqual(a, 0) self.assertEqual(b, None) with self.subTest("finished"): sleep(2) self.assertEqual(a, 10) self.assertEqual(b, current()) later(add, 10, timeout=2) with self.subTest("not yet"): sleep(1) self.assertEqual(a, 10) with self.subTest("finished"): sleep(2) self.assertEqual(a, 20) self.assertEqual(b, current())
def __init__(self): """Construct.""" self.thread = current() self.cid_view = {} self.cid_library = {} self.pre_url = None self.create_view() self.bindevent() self.register_listeners() printer.add_listener(self.sp_callback) if (setting.getboolean("libraryautocheck") and time() - setting.getfloat("lastcheckupdate", 0) > 24 * 60 * 60): download_manager.start_check_update() self.tv_refresh("view") self.tv_refresh("library") self.save() self.update() self.root.mainloop()
def __init__(self): """Construct.""" self.create_view() self.bind_event() self.thread = worker.current() self.loop = TkinterLoop(self.root, worker.update) self.pool_index = { id(mission_manager.view): self.view_table, id(mission_manager.library): self.library_table } self.register_listeners() printer.add_listener(self.sp_callback) if (setting.getboolean("libraryautocheck") and time() - setting.getfloat("lastcheckupdate", 0) > setting.getfloat("autocheck_interval") * 60 * 60): download_manager.start_check_update() self.update_table(mission_manager.view) self.update_table(mission_manager.library) self.save() self.loop.start()
def test_daemon(self): from worker import current, Worker with self.subTest("main thread is not deamon"): self.assertFalse(current().is_daemon()) with self.subTest("thread is not daemon by default"): thread = Worker().start() self.assertFalse(thread.is_daemon()) thread.stop().join() with self.subTest("should inherit parent if not set"): a = Worker(daemon=True).start() self.assertTrue(a.is_daemon()) b = Worker(parent=a).start() self.assertTrue(b.is_daemon()) a.stop().join() with self.subTest("parent will wait non-daemon child thread"): a = Worker().start() b = Worker(parent=a).start() a.stop().join() self.assertFalse(b.is_running()) with self.subTest("parent won't wait daemon child thread"): def blocker(): time.sleep(1) a = Worker().start() b = Worker(blocker, parent=a, daemon=True).start() a.stop().join() self.assertTrue(b.is_running()) b.join()
def __init__(self): """Construct.""" self.download_thread = None self.analyze_threads = ThreadSafeSet() self.library_thread = None self.library_err_count = None self.batch_analyzer = None thread = current() download_ch.sub(thread) @thread.listen("DOWNLOAD_ERROR") def _(event): _err, mission = event.data mission_manager.drop("view", mission) @thread.listen("DOWNLOAD_FINISHED") def _(event): """After download, execute command.""" if event.target is not self.download_thread: return cmd = event.data.module.config.get("runafterdownload") default_cmd = setting.get("runafterdownload") commands = [] if cmd: commands.append(cmd) if default_cmd and default_cmd not in commands: commands.append(default_cmd) for command in commands: command += " " + quote(path_join( profile(event.data.module.config["savepath"]), safefilepath(event.data.title) )) try: await_(subprocess.call, command, shell=True) # nosec except (OSError, subprocess.SubprocessError): traceback.print_exc() @thread.listen("DOWNLOAD_FINISHED") @thread.listen("DOWNLOAD_ERROR") def _(event): """After download, continue next mission""" if event.target is self.download_thread: self.download_thread = None self.start_download() @thread.listen("DOWNLOAD_INVALID") def _(event): """Something bad happened""" if event.target is self.download_thread: self.download_thread = None print("停止下載")
def __init__(self): """Construct.""" self.download_thread = None self.analyze_threads = ThreadSafeSet() self.library_thread = None self.library_err_count = None self.batch_analyzer = None thread = current() download_ch.sub(thread) @thread.listen("DOWNLOAD_ERROR") def _(event): _err, mission = event.data mission_manager.drop("view", mission) @thread.listen("DOWNLOAD_FINISHED") def _(event): """After download, execute command.""" if event.target is not self.download_thread: return cmd = event.data.module.config.get("runafterdownload") default_cmd = setting.get("runafterdownload") commands = [] if cmd: commands.append(cmd) if default_cmd and default_cmd not in commands: commands.append(default_cmd) for command in commands: command += " " + quote( path_join(profile(event.data.module.config["savepath"]), safefilepath(event.data.title))) try: await_(subprocess.call, command, shell=True) # nosec except (OSError, subprocess.SubprocessError): traceback.print_exc() @thread.listen("DOWNLOAD_FINISHED") @thread.listen("DOWNLOAD_ERROR") def _(event): """After download, continue next mission""" if event.target is self.download_thread: self.download_thread = None self.start_download() @thread.listen("DOWNLOAD_INVALID") def _(event): """Something bad happened""" if event.target is self.download_thread: self.download_thread = None print("停止下載")
def __init__(self): """Construct.""" self.pool = {} self.view = OrderedDict() self.library = OrderedDict() self.edit = False self.lock = Lock() self.load() thread = current() mission_ch.sub(thread) @thread.listen("MISSION_PROPERTY_CHANGED") def _(event): """Set the edit flag after mission changed.""" self.edit = True
def __init__(self): """Construct.""" self.download_thread = None self.analyze_threads = ThreadSafeSet() self.library_thread = None self.library_err_count = None self.batch_analyzer = None self.continued_failure = 0 thread = current() download_ch.sub(thread) @thread.listen("DOWNLOAD_ERROR") def _(event): _err, mission = event.data mission_manager.drop("view", mission) self.continued_failure += 1 @thread.listen("DOWNLOAD_FINISHED") def _(event): """After download, execute command.""" self.continued_failure = 0 if event.target is not self.download_thread: return cmd = event.data.module.config.get("runafterdownload") default_cmd = setting.get("runafterdownload") commands = [] if cmd: commands.append(cmd) if default_cmd and default_cmd not in commands: commands.append(default_cmd) def run_command(): for command in commands: target = quote( path_join( profile(event.data.module.config["savepath"]), safefilepath(event.data.title))) if "{target}" in command: command = command.format(target=target) else: command += " " + target print(f"run command: {command}") try: await_(subprocess.call, command, shell=True) # nosec except (OSError, subprocess.SubprocessError): traceback.print_exc() async_(run_command) @thread.listen("DOWNLOAD_FINISHED") @thread.listen("DOWNLOAD_ERROR") def _(event): """After download, continue next mission""" if event.target is not self.download_thread: return self.download_thread = None if self.continued_failure >= len( mission_manager.get_all("view", lambda m: m.state != "FINISHED")): print(f"連續失敗 {self.continued_failure} 次,停止下載") return self.start_download(continued=True) @thread.listen("DOWNLOAD_INVALID") def _(event): """Something bad happened""" if event.target is self.download_thread: self.download_thread = None print("停止下載")
def __init__(self): """Construct.""" self.download_thread = None self.analyze_threads = set() self.library_thread = None self.library_err_count = None self.batch_analyzer = None thread = current() download_ch.sub(thread) @thread.listen("DOWNLOAD_PAUSE") @thread.listen("DOWNLOAD_INVALID") @thread.listen("DOWNLOAD_ERROR") @thread.listen("DOWNLOAD_FINISHED") def _(event): try: _err, mission = event.data except TypeError: mission = event.data if mission.url in mission_manager.pool: uninit_episode(mission) @thread.listen("DOWNLOAD_ERROR") def _(event): _err, mission = event.data mission_manager.drop("view", mission) @thread.listen("DOWNLOAD_FINISHED") def _(event): """After download, execute command.""" if event.target is not self.download_thread: return cmd = event.data.module.config.get("runafterdownload") default_cmd = setting.get("runafterdownload") commands = [] if cmd: commands.append(cmd) if default_cmd and default_cmd not in commands: commands.append(default_cmd) for command in commands: command += " " + quote( path_join(profile(event.data.module.config["savepath"]), safefilepath(event.data.title))) try: await_(subprocess.call, command, shell=True) # nosec except (OSError, subprocess.SubprocessError): traceback.print_exc() @thread.listen("DOWNLOAD_FINISHED") @thread.listen("DOWNLOAD_ERROR") def _(event): """After download, continue next mission""" if event.target is self.download_thread: self.download_thread = None self.start_download() @thread.listen("DOWNLOAD_INVALID") def _(event): """Something bad happened""" if event.target is self.download_thread: self.download_thread = None print("停止下載") @thread.listen("ANALYZE_FAILED") @thread.listen("ANALYZE_FINISHED") def _(event): """After analyze, continue next (library)""" try: _err, mission = event.data except TypeError: mission = event.data if event.target is self.library_thread: uninit_episode(mission) if mission.state == "UPDATE": mission_manager.lift("library", mission) if mission.state == "ERROR": if self.library_err_count > 10: print("Too many error!") download_ch.pub("LIBRARY_CHECK_UPDATE_FAILED") else: self.library_err_count += 1 mission_manager.drop("library", mission) later(self.do_check_update, 5, target=thread) return self.do_check_update() @thread.listen("ANALYZE_INVALID") def _(event): """Cleanup library thread with PauseDownloadError""" _err, mission = event.data if event.target is self.library_thread: uninit_episode(mission) self.library_thread = None print("Failed to check update") @thread.listen("ANALYZE_FINISHED") def _(event): """After analyze, add to view (view analyzer)""" if event.target in self.analyze_threads: mission = event.data uninit_episode(mission) mission_manager.add("view", mission) download_ch.pub("ANALYZE_NEW_MISSION", mission) @thread.listen("ANALYZE_FINISHED") @thread.listen("ANALYZE_FAILED") def _(event): if event.target in self.analyze_threads: self.analyze_threads.remove(event.target) @thread.listen("BATCH_ANALYZE_END") def _(event): self.batch_analyzer = None @thread.listen("BATCH_ANALYZE_ITEM_FINISHED") def _(event): _analyzer, mission = event.data mission_manager.add("view", mission)
def __init__(self): """Construct.""" self.download_thread = None self.analyze_threads = set() self.library_thread = None self.library_err_count = None thread = current() download_ch.sub(thread) @thread.listen("DOWNLOAD_PAUSE") @thread.listen("DOWNLOAD_INVALID") @thread.listen("DOWNLOAD_ERROR") @thread.listen("DOWNLOAD_FINISHED") def _(event): try: err, mission = event.data except Exception: mission = event.data if mission.url in mission_manager.pool: uninit_episode(mission) @thread.listen("DOWNLOAD_ERROR") def _(event): err, mission = event.data mission_manager.drop("view", mission) @thread.listen("DOWNLOAD_FINISHED") def _(event): """After download, execute command.""" if event.target is not self.download_thread: return r1 = event.data.module.config.get("runafterdownload") r2 = setting.get("runafterdownload") if r1 == r2 and r1: commands = [r1] elif r1: commands = [r1, r2] else: commands = [] for command in commands: command = command + " " + path_join( event.data.module.config["savepath"], safefilepath(event.data.title) ) try: subprocess.call(command) except Exception: print("Failed to run process: {}".format(command)) @thread.listen("DOWNLOAD_FINISHED") @thread.listen("DOWNLOAD_ERROR") def _(event): """After download, continue next mission""" if event.target is self.download_thread: self.download_thread = None self.start_download() @thread.listen("DOWNLOAD_INVALID") def _(event): """Something bad happened""" if event.target is self.download_thread: self.download_thread = None print("停止下載") @thread.listen("ANALYZE_FAILED") @thread.listen("ANALYZE_FINISHED") def _(event): """After analyze, continue next (library)""" try: err, mission = event.data except Exception: mission = event.data if event.target is self.library_thread: uninit_episode(mission) if mission.state == "UPDATE": mission_manager.lift("library", mission) if mission.state == "ERROR": if self.library_err_count > 10: print("Too many error!") download_ch.pub("LIBRARY_CHECK_UPDATE_FAILED") else: self.library_err_count += 1 mission_manager.drop("library", mission) later(self.do_check_update, 5) return self.do_check_update() @thread.listen("ANALYZE_INVALID") def _(event): """Cleanup library thread with PauseDownloadError""" err, mission = event.data if event.target is self.library_thread: uninit_episode(mission) self.library_thread = None print("Failed to check update") @thread.listen("ANALYZE_FINISHED") def _(event): """After analyze, add to view (view analyzer)""" if event.target in self.analyze_threads: mission = event.data uninit_episode(mission) mission_manager.add("view", mission) @thread.listen("ANALYZE_FINISHED") @thread.listen("ANALYZE_FAILED") def _(event): if event.target in self.analyze_threads: self.analyze_threads.remove(event.target)
def add(value): nonlocal a nonlocal b b = current() a += value