15.2.89. camcops_server.camcops_server_core

camcops_server/camcops_server_core.py


Copyright (C) 2012, University of Cambridge, Department of Psychiatry. Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

This file is part of CamCOPS.

CamCOPS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

CamCOPS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.


Main functions used by camcops_server.py

We split these off, because the imports can be very slow, and we want a rapid command-line response for simple commands.

Importing this module does the following:

  • ensure that all models are loaded;

  • provide log message around some of the slow imports.

camcops_server.camcops_server_core.check_index(cfg: camcops_server.cc_modules.cc_config.CamcopsConfig, show_all_bad: bool = False) bool[source]

Checks the server task index for validity.

Parameters
Returns

are the indexes all good?

camcops_server.camcops_server_core.cmd_export(recipient_names: Optional[List[str]] = None, all_recipients: bool = False, via_index: bool = True, schedule_via_backend: bool = False) None[source]

Send all outbound incremental export messages (e.g. HL7).

Parameters
  • recipient_names – List of export recipient names (as per the config file).

  • all_recipients – Use all recipients?

  • via_index – Use the task index (faster)?

  • schedule_via_backend – Schedule the export via the backend, rather than performing it now.

camcops_server.camcops_server_core.cmd_show_export_queue(recipient_names: Optional[List[str]] = None, all_recipients: bool = False, via_index: bool = True, pretty: bool = False, debug_show_fhir: bool = False, debug_fhir_include_docs: bool = False) None[source]

Shows tasks that would be exported.

Parameters
  • recipient_names – List of export recipient names (as per the config file).

  • all_recipients – Use all recipients?

  • via_index – Use the task index (faster)?

  • pretty – Use str(task) not repr(task)? (Prettier, but slower because it has to query the patient.)

  • debug_show_fhir – Show FHIR output for each task, as JSON?

  • debug_fhir_include_docs – (If debug_show_fhir.) Include document content? Large!

camcops_server.camcops_server_core.dev_cli() None[source]

Fire up a developer debug command-line.

camcops_server.camcops_server_core.enable_user_cli(username: Optional[str] = None) bool[source]

Re-enable a locked user account from the command line.

camcops_server.camcops_server_core.ensure_database_is_ok() None[source]

Opens a link to the database and checks it’s of the correct version (or otherwise raises an assertion error).

camcops_server.camcops_server_core.ensure_ok_for_webserver() None[source]

Prerequisites for firing up the web server.

camcops_server.camcops_server_core.get_new_password_from_cli(username: str) str[source]

Asks the user (via stdout/stdin) for a new password for the specified username. Returns the password.

camcops_server.camcops_server_core.get_username_from_cli(req: camcops_server.cc_modules.cc_request.CamcopsRequest, prompt: str, starting_username: str = '', must_exist: bool = False, must_not_exist: bool = False) str[source]

Asks the user (via stdout/stdin) for a username.

Parameters
  • req – CamcopsRequest object

  • prompt – textual prompt

  • starting_username – try this username and ask only if it fails tests

  • must_exist – the username must exist

  • must_not_exist – the username must not exist

Returns

the username

camcops_server.camcops_server_core.join_url_fragments(*fragments: str) str[source]

Combines fragments to make a URL.

(urllib.parse.urljoin doesn’t do what we want.)

camcops_server.camcops_server_core.launch_celery_beat(verbose: bool = False, cleanup_timeout_s: float = 10.0) None[source]

Launch the Celery Beat scheduler.

(This can be combined with celery worker, but that’s not recommended; https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#starting-the-scheduler).

camcops_server.camcops_server_core.launch_celery_flower(address: str = '127.0.0.1', port: int = 5555, cleanup_timeout_s: float = 10.0) None[source]

Launch the Celery Flower monitor.

camcops_server.camcops_server_core.launch_celery_workers(verbose: bool = False, cleanup_timeout_s: float = 10.0) None[source]

Launch Celery workers.

See also advice in

camcops_server.camcops_server_core.make_data_dictionary(filename: str, recipient_name: str, cris: bool = False) None[source]

Writes a data dictionary for the CRATE anonymisation tool. See camcops_server.cc_export.write_crate_data_dictionary().

Parameters
  • filename – destination filename

  • recipient_name – export recipient name

  • cris – make DD for CRIS, not CRATE

camcops_server.camcops_server_core.make_superuser(username: Optional[str] = None, password: Optional[str] = None) bool[source]

Make a superuser from the command line.

camcops_server.camcops_server_core.make_wsgi_app(debug_toolbar: bool = False, reverse_proxied_config: cardinal_pythonlib.wsgi.reverse_proxied_mw.ReverseProxiedConfig = None, debug_reverse_proxy: bool = False, show_requests: bool = True, show_request_immediately: bool = True, show_response: bool = True, show_timing: bool = True, static_cache_duration_s: int = 0) Router[source]

Makes and returns a WSGI application, attaching all our special methods.

Parameters
  • debug_toolbar – Add the Pyramid debug toolbar?

  • reverse_proxied_config – An optional cardinal_pythonlib.wsgi.reverse_proxied_mw.ReverseProxiedConfig object giving details about a reverse proxy configuration (or details that there isn’t one)

  • debug_reverse_proxy – Show debugging information about the reverse proxy middleware, if such middleware is required?

  • show_requests – Write incoming requests to the Python log?

  • show_request_immediately – [Applicable if show_requests] Show the request immediately, so it’s written to the log before the WSGI app does its processing, and is guaranteed to be visible even if the WSGI app hangs? The only reason to use False is probably if you intend to show response and/or timing information and you want to minimize the number of lines written to the log; in this case, only a single line is written to the log (after the wrapped WSGI app has finished processing).

  • show_response – [Applicable if show_requests] Show the HTTP response code?

  • show_timing – [Applicable if show_requests] Show the time that the wrapped WSGI app took?

  • static_cache_duration_s – Lifetime (in seconds) for the HTTP cache-control setting for static content.

Returns

the WSGI app

QUESTION: how do we access the WSGI environment (passed to the WSGI app) from within a Pyramid request?

ANSWER:

Configurator.make_wsgi_app() calls Router.__init__()
and returns: app = Router(...)
The WSGI framework uses: response = app(environ, start_response)
which therefore calls: Router.__call__(environ, start_response)
which does:
      response = self.execution_policy(environ, self)
      return response(environ, start_response)
So something LIKE this will be called:
      Router.default_execution_policy(environ, router)
          with router.request_context(environ) as request:
              # ...
So the environ is handled by Router.request_context(environ)
which will call BaseRequest.__init__()
which does:
      d = self.__dict__
      d['environ'] = environ
so we should be able to use
      request.environ  # type: Dict[str, str]
camcops_server.camcops_server_core.precache() None[source]

Populates the major caches. (These are process-wide caches, e.g. using dogpile’s @cache_region_static.cache_on_arguments, not config-specific caches.)

camcops_server.camcops_server_core.print_database_title() None[source]

Prints the database title (for the current config) to stdout.

camcops_server.camcops_server_core.print_tasklist() None[source]

Prints the list of tasks to stdout.

camcops_server.camcops_server_core.reindex(cfg: camcops_server.cc_modules.cc_config.CamcopsConfig) None[source]

Drops and regenerates the server task index.

Parameters

cfg – a camcops_server.cc_modules.cc_config.CamcopsConfig

camcops_server.camcops_server_core.reset_password(username: Optional[str] = None) bool[source]

Reset a password from the command line.

camcops_server.camcops_server_core.serve_cherrypy(application: Router, host: str, port: int, unix_domain_socket_filename: str, threads_start: int, threads_max: int, server_name: str, log_screen: bool, ssl_certificate: Optional[str], ssl_private_key: Optional[str], root_path: str) None[source]

Start CherryPy server.

  • Multithreading.

  • Any platform.

camcops_server.camcops_server_core.serve_gunicorn(application: Router, host: str, port: int, unix_domain_socket_filename: str, num_workers: int, ssl_certificate: Optional[str], ssl_private_key: Optional[str], reload: bool = False, timeout_s: int = 30, debug_show_gunicorn_options: bool = False) None[source]

Start Gunicorn server

camcops_server.camcops_server_core.show_database_schema(schemastem: str, make_image: bool = False, java: Optional[str] = None, plantuml: Optional[str] = None, height_width_limit: int = 20000, java_memory_limit_mb: int = 2048) None[source]

Prints the database schema to a PNG picture.

Parameters
  • schemastem – filename stem

  • make_image – Make a PNG image? (May be impractically large!)

  • java – (for make_image) Java executable

  • plantuml – (for make_image) PlantUML Java .jar file

  • height_width_limit – (for make_image) maximum height and width for PNG; see https://plantuml.com/faq

  • java_memory_limit_mb – (for make_image) Java virtual machine memory limit, in Mb

camcops_server.camcops_server_core.test_serve_pyramid(application: Router, host: str = None, port: int = None) None[source]

Launches an extremely simple Pyramid web server (via wsgiref.make_server).