def post(self, request): import sys from otree.common import dump_db if '--inside-zipserver' in sys.argv: dump_db() sys.exit(0)
def handle(self, *args, **options): self.verbosity = options.get("verbosity", 1) if not settings.DEBUG: # this tends to cause confusion. people don't know why they get server 500 error, # and it's worse with zipserver, where it is not possible to run collectstatic. sys.exit( 'Error: devserver & zipserver cannot be used in production mode. ' 'Ensure that your settings.py does not contain a DEBUG setting, ' 'and that the OTREE_PRODUCTION env var is not set.') # for performance, # only run checks when the server starts, not when it reloads # (RUN_MAIN is set by Django autoreloader). if not os.environ.get('RUN_MAIN'): try: # don't suppress output. it's good to know that check is # not failing silently or not being run. # also, intercepting stdout doesn't even seem to work here. self.check(display_num_errors=True) except Exception as exc: otree_startup.print_colored_traceback_and_exit(exc) # better to do this here, because: # (1) it's redundant to do it on every reload # (2) we can exit if we run this before the autoreloader is started if TMP_MIGRATIONS_DIR.exists() and ( not VERSION_FILE.exists() or VERSION_FILE.read_text() != CURRENT_VERSION): # - Don't delete the DB, because it might have important data # - Don't delete __temp_migrations, because then we erase the knowledge that # oTree was updated. If the user starts the server at a later time, we can't remind them # that they needed to delete the DB. So, the two things must be deleted together. self.stdout.write(MSG_OTREE_UPDATE_DELETE_DB) sys.exit(0) TMP_MIGRATIONS_DIR.mkdir(exist_ok=True) VERSION_FILE.write_text(CURRENT_VERSION) TMP_MIGRATIONS_DIR.joinpath('__init__.py').touch(exist_ok=True) # python docs say: invalidate_cache must be called after creating new modules # i suspect invalidate_cache is needed to avoid this issue: # https://groups.google.com/d/msg/otree/d3fOpKCgLWo/-TSiZHy5CAAJ # because it only happened on mac and was sporadic like a race condition # seems to have no impact on perf importlib.invalidate_caches() is_reloader_process = options['use_reloader'] and not os.environ.get( 'RUN_MAIN') if not is_reloader_process: # this handles restarts due Ctrl+C # can't handle this signal in the autoreloader process, # since the DB is stored in the main django process's memory. # i guess the child process receives the SIGINT # from the parent autoreloader process. signal.signal(signal.SIGINT, dump_db_and_exit) try: super().handle(*args, **options) except SystemExit as exc: # this is designed to handle the sys.exit(3) that is fired # by the child process file-watcher thread, when a file is changed. # it needs to be here rather than inner_run because that is only # run by the child process main_func thread. # this also gets run if using zipserver and a sys.exit occurs. # if an exception occurs inside the main_func thread that executes inner_run, # it will just print the TB and hang, as usual. Then the user presses Ctrl+C, # which triggers the SIGINT handler above. # if the main_func thread calls sys.exit that is not a concern here # because that will just exit that thread and not bubble up here. if not is_reloader_process: dump_db() raise