14.2.82. camcops_server.cc_modules.cc_task

camcops_server/cc_modules/cc_task.py


Copyright (C) 2012-2019 Rudolf Cardinal (rudolf@pobox.com).

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 <http://www.gnu.org/licenses/>.


Represents CamCOPS tasks.

Core task export methods:

Format Comment
HTML The task in a user-friendly format.
PDF Essentially the HTML output, but with page headers and (for clinician tasks) a signature block, and without additional HTML administrative hyperlinks.
XML Centres on the task with its subdata integrated.
TSV Tab-separated value format.
SQL As part of an SQL or SQLite download.
class camcops_server.cc_modules.cc_task.Task(**kwargs)[source]

Abstract base class for all tasks.

Note:

A simple constructor that allows initialization from kwargs.

Sets attributes on the constructed instance using the names and values in kwargs.

Only keys that are present as attributes of the instance’s class are allowed. These could be, for example, any mapped columns or relationships.

classmethod all_subclasses_by_longname(req: CamcopsRequest) → List[Type[_ForwardRef('Task')]][source]

Return all task classes, ordered by long name.

classmethod all_subclasses_by_shortname() → List[Type[_ForwardRef('Task')]][source]

Return all task classes, ordered by short name.

classmethod all_subclasses_by_tablename() → List[Type[_ForwardRef('Task')]][source]

Return all task classes, ordered by table name.

classmethod all_tables_with_min_client_version() → Dict[str, semantic_version.base.Version][source]

Returns a dictionary mapping all this task’s tables (primary and ancillary) to the corresponding minimum client version.

all_true(fields: List[str]) → bool[source]

Do all the specified fields evaluate to True (are they all truthy)?

any_patient_idnums_invalid(req: CamcopsRequest) → bool[source]

Do we have a patient who has any invalid ID numbers?

Parameters:req – a camcops_server.cc_modules.cc_request.CamcopsRequest
apply_special_note(req: CamcopsRequest, note: str, from_console: bool = False) → None[source]

Manually applies a special note to a task.

Applies it to all predecessor/successor versions as well. WRITES TO THE DATABASE.

are_all_fields_complete(fields: List[str]) → bool[source]

Are all specified fields not None?

audit(req: CamcopsRequest, details: str, from_console: bool = False) → None[source]

Audits actions to this task.

cancel_from_export_log(req: CamcopsRequest, from_console: bool = False) → None[source]

Marks all instances of this task as “cancelled” in the export log, so it will be resent.

contains_all_strings(strings: List[str]) → bool[source]

Does this task contain all of the specified strings?

Parameters:strings – list of strings; each string must be present in at least one of our text columns
Returns:are all strings present?
contains_text(text: str) → bool[source]

Does this task contain the specified text?

Parameters:text – string that must be present in at least one of our text columns
Returns:is the strings present?
count_booleans(fields: List[str]) → int[source]

How many of the specified fields evaluate to True (are truthy)?

count_where(fields: List[str], wherevalues: List[Any]) → int[source]

Count how many values for the specified fields are in wherevalues.

count_wherenot(fields: List[str], notvalues: List[Any]) → int[source]

Count how many values for the specified fields are NOT in notvalues.

delete_entirely(req: CamcopsRequest) → None[source]

Completely delete this task, its lineage, and its dependants.

dump() → None[source]

Dump a description of the task instance to the Python log, for debugging.

extrastrings_exist(req: CamcopsRequest) → bool[source]

Does the server have any extra strings for this task?

field_contents_invalid_because() → List[str][source]

Explains why contents are invalid.

field_contents_valid() → bool[source]

Checks field contents validity.

This is a high-speed function that doesn’t bother with explanations, since we use it for lots of task is_complete() calculations.

static fieldnames_from_list(prefix: str, suffixes: Iterable[Any]) → List[str][source]

Returns a list of fieldnames made by appending each suffix to the prefix.

Parameters:
  • prefix – string prefix
  • suffixes – list of suffixes, which will be coerced to str
Returns:

list of fieldnames, as above

static fieldnames_from_prefix(prefix: str, start: int, end: int) → List[str][source]

Returns a list of field (column, attribute) names from a prefix. For example, fieldnames_from_prefix("q", 1, 5) produces ["q1", "q2", "q3", "q4", "q5"].

Parameters:
  • prefix – string prefix
  • start – first value (inclusive)
  • end – last value (inclusive
Returns:

list of fieldnames, as above

classmethod gen_all_subclasses() → Generator[[Type[_ForwardRef('Task')], NoneType], NoneType][source]

Generate all non-abstract SQLAlchemy ORM subclasses of Task – that is, all task classes.

We require that actual tasks are subclasses of both Task and camcops_server.cc_modules.cc_sqlalchemy.Base.

OLD WAY (ignore): this means we can (a) inherit from Task to make an abstract base class for actual tasks, as with PCL, HADS, HoNOS, etc.; and (b) not have those intermediate classes appear in the task list. Since all actual classes must be SQLAlchemy ORM objects inheriting from Base, that common inheritance is an excellent way to define them.

NEW WAY: things now inherit from Base/Task without necessarily being actual tasks; we discriminate using __abstract__ and/or __tablename__. See https://docs.sqlalchemy.org/en/latest/orm/inheritance.html#abstract-concrete-classes

classmethod gen_text_filter_columns() → Generator[[Tuple[str, sqlalchemy.sql.schema.Column], NoneType], NoneType][source]

Yields tuples of attrname, column, for columns that are suitable for text filtering.

get_adding_user_id() → int[source]

Returns the user ID of the user who uploaded this task.

get_adding_user_username() → str[source]

Returns the username of the user who uploaded this task.

get_all_summary_tables(req: CamcopsRequest) → List[camcops_server.cc_modules.cc_summaryelement.ExtraSummaryTable][source]

Returns all camcops_server.cc_modules.cc_summaryelement.ExtraSummaryTable objects for this class, including any provided by subclasses, plus SNOMED CT codes if enabled.

get_blob_fields() → List[str][source]

Returns field (column) names for all BLOB fields in this class.

get_clinical_text(req: CamcopsRequest) → Union[typing.List[_ForwardRef('CtvInfo')], NoneType][source]

Tasks that provide clinical text information should override this to provide a list of camcops_server.cc_modules.cc_ctvinfo.CtvInfo objects.

Return None (default) for a task that doesn’t provide clinical text, or [] for one that does in general but has no information for this particular instance, or a list of camcops_server.cc_modules.cc_ctvinfo.CtvInfo objects.

get_clinician_name() → str[source]

Get the clinician’s name.

May be overridden by TaskHasClinicianMixin.

get_creation_datetime() → Union[pendulum.datetime.DateTime, NoneType][source]

Creation datetime, or None.

get_creation_datetime_utc() → Union[pendulum.datetime.DateTime, NoneType][source]

Creation datetime in UTC, or None.

get_creation_datetime_utc_tz_unaware() → Union[datetime.datetime, NoneType][source]

Creation time as a datetime.datetime object on UTC with no timezone (i.e. an “offset-naive” datetime), or None.

get_extra_summary_tables(req: CamcopsRequest) → List[camcops_server.cc_modules.cc_summaryelement.ExtraSummaryTable][source]

Override if you wish to create extra summary tables, not just add summary columns to task/ancillary tables.

Return a list of camcops_server.cc_modules.cc_summaryelement.ExtraSummaryTable objects.

get_extrastring_taskname() → str[source]

Get the taskname used as the top-level key for this task’s extra strings (loaded by the server from XML files). By default this is the task’s primary tablename, but tasks may override that via extrastring_taskname.

classmethod get_fieldnames() → List[str][source]

Returns all field (column) names for this task’s primary table.

get_hl7_data_segments(req: CamcopsRequest, recipient_def: ExportRecipient) → List[hl7.containers.Segment][source]

Returns a list of HL7 data segments.

These will be:

  • OBR segment
  • OBX segment
  • any extra ones offered by the task
get_hl7_extra_data_segments(recipient_def: ExportRecipient) → List[hl7.containers.Segment][source]

Return a list of any extra HL7 data segments. (See get_hl7_data_segments().)

May be overridden.

get_html(req: CamcopsRequest, anonymise: bool = False) → str[source]

Returns HTML representing the task, for our HTML view.

Parameters:
get_is_complete_td_pair(req: CamcopsRequest) → str[source]

HTML to indicate whether task is complete or not, and to make it very obvious visually when it isn’t.

get_is_complete_tr(req: CamcopsRequest) → str[source]

HTML table row to indicate whether task is complete or not, and to make it very obvious visually when it isn’t.

get_manually_erasing_user_username() → str[source]

Returns the username of the user who erased this task manually on the server.

get_patient_address() → str[source]

Get the patient’s address, or “”.

get_patient_dob() → Union[pendulum.date.Date, NoneType][source]

Get the patient’s DOB, or None.

get_patient_dob_first11chars() → Union[str, NoneType][source]

Gets the patient’s date of birth in an 11-character human-readable short format. For example: 29 Dec 1999.

get_patient_forename() → str[source]

Get the patient’s forename, in upper case, or “”.

get_patient_hl7_pid_segment(req: CamcopsRequest, recipient_def: ExportRecipient) → Union[hl7.containers.Segment, str][source]

Get an HL7 PID segment for the patient, or “”.

get_patient_idnum_object(which_idnum: int) → Union[_ForwardRef('PatientIdNum'), NoneType][source]

Get the patient’s camcops_server.cc_modules.cc_patientidnum.PatientIdNum for the specified ID number type (which_idnum), or None.

get_patient_idnum_objects() → List[_ForwardRef('PatientIdNum')][source]

Gets all camcops_server.cc_modules.cc_patientidnum.PatientIdNum objects for the patient.

get_patient_idnum_value(which_idnum: int) → Union[int, NoneType][source]

Get the patient’s ID number value for the specified ID number type (which_idnum), or None.

get_patient_server_pk() → Union[int, NoneType][source]

Get the server PK of the patient, or None.

get_patient_sex() → str[source]

Get the patient’s sex, or “”.

get_patient_surname() → str[source]

Get the patient’s surname, in upper case, or “”.

get_pdf(req: CamcopsRequest, anonymise: bool = False) → bytes[source]

Returns a PDF representing the task.

Parameters:
get_pdf_html(req: CamcopsRequest, anonymise: bool = False) → str[source]

Gets the HTML used to make the PDF (slightly different from the HTML used for the HTML view).

get_pk() → Union[int, NoneType][source]

Returns the server-side primary key for this task.

get_preserving_user_username() → str[source]

Returns the username of the user who “preserved” this task (marking it to be saved on the server and then deleting it from the client).

get_removing_user_username() → str[source]

Returns the username of the user who deleted this task (by removing it on the client and re-uploading).

get_rio_metadata(req: CamcopsRequest, which_idnum: int, uploading_user_id: str, document_type: str) → str[source]

Returns metadata for the task that Servelec’s RiO electronic patient record may want.

Parameters:
  • req – a camcops_server.cc_modules.cc_request.CamcopsRequest
  • which_idnum – which CamCOPS ID number type corresponds to the RiO client ID?
  • uploading_user_id – RiO user ID (string) of the user who will be recorded as uploading this information; see below
  • document_type – a string indicating the RiO-defined document type (this is system-specific); see below
Returns:

a newline-terminated single line of CSV values; see below

Called by camcops_server.cc_modules.cc_exportmodels.ExportedTaskFileGroup.export_task().

From Servelec (Lee Meredith) to Rudolf Cardinal, 2014-12-04:

Batch Document Upload

The RiO batch document upload function can be used to upload
documents in bulk automatically.  RiO includes a Batch Upload
windows service which monitors a designated folder for new files.
Each file which is scanned must be placed in the designated folder
along with a meta-data file which describes the document.  So
essentially if a document had been scanned in and was called
‘ThisIsANewReferralLetterForAPatient.pdf’ then there would also
need to be a meta file in the same folder called
‘ThisIsANewReferralLetterForAPatient.metadata’.  The contents of
the meta file would need to include the following:

    Field Order; Field Name; Description; Data Mandatory (Y/N);
    Format

    1; ClientID; RiO Client ID which identifies the patient in RiO
    against which the document will be uploaded.; Y; 15
    Alphanumeric Characters

    2; UserID; User ID of the uploaded document, this is any user
    defined within the RiO system and can be a single system user
    called ‘AutomaticDocumentUploadUser’ for example.; Y; 10
    Alphanumeric Characters

        [NB example longer than that!]

    3; DocumentType; The RiO defined document type eg: APT; Y; 80
    Alphanumeric Characters

    4; Title; The title of the document; N; 40 Alphanumeric
    Characters

    5; Description; The document description.; N; 500 Alphanumeric
    Characters

    6; Author; The author of the document; N; 80 Alphanumeric
    Characters

    7; DocumentDate; The date of the document; N; dd/MM/yyyy HH:mm

    8; FinalRevision; The revision values are 0 Draft or 1 Final,
    this is defaulted to 1 which is Final revision.; N; 0 or 1

As an example, this is what would be needed in a meta file:

    “1000001”,”TRUST1”,”APT”,”A title”, “A description of the
        document”, “An author”,”01/12/2012 09:45”,”1”

(on one line)

Clarification, from Lee Meredith to Rudolf Cardinal, 2015-02-18:

get_seconds_from_creation_to_first_finish() → Union[float, NoneType][source]

Time in seconds from creation time to first finish (i.e. first exit if the first exit was a finish rather than an abort), or None.

get_snomed_codes(req: CamcopsRequest) → List[_ForwardRef('SnomedExpression')][source]

Returns all SNOMED-CT codes for this task.

Parameters:req – the camcops_server.cc_modules.cc_request.CamcopsRequest
Returns:a list of camcops_server.cc_modules.cc_snomed.SnomedExpression objects
get_standard_clinician_comments_block(req: CamcopsRequest, comments: str) → str[source]

HTML DIV for clinician’s comments.

get_task_html(req: CamcopsRequest) → str[source]

HTML for the main task content.

Must be overridden by derived classes.

classmethod get_text_filter_columns() → List[sqlalchemy.sql.schema.Column][source]

Cached function to return a list of SQLAlchemy Column objects suitable for text filtering.

get_trackers(req: CamcopsRequest) → List[_ForwardRef('TrackerInfo')][source]

Tasks that provide quantitative information for tracking over time should override this and return a list of camcops_server.cc_modules.cc_trackerhelpers.TrackerInfo objects, one per tracker.

The information is read by camcops_server.cc_modules.cc_tracker.Tracker.get_all_plots_for_one_task_html().

Time information will be retrieved using get_creation_datetime().

get_tsv_pages(req: CamcopsRequest) → List[_ForwardRef('TsvPage')][source]

Returns information used for the basic research dump in TSV format.

get_twocol_bool_row(req: CamcopsRequest, fieldname: str, label: str = None) → str[source]

HTML table row, two columns, with Boolean Y/N formatter for value.

Parameters:
Returns:

two-column HTML table row (label, value)

get_twocol_bool_row_present_absent(req: CamcopsRequest, fieldname: str, label: str = None) → str[source]

HTML table row, two columns, with Boolean present/absent formatter for value.

Parameters:
Returns:

two-column HTML table row (label, value)

get_twocol_bool_row_true_false(req: CamcopsRequest, fieldname: str, label: str = None) → str[source]

HTML table row, two columns, with Boolean true/false formatter for value.

Parameters:
Returns:

two-column HTML table row (label, value)

static get_twocol_picture_row(blob: Union[camcops_server.cc_modules.cc_blob.Blob, NoneType], label: str) → str[source]

HTML table row, two columns, with PNG on right.

Parameters:
Returns:

two-column HTML table row (label, picture)

get_twocol_string_row(fieldname: str, label: str = None) → str[source]

HTML table row, two columns, with web-safing of value.

Parameters:
  • fieldname – field (attribute) name; the value will be retrieved from this attribute
  • label – descriptive label
Returns:

two-column HTML table row (label, value)

get_twocol_val_row(fieldname: str, default: str = None, label: str = None) → str[source]

HTML table row, two columns, without web-safing of value.

Parameters:
  • fieldname – field (attribute) name; the value will be retrieved from this attribute
  • default – default to show if the value is None
  • label – descriptive label
Returns:

two-column HTML table row (label, value)

get_values(fields: List[str]) → List[source]

Get list of object’s values from list of field names.

get_xml(req: CamcopsRequest, options: camcops_server.cc_modules.cc_simpleobjects.TaskExportOptions = None, indent_spaces: int = 4, eol: str = '\n') → str[source]

Returns XML describing the task.

Parameters:
Returns:

an XML UTF-8 document representing the task.

get_xml_root(req: CamcopsRequest, options: camcops_server.cc_modules.cc_simpleobjects.TaskExportOptions) → camcops_server.cc_modules.cc_xml.XmlElement[source]

Returns an XML tree. The return value is the root camcops_server.cc_modules.cc_xml.XmlElement.

Override to include other tables, or to deal with BLOBs, if the default methods are insufficient.

Parameters:
is_complete() → bool[source]

Is the task instance complete?

Must be overridden.

is_erased() → bool[source]

Has the task been manually erased? See manually_erase().

is_female() → bool[source]

Is the patient female?

is_field_complete(field: str) → bool[source]

Is the field not None?

is_live_on_tablet() → bool[source]

Is the task instance live on a tablet?

is_male() → bool[source]

Is the patient male?

is_preserved() → bool[source]

Is the task preserved and erased from the tablet?

is_respondent_complete() → bool[source]

Is the respondent information complete?

May be overridden by TaskHasRespondentMixin.

static longname(req: CamcopsRequest) → str[source]

Long name (in the relevant language).

manually_erase(req: CamcopsRequest) → None[source]

Manually erases a task (including sub-tables). Also erases linked non-current records. This WIPES THE CONTENTS but LEAVES THE RECORD AS A PLACEHOLDER.

Audits the erasure. Propagates erase through to the HL7 log, so those records will be re-sent. WRITES TO DATABASE.

mean_fields(fields: List[str], ignorevalue: Any = None) → Union[int, float, NoneType][source]

Return the mean of the values stored in all specified fields (skipping any whose value is ignorevalue).

n_complete(fields: List[str]) → int[source]

How many of the specified fields are not None?

n_incomplete(fields: List[str]) → int[source]

How many of the specified fields are None?

patient

Returns the camcops_server.cc_modules.cc_patient.Patient for this task.

Overridden by TaskHasPatientMixin.

standard_task_summary_fields() → List[camcops_server.cc_modules.cc_summaryelement.SummaryElement][source]

Returns summary fields/values provided by all tasks.

suggested_pdf_filename(req: CamcopsRequest) → str[source]

Suggested filename for the PDF copy (for downloads).

sum_fields(fields: List[str], ignorevalue: Any = None) → Union[int, float][source]

Sum values stored in all specified fields (skipping any whose value is ignorevalue; treating fields containing None as zero).

was_forcibly_preserved() → bool[source]

Was this task forcibly preserved?

write_pdf_to_disk(req: CamcopsRequest, filename: str) → None[source]

Writes the PDF to disk, using filename.

wxstring(req: CamcopsRequest, name: str, defaultvalue: str = None, provide_default_if_none: bool = True) → str[source]

Return a web-safe version of an extra string for this task.

Parameters:
  • reqcamcops_server.cc_modules.cc_request.CamcopsRequest
  • name – name (second-level key) of the string, within the set of this task’s extra strings
  • defaultvalue – default to return if the string is not found
  • provide_default_if_none – if True and default is None, return a helpful missing-string message in the style “string x.y not found”
xstring(req: CamcopsRequest, name: str, defaultvalue: str = None, provide_default_if_none: bool = True) → str[source]

Return a raw (not necessarily web-safe) version of an extra string for this task.

Parameters:
  • reqcamcops_server.cc_modules.cc_request.CamcopsRequest
  • name – name (second-level key) of the string, within the set of this task’s extra strings
  • defaultvalue – default to return if the string is not found
  • provide_default_if_none – if True and default is None, return a helpful missing-string message in the style “string x.y not found”
class camcops_server.cc_modules.cc_task.TaskHasClinicianMixin[source]

Mixin to add clinician columns and override clinician-related methods.

Must be to the LEFT of Task in the class’s base class list, i.e. must have higher precedence than Task in the method resolution order.

get_clinician_name() → str[source]

Returns the clinician’s name.

class camcops_server.cc_modules.cc_task.TaskHasPatientMixin[source]

Mixin for tasks that have a patient (aren’t anonymous).

class camcops_server.cc_modules.cc_task.TaskHasRespondentMixin[source]

Mixin to add respondent columns and override respondent-related methods.

A respondent is someone who isn’t the patient and isn’t a clinician, such as a family member or carer.

Must be to the LEFT of Task in the class’s base class list, i.e. must have higher precedence than Task in the method resolution order.

Notes:

  • If you don’t use @declared_attr, the comment property on columns doesn’t work.
is_respondent_complete() → bool[source]

Do we have sufficient information about the respondent? (That means: name, relationship to the patient.)

class camcops_server.cc_modules.cc_task.TaskTests(methodName='runTest')[source]

Unit tests.

Create an instance of the class that will use the named test method when executed. Raises a ValueError if the instance does not have a method with the specified name.

camcops_server.cc_modules.cc_task.all_task_classes() → List[Type[camcops_server.cc_modules.cc_task.Task]][source]

Returns all task base table names.

camcops_server.cc_modules.cc_task.all_task_tablenames() → List[str][source]

Returns all task base table names.

camcops_server.cc_modules.cc_task.all_task_tables_with_min_client_version() → Dict[str, semantic_version.base.Version][source]

Across all tasks, return a mapping from each of their tables to the minimum client version.

Used by camcops_server.cc_modules.client_api.all_tables_with_min_client_version().

camcops_server.cc_modules.cc_task.get_from_dict(d: Dict, key: Any, default: Any = '[invalid_value]') → Any[source]

Returns a value from a dictionary. This is not a very complex function… all it really does in practice is provide a default for default.

Parameters:
  • d – the dictionary
  • key – the key
  • default – value to return if none is provided
camcops_server.cc_modules.cc_task.tablename_to_task_class_dict() → Dict[str, Type[camcops_server.cc_modules.cc_task.Task]][source]

Returns a mapping from task base tablenames to task classes.