Пример #1
0
    def get_xml_root(self,
                     req: "CamcopsRequest",
                     options: TaskExportOptions = None) -> XmlElement:
        """
        Get root of XML tree, as an
        :class:`camcops_server.cc_modules.cc_xml.XmlElement`.

        Args:
            req: a :class:`camcops_server.cc_modules.cc_request.CamcopsRequest`
            options: a :class:`camcops_server.cc_modules.cc_simpleobjects.TaskExportOptions`
        """  # noqa
        # No point in skipping old ID columns (1-8) now; they're gone.
        branches = self._get_xml_branches(req, options=options)
        # Now add new-style IDs:
        pidnum_branches = []  # type: List[XmlElement]
        pidnum_options = TaskExportOptions(xml_include_plain_columns=True,
                                           xml_with_header_comments=False)
        for pidnum in self.idnums:  # type: PatientIdNum
            pidnum_branches.append(
                pidnum._get_xml_root(req, options=pidnum_options))
        branches.append(XmlElement(name="idnums", value=pidnum_branches))
        # Special notes
        branches.append(XML_COMMENT_SPECIAL_NOTES)
        special_notes = self.special_notes  # type: List[SpecialNote]
        for sn in special_notes:
            branches.append(sn.get_xml_root())
        return XmlElement(name=self.__tablename__, value=branches)
Пример #2
0
    def test_hl7core_func(self) -> None:
        self.announce("test_hl7core_func")

        pitlist = [
            HL7PatientIdentifier(pid="1",
                                 id_type="TT",
                                 assigning_authority="AA")
        ]
        # noinspection PyTypeChecker
        dob = Date.today()  # type: Date
        now = Pendulum.now()
        task = self.dbsession.query(Phq9).first()
        assert task, "Missing Phq9 in demo database!"

        self.assertIsInstance(get_mod11_checkdigit("12345"), str)
        self.assertIsInstance(get_mod11_checkdigit("badnumber"), str)
        self.assertIsInstance(get_mod11_checkdigit("None"), str)
        self.assertIsInstance(make_msh_segment(now, "control_id"), hl7.Segment)
        self.assertIsInstance(
            make_pid_segment(
                forename="fname",
                surname="sname",
                dob=dob,
                sex="M",
                address="Somewhere",
                patient_id_list=pitlist,
            ),
            hl7.Segment,
        )
        self.assertIsInstance(make_obr_segment(task), hl7.Segment)
        for task_format in (FileType.PDF, FileType.HTML, FileType.XML):
            for comments in (True, False):
                export_options = TaskExportOptions(
                    xml_include_comments=comments,
                    xml_with_header_comments=comments,
                )
                self.assertIsInstance(
                    make_obx_segment(
                        req=self.req,
                        task=task,
                        task_format=task_format,
                        observation_identifier="obs_id",
                        observation_datetime=now,
                        responsible_observer="responsible_observer",
                        export_options=export_options,
                    ),
                    hl7.Segment,
                )
        self.assertIsInstance(escape_hl7_text("blahblah"), str)
Пример #3
0
 def get_xml_element(self, req: "CamcopsRequest") -> XmlElement:
     """
     Returns an :class:`camcops_server.cc_modules.cc_xml.XmlElement`
     representing this BLOB.
     """
     options = TaskExportOptions(xml_skip_fields=["theblob"],
                                 xml_include_plain_columns=True,
                                 include_blobs=False)
     branches = self._get_xml_branches(req, options)
     blobdata = self._get_xml_theblob_value_binary()
     branches.append(
         get_xml_blob_element(name="theblob",
                              blobdata=blobdata,
                              comment=Blob.theblob.comment))
     return XmlElement(name=self.__tablename__, value=branches)
Пример #4
0
    def _get_xml_branches(self, req: "CamcopsRequest",
                          options: TaskExportOptions) -> List[XmlElement]:
        """
        Gets the values of SQLAlchemy columns as XmlElement objects.
        Optionally, find any SQLAlchemy relationships that are relationships
        to Blob objects, and include them too.

        Used by :func:`_get_xml_root` above, but also by Tasks themselves.

        Args:
            req: a :class:`camcops_server.cc_modules.cc_request.CamcopsRequest`
            options: a :class:`camcops_server.cc_modules.cc_simpleobjects.TaskExportOptions`
        """  # noqa
        # log.debug("_get_xml_branches for {!r}", self)
        options = options or TaskExportOptions(
            xml_include_plain_columns=True,
            xml_include_calculated=True,
            xml_sort_by_name=True,
        )
        branches = []  # type: List[XmlElement]
        if options.xml_with_header_comments:
            branches.append(XML_COMMENT_STORED)
        if options.xml_include_plain_columns:
            new_branches = make_xml_branches_from_columns(
                self, skip_fields=options.xml_skip_fields)
            if options.xml_sort_by_name:
                new_branches.sort(key=lambda el: el.name)
            branches += new_branches
        if options.include_blobs:
            new_branches = make_xml_branches_from_blobs(
                req, self, skip_fields=options.xml_skip_fields)
            if options.xml_sort_by_name:
                new_branches.sort(key=lambda el: el.name)
            branches += new_branches
        # Calculated
        if options.xml_include_calculated:
            if options.xml_with_header_comments:
                branches.append(XML_COMMENT_CALCULATED)
            branches.extend(
                make_xml_branches_from_summaries(
                    self.get_summaries(req),
                    skip_fields=options.xml_skip_fields,
                    sort_by_name=options.xml_sort_by_name,
                ))
        # log.debug("... branches for {!r}: {!r}", self, branches)
        return branches
Пример #5
0
def export_whole_database(req: "CamcopsRequest",
                          recipient: ExportRecipient,
                          via_index: bool = True) -> None:
    """
    Exports to a database.
    
    Holds a recipient-specific file lock in the process.
    
    Args:
        req: a :class:`camcops_server.cc_modules.cc_request.CamcopsRequest`
        recipient: an :class:`camcops_server.cc_modules.cc_exportmodels.ExportRecipient`
        via_index: use the task index (faster)?
    """  # noqa
    cfg = req.config
    lockfilename = cfg.get_export_lockfilename_db(
        recipient_name=recipient.recipient_name)
    try:
        with lockfile.FileLock(lockfilename, timeout=0):  # doesn't wait
            collection = get_collection_for_export(req,
                                                   recipient,
                                                   via_index=via_index)
            dst_engine = create_engine(recipient.db_url,
                                       echo=recipient.db_echo)
            log.info("Exporting to database: {}",
                     get_safe_url_from_engine(dst_engine))
            dst_session = sessionmaker(bind=dst_engine)()  # type: SqlASession
            task_generator = gen_tasks_having_exportedtasks(collection)
            export_options = TaskExportOptions(
                include_blobs=recipient.db_include_blobs,
                # *** todo: other options, specifically DB_PATIENT_ID_PER_ROW
            )
            copy_tasks_and_summaries(
                tasks=task_generator,
                dst_engine=dst_engine,
                dst_session=dst_session,
                export_options=export_options,
                req=req,
            )
            dst_session.commit()
    except lockfile.AlreadyLocked:
        log.warning(
            "Export logfile {!r} already locked by another process; "
            "aborting", lockfilename)
Пример #6
0
def _gen_columns_for_anon_staging_db(
    req: "CamcopsRequest", recipient: "ExportRecipientInfo"
) -> Generator[Union[Column, CamcopsColumn], None, None]:
    """
    Generates all columns for an anonymisation staging database.
    """
    url = SQLITE_MEMORY_URL
    engine = create_engine(url, echo=False)
    session = sessionmaker(bind=engine)()  # type: SqlASession
    export_options = TaskExportOptions(
        include_blobs=recipient.db_include_blobs,
        db_patient_id_per_row=recipient.db_patient_id_per_row,
        db_make_all_tables_even_empty=True,
        db_include_summaries=recipient.db_add_summaries,
    )

    dc = DumpController(
        dst_engine=engine,
        dst_session=session,
        export_options=export_options,
        req=req,
    )
    for col in dc.gen_all_dest_columns():
        yield col
Пример #7
0
    def _get_xml(
        self,
        audit_string: str,
        xml_name: str,
        indent_spaces: int = 4,
        eol: str = "\n",
        include_comments: bool = False,
    ) -> str:
        """
        Returns an XML document representing this object.

        Args:
            audit_string: description used to audit access to this information
            xml_name: name of the root XML element
            indent_spaces: number of spaces to indent formatted XML
            eol: end-of-line string
            include_comments: include comments describing each field?

        Returns:
            an XML UTF-8 document representing the task.
        """
        iddef = self.taskfilter.get_only_iddef()
        if not iddef:
            raise ValueError("Tracker/CTV doesn't have a single ID number "
                             "criterion")
        branches = [
            self.consistency_info.get_xml_root(),
            XmlElement(
                name="_search_criteria",
                value=[
                    XmlElement(
                        name="task_tablename_list",
                        value=",".join(self.taskfilter.task_tablename_list),
                    ),
                    XmlElement(
                        name=ViewParam.WHICH_IDNUM,
                        value=iddef.which_idnum,
                        datatype=XmlDataTypes.INTEGER,
                    ),
                    XmlElement(
                        name=ViewParam.IDNUM_VALUE,
                        value=iddef.idnum_value,
                        datatype=XmlDataTypes.INTEGER,
                    ),
                    XmlElement(
                        name=ViewParam.START_DATETIME,
                        value=format_datetime(self.taskfilter.start_datetime,
                                              DateFormat.ISO8601),
                        datatype=XmlDataTypes.DATETIME,
                    ),
                    XmlElement(
                        name=ViewParam.END_DATETIME,
                        value=format_datetime(self.taskfilter.end_datetime,
                                              DateFormat.ISO8601),
                        datatype=XmlDataTypes.DATETIME,
                    ),
                ],
            ),
        ]
        options = TaskExportOptions(
            xml_include_plain_columns=True,
            xml_include_calculated=True,
            include_blobs=False,
        )
        for t in self.collection.all_tasks:
            branches.append(t.get_xml_root(self.req, options))
            audit(
                self.req,
                audit_string,
                table=t.tablename,
                server_pk=t.pk,
                patient_server_pk=t.get_patient_server_pk(),
            )
        tree = XmlElement(name=xml_name, value=branches)
        return get_xml_document(
            tree,
            indent_spaces=indent_spaces,
            eol=eol,
            include_comments=include_comments,
        )
Пример #8
0
 def get_task_export_options(self) -> TaskExportOptions:
     return TaskExportOptions(
         xml_include_comments=self.xml_field_comments,
         xml_with_header_comments=self.xml_field_comments,
     )