hydrus/test.py

631 lines
18 KiB
Python
Raw Normal View History

2015-11-25 22:00:57 +00:00
#!/usr/bin/env python2
2014-07-30 21:18:17 +00:00
import locale
try: locale.setlocale( locale.LC_ALL, '' )
except: pass
2013-07-10 20:25:57 +00:00
from include import HydrusConstants as HC
2014-04-23 20:56:12 +00:00
from include import ClientConstants as CC
2017-05-10 21:33:58 +00:00
from include import HydrusGlobals as HG
2015-03-18 21:46:29 +00:00
from include import ClientDefaults
2015-10-21 21:53:10 +00:00
from include import ClientNetworking
2018-04-18 22:10:15 +00:00
from include import ClientNetworkingBandwidth
2018-03-07 22:48:29 +00:00
from include import ClientNetworkingDomain
from include import ClientNetworkingLogin
2018-04-18 22:10:15 +00:00
from include import ClientNetworkingSessions
2017-03-02 02:14:56 +00:00
from include import ClientServices
2018-01-03 22:37:30 +00:00
from include import ClientThreading
from include import HydrusExceptions
2015-08-26 21:18:39 +00:00
from include import HydrusPubSub
2013-10-23 21:36:47 +00:00
from include import HydrusSessions
2013-07-24 20:26:00 +00:00
from include import HydrusTags
2015-08-26 21:18:39 +00:00
from include import HydrusThreading
2013-08-07 22:25:18 +00:00
from include import TestClientConstants
2013-07-31 21:26:38 +00:00
from include import TestClientDaemons
2017-09-27 21:52:54 +00:00
from include import TestClientData
2018-08-01 20:44:57 +00:00
from include import TestClientImageHandling
2018-06-27 19:27:05 +00:00
from include import TestClientImportOptions
2018-08-01 20:44:57 +00:00
from include import TestClientImportSubscriptions
2017-03-22 22:38:15 +00:00
from include import TestClientListBoxes
2017-06-28 20:23:21 +00:00
from include import TestClientNetworking
2013-07-10 20:25:57 +00:00
from include import TestConstants
2013-07-24 20:26:00 +00:00
from include import TestDialogs
2013-07-10 20:25:57 +00:00
from include import TestDB
from include import TestFunctions
2014-04-16 20:31:59 +00:00
from include import TestHydrusNATPunch
2017-06-21 21:15:59 +00:00
from include import TestHydrusNetworking
2017-03-08 23:23:12 +00:00
from include import TestHydrusSerialisable
2013-11-20 21:12:21 +00:00
from include import TestHydrusServer
2013-11-06 18:22:07 +00:00
from include import TestHydrusSessions
2013-07-17 20:56:13 +00:00
from include import TestHydrusTags
2013-07-31 21:26:38 +00:00
import collections
2013-07-24 20:26:00 +00:00
import os
2015-08-26 21:18:39 +00:00
import random
2015-12-02 22:32:18 +00:00
import shutil
2013-11-06 18:22:07 +00:00
import sys
2015-12-02 22:32:18 +00:00
import tempfile
2013-11-27 18:27:11 +00:00
import threading
2014-04-16 20:31:59 +00:00
import time
2013-07-10 20:25:57 +00:00
import unittest
2013-07-24 20:26:00 +00:00
import wx
2013-11-27 18:27:11 +00:00
from twisted.internet import reactor
2015-03-18 21:46:29 +00:00
from include import ClientCaches
from include import ClientData
2018-05-16 20:09:50 +00:00
from include import ClientOptions
2015-03-25 22:04:19 +00:00
from include import HydrusData
2016-08-17 20:07:22 +00:00
from include import HydrusPaths
2013-07-10 20:25:57 +00:00
2013-11-06 18:22:07 +00:00
only_run = None
2015-09-02 23:16:09 +00:00
class Controller( object ):
2013-07-24 20:26:00 +00:00
2015-09-02 23:16:09 +00:00
def __init__( self ):
2013-07-24 20:26:00 +00:00
2017-07-12 20:03:45 +00:00
self.db_dir = tempfile.mkdtemp()
2016-02-03 22:12:53 +00:00
2017-07-12 20:03:45 +00:00
TestConstants.DB_DIR = self.db_dir
2016-02-03 22:12:53 +00:00
2017-07-12 20:03:45 +00:00
self._server_files_dir = os.path.join( self.db_dir, 'server_files' )
self._updates_dir = os.path.join( self.db_dir, 'test_updates' )
2016-02-03 22:12:53 +00:00
2017-07-12 20:03:45 +00:00
client_files_default = os.path.join( self.db_dir, 'client_files' )
2016-06-01 20:04:15 +00:00
2017-01-25 22:56:55 +00:00
HydrusPaths.MakeSureDirectoryExists( self._server_files_dir )
HydrusPaths.MakeSureDirectoryExists( self._updates_dir )
2016-08-17 20:07:22 +00:00
HydrusPaths.MakeSureDirectoryExists( client_files_default )
2016-02-17 22:06:47 +00:00
2017-05-10 21:33:58 +00:00
HG.controller = self
HG.client_controller = self
HG.server_controller = self
HG.test_controller = self
2015-08-26 21:18:39 +00:00
2017-08-09 21:33:51 +00:00
self.gui = self
self._call_to_threads = []
2016-02-03 22:12:53 +00:00
self._pubsub = HydrusPubSub.HydrusPubSub( self )
2015-12-02 22:32:18 +00:00
2018-05-16 20:09:50 +00:00
self.new_options = ClientOptions.ClientOptions( self.db_dir )
2015-10-14 21:02:25 +00:00
2017-12-06 22:06:56 +00:00
HC.options = ClientDefaults.GetClientDefaultOptions()
self.options = HC.options
2014-03-26 21:23:10 +00:00
def show_text( text ): pass
2015-03-25 22:04:19 +00:00
HydrusData.ShowText = show_text
2014-03-26 21:23:10 +00:00
2013-07-24 20:26:00 +00:00
self._reads = {}
2014-07-16 20:50:18 +00:00
self._reads[ 'local_booru_share_keys' ] = []
2013-11-27 18:27:11 +00:00
self._reads[ 'messaging_sessions' ] = []
2014-03-12 22:08:23 +00:00
self._reads[ 'tag_censorship' ] = []
2015-03-18 21:46:29 +00:00
self._reads[ 'options' ] = ClientDefaults.GetClientDefaultOptions()
2017-08-16 21:58:06 +00:00
self._reads[ 'file_system_predicates' ] = []
self._reads[ 'media_results' ] = []
self.example_tag_repo_service_key = HydrusData.GenerateKey()
2014-08-13 22:18:12 +00:00
services = []
2016-12-21 22:30:54 +00:00
2017-03-02 02:14:56 +00:00
services.append( ClientServices.GenerateService( CC.LOCAL_BOORU_SERVICE_KEY, HC.LOCAL_BOORU, CC.LOCAL_BOORU_SERVICE_KEY ) )
services.append( ClientServices.GenerateService( CC.COMBINED_LOCAL_FILE_SERVICE_KEY, HC.COMBINED_LOCAL_FILE, CC.COMBINED_LOCAL_FILE_SERVICE_KEY ) )
services.append( ClientServices.GenerateService( CC.LOCAL_FILE_SERVICE_KEY, HC.LOCAL_FILE_DOMAIN, CC.LOCAL_FILE_SERVICE_KEY ) )
services.append( ClientServices.GenerateService( CC.TRASH_SERVICE_KEY, HC.LOCAL_FILE_TRASH_DOMAIN, CC.LOCAL_FILE_SERVICE_KEY ) )
services.append( ClientServices.GenerateService( CC.LOCAL_TAG_SERVICE_KEY, HC.LOCAL_TAG, CC.LOCAL_TAG_SERVICE_KEY ) )
2017-08-16 21:58:06 +00:00
services.append( ClientServices.GenerateService( self.example_tag_repo_service_key, HC.TAG_REPOSITORY, 'example tag repo' ) )
services.append( ClientServices.GenerateService( CC.COMBINED_TAG_SERVICE_KEY, HC.COMBINED_TAG, CC.COMBINED_TAG_SERVICE_KEY ) )
2017-04-26 21:58:12 +00:00
services.append( ClientServices.GenerateService( TestConstants.LOCAL_RATING_LIKE_SERVICE_KEY, HC.LOCAL_RATING_LIKE, 'example local rating like service' ) )
services.append( ClientServices.GenerateService( TestConstants.LOCAL_RATING_NUMERICAL_SERVICE_KEY, HC.LOCAL_RATING_NUMERICAL, 'example local rating numerical service' ) )
2016-12-21 22:30:54 +00:00
2014-08-13 22:18:12 +00:00
self._reads[ 'services' ] = services
2016-07-27 21:53:34 +00:00
client_files_locations = {}
for prefix in HydrusData.IterateHexPrefixes():
for c in ( 'f', 't', 'r' ):
client_files_locations[ c + prefix ] = client_files_default
2015-12-02 22:32:18 +00:00
self._reads[ 'client_files_locations' ] = client_files_locations
2013-11-27 18:27:11 +00:00
self._reads[ 'sessions' ] = []
2013-07-24 20:26:00 +00:00
self._reads[ 'tag_parents' ] = {}
self._reads[ 'tag_siblings' ] = {}
2017-12-20 22:55:48 +00:00
self._reads[ 'in_inbox' ] = False
2013-07-24 20:26:00 +00:00
2013-07-31 21:26:38 +00:00
self._writes = collections.defaultdict( list )
2013-11-27 18:27:11 +00:00
self._managers = {}
2013-07-24 20:26:00 +00:00
2017-06-28 20:23:21 +00:00
self.services_manager = ClientCaches.ServicesManager( self )
self.client_files_manager = ClientCaches.ClientFilesManager( self )
2014-08-13 22:18:12 +00:00
2018-04-25 22:07:52 +00:00
self.parsing_cache = ClientCaches.ParsingCache()
2018-04-18 22:10:15 +00:00
bandwidth_manager = ClientNetworkingBandwidth.NetworkBandwidthManager()
session_manager = ClientNetworkingSessions.NetworkSessionManager()
2018-03-07 22:48:29 +00:00
domain_manager = ClientNetworkingDomain.NetworkDomainManager()
login_manager = ClientNetworkingLogin.NetworkLoginManager()
self.network_engine = ClientNetworking.NetworkEngine( self, bandwidth_manager, session_manager, domain_manager, login_manager )
self.CallToThreadLongRunning( self.network_engine.MainLoop )
2015-11-25 22:00:57 +00:00
self._managers[ 'tag_censorship' ] = ClientCaches.TagCensorshipManager( self )
self._managers[ 'tag_siblings' ] = ClientCaches.TagSiblingsManager( self )
self._managers[ 'tag_parents' ] = ClientCaches.TagParentsManager( self )
self._managers[ 'undo' ] = ClientCaches.UndoManager( self )
2017-12-06 22:06:56 +00:00
self.server_session_manager = HydrusSessions.HydrusSessionManagerServer()
self.local_booru_manager = ClientCaches.LocalBooruCache( self )
2014-07-16 20:50:18 +00:00
2013-09-04 16:48:44 +00:00
self._cookies = {}
2018-02-28 22:30:36 +00:00
self._job_scheduler = HydrusThreading.JobScheduler( self )
self._job_scheduler.start()
2013-07-10 20:25:57 +00:00
2016-07-20 19:57:10 +00:00
def _GetCallToThread( self ):
for call_to_thread in self._call_to_threads:
if not call_to_thread.CurrentlyWorking():
return call_to_thread
if len( self._call_to_threads ) > 100:
raise Exception( 'Too many call to threads!' )
2018-02-14 21:47:18 +00:00
call_to_thread = HydrusThreading.THREADCallToThread( self, 'CallToThread' )
2016-07-20 19:57:10 +00:00
self._call_to_threads.append( call_to_thread )
call_to_thread.start()
return call_to_thread
2017-01-18 22:52:39 +00:00
def _SetupWx( self ):
self.locale = wx.Locale( wx.LANGUAGE_DEFAULT ) # Very important to init this here and keep it non garbage collected
CC.GlobalBMPs.STATICInitialise()
2017-11-15 22:35:49 +00:00
self.frame_icon = wx.Icon( os.path.join( HC.STATIC_DIR, 'hydrus_32_non-transparent.png' ), wx.BITMAP_TYPE_PNG )
2017-01-18 22:52:39 +00:00
2015-08-26 21:18:39 +00:00
def pub( self, topic, *args, **kwargs ):
pass
def pubimmediate( self, topic, *args, **kwargs ):
self._pubsub.pubimmediate( topic, *args, **kwargs )
def sub( self, object, method_name, topic ):
self._pubsub.sub( object, method_name, topic )
2018-05-23 21:05:06 +00:00
def AcquirePageKey( self ):
return HydrusData.GenerateKey()
2018-01-03 22:37:30 +00:00
def CallBlockingToWx( self, func, *args, **kwargs ):
def wx_code( job_key ):
try:
result = func( *args, **kwargs )
job_key.SetVariable( 'result', result )
except HydrusExceptions.PermissionException as e:
job_key.SetVariable( 'error', e )
except Exception as e:
job_key.SetVariable( 'error', e )
HydrusData.Print( 'CallBlockingToWx just caught this error:' )
HydrusData.DebugPrint( traceback.format_exc() )
finally:
job_key.Finish()
job_key = ClientThreading.JobKey()
job_key.Begin()
wx.CallAfter( wx_code, job_key )
while not job_key.IsDone():
if HG.model_shutdown:
raise HydrusExceptions.ShutdownException( 'Application is shutting down!' )
time.sleep( 0.05 )
if job_key.HasVariable( 'result' ):
# result can be None, for wx_code that has no return variable
result = job_key.GetIfHasVariable( 'result' )
return result
error = job_key.GetIfHasVariable( 'error' )
if error is not None:
raise error
raise HydrusExceptions.ShutdownException()
2015-08-26 21:18:39 +00:00
def CallToThread( self, callable, *args, **kwargs ):
2016-07-20 19:57:10 +00:00
call_to_thread = self._GetCallToThread()
2015-08-26 21:18:39 +00:00
call_to_thread.put( callable, *args, **kwargs )
2017-08-09 21:33:51 +00:00
CallToThreadLongRunning = CallToThread
2018-05-16 20:09:50 +00:00
def CallLater( self, initial_delay, func, *args, **kwargs ):
2018-02-21 21:59:37 +00:00
2018-02-28 22:30:36 +00:00
call = HydrusData.Call( func, *args, **kwargs )
2018-05-16 20:09:50 +00:00
job = HydrusThreading.SchedulableJob( self, self._job_scheduler, initial_delay, call )
2018-02-28 22:30:36 +00:00
self._job_scheduler.AddJob( job )
return job
2018-05-16 20:09:50 +00:00
def CallLaterWXSafe( self, window, initial_delay, func, *args, **kwargs ):
2018-02-28 22:30:36 +00:00
call = HydrusData.Call( func, *args, **kwargs )
2018-05-16 20:09:50 +00:00
job = ClientThreading.WXAwareJob( self, self._job_scheduler, window, initial_delay, call )
2018-02-28 22:30:36 +00:00
self._job_scheduler.AddJob( job )
return job
2018-05-16 20:09:50 +00:00
def CallRepeating( self, initial_delay, period, func, *args, **kwargs ):
2018-02-28 22:30:36 +00:00
call = HydrusData.Call( func, *args, **kwargs )
2018-05-16 20:09:50 +00:00
job = HydrusThreading.RepeatingJob( self, self._job_scheduler, initial_delay, period, call )
2018-02-28 22:30:36 +00:00
self._job_scheduler.AddJob( job )
return job
2018-05-16 20:09:50 +00:00
def CallRepeatingWXSafe( self, window, initial_delay, period, func, *args, **kwargs ):
2018-02-28 22:30:36 +00:00
call = HydrusData.Call( func, *args, **kwargs )
2018-05-16 20:09:50 +00:00
job = ClientThreading.WXAwareRepeatingJob( self, self._job_scheduler, window, initial_delay, period, call )
2018-02-28 22:30:36 +00:00
self._job_scheduler.AddJob( job )
return job
2018-02-21 21:59:37 +00:00
2017-08-16 21:58:06 +00:00
def DBCurrentlyDoingJob( self ):
return False
2016-10-12 21:52:50 +00:00
def GetFilesDir( self ):
return self._server_files_dir
2015-10-14 21:02:25 +00:00
def GetNewOptions( self ):
2017-11-08 22:07:12 +00:00
return self.new_options
2015-10-14 21:02:25 +00:00
2017-06-28 20:23:21 +00:00
def GetManager( self, manager_type ):
2015-07-01 22:02:07 +00:00
2017-06-28 20:23:21 +00:00
return self._managers[ manager_type ]
2015-07-01 22:02:07 +00:00
2013-07-31 21:26:38 +00:00
def GetWrite( self, name ):
write = self._writes[ name ]
del self._writes[ name ]
return write
2017-05-17 21:53:02 +00:00
def IsBooted( self ):
return True
2017-08-16 21:58:06 +00:00
def IsCurrentPage( self, page_key ):
return False
2016-08-31 19:55:14 +00:00
def IsFirstStart( self ):
return True
2017-08-09 21:33:51 +00:00
def IShouldRegularlyUpdate( self, window ):
return True
2018-07-04 20:48:28 +00:00
def JustWokeFromSleep( self ):
return False
2015-11-04 22:30:28 +00:00
def ModelIsShutdown( self ):
2017-05-10 21:33:58 +00:00
return HG.model_shutdown
2015-11-04 22:30:28 +00:00
2018-05-23 21:05:06 +00:00
def PageAlive( self, page_key ):
2017-08-16 21:58:06 +00:00
return False
def PageClosedButNotDestroyed( self, page_key ):
return False
2017-03-08 23:23:12 +00:00
def Read( self, name, *args, **kwargs ):
return self._reads[ name ]
2018-02-21 21:59:37 +00:00
def RegisterUIUpdateWindow( self, window ):
pass
2018-05-23 21:05:06 +00:00
def ReleasePageKey( self, page_key ):
pass
2017-06-21 21:15:59 +00:00
def ReportDataUsed( self, num_bytes ):
pass
def ReportRequestUsed( self ):
2017-03-08 23:23:12 +00:00
pass
2013-07-10 20:25:57 +00:00
2014-12-03 22:56:40 +00:00
def ResetIdleTimer( self ): pass
2015-09-02 23:16:09 +00:00
def Run( self ):
2017-01-18 22:52:39 +00:00
self._SetupWx()
2015-09-02 23:16:09 +00:00
suites = []
if only_run is None: run_all = True
else: run_all = False
2018-01-03 22:37:30 +00:00
# the gui stuff runs fine on its own but crashes in the full test if it is not early, wew
# something to do with the delayed button clicking stuff
if run_all or only_run == 'gui':
suites.append( unittest.TestLoader().loadTestsFromModule( TestDialogs ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientListBoxes ) )
2017-09-06 20:18:20 +00:00
if run_all or only_run == 'daemons':
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientDaemons ) )
2017-03-22 22:38:15 +00:00
if run_all or only_run == 'data':
2017-09-06 20:18:20 +00:00
2017-03-22 22:38:15 +00:00
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientConstants ) )
2017-09-27 21:52:54 +00:00
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientData ) )
2018-06-27 19:27:05 +00:00
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientImportOptions ) )
2017-03-22 22:38:15 +00:00
suites.append( unittest.TestLoader().loadTestsFromModule( TestFunctions ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusSerialisable ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusSessions ) )
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusTags ) )
2017-09-06 20:18:20 +00:00
if run_all or only_run == 'db':
suites.append( unittest.TestLoader().loadTestsFromModule( TestDB ) )
2017-06-28 20:23:21 +00:00
if run_all or only_run == 'networking':
2017-09-06 20:18:20 +00:00
2017-06-28 20:23:21 +00:00
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientNetworking ) )
2017-06-21 21:15:59 +00:00
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusNetworking ) )
2017-09-06 20:18:20 +00:00
2018-08-01 20:44:57 +00:00
if run_all or only_run == 'import':
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientImportSubscriptions ) )
2017-09-06 20:18:20 +00:00
if run_all or only_run == 'image':
suites.append( unittest.TestLoader().loadTestsFromModule( TestClientImageHandling ) )
if run_all or only_run == 'nat':
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusNATPunch ) )
if run_all or only_run == 'server':
suites.append( unittest.TestLoader().loadTestsFromModule( TestHydrusServer ) )
2015-09-02 23:16:09 +00:00
suite = unittest.TestSuite( suites )
2018-01-03 22:37:30 +00:00
runner = unittest.TextTestRunner( verbosity = 2 )
2015-09-02 23:16:09 +00:00
runner.run( suite )
2017-08-16 21:58:06 +00:00
def SetRead( self, name, value ):
self._reads[ name ] = value
2013-07-10 20:25:57 +00:00
2018-01-03 22:37:30 +00:00
def SetStatusBarDirty( self ):
pass
2017-08-16 21:58:06 +00:00
def SetWebCookies( self, name, value ):
self._cookies[ name ] = value
2015-12-02 22:32:18 +00:00
def TidyUp( self ):
2017-01-25 22:56:55 +00:00
time.sleep( 2 )
2017-07-12 20:03:45 +00:00
HydrusPaths.DeletePath( self.db_dir )
2015-12-02 22:32:18 +00:00
2015-11-04 22:30:28 +00:00
def ViewIsShutdown( self ):
2017-05-10 21:33:58 +00:00
return HG.view_shutdown
2015-11-04 22:30:28 +00:00
2017-10-04 17:51:58 +00:00
def WaitUntilModelFree( self ):
2017-08-16 21:58:06 +00:00
2017-10-04 17:51:58 +00:00
return
def WaitUntilViewFree( self ):
return
2017-08-16 21:58:06 +00:00
2013-07-31 21:26:38 +00:00
def Write( self, name, *args, **kwargs ):
self._writes[ name ].append( ( args, kwargs ) )
2013-08-14 20:21:49 +00:00
def WriteSynchronous( self, name, *args, **kwargs ):
2013-07-31 21:26:38 +00:00
self._writes[ name ].append( ( args, kwargs ) )
if name == 'import_file':
2013-08-07 22:25:18 +00:00
2017-07-19 21:21:41 +00:00
( file_import_job, ) = args
2013-08-07 22:25:18 +00:00
2017-07-19 21:21:41 +00:00
if file_import_job.GetHash().encode( 'hex' ) == 'a593942cb7ea9ffcd8ccf2f0fa23c338e23bfecd9a3e508dfc0bcf07501ead08': # 'blarg' in sha256 hex
raise Exception( 'File failed to import for some reason!' )
else:
2018-05-09 20:23:00 +00:00
return ( CC.STATUS_SUCCESSFUL_AND_NEW, '' )
2017-07-19 21:21:41 +00:00
2015-09-09 22:04:39 +00:00
2013-07-31 21:26:38 +00:00
2013-07-24 20:26:00 +00:00
if __name__ == '__main__':
2013-07-10 20:25:57 +00:00
2013-11-06 18:22:07 +00:00
args = sys.argv[1:]
if len( args ) > 0:
only_run = args[0]
else: only_run = None
2015-08-26 21:18:39 +00:00
try:
threading.Thread( target = reactor.run, kwargs = { 'installSignalHandlers' : 0 } ).start()
2015-09-02 23:16:09 +00:00
app = wx.App()
2016-06-08 20:27:22 +00:00
controller = Controller()
2015-09-02 23:16:09 +00:00
2016-06-08 20:27:22 +00:00
try:
2018-01-03 22:37:30 +00:00
# we run the tests on the wx thread atm
# keep a window alive the whole time so the app doesn't finish its mainloop
2016-06-08 20:27:22 +00:00
win = wx.Frame( None )
2017-03-22 22:38:15 +00:00
def do_it():
controller.Run()
2018-05-16 20:09:50 +00:00
win.DestroyLater()
2017-03-22 22:38:15 +00:00
2016-06-08 20:27:22 +00:00
2017-03-22 22:38:15 +00:00
wx.CallAfter( do_it )
2018-01-03 22:37:30 +00:00
2016-06-08 20:27:22 +00:00
app.MainLoop()
except:
import traceback
2016-10-19 20:02:56 +00:00
HydrusData.DebugPrint( traceback.format_exc() )
2016-06-08 20:27:22 +00:00
finally:
2017-05-10 21:33:58 +00:00
HG.view_shutdown = True
2016-06-08 20:27:22 +00:00
controller.pubimmediate( 'wake_daemons' )
2017-05-10 21:33:58 +00:00
HG.model_shutdown = True
2016-06-08 20:27:22 +00:00
controller.pubimmediate( 'wake_daemons' )
2016-10-12 21:52:50 +00:00
controller.TidyUp()
2016-06-08 20:27:22 +00:00
2015-08-26 21:18:39 +00:00
2015-09-16 18:11:00 +00:00
except:
import traceback
2016-10-19 20:02:56 +00:00
HydrusData.DebugPrint( traceback.format_exc() )
2015-09-16 18:11:00 +00:00
2015-08-26 21:18:39 +00:00
finally:
reactor.callFromThread( reactor.stop )
2016-06-08 20:27:22 +00:00
print( 'This was version ' + str( HC.SOFTWARE_VERSION ) )
2015-08-26 21:18:39 +00:00
2016-06-08 20:27:22 +00:00
raw_input()
2016-12-21 22:30:54 +00:00