diff --git a/.gitignore b/.gitignore index 0209b84..5cb0fd5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,10 @@ htmlcov .eggs # coverage -.coverage \ No newline at end of file +.coverage + +# VirtualEnvs! +venv + +# TOX +.tox diff --git a/.travis.yml b/.travis.yml index f6b0839..4dfb09b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,14 @@ language: python python: - - "2.7" - - "3.4" - - "3.5" - - "3.6" + - 2.7 + - 3.5 + - 3.6 +matrix: + include: + - python: 3.7 + dist: xenial + sudo: true + # command to install dependencies install: "python setup.py install" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c84a96a..61b9574 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,22 @@ Contributing to rwslib Thank you for considering contributing to rwslib. +Developer Setup +--------------- +1. Clone the repository + ``` + git clone https://github.com/mdsol/rwslib + ``` +2. Create a Virtual Env for the Local instance + ```bash + $ python -m venv venv + $ source venv/bin/activate + ``` +3. Install the development dependencies + ```bash + $ pip install -r requirements-dev.txt + ``` +4. Enjoy !!! Pull Requests ------------- diff --git a/docs/source/classes.rst b/docs/source/classes.rst index 55258f1..c048d18 100644 --- a/docs/source/classes.rst +++ b/docs/source/classes.rst @@ -4,172 +4,36 @@ Class Reference rwslib ====== -.. module:: rwslib - -.. autoclass:: RWSConnection - :members: send_request - -rwslib.builders -=============== -Note: Any Class with the Prefix **Mdsol** represents a Medidata Rave specific extension - -.. automodule:: rwslib.builders +.. automodule:: rwslib :members: - :undoc-members: - -.. autoclass:: ActionType -.. autoclass:: Address -.. autoclass:: AdminData -.. autoclass:: Alias -.. autoclass:: Annotation -.. autoclass:: Annotations -.. autoclass:: AuditRecord -.. autoclass:: BasicDefinitions -.. autoclass:: CheckValue -.. autoclass:: City -.. autoclass:: ClinicalData -.. autoclass:: CodeList -.. autoclass:: CodeListItem -.. autoclass:: CodeListRef -.. autoclass:: Comment -.. autoclass:: ControlType -.. autoclass:: Country -.. autoclass:: DataType -.. autoclass:: DateTimeStamp -.. autoclass:: Decode -.. autoclass:: DisplayName -.. autoclass:: Email -.. autoclass:: FirstName -.. autoclass:: Flag -.. autoclass:: FlagType -.. autoclass:: FlagValue -.. autoclass:: FormData -.. autoclass:: FormDef -.. autoclass:: FormRef -.. autoclass:: FullName -.. autoclass:: GlobalVariables -.. autoclass:: GranularityType -.. autoclass:: ItemData -.. autoclass:: ItemDef -.. autoclass:: ItemGroupData -.. autoclass:: ItemGroupDef -.. autoclass:: ItemGroupRef -.. autoclass:: ItemRef -.. autoclass:: LastName -.. autoclass:: LastUpdateMixin -.. autoclass:: Location -.. autoclass:: LocationRef -.. autoclass:: LocationType -.. autoclass:: LogicalRecordPositionType -.. autoclass:: LoginName -.. autoclass:: MODMAttribute -.. autoclass:: MODMExtensionRegistry -.. autoclass:: MODMMixin -.. autoclass:: MdsolAttribute -.. autoclass:: MdsolCheckAction -.. autoclass:: MdsolCheckStep -.. autoclass:: MdsolConfirmationMessage -.. autoclass:: MdsolCustomFunctionDef -.. autoclass:: MdsolDerivationDef -.. autoclass:: MdsolDerivationStep -.. autoclass:: MdsolEditCheckDef -.. autoclass:: MdsolEntryRestriction -.. autoclass:: MdsolHeaderText -.. autoclass:: MdsolHelpText -.. autoclass:: MdsolLabelDef -.. autoclass:: MdsolLabelRef -.. autoclass:: MdsolProtocolDeviation -.. autoclass:: MdsolQuery -.. autoclass:: MdsolReviewGroup -.. autoclass:: MdsolViewRestriction -.. autoclass:: MeasurementUnit -.. autoclass:: MeasurementUnitRef -.. autoclass:: MetaDataVersion -.. autoclass:: MetaDataVersionRef -.. autoclass:: MilestoneMixin -.. autoclass:: ODM -.. autoclass:: ODMElement -.. autoclass:: Organization -.. autoclass:: OtherText -.. autoclass:: Phone -.. autoclass:: PostalCode -.. autoclass:: Protocol -.. autoclass:: ProtocolDeviationStatus -.. autoclass:: QueryStatusType -.. autoclass:: Question -.. autoclass:: RangeCheck -.. autoclass:: RangeCheckComparatorType -.. autoclass:: RangeCheckType -.. autoclass:: ReasonForChange -.. autoclass:: Signature -.. autoclass:: SignatureRef -.. autoclass:: SimpleChildElement -.. autoclass:: SiteRef -.. autoclass:: SourceID -.. autoclass:: StateProv -.. autoclass:: StepType -.. autoclass:: StreetName -.. autoclass:: Study -.. autoclass:: StudyEventData -.. autoclass:: StudyEventDef -.. autoclass:: StudyEventRef -.. autoclass:: SubjectData -.. autoclass:: Symbol -.. autoclass:: TransactionalElement -.. autoclass:: TranslatedText -.. autoclass:: User -.. autoclass:: UserRef -.. autoclass:: UserType - -rwslib.rws_requests -=================== -.. module:: rwslib.rws_requests +Rave Web Services Request Objects +================================= -.. autoclass:: StudyDatasetRequest -.. autoclass:: SubjectDatasetRequest -.. autoclass:: VersionDatasetRequest -.. autoclass:: ConfigurableDatasetRequest - -rwslib.rwsobjects -================= -.. module:: rwslib.rwsobjects +.. automodule:: rwslib.rws_requests + :members: + :exclude-members: url_path -.. autoclass:: ODMDoc -.. autoclass:: RWSResponse -.. autoclass:: RWSException -.. autoclass:: RWSError -.. autoclass:: RWSErrorResponse -.. autoclass:: RWSPostResponse -.. autoclass:: RWSStudies -.. autoclass:: RWSSubjects -.. autoclass:: RWSSubjectListItem -.. autoclass:: RWSStudyMetadataVersions -.. autoclass:: MetaDataVersion +Rave Web Services Objects +========================= -rwslib.rws_requests.biostats_gateway -==================================== +.. automodule:: rwslib.rwsobjects + :members: -.. module:: rwslib.rws_requests.biostats_gateway -.. autoclass:: CVMetaDataRequest -.. autoclass:: FormDataRequest -.. autoclass:: ProjectMetaDataRequest -.. autoclass:: ViewMetaDataRequest -.. autoclass:: CommentDataRequest -.. autoclass:: ProtocolDeviationsRequest -.. autoclass:: DataDictionariesRequest +Biostats Gateway +================ -rwslib.rws_requests.odm_adapter -=============================== +.. automodule:: rwslib.rws_requests.biostats_gateway + :members: + :exclude-members: url_path, studyoid -.. module:: rwslib.rws_requests.odm_adapter +ODM Adapter +=========== -.. autoclass:: AuditRecordsRequest -.. autoclass:: VersionFoldersRequest -.. autoclass:: SitesMetadataRequest -.. autoclass:: UsersRequest -.. autoclass:: SignatureDefinitionsRequest +.. automodule:: rwslib.rws_requests.odm_adapter + :members: + :exclude-members: url_path, studyoid diff --git a/docs/source/classes_builders.rst b/docs/source/classes_builders.rst new file mode 100644 index 0000000..d0477d2 --- /dev/null +++ b/docs/source/classes_builders.rst @@ -0,0 +1,41 @@ +Class Reference for Builders +**************************** + +Metadata Builders +================= + +.. note:: Any Class with the Prefix **Mdsol** represents a Medidata Rave specific extension + +.. automodule:: rwslib.builders.metadata + :members: + :exclude-members: build + +Clinical Data Builders +====================== + +.. note:: Any Class with the Prefix **Mdsol** represents a Medidata Rave specific extension + +.. automodule:: rwslib.builders.clinicaldata + :members: + :exclude-members: build + + +Medidata Extensions to ODM (MODM) Builders +========================================== + +.. note:: Any Class with the Prefix **Mdsol** represents a Medidata Rave specific extension + +.. automodule:: rwslib.builders.clinicaldata + :members: + :exclude-members: build + + +Administrative Data Builders +============================ + +.. note:: Any Class with the Prefix **Mdsol** represents a Medidata Rave specific extension + +.. automodule:: rwslib.builders.admindata + :members: + :exclude-members: build + diff --git a/docs/source/index.rst b/docs/source/index.rst index cfbb1a9..d695e23 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -25,6 +25,7 @@ Contents: odm_adapter rwscmd classes + classes_builders Indices and tables ================== diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..6fc2c28 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,5 @@ +-r requirements.txt +httpretty +tox +mock +sphinx diff --git a/requirements.txt b/requirements.txt index f40080e..313c8d1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,6 @@ lxml requests -httpretty -tox six -enum34 -mock +enum34; python_version < '3.4' click faker diff --git a/rwslib/__init__.py b/rwslib/__init__.py index 805bdca..2dc1087 100644 --- a/rwslib/__init__.py +++ b/rwslib/__init__.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- -__title__ = 'rwslib' -__author__ = 'Ian Sparks (isparks@mdsol.com)' -__version__ = '1.2.2' -__license__ = 'MIT' -__copyright__ = 'Copyright 2017 Medidata Solutions Inc' +__title__ = "rwslib" +__author__ = "Ian Sparks (isparks@mdsol.com)" +__version__ = "1.2.3" +__license__ = "MIT" +__copyright__ = "Copyright 2017 Medidata Solutions Inc" import requests @@ -14,43 +14,56 @@ import time -#------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------------------------------- # Classes class AuthorizationException(Exception): """Raised if a request requires authorization but no authorization header is provided""" + pass class RWSConnection(object): """A connection to RWS""" - def __init__(self, domain, username=None, password=None, auth=None, virtual_dir='RaveWebServices'): - """Create a connection to Rave + def __init__( + self, + domain, + username=None, + password=None, + auth=None, + virtual_dir="RaveWebServices", + ): + """ + Create a connection to Rave - If the domain does not start with http then it is assumed to be the name of the medidata - url and https:// will be added as a prefix and .mdsol.com will be added as a postfix. + :param str domain: Rave URL Name + :param str username: Rave User Login + :param str password: Rave User password + :param str auth: Authentication tuple (usually something like `(username, password)` + :param str virtual_dir: Name of the Rave Web Services prefix (usually `RaveWebServices`, but can be customised) - e.g. + .. note:: + If the `domain` does not start with http then it is assumed to be the name of the Medidata + url and https:// will be added as a prefix and .mdsol.com will be added as a postfix. - innovate = https://innovate.mdsol.com - http://mytest = http:/mytest + * innovate => https://innovate.mdsol.com + * http://mytest => http:/mytest """ - if domain.lower().startswith('http'): + if domain.lower().startswith("http"): self.domain = domain else: - self.domain = 'https://%s.mdsol.com' % domain + self.domain = "https://%s.mdsol.com" % domain self.auth = None if auth is not None: self.auth = auth elif username is not None and password is not None: # Make a basic auth - self.auth = (username, password,) - + self.auth = (username, password) self.base_url = make_url(self.domain, virtual_dir) @@ -73,45 +86,50 @@ def send_request(self, request_object, timeout=None, retries=1, **kwargs): # Construct a URL from the object and make a call full_url = make_url(self.base_url, request_object.url_path()) if request_object.requires_authorization: - kwargs['auth'] = self.auth + kwargs["auth"] = self.auth # TODO: Look at different connect and read timeouts? - kwargs['timeout'] = timeout + kwargs["timeout"] = timeout kwargs.update(request_object.args()) - - #Explicit use of requests library here. Could alter in future to inject library to use in case - #requests not available. + # Explicit use of requests library here. Could alter in future to inject library to use in case + # requests not available. # Get a session that allows us to customize HTTP requests session = requests.Session() # Mount a custom adapter that retries failed connections for HTTP and HTTPS requests. - for scheme in ["http://","https://"]: + for scheme in ["http://", "https://"]: session.mount(scheme, requests.adapters.HTTPAdapter(max_retries=retries)) - - action = {"GET": session.get, - "POST": session.post}[request_object.method] + action = {"GET": session.get, "POST": session.post}[request_object.method] start_time = time.time() try: r = action(full_url, **kwargs) - except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout) as exc: + except ( + requests.exceptions.ConnectTimeout, + requests.exceptions.ReadTimeout, + ) as exc: if isinstance(exc, (requests.exceptions.ConnectTimeout,)): - raise RWSException("Server Connection Timeout", "Connection timeout for {}".format(full_url)) + raise RWSException( + "Server Connection Timeout", + "Connection timeout for {}".format(full_url), + ) elif isinstance(exc, (requests.exceptions.ReadTimeout,)): - raise RWSException("Server Read Timeout", "Read timeout for {}".format(full_url)) + raise RWSException( + "Server Read Timeout", "Read timeout for {}".format(full_url) + ) self.request_time = time.time() - start_time - self.last_result = r #see also r.elapsed for timedelta object. + self.last_result = r # see also r.elapsed for timedelta object. if r.status_code in [400, 404]: # Is it a RWS response? - if r.text.startswith('HTTP Error 401.0 - Unauthorized' in r.text: + if "

HTTP Error 401.0 - Unauthorized

" in r.text: raise RWSException("Unauthorized.", r.text) # Check if the content_type is text/xml. Use startswith # in case the charset is also specified: # content-type: text/xml; charset=utf-8 - if r.headers.get('content-type').startswith("text/xml"): + if r.headers.get("content-type").startswith("text/xml"): # XML response - if r.text.startswith(' - + Extends ODMDoc, inheriting attributes like filetype, creationdatetime etc. + + Parses XML of the form: + + .. code-block:: xml + + + """ def __init__(self, xml): @@ -100,15 +116,17 @@ def __init__(self, xml): class RWSErrorResponse(XMLRepr): """ -Parses messages of the form:: - - - + Parses messages of the form: + + .. code-block:: xml + + + """ def __init__(self, xml): @@ -117,21 +135,23 @@ def __init__(self, xml): r_get = self.root.get self.referencenumber = r_get("ReferenceNumber") - self.inboundodmfileoid = r_get('InboundODMFileOID') - self.istransactionsuccessful = r_get('IsTransactionSuccessful') == "1" + self.inboundodmfileoid = r_get("InboundODMFileOID") + self.istransactionsuccessful = r_get("IsTransactionSuccessful") == "1" self.reasoncode = r_get("ReasonCode") self.errordescription = r_get("ErrorClientResponseMessage") class RWSResponse(XMLRepr): """ -Parses messages of the form:: + Parses messages of the form: - - + .. code-block:: xml + + + """ def __init__(self, xml): @@ -140,8 +160,8 @@ def __init__(self, xml): r_get = self.root.get self.referencenumber = r_get("ReferenceNumber") - self.inboundodmfileoid = r_get('InboundODMFileOID') - self.istransactionsuccessful = r_get('IsTransactionSuccessful') == "1" + self.inboundodmfileoid = r_get("InboundODMFileOID") + self.istransactionsuccessful = r_get("IsTransactionSuccessful") == "1" self.subjects_touched = 0 self.folders_touched = 0 @@ -149,29 +169,34 @@ def __init__(self, xml): self.fields_touched = 0 self.loglines_touched = 0 - success_stats = r_get('SuccessStatistics', '') + success_stats = r_get("SuccessStatistics", "") # Clinical data post - if success_stats.startswith('Rave objects touched:'): + if success_stats.startswith("Rave objects touched:"): success_stats = success_stats[ - len('Rave objects touched:') + 1:] # Subjects=0; Folders=0; Forms=0; Fields=0; LogLines=0 - parts = success_stats.split(';') # [Subjects=0, Folders=0, Forms=0, Fields=0, LogLines=0] + len("Rave objects touched:") + 1 : + ] # Subjects=0; Folders=0; Forms=0; Fields=0; LogLines=0 + parts = success_stats.split( + ";" + ) # [Subjects=0, Folders=0, Forms=0, Fields=0, LogLines=0] for part in parts: - name, value = part.strip().split('=') + name, value = part.strip().split("=") # if value[-1] == ';': # value = value[:-1] - if name == 'Subjects': + if name == "Subjects": self.subjects_touched = int(value) - elif name == 'Folders': + elif name == "Folders": self.folders_touched = int(value) - elif name == 'Forms': + elif name == "Forms": self.forms_touched = int(value) - elif name == 'Fields': + elif name == "Fields": self.fields_touched = int(value) - elif name == 'LogLines': + elif name == "LogLines": self.loglines_touched = int(value) else: - raise KeyError('Unknown Rave Object %s in response %s' % (name, success_stats,)) + raise KeyError( + "Unknown Rave Object %s in response %s" % (name, success_stats) + ) # Note: Metadata post has success_stats == 'N/A' self.new_records = r_get("NewRecords") @@ -179,14 +204,16 @@ def __init__(self, xml): class RWSPostResponse(RWSResponse): """ -Parses responses from PostODMClinicalData messages with the format:: - - - + Parses responses from PostODMClinicalData messages with the format: + + .. code-block:: xml + + + """ def __init__(self, xml): @@ -194,10 +221,10 @@ def __init__(self, xml): RWSResponse.__init__(self, xml) r_get = self.root.get # These counts may only come as a result of a Clinical data POST - snis = r_get('SubjectNumberInStudy') + snis = r_get("SubjectNumberInStudy") self.subjects_in_study = int(snis) if snis is not None else None - sniss = r_get('SubjectNumberInStudySite') + sniss = r_get("SubjectNumberInStudySite") self.subjects_in_study_site = int(sniss) if sniss is not None else None # DraftImported only comes from a MetaData Post @@ -206,7 +233,10 @@ def __init__(self, xml): class RWSPostErrorResponse(RWSResponse): - """Responses to Clinical data post messages have additional Attributes to normal RWS Response messages:: + """ + Responses to Clinical data post messages have additional Attributes to normal RWS Response messages: + + .. code-block:: xml - + + """ + def __init__(self, xml): + """ + :param str xml: Error response + """ RWSResponse.__init__(self, xml) # Get additional properties r_get = self.root.get - self.reason_code = r_get('ReasonCode') - self.error_origin_location = r_get('ErrorOriginLocation') - self.error_client_response_message = r_get('ErrorClientResponseMessage') + self.reason_code = r_get("ReasonCode") + self.error_origin_location = r_get("ErrorOriginLocation") + self.error_client_response_message = r_get("ErrorClientResponseMessage") class RWSStudyListItem(object): """An item in the RWS Study List response""" - def __init__(self): - self.oid = None - self.studyname = None - self.protocolname = None - self.environment = None - self.projecttype = None + def __init__( + self, + oid=None, + studyname=None, + protocolname=None, + environment=None, + projecttype=None, + ): + """ + :param str oid: Study OID + :param str studyname: Study Name + :param str protocolname: Protocol Name + :param str environment: Study Environment + :param str projecttype: Project Type + """ + self.oid = oid + self.studyname = studyname + self.protocolname = protocolname + self.environment = environment + self.projecttype = projecttype def isProd(self): - """Is production if environment is empty""" - return self.environment == '' and self.projecttype != 'GlobalLibraryVolume' + """ + Is production if environment is empty + + :rtype: bool + """ + return self.environment == "" and self.projecttype != "GlobalLibraryVolume" @classmethod def fromElement(cls, elem): - """Read properties from an XML Element - - - - Fixitol (Dev) - - Fixitol - - """ + Read properties from an XML Element to build a StudyList Item - self = cls() - - self.oid = elem.get('OID') + :param lxml.etree.Element elem: The source Study XML Element - # Not all returned documents have a projecttype (GlobalLibraryVolumes do) - self.projecttype = elem.get(MEDI_NS + "ProjectType", "Project") + .. code-block:: xml - e_global_variables = elem.find(ODM_NS + 'GlobalVariables') - self.studyname = e_global_variables.find(ODM_NS + 'StudyName').text - self.protocolname = e_global_variables.find(ODM_NS + 'ProtocolName').text + + + Fixitol (Dev) + + Fixitol + + - self.environment = getEnvironmentFromNameAndProtocol(self.studyname, self.protocolname) + """ + e_global_variables = elem.find(ODM_NS + "GlobalVariables") + studyname = e_global_variables.find(ODM_NS + "StudyName").text + protocolname = e_global_variables.find(ODM_NS + "ProtocolName").text + self = cls( + oid=elem.get("OID"), + projecttype=elem.get(MEDI_NS + "ProjectType", "Project"), + studyname=studyname, + protocolname=protocolname, + environment=getEnvironmentFromNameAndProtocol( + studyname, protocolname + ), + ) return self @@ -275,42 +333,48 @@ def fromElement(cls, elem): # less bad about it. class RWSStudies(list, ODMDoc): """ -Represents a list of studies. Extends the list class and adds a couple of extra properties:: - - - - - Fixitol (Dev) - - Fixitol - - - - - IANTEST - - IANTEST - - - + Represents a list of studies. Extends the list class and adds a couple of extra properties: + + .. code-block:: xml + + + + + Fixitol (Dev) + + Fixitol + + + + + IANTEST + + IANTEST + + + """ def __init__(self, xml): # Get basic properties ODMDoc.__init__(self, xml) - for estudy in self.root.findall(ODM_NS + 'Study'): + for estudy in self.root.findall(ODM_NS + "Study"): self.append(RWSStudyListItem.fromElement(estudy)) class MetaDataVersion(object): """ - + A single MetaDataVersion instance + + .. code-block:: xml + + """ def __init__(self): @@ -319,135 +383,150 @@ def __init__(self): @classmethod def fromElement(cls, elem): - """Read properties from an XML Element + """ + Read properties from a MetaDataVersion element - + :param lxml.etree._Element elem: Source etree Element """ self = cls() - self.oid = elem.get('OID') - self.name = elem.get('Name') + self.oid = elem.get("OID") + self.name = elem.get("Name") return self class RWSStudyMetadataVersions(list, ODMDoc, RWSStudyListItem): """ -Parses responses from MetaDataVersions request:: - - - - - IANTEST - - IANTEST - - - - - - + Parses responses from MetaDataVersions request: + + .. code-block:: xml + + + + + IANTEST + + IANTEST + + + + + + """ def __init__(self, xml): # Get basic properties ODMDoc.__init__(self, xml) - root = self.root # from ODMDoc + root = self.root # type: lxml.etree._Element - e_study = root.find(ODM_NS + 'Study') + e_study = root.find(ODM_NS + "Study") # type: lxml.etree._Element # Quick way to grab the elements here, nasty though self.study = RWSStudyListItem.fromElement(e_study) - for e_version in e_study.findall(ODM_NS + 'MetaDataVersion'): + for e_version in e_study.findall(ODM_NS + "MetaDataVersion"): self.append(MetaDataVersion.fromElement(e_version)) class RWSSubjectListItem(object): """ -Parses response of Subject List request:: - - - - - - - -Optionally ClinicalData may include status:: - - - -The SubjectKey can be either a Subject ID or a UUID depending on the value of SubjectKeyType:: - - - - - - - -May include links:: - - - - - - - + Parses response of Subject List request: + + .. code-block:: xml + + + + + + + + Optionally ClinicalData may include status: + + .. code-block:: xml + + + + The SubjectKey can be either a Subject ID or a UUID depending on the value of SubjectKeyType: + + .. code-block:: xml + + + + + + + + The Response may include links: + + .. code-block:: xml + + + + + + + + """ - STATUS_PROPERTIES = ["Overdue", - "Touched", - "Empty", - "Incomplete", - "NonConformant", - "RequiresSecondPass", - "RequiresReconciliation", - "RequiresVerification", - "Verified", - "Frozen", - "Locked", - "RequiresReview", - "PendingReview", - "Reviewed", - "RequiresAnswerQuery", - "RequiresPendingCloseQuery", - "RequiresCloseQuery", - "StickyPlaced", - "Signed", - "SignatureCurrent", - "RequiresTranslation", - "RequiresCoding", - "RequiresPendingAnswerQuery", - "RequiresSignature", - "ReadyForFreeze", - "ReadyForLock", - "SubjectKeyType", - "SubjectName"] + + STATUS_PROPERTIES = [ + "Overdue", + "Touched", + "Empty", + "Incomplete", + "NonConformant", + "RequiresSecondPass", + "RequiresReconciliation", + "RequiresVerification", + "Verified", + "Frozen", + "Locked", + "RequiresReview", + "PendingReview", + "Reviewed", + "RequiresAnswerQuery", + "RequiresPendingCloseQuery", + "RequiresCloseQuery", + "StickyPlaced", + "Signed", + "SignatureCurrent", + "RequiresTranslation", + "RequiresCoding", + "RequiresPendingAnswerQuery", + "RequiresSignature", + "ReadyForFreeze", + "ReadyForLock", + "SubjectKeyType", + "SubjectName", + ] def __init__(self): """The ODM message has a ClinicalData element with a single SubjectData and SiteRef elements @@ -459,9 +538,9 @@ def __init__(self): self.subjectkeytype = None self.locationoid = None - self.active = None # SubjectActive + self.active = None # SubjectActive self.deleted = None # Deleted - self.links = [] # Link if requested + self.links = [] # Link if requested # Optional properties, only if status included for prop in RWSSubjectListItem.STATUS_PROPERTIES: @@ -470,11 +549,13 @@ def __init__(self): @property def subject_name(self): """ - Get the subject name consistently - if the SubjectKeyType is SubjectUUID - then the subject name lives in the mdsol:SubjectName attribute - + Get the subject name consistently + :rtype str :return: The Subject ID for the subject - :rtype + + .. note:: + * If the `SubjectKeyType` is `SubjectUUID` then the subject name lives in the `mdsol:SubjectName` attribute + * If the `SubjectKeyType` is `SubjectName` then the subject name lives in the `SubjectKey` attribute """ if self.subjectkeytype and self.subjectkeytype == "SubjectUUID".lower(): # if the SubjectKeyType is "SubjectUUID", then return the SubjectName @@ -488,24 +569,26 @@ def fromElement(cls, elem): Read properties from an XML Element """ self = cls() - self.studyoid = elem.get('StudyOID') - self.metadataversionoid = elem.get('MetaDataVersionOID') - e_subjectdata = elem.findall(ODM_NS + 'SubjectData')[0] - self.subjectkey = e_subjectdata.get('SubjectKey') - e_siteref = e_subjectdata.findall(ODM_NS + 'SiteRef')[0] - self.locationoid = e_siteref.get('LocationOID') - - e_links = e_subjectdata.findall(MEDI_NS + 'Link') + self.studyoid = elem.get("StudyOID") + self.metadataversionoid = elem.get("MetaDataVersionOID") + e_subjectdata = elem.findall(ODM_NS + "SubjectData")[0] + self.subjectkey = e_subjectdata.get("SubjectKey") + e_siteref = e_subjectdata.findall(ODM_NS + "SiteRef")[0] + self.locationoid = e_siteref.get("LocationOID") + + e_links = e_subjectdata.findall(MEDI_NS + "Link") for e_link in e_links: - self.links.append(e_link.get(XLINK_NS + 'href')) + self.links.append(e_link.get(XLINK_NS + "href")) - decodes = {'yes': True, 'no': False, '': None} + decodes = {"yes": True, "no": False, "": None} for prop in RWSSubjectListItem.STATUS_PROPERTIES: val = e_subjectdata.get(MEDI_NS + prop, "").lower() setattr(self, prop.lower(), decodes.get(val, val)) # By default we only get back active and non-deleted subjects - self.active = decodes[e_subjectdata.get(MEDI_NS + "SubjectActive", "yes").lower()] + self.active = decodes[ + e_subjectdata.get(MEDI_NS + "SubjectActive", "yes").lower() + ] self.deleted = decodes[e_subjectdata.get(MEDI_NS + "Deleted", "no").lower()] return self @@ -513,27 +596,29 @@ def fromElement(cls, elem): class RWSSubjects(list, ODMDoc): """ -Represents a list of subjects:: - - - - - - - - - - - - - - - - - + Represents a list of subjects: + + .. code-block:: xml + + + + + + + + + + + + + + + + + """ @@ -543,5 +628,5 @@ def __init__(self, xml): root = self.root # from ODMDoc - for e_clindata in root.findall(ODM_NS + 'ClinicalData'): + for e_clindata in root.findall(ODM_NS + "ClinicalData"): self.append(RWSSubjectListItem.fromElement(e_clindata)) diff --git a/rwslib/tests/__init__.py b/rwslib/tests/__init__.py index 984811f..369f8f6 100644 --- a/rwslib/tests/__init__.py +++ b/rwslib/tests/__init__.py @@ -9,6 +9,4 @@ def all_tests(): suite = unittest.TestSuite() loader = unittest.TestLoader() suite.addTests(loader.discover('rwslib.tests')) - suite.addTests(loader.discover('rwslib.extras.audit_event')) - suite.addTests(loader.discover('rwslib.extras')) # Local cv tests return suite diff --git a/rwslib/tests/test_builders_clinicaldata.py b/rwslib/tests/test_builders_clinicaldata.py index 198aa94..d4c04fe 100644 --- a/rwslib/tests/test_builders_clinicaldata.py +++ b/rwslib/tests/test_builders_clinicaldata.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -__author__ = 'isparks' +__author__ = "isparks" import unittest @@ -8,20 +8,20 @@ from rwslib.tests.common import obj_to_doc from datetime import datetime + class TestClinicalData(unittest.TestCase): """Test ClinicalData classes""" def setUp(self): self.tested = ClinicalData("STUDY1", "DEV")( SubjectData("SITE1", "SUBJECT1")( - StudyEventData('VISIT_1')( + StudyEventData("VISIT_1")( FormData("TESTFORM_A")( ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ), ItemGroupData(item_group_repeat_key=2)( - ItemData("Field3", "ValueC"), + ItemData("Field3", "ValueC") ), ) ) @@ -39,9 +39,11 @@ def test_metadata_version_oid(self): """ Test we can handle a MDV as a String """ - self.tested.metadata_version_oid = '2' + self.tested.metadata_version_oid = "2" doc = obj_to_doc(self.tested) - self.assertEqual(doc.attrib["MetaDataVersionOID"], self.tested.metadata_version_oid) + self.assertEqual( + doc.attrib["MetaDataVersionOID"], self.tested.metadata_version_oid + ) def test_metadata_version_oid_as_int(self): """ @@ -49,7 +51,9 @@ def test_metadata_version_oid_as_int(self): """ self.tested.metadata_version_oid = 56 doc = obj_to_doc(self.tested) - self.assertEqual(doc.attrib["MetaDataVersionOID"], str(self.tested.metadata_version_oid)) + self.assertEqual( + doc.attrib["MetaDataVersionOID"], str(self.tested.metadata_version_oid) + ) def test_only_accepts_subjectdata(self): """Test that only SubjectData can be inserted""" @@ -68,10 +72,10 @@ def test_builder(self): def test_add_to_odm(self): """We can add multiple ClinicalData to an ODM""" odm = ODM("Some test case") - odm << ClinicalData("Study1", "Dev") - odm << ClinicalData("Study1", "Dev") + odm << ClinicalData("Study1", "Dev") + odm << ClinicalData("Study1", "Dev") tested = obj_to_doc(odm) - self.assertEqual('ODM', tested.tag) + self.assertEqual("ODM", tested.tag) self.assertTrue(2, len(list(tested))) @@ -80,14 +84,13 @@ class TestSubjectData(unittest.TestCase): def setUp(self): self.tested = SubjectData("SITE1", "SUBJECT1")( - StudyEventData('VISIT_1')( + StudyEventData("VISIT_1")( FormData("TESTFORM_A")( ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ), ItemGroupData(item_group_repeat_key=2)( - ItemData("Field3", "ValueC"), + ItemData("Field3", "ValueC") ), ) ) @@ -104,7 +107,7 @@ def test_invalid_transaction_type_direct_assign(self): """Test transaction type will not allow you to set to invalid choice""" def do(): - self.tested.transaction_type = 'UpDateSert' + self.tested.transaction_type = "UpDateSert" self.assertRaises(AttributeError, do) @@ -116,7 +119,7 @@ def test_invalid_transaction_type(self): """According to docs does not permit upserts""" def do(): - SubjectData("SITEA", "SUB1", transaction_type='upsert') + SubjectData("SITEA", "SUB1", transaction_type="upsert") self.assertRaises(AttributeError, do) @@ -147,45 +150,57 @@ def do(): def test_accepts_auditrecord(self): """Test that AuditRecord can be inserted""" - ar = AuditRecord(used_imputation_method=False, - identifier='ABC1', - include_file_oid=False)( - UserRef('test_user'), - LocationRef('test_site'), + ar = AuditRecord( + used_imputation_method=False, identifier="ABC1", include_file_oid=False + )( + UserRef("test_user"), + LocationRef("test_site"), ReasonForChange("Testing"), - DateTimeStamp(datetime.now()) + DateTimeStamp(datetime.now()), ) self.tested << ar self.assertEqual(self.tested.audit_record, ar) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 3) # 1 StudyEventData + 1 SiteRef + 1 AuditRecord + self.assertTrue( + len(list(t)) == 3 + ) # 1 StudyEventData + 1 SiteRef + 1 AuditRecord def test_add_annotations(self): """Test we can add one or more annotations""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] for i in range(0, 4): - self.tested << Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + self.tested << Annotation( + comment=Comment("Some Comment %s" % i), flags=flags + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 6) # 1 StudyEventData + 1 SiteRef + 4 annotations + self.assertTrue( + len(list(t)) == 6 + ) # 1 StudyEventData + 1 SiteRef + 4 annotations def test_add_signature(self): """Test we can add one signature""" - self.tested << Signature(signature_id="Some ID", - user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + self.tested << Signature( + signature_id="Some ID", + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 3) # 1 studyeventdata + 1 SiteRef + 1 signature + self.assertTrue(len(list(t)) == 3) # 1 studyeventdata + 1 SiteRef + 1 signature def test_multiple_subject_data(self): """We can add multiple SubjectData to the Clinical Data""" @@ -195,25 +210,23 @@ def test_multiple_subject_data(self): doc = obj_to_doc(cd) self.assertEqual(2, len(doc)) + class TestStudyEventData(unittest.TestCase): """Test StudyEventData classes""" def setUp(self): - self.tested = StudyEventData('VISIT_1')( + self.tested = StudyEventData("VISIT_1")( FormData("TESTFORM_A")( ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") - ), - ItemGroupData(item_group_repeat_key=2)( - ItemData("Field3", "ValueC"), + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ), + ItemGroupData(item_group_repeat_key=2)(ItemData("Field3", "ValueC")), ) ) def test_transaction_type(self): """Test transaction type inserted if set""" - self.tested.transaction_type = 'Update' + self.tested.transaction_type = "Update" doc = obj_to_doc(self.tested) self.assertEqual(doc.attrib["TransactionType"], self.tested.transaction_type) @@ -226,37 +239,31 @@ def test_builders_basic(self): def test_study_event_repeat_key(self): """ If supplied we export the study event repeat key""" - tested = StudyEventData('VISIT_1', study_event_repeat_key="1")( + tested = StudyEventData("VISIT_1", study_event_repeat_key="1")( FormData("TESTFORM_A")( ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") - ), - ItemGroupData(item_group_repeat_key=2)( - ItemData("Field3", "ValueC"), + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ), + ItemGroupData(item_group_repeat_key=2)(ItemData("Field3", "ValueC")), ) ) t = obj_to_doc(tested) self.assertEqual("StudyEventData", t.tag) - self.assertEqual("1", t.attrib['StudyEventRepeatKey']) + self.assertEqual("1", t.attrib["StudyEventRepeatKey"]) def test_study_event_repeat_key_as_int(self): """ If supplied we export the study event repeat key""" - tested = StudyEventData('VISIT_1', study_event_repeat_key=1)( + tested = StudyEventData("VISIT_1", study_event_repeat_key=1)( FormData("TESTFORM_A")( ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") - ), - ItemGroupData(item_group_repeat_key=2)( - ItemData("Field3", "ValueC"), + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ), + ItemGroupData(item_group_repeat_key=2)(ItemData("Field3", "ValueC")), ) ) t = obj_to_doc(tested) self.assertEqual("StudyEventData", t.tag) - self.assertEqual("1", t.attrib['StudyEventRepeatKey']) + self.assertEqual("1", t.attrib["StudyEventRepeatKey"]) def test_only_add_formdata_once(self): """Test that an FormData object can only be added once""" @@ -270,35 +277,43 @@ def do(): def test_add_annotations(self): """Test we can add one or more annotations""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] for i in range(0, 4): - self.tested << Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + self.tested << Annotation( + comment=Comment("Some Comment %s" % i), flags=flags + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 5) # one formdata + 4 annotations + self.assertTrue(len(list(t)) == 5) # one formdata + 4 annotations def test_add_signature(self): """Test we can add one signature""" - self.tested << Signature(signature_id="Some ID", - user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + self.tested << Signature( + signature_id="Some ID", + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 2) # 1 formdata + 1 signature + self.assertTrue(len(list(t)) == 2) # 1 formdata + 1 signature def test_invalid_transaction_type_direct_assign(self): """Test transaction type will not allow you to set to invalid choice""" def do(): - self.tested.transaction_type = 'upsert' + self.tested.transaction_type = "upsert" self.assertRaises(AttributeError, do) @@ -306,7 +321,7 @@ def test_invalid_transaction_type(self): """According to docs does not permit upserts""" def do(): - StudyEventData("V2", transaction_type='upsert') + StudyEventData("V2", transaction_type="upsert") self.assertRaises(AttributeError, do) @@ -325,16 +340,9 @@ class TestFormData(unittest.TestCase): def setUp(self): self.tested = FormData("TESTFORM_A")( - ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") - ), - ItemGroupData()( - ItemData("Field3", "ValueC"), - ), - ItemGroupData()( - ItemData("Field4", "ValueD"), - ), + ItemGroupData()(ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB")), + ItemGroupData()(ItemData("Field3", "ValueC")), + ItemGroupData()(ItemData("Field4", "ValueD")), ) def test_children(self): @@ -345,7 +353,7 @@ def test_invalid_transaction_type(self): """Can only be insert, update, upsert not context""" def do(): - FormData("MYFORM", transaction_type='context') + FormData("MYFORM", transaction_type="context") self.assertRaises(AttributeError, do) @@ -376,7 +384,7 @@ def test_builders_basic(self): def test_transaction_type(self): """Test transaction type inserted if set""" - self.tested.transaction_type = 'Update' + self.tested.transaction_type = "Update" doc = obj_to_doc(self.tested) self.assertEqual(doc.attrib["TransactionType"], self.tested.transaction_type) @@ -384,46 +392,51 @@ def test_invalid_transaction_type_direct_assign(self): """Test transaction type will not allow you to set to invalid choice""" def do(): - self.tested.transaction_type = 'invalid' + self.tested.transaction_type = "invalid" self.assertRaises(AttributeError, do) def test_form_repeat_key(self): """Test transaction type inserted if set""" tested = FormData("TESTFORM_A", form_repeat_key=9)( - ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") - ) + ItemGroupData()(ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB")) ) doc = obj_to_doc(tested) self.assertEqual(doc.attrib["FormRepeatKey"], "9") def test_add_annotations(self): """Test we can add one or more annotations""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] for i in range(0, 4): - self.tested << Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + self.tested << Annotation( + comment=Comment("Some Comment %s" % i), flags=flags + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 7) # three igdata + 4 annotations + self.assertTrue(len(list(t)) == 7) # three igdata + 4 annotations def test_add_signature(self): """Test we can add one signature""" - self.tested << Signature(signature_id="Some ID", - user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + self.tested << Signature( + signature_id="Some ID", + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 4) # three igdata + 1 signature + self.assertTrue(len(list(t)) == 4) # three igdata + 1 signature class TestItemGroupData(unittest.TestCase): @@ -431,8 +444,7 @@ class TestItemGroupData(unittest.TestCase): def setUp(self): self.tested = ItemGroupData()( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ) def test_children(self): @@ -457,7 +469,7 @@ def do(): def test_invalid_transaction_type(self): def do(): - ItemGroupData(transaction_type='invalid') + ItemGroupData(transaction_type="invalid") self.assertRaises(AttributeError, do) @@ -469,7 +481,7 @@ def test_builders_basic(self): def test_transaction_type(self): """Test transaction type inserted if set""" - self.tested.transaction_type = 'Context' + self.tested.transaction_type = "Context" doc = obj_to_doc(self.tested, "TESTFORM") self.assertEqual(doc.attrib["TransactionType"], "Context") @@ -484,64 +496,86 @@ def test_whole_item_group(self): def test_add_annotations(self): """Test we can add one or more annotations""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] for i in range(0, 4): - self.tested << Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + self.tested << Annotation( + comment=Comment("Some Comment %s" % i), flags=flags + ) t = obj_to_doc(self.tested, "TESTFORM") self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 6) # two itemdata + 4 annotations + self.assertTrue(len(list(t)) == 6) # two itemdata + 4 annotations def test_add_annotations_on_create_multiple(self): """Test we can add one or more annotations at initialisation""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] - annotations = [Annotation(comment=Comment("Some Comment %s" % i), flags=flags) for i in range(0, 4)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] + annotations = [ + Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + for i in range(0, 4) + ] # add a list of annotations igd = ItemGroupData(annotations=annotations)( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ) t = obj_to_doc(igd, "TESTFORM") self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 6) # two itemdata + 4 annotations + self.assertTrue(len(list(t)) == 6) # two itemdata + 4 annotations def test_add_annotations_on_create_single(self): """Test we can add one or more annotations at initialisation with one""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] - annotations = [Annotation(comment=Comment("Some Comment %s" % i), flags=flags) for i in range(0, 4)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] + annotations = [ + Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + for i in range(0, 4) + ] # add a list of annotations igd = ItemGroupData(annotations=annotations[0])( - ItemData("Field1", "ValueA"), - ItemData("Field2", "ValueB") + ItemData("Field1", "ValueA"), ItemData("Field2", "ValueB") ) t = obj_to_doc(igd, "TESTFORM") self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 3) # two itemdata + 4 annotations + self.assertTrue(len(list(t)) == 3) # two itemdata + 4 annotations def test_add_signature(self): """Test we can add one signature""" - self.tested << Signature(signature_id="Some ID", - user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + self.tested << Signature( + signature_id="Some ID", + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) t = obj_to_doc(self.tested, "TESTFORM") self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 3) # two itemdata + 1 signature + self.assertTrue(len(list(t)) == 3) # two itemdata + 1 signature class TestItemData(unittest.TestCase): """Test ItemData classes""" def setUp(self): - self.tested = ItemData('FIELDA', "TEST") + self.tested = ItemData("FIELDA", "TEST") def test_basic(self): tested = self.tested @@ -574,63 +608,65 @@ def test_isnull_not_set(self): # Check IsNull attribute is missing def do(): - doc.attrib['IsNull'] + doc.attrib["IsNull"] self.assertRaises(KeyError, do) def test_specify(self): """Test specify""" - specify_value = 'A Specify' + specify_value = "A Specify" self.tested.specify_value = specify_value doc = obj_to_doc(self.tested) - self.assertEqual(doc.attrib['mdsol:SpecifyValue'], specify_value) + self.assertEqual(doc.attrib["mdsol:SpecifyValue"], specify_value) def test_freeze_lock_verify(self): - tested = ItemData('FIELDA', "TEST", lock=True, verify=True, freeze=False) + tested = ItemData("FIELDA", "TEST", lock=True, verify=True, freeze=False) self.assertEqual(tested.lock, True) self.assertEqual(tested.freeze, False) self.assertEqual(tested.verify, True) def test_builder(self): """Test building XML""" - tested = ItemData('FIELDA', "TEST", lock=True, verify=True, freeze=False) - - tested << AuditRecord(edit_point=AuditRecord.EDIT_DATA_MANAGEMENT, - used_imputation_method=False, - identifier="x2011", - include_file_oid=False)( + tested = ItemData("FIELDA", "TEST", lock=True, verify=True, freeze=False) + + tested << AuditRecord( + edit_point=AuditRecord.EDIT_DATA_MANAGEMENT, + used_imputation_method=False, + identifier="x2011", + include_file_oid=False, + )( UserRef("Fred"), LocationRef("Site102"), ReasonForChange("Data Entry Error"), - DateTimeStamp(datetime(2015, 9, 11, 10, 15, 22, 80)) + DateTimeStamp(datetime(2015, 9, 11, 10, 15, 22, 80)), ) tested << MdsolQuery() tested << MeasurementUnitRef("Celsius") doc = obj_to_doc(tested) - self.assertEqual(doc.attrib['ItemOID'], "FIELDA") - self.assertEqual(doc.attrib['Value'], "TEST") - self.assertEqual(doc.attrib['mdsol:Verify'], "Yes") - self.assertEqual(doc.attrib['mdsol:Lock'], "Yes") - self.assertEqual(doc.attrib['mdsol:Freeze'], "No") + self.assertEqual(doc.attrib["ItemOID"], "FIELDA") + self.assertEqual(doc.attrib["Value"], "TEST") + self.assertEqual(doc.attrib["mdsol:Verify"], "Yes") + self.assertEqual(doc.attrib["mdsol:Lock"], "Yes") + self.assertEqual(doc.attrib["mdsol:Freeze"], "No") self.assertEqual(doc.tag, "ItemData") - self.assertEqual("AuditRecord", doc.getchildren()[0].tag) - self.assertEqual("MeasurementUnitRef", doc.getchildren()[1].tag) - self.assertEqual("mdsol:Query", doc.getchildren()[2].tag) + self.assertEqual("AuditRecord", list(doc)[0].tag) + self.assertEqual("MeasurementUnitRef", list(doc)[1].tag) + self.assertEqual("mdsol:Query", list(doc)[2].tag) def test_transaction_type(self): tested = self.tested - tested.transaction_type = 'Update' + tested.transaction_type = "Update" doc = obj_to_doc(tested) - self.assertEqual(doc.attrib['TransactionType'], "Update") + self.assertEqual(doc.attrib["TransactionType"], "Update") def test_null_value(self): """Null or empty string values are treated specially with IsNull property and no value""" tested = self.tested - tested.value = '' + tested.value = "" doc = obj_to_doc(tested) - self.assertEqual(doc.attrib['IsNull'], "Yes") + self.assertEqual(doc.attrib["IsNull"], "Yes") # Check Value attribute is also missing def do(): @@ -640,19 +676,26 @@ def do(): def test_invalid_transaction_type(self): def do(): - ItemData("A", "val", transaction_type='invalid') + ItemData("A", "val", transaction_type="invalid") self.assertRaises(AttributeError, do) def test_add_annotations(self): """Test we can add one or more annotations""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] for i in range(0, 4): - self.tested << Annotation(comment=Comment("Some Comment %s" % i), flags=flags) + self.tested << Annotation( + comment=Comment("Some Comment %s" % i), flags=flags + ) t = obj_to_doc(self.tested) self.assertEqual(self.__class__.__name__[4:], t.tag) - self.assertTrue(len(t.getchildren()) == 4) # one formdata + 4 annotations + self.assertTrue(len(list(t)) == 4) # one formdata + 4 annotations class TestUserRef(unittest.TestCase): @@ -662,10 +705,10 @@ def test_accepts_no_children(self): def test_builder(self): """Test building XML""" - tested = UserRef('Fred') + tested = UserRef("Fred") doc = obj_to_doc(tested) - self.assertEqual(doc.attrib['UserOID'], "Fred") + self.assertEqual(doc.attrib["UserOID"], "Fred") self.assertEqual(doc.tag, "UserRef") @@ -676,10 +719,10 @@ def test_accepts_no_children(self): def test_builder(self): """Test building XML""" - tested = LocationRef('Gainesville') + tested = LocationRef("Gainesville") doc = obj_to_doc(tested) - self.assertEqual(doc.attrib['LocationOID'], "Gainesville") + self.assertEqual(doc.attrib["LocationOID"], "Gainesville") self.assertEqual(doc.tag, "LocationRef") def test_builder_int_oid(self): @@ -687,7 +730,7 @@ def test_builder_int_oid(self): tested = LocationRef(12) doc = obj_to_doc(tested) - self.assertEqual(doc.attrib['LocationOID'], "12") + self.assertEqual(doc.attrib["LocationOID"], "12") self.assertEqual(doc.tag, "LocationRef") @@ -728,10 +771,12 @@ def test_builder_with_string(self): class TestAuditRecord(unittest.TestCase): def setUp(self): - self.tested = AuditRecord(edit_point=AuditRecord.EDIT_DATA_MANAGEMENT, - used_imputation_method=False, - identifier='X2011', - include_file_oid=False) + self.tested = AuditRecord( + edit_point=AuditRecord.EDIT_DATA_MANAGEMENT, + used_imputation_method=False, + identifier="X2011", + include_file_oid=False, + ) self.tested << UserRef("Fred") self.tested << LocationRef("Site102") self.tested << ReasonForChange("Data Entry Error") @@ -739,18 +784,18 @@ def setUp(self): def test_identifier_must_not_start_digit(self): with self.assertRaises(AttributeError): - AuditRecord(identifier='2011') + AuditRecord(identifier="2011") with self.assertRaises(AttributeError): - AuditRecord(identifier='*Hello') + AuditRecord(identifier="*Hello") # Underscore OK - ar = AuditRecord(identifier='_Hello') - self.assertEqual('_Hello', ar.audit_id) + ar = AuditRecord(identifier="_Hello") + self.assertEqual("_Hello", ar.audit_id) # Letter OK - ar = AuditRecord(identifier='Hello') - self.assertEqual('Hello', ar.audit_id) + ar = AuditRecord(identifier="Hello") + self.assertEqual("Hello", ar.audit_id) def test_accepts_no_invalid_children(self): with self.assertRaises(ValueError): @@ -758,7 +803,7 @@ def test_accepts_no_invalid_children(self): def test_invalid_edit_point(self): with self.assertRaises(AttributeError): - AuditRecord(edit_point='Blah') + AuditRecord(edit_point="Blah") def test_builder(self): doc = obj_to_doc(self.tested) @@ -766,10 +811,10 @@ def test_builder(self): self.assertEqual(AuditRecord.EDIT_DATA_MANAGEMENT, doc.attrib["EditPoint"]) self.assertEqual("No", doc.attrib["UsedImputationMethod"]) self.assertEqual("No", doc.attrib["mdsol:IncludeFileOID"]) - self.assertEqual("UserRef", doc.getchildren()[0].tag) - self.assertEqual("LocationRef", doc.getchildren()[1].tag) - self.assertEqual("DateTimeStamp", doc.getchildren()[2].tag) - self.assertEqual("ReasonForChange", doc.getchildren()[3].tag) + self.assertEqual("UserRef", list(doc)[0].tag) + self.assertEqual("LocationRef", list(doc)[1].tag) + self.assertEqual("DateTimeStamp", list(doc)[2].tag) + self.assertEqual("ReasonForChange", list(doc)[3].tag) def test_no_user_ref(self): """Test with no user ref should fail on build with a ValueError""" @@ -799,71 +844,78 @@ def test_creates_expected_element(self): t = SignatureRef("ASIGNATURE") doc = obj_to_doc(t) self.assertEqual("SignatureRef", doc.tag) - self.assertEqual("ASIGNATURE", doc.attrib['SignatureOID']) + self.assertEqual("ASIGNATURE", doc.attrib["SignatureOID"]) class TestSignature(unittest.TestCase): def test_creates_expected_element(self): """We create a Signature element""" - t = Signature(signature_id="Some ID", - user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + t = Signature( + signature_id="Some ID", + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) doc = obj_to_doc(t) - self.assertEqual('Signature', doc.tag) - self.assertEqual('Some ID', doc.attrib['ID']) + self.assertEqual("Signature", doc.tag) + self.assertEqual("Some ID", doc.attrib["ID"]) # all four elements are present - self.assertTrue(len(doc.getchildren()) == 4) + self.assertTrue(len(list(doc)) == 4) def test_creates_expected_element_no_id(self): """We create a Signature element without an ID""" - t = Signature(user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + t = Signature( + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) doc = obj_to_doc(t) - self.assertEqual('Signature', doc.tag) - self.assertTrue('ID' not in doc.attrib) + self.assertEqual("Signature", doc.tag) + self.assertTrue("ID" not in doc.attrib) # all four elements are present - self.assertTrue(len(doc.getchildren()) == 4) + self.assertTrue(len(list(doc)) == 4) def test_all_elements_are_required(self): """All the sub-elements are required""" - all = dict(user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + all = dict( + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) t0 = Signature() with self.assertRaises(ValueError) as exc: doc = obj_to_doc(t0) self.assertEqual("User Reference not set.", str(exc.exception)) - t1 = Signature(user_ref=all.get('user_ref')) + t1 = Signature(user_ref=all.get("user_ref")) with self.assertRaises(ValueError) as exc: doc = obj_to_doc(t1) self.assertEqual("Location Reference not set.", str(exc.exception)) - t2 = Signature(user_ref=all.get('user_ref'), location_ref=all.get('location_ref')) + t2 = Signature( + user_ref=all.get("user_ref"), location_ref=all.get("location_ref") + ) with self.assertRaises(ValueError) as exc: doc = obj_to_doc(t2) self.assertEqual("Signature Reference not set.", str(exc.exception)) - t3 = Signature(user_ref=all.get('user_ref'), - location_ref=all.get('location_ref'), - signature_ref=all.get('signature_ref')) + t3 = Signature( + user_ref=all.get("user_ref"), + location_ref=all.get("location_ref"), + signature_ref=all.get("signature_ref"), + ) with self.assertRaises(ValueError) as exc: doc = obj_to_doc(t3) self.assertEqual("DateTime not set.", str(exc.exception)) @@ -871,30 +923,33 @@ def test_all_elements_are_required(self): def test_signature_builder(self): """""" tested = Signature(signature_id="Some ID") - all = dict(user_ref=UserRef(oid="AUser"), - location_ref=LocationRef(oid="ALocation"), - signature_ref=SignatureRef(oid="ASignature"), - date_time_stamp=DateTimeStamp(date_time=datetime(year=2016, - month=12, - day=25, - hour=12, - minute=0, - second=0))) + all = dict( + user_ref=UserRef(oid="AUser"), + location_ref=LocationRef(oid="ALocation"), + signature_ref=SignatureRef(oid="ASignature"), + date_time_stamp=DateTimeStamp( + date_time=datetime( + year=2016, month=12, day=25, hour=12, minute=0, second=0 + ) + ), + ) for child in all.values(): tested << child doc = obj_to_doc(tested) - self.assertEqual('Signature', doc.tag) - self.assertEqual('Some ID', doc.attrib['ID']) + self.assertEqual("Signature", doc.tag) + self.assertEqual("Some ID", doc.attrib["ID"]) # all four elements are present - self.assertTrue(len(doc.getchildren()) == 4) + self.assertTrue(len(list(doc)) == 4) def test_signature_builder_with_invalid_input(self): """""" tested = Signature(signature_id="Some ID") with self.assertRaises(ValueError) as exc: tested << ItemData(itemoid="GENDER", value="MALE") - self.assertEqual("Signature cannot accept a child element of type ItemData", - str(exc.exception)) + self.assertEqual( + "Signature cannot accept a child element of type ItemData", + str(exc.exception), + ) class TestAnnotation(unittest.TestCase): @@ -902,45 +957,50 @@ class TestAnnotation(unittest.TestCase): def test_happy_path(self): """ Simple Annotation with a single flag and comment""" - tested = Annotation(annotation_id="APPLE", - seqnum=1) - f = Flag(flag_value=FlagValue("Some value", codelist_oid="ANOID"), - flag_type=FlagType("Some type", codelist_oid="ANOTHEROID")) + tested = Annotation(annotation_id="APPLE", seqnum=1) + f = Flag( + flag_value=FlagValue("Some value", codelist_oid="ANOID"), + flag_type=FlagType("Some type", codelist_oid="ANOTHEROID"), + ) c = Comment("Some Comment") tested << f tested << c t = obj_to_doc(tested) - self.assertEqual('Annotation', t.tag) - self.assertEqual('1', t.attrib['SeqNum']) - self.assertEqual("APPLE", t.attrib['ID']) - self.assertTrue(len(t.getchildren()) == 2) + self.assertEqual("Annotation", t.tag) + self.assertEqual("1", t.attrib["SeqNum"]) + self.assertEqual("APPLE", t.attrib["ID"]) + self.assertTrue(len(list(t)) == 2) def test_happy_path_id_optional(self): """ Simple Annotation with a single flag and comment, no ID""" tested = Annotation(seqnum=1) - f = Flag(flag_value=FlagValue("Some value", codelist_oid="ANOID"), - flag_type=FlagType("Some type", codelist_oid="ANOTHEROID")) + f = Flag( + flag_value=FlagValue("Some value", codelist_oid="ANOID"), + flag_type=FlagType("Some type", codelist_oid="ANOTHEROID"), + ) c = Comment("Some Comment") tested << f tested << c t = obj_to_doc(tested) - self.assertEqual('Annotation', t.tag) - self.assertEqual('1', t.attrib['SeqNum']) + self.assertEqual("Annotation", t.tag) + self.assertEqual("1", t.attrib["SeqNum"]) self.assertNotIn("ID", t.attrib) - self.assertTrue(len(t.getchildren()) == 2) + self.assertTrue(len(list(t)) == 2) def test_happy_path_seqnum_defaulted(self): """ Simple Annotation with a single flag and comment, SeqNum missing""" tested = Annotation() - f = Flag(flag_value=FlagValue("Some value", codelist_oid="ANOID"), - flag_type=FlagType("Some type", codelist_oid="ANOTHEROID")) + f = Flag( + flag_value=FlagValue("Some value", codelist_oid="ANOID"), + flag_type=FlagType("Some type", codelist_oid="ANOTHEROID"), + ) c = Comment("Some Comment") tested << f tested << c t = obj_to_doc(tested) - self.assertEqual('Annotation', t.tag) - self.assertEqual('1', t.attrib['SeqNum']) - self.assertTrue(len(t.getchildren()) == 2) + self.assertEqual("Annotation", t.tag) + self.assertEqual("1", t.attrib["SeqNum"]) + self.assertTrue(len(list(t)) == 2) def test_happy_path_multiple_flags(self): """ Simple Annotation with a multiple flags and comment""" @@ -948,69 +1008,89 @@ def test_happy_path_multiple_flags(self): c = Comment("Some Comment") # Add some flags for i in range(0, 3): - tested << Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) + tested << Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) tested << c t = obj_to_doc(tested) - self.assertEqual('Annotation', t.tag) - self.assertTrue(len(t.getchildren()) == 4) + self.assertEqual("Annotation", t.tag) + self.assertTrue(len(list(t)) == 4) def test_happy_path_multiple_flags_on_init(self): """ Simple Annotation with a multiple flags and comment created at init""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] tested = Annotation(comment=Comment("Some Comment"), flags=flags) t = obj_to_doc(tested) - self.assertEqual('Annotation', t.tag) - self.assertTrue(len(t.getchildren()) == 4) + self.assertEqual("Annotation", t.tag) + self.assertTrue(len(list(t)) == 4) def test_happy_path_flag_on_init(self): """ Simple Annotation with a single flag and comment created at init""" - flags = [Flag(flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), - flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i)) for i in range(0, 3)] + flags = [ + Flag( + flag_value=FlagValue("Some value %s" % i, codelist_oid="ANOID%s" % i), + flag_type=FlagType("Some type %s" % i, codelist_oid="ANOTHEROID%s" % i), + ) + for i in range(0, 3) + ] tested = Annotation(comment=Comment("Some Comment"), flags=flags[0]) t = obj_to_doc(tested) - self.assertEqual('Annotation', t.tag) - self.assertTrue(len(t.getchildren()) == 2) + self.assertEqual("Annotation", t.tag) + self.assertTrue(len(list(t)) == 2) def test_not_flag_on_init(self): """ Simple Annotation with not a flag raises an exception and comment created at init""" notflags = ItemData(itemoid="GENDER", value="MALE") with self.assertRaises(AttributeError) as exc: tested = Annotation(comment=Comment("Some Comment"), flags=notflags) - self.assertEqual("Flags attribute should be an iterable or Flag", - str(exc.exception)) + self.assertEqual( + "Flags attribute should be an iterable or Flag", str(exc.exception) + ) def test_only_accept_valid_children(self): """ Annotation can only take one or more Flags and one Comment""" - tested = Annotation(annotation_id='An Annotation') + tested = Annotation(annotation_id="An Annotation") with self.assertRaises(ValueError) as exc: tested << ItemData(itemoid="GENDER", value="MALE") - self.assertEqual("Annotation cannot accept a child element of type ItemData", - str(exc.exception)) + self.assertEqual( + "Annotation cannot accept a child element of type ItemData", + str(exc.exception), + ) tested << Comment("A comment") with self.assertRaises(ValueError) as exc: tested << Comment("Another Comment") - self.assertEqual("Annotation already has a Comment element set.", - str(exc.exception)) + self.assertEqual( + "Annotation already has a Comment element set.", str(exc.exception) + ) def test_only_valid_id_accepted(self): """ Annotation ID must be a non empty string""" - for nonsense in ('', ' '): + for nonsense in ("", " "): with self.assertRaises(AttributeError) as exc: tested = Annotation(annotation_id=nonsense) - self.assertEqual("Invalid ID value supplied", - str(exc.exception), - "Value should raise with '%s'" % nonsense) + self.assertEqual( + "Invalid ID value supplied", + str(exc.exception), + "Value should raise with '%s'" % nonsense, + ) def test_only_valid_seqnum_accepted(self): """ Annotation ID must be a non empty string""" - for nonsense in ('apple', ' ', -1): + for nonsense in ("apple", " ", -1): with self.assertRaises(AttributeError) as exc: tested = Annotation(seqnum=nonsense) - self.assertEqual("Invalid SeqNum value supplied", - str(exc.exception), - "Value should raise with '%s'" % nonsense) + self.assertEqual( + "Invalid SeqNum value supplied", + str(exc.exception), + "Value should raise with '%s'" % nonsense, + ) def test_need_flags(self): """ Annotation needs a Flag """ @@ -1021,21 +1101,32 @@ def test_need_flags(self): def test_transaction_type(self): """ Annotation can take a transaction type """ - tested = Annotation(flags=Flag(flag_value=FlagValue("Some value", codelist_oid="ANOID"), - flag_type=FlagType("Some type", codelist_oid="ANOTHEROID")), - comment=Comment("A comment"), transaction_type='Update') + tested = Annotation( + flags=Flag( + flag_value=FlagValue("Some value", codelist_oid="ANOID"), + flag_type=FlagType("Some type", codelist_oid="ANOTHEROID"), + ), + comment=Comment("A comment"), + transaction_type="Update", + ) t = obj_to_doc(tested) self.assertEqual("Annotation", t.tag) - self.assertEqual("Update", t.attrib['TransactionType']) + self.assertEqual("Update", t.attrib["TransactionType"]) class TestAnnotations(unittest.TestCase): def test_happy_path(self): """We create a Annotations object and add annotations to it""" obj = Annotations() - obj << Annotation(annotation_id="1")(Flag()(FlagValue("test 1", codelist_oid="MILESTONE"))) - obj << Annotation(annotation_id="2")(Flag()(FlagValue("test 2", codelist_oid="MILESTONE"))) - obj << Annotation(annotation_id="3")(Flag()(FlagValue("test 3", codelist_oid="MILESTONE"))) + obj << Annotation(annotation_id="1")( + Flag()(FlagValue("test 1", codelist_oid="MILESTONE")) + ) + obj << Annotation(annotation_id="2")( + Flag()(FlagValue("test 2", codelist_oid="MILESTONE")) + ) + obj << Annotation(annotation_id="3")( + Flag()(FlagValue("test 3", codelist_oid="MILESTONE")) + ) tested = obj_to_doc(obj) self.assertEqual("Annotations", tested.tag) self.assertEqual(3, len(list(tested))) @@ -1045,7 +1136,9 @@ def test_sad_path(self): obj = Annotations() with self.assertRaises(ValueError) as exc: obj << Flag()(FlagValue("test 1", codelist_oid="MILESTONE")) - self.assertEqual("Annotations cannot accept a child element of type Flag", str(exc.exception)) + self.assertEqual( + "Annotations cannot accept a child element of type Flag", str(exc.exception) + ) class TestFlag(unittest.TestCase): @@ -1057,8 +1150,8 @@ def test_happy_path(self): tested << FlagValue("Some value", codelist_oid="ANOID") tested << FlagType("Some type", codelist_oid="ANOTHEROID") t = obj_to_doc(tested) - self.assertEqual('Flag', t.tag) - self.assertTrue(len(t.getchildren()) == 2) + self.assertEqual("Flag", t.tag) + self.assertTrue(len(list(t)) == 2) def test_no_value(self): """No FlagValue is an exception""" @@ -1073,19 +1166,22 @@ def test_only_expected_types(self): tested = Flag() with self.assertRaises(ValueError) as exc: tested << ItemData(itemoid="GENDER", value="MALE") - self.assertEqual("Flag cannot accept a child element of type ItemData", - str(exc.exception)) + self.assertEqual( + "Flag cannot accept a child element of type ItemData", str(exc.exception) + ) def test_only_expected_types_instance_vars(self): """We can only add Flag-type elements""" with self.assertRaises(ValueError) as exc: tested = Flag(flag_type=ItemData(itemoid="GENDER", value="MALE")) - self.assertEqual("Flag cannot accept a child element of type ItemData", - str(exc.exception)) + self.assertEqual( + "Flag cannot accept a child element of type ItemData", str(exc.exception) + ) with self.assertRaises(ValueError) as exc: tested = Flag(flag_value=ItemData(itemoid="GENDER", value="MALE")) - self.assertEqual("Flag cannot accept a child element of type ItemData", - str(exc.exception)) + self.assertEqual( + "Flag cannot accept a child element of type ItemData", str(exc.exception) + ) class TestFlagType(unittest.TestCase): @@ -1096,9 +1192,9 @@ def test_happy_path(self): tested = FlagType("A Type") tested.codelist_oid = "ANOID" t = obj_to_doc(tested) - self.assertEqual('FlagType', t.tag) - self.assertEqual('ANOID', t.attrib['CodeListOID']) - self.assertEqual('A Type', t.text) + self.assertEqual("FlagType", t.tag) + self.assertEqual("ANOID", t.attrib["CodeListOID"]) + self.assertEqual("A Type", t.text) def test_no_oid_exception(self): """Create a FlagType object without a CodeListOID is an exception""" @@ -1110,7 +1206,7 @@ def test_no_oid_exception(self): def test_invalid_oid_exception(self): """Assigning a nonsensical value is an error""" tested = FlagType("A Type") - for nonsense in (None, '', ' '): + for nonsense in (None, "", " "): with self.assertRaises(AttributeError) as exc: tested.codelist_oid = nonsense self.assertEqual("Empty CodeListOID value is invalid.", str(exc.exception)) @@ -1118,7 +1214,7 @@ def test_invalid_oid_exception(self): def test_invalid_oid_exception_at_creation(self): """Assigning a nonsensical value is an error""" with self.assertRaises(AttributeError) as exc: - tested = FlagType("A Type", codelist_oid='') + tested = FlagType("A Type", codelist_oid="") self.assertEqual("Empty CodeListOID value is invalid.", str(exc.exception)) @@ -1130,9 +1226,9 @@ def test_happy_path(self): tested = FlagValue("A Value") tested.codelist_oid = "ANOID" t = obj_to_doc(tested) - self.assertEqual('FlagValue', t.tag) - self.assertEqual('ANOID', t.attrib['CodeListOID']) - self.assertEqual('A Value', t.text) + self.assertEqual("FlagValue", t.tag) + self.assertEqual("ANOID", t.attrib["CodeListOID"]) + self.assertEqual("A Value", t.text) def test_no_oid_exception(self): """Create a FlagType object without a CodeListOID is an exception""" @@ -1144,7 +1240,7 @@ def test_no_oid_exception(self): def test_invalid_oid_exception(self): """Assigning a nonsensical value is an error""" tested = FlagValue("A Type") - for nonsense in (None, '', ' '): + for nonsense in (None, "", " "): with self.assertRaises(AttributeError) as exc: tested.codelist_oid = nonsense self.assertEqual("Empty CodeListOID value is invalid.", str(exc.exception)) @@ -1152,7 +1248,7 @@ def test_invalid_oid_exception(self): def test_invalid_oid_exception_at_creation(self): """Assigning a nonsensical value is an error""" with self.assertRaises(AttributeError) as exc: - tested = FlagValue("A Value", codelist_oid='') + tested = FlagValue("A Value", codelist_oid="") self.assertEqual("Empty CodeListOID value is invalid.", str(exc.exception)) @@ -1162,47 +1258,47 @@ class TestComment(unittest.TestCase): def test_happy_path(self): """Creating a valid Comment, no problems""" tested = Comment() - tested.text = 'Some comment' - tested.sponsor_or_site = 'Site' + tested.text = "Some comment" + tested.sponsor_or_site = "Site" t = obj_to_doc(tested) - self.assertEqual('Comment', t.tag) - self.assertEqual('Site', t.attrib['SponsorOrSite']) - self.assertEqual('Some comment', t.text) + self.assertEqual("Comment", t.tag) + self.assertEqual("Site", t.attrib["SponsorOrSite"]) + self.assertEqual("Some comment", t.text) def test_happy_path_no_commenter(self): """Creating a valid Comment without a commenter, no problems""" tested = Comment() - tested.text = 'Some comment' + tested.text = "Some comment" t = obj_to_doc(tested) - self.assertEqual('Comment', t.tag) - self.assertNotIn('SponsorOrSite', t.attrib) - self.assertEqual('Some comment', t.text) + self.assertEqual("Comment", t.tag) + self.assertNotIn("SponsorOrSite", t.attrib) + self.assertEqual("Some comment", t.text) def test_invalid_commenter(self): """Creating a valid Comment with an invalid commenter, get an exception""" tested = Comment() - tested.text = 'Some comment' + tested.text = "Some comment" with self.assertRaises(AttributeError) as exc: - tested.sponsor_or_site = 'Some guy off the street' - self.assertEqual("Comment sponsor_or_site value of Some guy off the street is not valid", - str(exc.exception)) + tested.sponsor_or_site = "Some guy off the street" + self.assertEqual( + "Comment sponsor_or_site value of Some guy off the street is not valid", + str(exc.exception), + ) def test_invalid_no_comment(self): """Creating a invalid Comment, get an exception""" tested = Comment() with self.assertRaises(ValueError) as exc: t = obj_to_doc(tested) - self.assertEqual("Text is not set.", - str(exc.exception)) + self.assertEqual("Text is not set.", str(exc.exception)) def test_invalid_text_comment(self): """Creating a Comment with invalid text, get an exception""" tested = Comment() - for nonsense in (None, '', ' '): + for nonsense in (None, "", " "): with self.assertRaises(AttributeError) as exc: tested.text = nonsense - self.assertEqual("Empty text value is invalid.", - str(exc.exception)) + self.assertEqual("Empty text value is invalid.", str(exc.exception)) class TestSourceID(unittest.TestCase): @@ -1210,8 +1306,8 @@ def test_create_source_id(self): """We can create a source ID""" obj = SourceID("12345") tested = obj_to_doc(obj) - self.assertEqual('SourceID', tested.tag) - self.assertEqual('12345', tested.text) + self.assertEqual("SourceID", tested.tag) + self.assertEqual("12345", tested.text) def test_add_to_audit(self): """We can add a SourceID to an Audit""" @@ -1227,15 +1323,16 @@ def test_add_to_audit(self): class TestSiteRef(unittest.TestCase): - def test_uuid_type(self): """We can define a SiteRef using a UUID""" siteref = SiteRef(oid="E20DEF2D-0CD4-4B3A-B963-AC7D592CB85B") siteref.add_attribute("LocationOIDType", "SiteUUID") tested = obj_to_doc(siteref) self.assertEqual("SiteRef", tested.tag) - self.assertEqual("E20DEF2D-0CD4-4B3A-B963-AC7D592CB85B", tested.get('LocationOID')) - self.assertEqual("SiteUUID", tested.get('mdsol:LocationOIDType')) + self.assertEqual( + "E20DEF2D-0CD4-4B3A-B963-AC7D592CB85B", tested.get("LocationOID") + ) + self.assertEqual("SiteUUID", tested.get("mdsol:LocationOIDType")) def test_uuid_type(self): """We can define a SiteRef using a UUID""" @@ -1243,5 +1340,7 @@ def test_uuid_type(self): siteref.add_attribute("LocationOIDType", "SiteUUID") tested = obj_to_doc(siteref) self.assertEqual("SiteRef", tested.tag) - self.assertEqual("E20DEF2D-0CD4-4B3A-B963-AC7D592CB85B", tested.get('LocationOID')) - self.assertEqual("SiteUUID", tested.get('mdsol:LocationOIDType')) + self.assertEqual( + "E20DEF2D-0CD4-4B3A-B963-AC7D592CB85B", tested.get("LocationOID") + ) + self.assertEqual("SiteUUID", tested.get("mdsol:LocationOIDType")) diff --git a/rwslib/tests/test_builders_metadata.py b/rwslib/tests/test_builders_metadata.py index d5d535f..c642db8 100644 --- a/rwslib/tests/test_builders_metadata.py +++ b/rwslib/tests/test_builders_metadata.py @@ -50,7 +50,7 @@ def test_builder(self): tested = Symbol()(TranslatedText('en', 'Test string')) doc = obj_to_doc(tested) self.assertEqual(doc.tag, "Symbol") - self.assertEqual(doc.getchildren()[0].tag, "TranslatedText") + self.assertEqual(list(doc)[0].tag, "TranslatedText") class TestMeasurementUnits(unittest.TestCase): @@ -81,7 +81,7 @@ def test_builder(self): tested = MeasurementUnit('MU_OID', 'MU_NAME')(Symbol()) doc = obj_to_doc(tested) self.assertEqual(doc.tag, "MeasurementUnit") - self.assertEqual(doc.getchildren()[0].tag, "Symbol") + self.assertEqual(list(doc)[0].tag, "Symbol") class TestBasicDefinitions(unittest.TestCase): @@ -104,7 +104,7 @@ def test_builder(self): tested = BasicDefinitions()(MeasurementUnit("MU_OID", "MUNAME")) doc = obj_to_doc(tested) self.assertEqual(doc.tag, "BasicDefinitions") - self.assertEqual(doc.getchildren()[0].tag, "MeasurementUnit") + self.assertEqual(list(doc)[0].tag, "MeasurementUnit") class TestGlobalVariables(unittest.TestCase): @@ -132,12 +132,12 @@ def test_builder(self): tested = GlobalVariables('project_name', description="A description") doc = obj_to_doc(tested) self.assertEqual(doc.tag, "GlobalVariables") - self.assertEqual(doc.getchildren()[0].tag, "StudyName") - self.assertEqual("project_name", doc.getchildren()[0].text) - self.assertEqual(doc.getchildren()[1].tag, "StudyDescription") - self.assertEqual("A description", doc.getchildren()[1].text) - self.assertEqual(doc.getchildren()[2].tag, "ProtocolName") - self.assertEqual("project_name", doc.getchildren()[2].text) + self.assertEqual(list(doc)[0].tag, "StudyName") + self.assertEqual("project_name", list(doc)[0].text) + self.assertEqual(list(doc)[1].tag, "StudyDescription") + self.assertEqual("A description", list(doc)[1].text) + self.assertEqual(list(doc)[2].tag, "ProtocolName") + self.assertEqual("project_name", list(doc)[2].text) class TestStudyEventRef(unittest.TestCase): @@ -145,6 +145,24 @@ def test_cannot_accept_child(self): with self.assertRaises(ValueError): StudyEventRef("OID", 2, False) << object() + def test_optional_order_number(self): + ser = StudyEventRef("OID") + doc = obj_to_doc(ser) + self.assertIsNone(doc.get('OrderNumber')) + self.assertEquals("No", doc.get('Mandatory')) + + def test_zero_order_number(self): + """Not that it's entirely sensible, but it's cleaner""" + ser = StudyEventRef("OID", order_number=0) + doc = obj_to_doc(ser) + self.assertEquals("0", str(doc.get('OrderNumber'))) + + def test_mandatory_study_event_ref(self): + ser = StudyEventRef("OID", mandatory=True) + doc = obj_to_doc(ser) + self.assertIsNone(doc.get('OrderNumber')) + self.assertEquals("Yes", doc.get('Mandatory')) + class TestProtocol(unittest.TestCase): def test_can_accept_studyeventref_child(self): @@ -160,7 +178,7 @@ def test_builder(self): """XML produced""" doc = obj_to_doc(Protocol()(StudyEventRef("OID", 1, True))) self.assertEqual(doc.tag, "Protocol") - self.assertEqual(doc.getchildren()[0].tag, "StudyEventRef") + self.assertEqual(list(doc)[0].tag, "StudyEventRef") class TestFormRef(unittest.TestCase): @@ -203,7 +221,7 @@ def test_builder(self): self.assertEqual("4", doc.attrib['mdsol:EndWinDays']) self.assertEqual("5", doc.attrib['mdsol:OverDueDays']) self.assertEqual("6", doc.attrib['mdsol:CloseDays']) - self.assertEqual("FormRef", doc.getchildren()[0].tag) + self.assertEqual("FormRef", list(doc)[0].tag) class TestItemGroupRef(unittest.TestCase): @@ -211,6 +229,12 @@ def test_accepts_no_children(self): with self.assertRaises(ValueError): ItemGroupRef("ItemGroup1", 1) << object() + def test_optional_order_number(self): + igr = ItemGroupRef("ItemGroup1") + doc = obj_to_doc(igr) + self.assertEqual("ItemGroup1", doc.attrib['ItemGroupOID']) + self.assertNotIn('OrderNumber', doc.attrib) + def test_builder(self): tested = ItemGroupRef("ItemGroup1", 1, mandatory=True) doc = obj_to_doc(tested) @@ -300,8 +324,8 @@ def test_build(self): self.assertEqual("IMPUTE1", doc.attrib['ImputationMethodOID']) self.assertEqual("AROLE", doc.attrib['Role']) self.assertEqual("ROLEX", doc.attrib['RoleCodeListOID']) - self.assertEqual("mdsol:Attribute", doc.getchildren()[0].tag) - self.assertEqual("mdsol:Attribute", doc.getchildren()[1].tag) + self.assertEqual("mdsol:Attribute", list(doc)[0].tag) + self.assertEqual("mdsol:Attribute", list(doc)[1].tag) class TestQuestion(unittest.TestCase): @@ -317,7 +341,7 @@ def test_build(self): tested = Question()(TranslatedText('How are you feeling?')) doc = obj_to_doc(tested) self.assertEqual(doc.tag, "Question") - self.assertEqual("TranslatedText", doc.getchildren()[0].tag) + self.assertEqual("TranslatedText", list(doc)[0].tag) class TestMeasurementUnitRef(unittest.TestCase): @@ -326,11 +350,10 @@ def test_cannot_accept_child(self): MeasurementUnitRef("KG") << object() def test_build(self): - tested = MeasurementUnitRef("KG", order_number=1) + tested = MeasurementUnitRef("KG") doc = obj_to_doc(tested) self.assertEqual(doc.tag, "MeasurementUnitRef") self.assertEqual("KG", doc.attrib['MeasurementUnitOID']) - self.assertEqual("1", doc.attrib['mdsol:OrderNumber']) class TestCodeListRef(unittest.TestCase): @@ -383,8 +406,8 @@ def test_build(self): self.assertEqual("L_AGE", doc.attrib['OID']) self.assertEqual("Age Label", doc.attrib['Name']) self.assertEqual("4", doc.attrib['FieldNumber']) - self.assertEqual("TranslatedText", doc.getchildren()[0].tag) - self.assertEqual("mdsol:ViewRestriction", doc.getchildren()[1].tag) + self.assertEqual("TranslatedText", list(doc)[0].tag) + self.assertEqual("mdsol:ViewRestriction", list(doc)[1].tag) class TestCheckValue(unittest.TestCase): @@ -433,8 +456,8 @@ def test_build(self): self.assertEqual("RangeCheck", doc.tag) self.assertEqual("Soft", doc.attrib['SoftHard']) self.assertEqual("GE", doc.attrib['Comparator']) - self.assertEqual("CheckValue", doc.getchildren()[0].tag) - self.assertEqual("MeasurementUnitRef", doc.getchildren()[1].tag) + self.assertEqual("CheckValue", list(doc)[0].tag) + self.assertEqual("MeasurementUnitRef", list(doc)[1].tag) class TestMdsolHeaderText(unittest.TestCase): @@ -610,15 +633,15 @@ def test_build(self): self.assertEqual("mmm yy dd", doc.attrib['mdsol:DateTimeFormat']) self.assertEqual("10", doc.attrib['mdsol:FieldNumber']) - self.assertEqual("Question", doc.getchildren()[0].tag) - self.assertEqual("CodeListRef", doc.getchildren()[1].tag) - self.assertEqual("MeasurementUnitRef", doc.getchildren()[2].tag) - self.assertEqual("RangeCheck", doc.getchildren()[3].tag) - self.assertEqual("mdsol:HeaderText", doc.getchildren()[4].tag) - self.assertEqual("mdsol:ViewRestriction", doc.getchildren()[5].tag) - self.assertEqual("mdsol:EntryRestriction", doc.getchildren()[6].tag) - self.assertEqual("mdsol:HelpText", doc.getchildren()[7].tag) - self.assertEqual("mdsol:ReviewGroup", doc.getchildren()[8].tag) + self.assertEqual("Question", list(doc)[0].tag) + self.assertEqual("CodeListRef", list(doc)[1].tag) + self.assertEqual("MeasurementUnitRef", list(doc)[2].tag) + self.assertEqual("RangeCheck", list(doc)[3].tag) + self.assertEqual("mdsol:HeaderText", list(doc)[4].tag) + self.assertEqual("mdsol:ViewRestriction", list(doc)[5].tag) + self.assertEqual("mdsol:EntryRestriction", list(doc)[6].tag) + self.assertEqual("mdsol:HelpText", list(doc)[7].tag) + self.assertEqual("mdsol:ReviewGroup", list(doc)[8].tag) class TestItemGroupDef(unittest.TestCase): @@ -660,8 +683,8 @@ def test_build(self): self.assertEqual("TESTROLE", doc.attrib['Role']) self.assertEqual("TESTPURPOSE", doc.attrib['Purpose']) self.assertEqual("A comment", doc.attrib['Comment']) - self.assertEqual("ItemRef", doc.getchildren()[0].tag) - self.assertEqual("mdsol:LabelRef", doc.getchildren()[1].tag) + self.assertEqual("ItemRef", list(doc)[0].tag) + self.assertEqual("mdsol:LabelRef", list(doc)[1].tag) class TestFormDef(unittest.TestCase): @@ -693,10 +716,10 @@ def test_builder(self): # Would not see LinkFormOID and LinkStudyEventOID together, they are mutually exclusive. Just for coverage. self.assertEqual("FRM1", doc.attrib['mdsol:LinkFormOID']) self.assertEqual("EVT1", doc.attrib['mdsol:LinkStudyEventOID']) - self.assertEqual("ItemGroupRef", doc.getchildren()[0].tag) - self.assertEqual("mdsol:HelpText", doc.getchildren()[1].tag) - self.assertEqual("mdsol:ViewRestriction", doc.getchildren()[2].tag) - self.assertEqual("mdsol:EntryRestriction", doc.getchildren()[3].tag) + self.assertEqual("ItemGroupRef", list(doc)[0].tag) + self.assertEqual("mdsol:HelpText", list(doc)[1].tag) + self.assertEqual("mdsol:ViewRestriction", list(doc)[2].tag) + self.assertEqual("mdsol:EntryRestriction", list(doc)[3].tag) class TestDecode(unittest.TestCase): @@ -716,7 +739,7 @@ def test_builder(self): tested << TranslatedText("Yes") doc = obj_to_doc(tested) self.assertEqual("Decode", doc.tag) - self.assertEqual("TranslatedText", doc.getchildren()[0].tag) + self.assertEqual("TranslatedText", list(doc)[0].tag) class TestCodeListItem(unittest.TestCase): @@ -739,7 +762,7 @@ def test_builder_basic(self): self.assertEqual("", doc.get('mdsol:Specify', '')) self.assertEqual("", doc.get('mdsol:OrderNumber', '')) self.assertEqual("Y", doc.attrib['CodedValue']) - self.assertEqual("Decode", doc.getchildren()[0].tag) + self.assertEqual("Decode", list(doc)[0].tag) def test_builder_order_specify(self): """XML produced with optional params set""" @@ -750,7 +773,7 @@ def test_builder_order_specify(self): self.assertEqual("Yes", doc.attrib['mdsol:Specify']) self.assertEqual("1", doc.attrib['mdsol:OrderNumber']) self.assertEqual("Y", doc.attrib['CodedValue']) - self.assertEqual("Decode", doc.getchildren()[0].tag) + self.assertEqual("Decode", list(doc)[0].tag) class TestCodeList(unittest.TestCase): @@ -778,7 +801,7 @@ def test_builder(self): self.assertEqual("CodeList", doc.tag) self.assertEqual(DataType.String.value, doc.attrib['DataType']) self.assertEqual("YESNO_CL", doc.attrib['SASFormatName']) - self.assertEqual("CodeListItem", doc.getchildren()[0].tag) + self.assertEqual("CodeListItem", list(doc)[0].tag) class TestConfirmationMessage(unittest.TestCase): @@ -917,8 +940,8 @@ def test_build(self): self.assertEqual("CHECK1", doc.attrib['OID']) self.assertEqual("FALSE", doc.attrib['NeedsRetesting']) self.assertEqual("FALSE", doc.attrib['BypassDuringMigration']) - self.assertEqual("mdsol:CheckStep", doc.getchildren()[0].tag) - self.assertEqual("mdsol:CheckAction", doc.getchildren()[1].tag) + self.assertEqual("mdsol:CheckStep", list(doc)[0].tag) + self.assertEqual("mdsol:CheckAction", list(doc)[1].tag) def test_cannot_accept_non_check_or_action_child(self): with self.assertRaises(ValueError): @@ -1050,7 +1073,7 @@ def test_build(self): self.assertEqual("3", doc.attrib['FolderRepeatNumber']) self.assertEqual("MaxBySubject", doc.attrib['LogicalRecordPosition']) - self.assertEqual("mdsol:DerivationStep", doc.getchildren()[0].tag) + self.assertEqual("mdsol:DerivationStep", list(doc)[0].tag) def test_cannot_accept_any_child(self): with self.assertRaises(ValueError): @@ -1145,17 +1168,17 @@ def test_builder(self): self.assertEqual("I confirm.", doc.attrib['mdsol:SignaturePrompt']) self.assertEqual("DM", doc.attrib['mdsol:PrimaryFormOID']) self.assertEqual("Yes", doc.attrib['mdsol:DeleteExisting']) - self.assertEqual("Protocol", doc.getchildren()[0].tag) - self.assertEqual("StudyEventDef", doc.getchildren()[1].tag) - self.assertEqual("FormDef", doc.getchildren()[2].tag) - self.assertEqual("ItemGroupDef", doc.getchildren()[3].tag) - self.assertEqual("ItemDef", doc.getchildren()[4].tag) - self.assertEqual("CodeList", doc.getchildren()[5].tag) - self.assertEqual("mdsol:ConfirmationMessage", doc.getchildren()[6].tag) - self.assertEqual("mdsol:LabelDef", doc.getchildren()[7].tag) - self.assertEqual("mdsol:EditCheckDef", doc.getchildren()[8].tag) - self.assertEqual("mdsol:DerivationDef", doc.getchildren()[9].tag) - self.assertEqual("mdsol:CustomFunctionDef", doc.getchildren()[10].tag) + self.assertEqual("Protocol", list(doc)[0].tag) + self.assertEqual("StudyEventDef", list(doc)[1].tag) + self.assertEqual("FormDef", list(doc)[2].tag) + self.assertEqual("ItemGroupDef", list(doc)[3].tag) + self.assertEqual("ItemDef", list(doc)[4].tag) + self.assertEqual("CodeList", list(doc)[5].tag) + self.assertEqual("mdsol:ConfirmationMessage", list(doc)[6].tag) + self.assertEqual("mdsol:LabelDef", list(doc)[7].tag) + self.assertEqual("mdsol:EditCheckDef", list(doc)[8].tag) + self.assertEqual("mdsol:DerivationDef", list(doc)[9].tag) + self.assertEqual("mdsol:CustomFunctionDef", list(doc)[10].tag) class TestStudy(unittest.TestCase): @@ -1225,9 +1248,9 @@ def test_builder(self): doc = obj_to_doc(tested) self.assertEqual(doc.tag, "Study") self.assertEqual(doc.attrib['mdsol:ProjectType'], "GlobalLibrary Volume") - self.assertEqual(doc.getchildren()[0].tag, "GlobalVariables") - self.assertEqual(doc.getchildren()[1].tag, "BasicDefinitions") - self.assertEqual(doc.getchildren()[2].tag, "MetaDataVersion") + self.assertEqual(list(doc)[0].tag, "GlobalVariables") + self.assertEqual(list(doc)[1].tag, "BasicDefinitions") + self.assertEqual(list(doc)[2].tag, "MetaDataVersion") class TestAlias(unittest.TestCase): @@ -1249,3 +1272,51 @@ def test_add_alias_to_item(self): self.assertEqual('ItemDef', doc.tag) self.assertEqual('Alias', list(doc)[0].tag) + def test_add_alias_to_protocol(self): + """Add an Alias to an Protocol""" + obj = Protocol() + obj << Alias(context="SDTM", name="DM.BRTHDTC") + doc = obj_to_doc(obj) + self.assertEqual('Protocol', doc.tag) + self.assertEqual('Alias', list(doc)[0].tag) + + def test_add_alias_to_studyevent(self): + """Add an Alias to an StudyEventDef""" + obj = StudyEventDef(oid="DM", name="Screening", repeating=False, event_type=StudyEventDef.SCHEDULED) + obj << Alias(context="MAPPING", name="Screening") + doc = obj_to_doc(obj) + self.assertEqual('StudyEventDef', doc.tag) + self.assertEqual('Alias', list(doc)[0].tag) + + def test_add_alias_to_form(self): + """Add an Alias to an FormDef""" + obj = FormDef(oid="DM", name="Demographics", repeating=False) + obj << Alias(context="MAPPING", name="DEMOG") + doc = obj_to_doc(obj) + self.assertEqual('FormDef', doc.tag) + self.assertEqual('Alias', list(doc)[0].tag) + + def test_add_alias_to_itemgroup(self): + """Add an Alias to an ItemGroupDef""" + obj = ItemGroupDef(oid="VS", name="Vitals", repeating=False) + obj << Alias(context="MAPPING", name="VITALS") + doc = obj_to_doc(obj) + self.assertEqual('ItemGroupDef', doc.tag) + self.assertEqual('Alias', list(doc)[0].tag) + + def test_add_alias_to_codelist(self): + """Add an Alias to an CodeList""" + obj = CodeList(oid="VSTEST", name="Vitals Tests", datatype=DataType.String) + obj << Alias(context="MAPPING", name="VITALS") + doc = obj_to_doc(obj) + self.assertEqual('CodeList', doc.tag) + self.assertEqual('Alias', list(doc)[0].tag) + + def test_add_alias_to_codelistitem(self): + """Add an Alias to an CodeListItem""" + obj = CodeListItem(coded_value="SYSBP") + obj << Alias(context="MAPPING", name="Systolic Blood Pressure") + doc = obj_to_doc(obj) + self.assertEqual('CodeListItem', doc.tag) + self.assertEqual('Alias', list(doc)[0].tag) + diff --git a/rwslib/extras/audit_event/test_context.py b/rwslib/tests/test_context.py similarity index 100% rename from rwslib/extras/audit_event/test_context.py rename to rwslib/tests/test_context.py diff --git a/rwslib/extras/test_local_cv.py b/rwslib/tests/test_local_cv.py similarity index 100% rename from rwslib/extras/test_local_cv.py rename to rwslib/tests/test_local_cv.py diff --git a/rwslib/extras/audit_event/test_odmadapter.py b/rwslib/tests/test_odmadapter.py similarity index 100% rename from rwslib/extras/audit_event/test_odmadapter.py rename to rwslib/tests/test_odmadapter.py diff --git a/rwslib/extras/audit_event/test_parser.py b/rwslib/tests/test_parser.py similarity index 89% rename from rwslib/extras/audit_event/test_parser.py rename to rwslib/tests/test_parser.py index e58a4a1..8c7c82d 100644 --- a/rwslib/extras/audit_event/test_parser.py +++ b/rwslib/tests/test_parser.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -__author__ = 'isparks' +__author__ = "isparks" import unittest from rwslib.extras.audit_event import parser @@ -8,21 +8,22 @@ class TestUtils(unittest.TestCase): """Tests of utilities in the parser unit""" + def test_make_int(self): self.assertEqual(-1, parser.make_int(None)) - self.assertEqual(-1, parser.make_int('')) - self.assertEqual(5, parser.make_int('5')) + self.assertEqual(-1, parser.make_int("")) + self.assertEqual(5, parser.make_int("5")) + self.assertEqual(6, parser.make_int(u"6")) with self.assertRaises(ValueError): - self.assertEqual(-1, parser.make_int('five')) + self.assertEqual(-1, parser.make_int("five")) class ParserTestCaseBase(unittest.TestCase): - def setUp(self): - class EventReporter(object): """Parser that will collect data""" + def __init__(self): """We will just collect contexts as they fire from the default""" self.contexts = [] @@ -41,6 +42,10 @@ def context(self): """Return the first context""" return self.contexts[0] if self.contexts else None + def close(self): + self.contexts = [] + return self.subjects_created + self.count = 0 self.eventer = EventReporter() @@ -55,11 +60,11 @@ def parse(self, data): class ParserTestCase(ParserTestCaseBase): - def test_subject_created(self): """Test basics with subject created""" - self.parse(u""" + self.parse( + u""" @@ -72,7 +77,10 @@ def test_subject_created(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -83,7 +91,9 @@ def test_subject_created(self): self.assertEqual("538bdc4d-78b7-4ff9-a59c-3d13c8d8380b", sc.subject.key) self.assertEqual(6434193, sc.audit_record.source_id) self.assertEqual(None, sc.audit_record.reason_for_change) - self.assertEqual(datetime.datetime(2014, 8, 13, 10, 40, 6), sc.audit_record.datetimestamp) + self.assertEqual( + datetime.datetime(2014, 8, 13, 10, 40, 6), sc.audit_record.datetimestamp + ) self.assertEqual("1001", sc.audit_record.location_oid) self.assertEqual("isparks", sc.audit_record.user_oid) @@ -93,7 +103,8 @@ def test_subject_created(self): def test_data_entered(self): """Test data entered with folder refs, reasons for change etc""" - self.parse(u""" + self.parse( + u""" @@ -115,7 +126,10 @@ def test_data_entered(self): -""".encode('ascii')) +""".encode( + "ascii" + ) + ) sc = self.context @@ -134,7 +148,8 @@ def test_data_entered(self): def test_query(self): """Test data entered with queries""" - self.parse(u""" + self.parse( + u""" @@ -157,7 +172,10 @@ def test_query(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -169,7 +187,8 @@ def test_query(self): def test_comment(self): """Test data entered with comment""" - self.parse(""" + self.parse( + """ @@ -192,7 +211,10 @@ def test_comment(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -204,7 +226,8 @@ def test_comment(self): def test_instance_name_changed(self): """ObjectNameChanged subcategory for changes of Instance names""" - self.parse(u""" + self.parse( + u""" @@ -219,7 +242,10 @@ def test_instance_name_changed(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -231,7 +257,8 @@ def test_instance_name_changed(self): def test_datapage_name_changed(self): """ObjectNameChanged subcategory for changes of datapage names""" - self.parse(u""" + self.parse( + u""" @@ -248,7 +275,10 @@ def test_datapage_name_changed(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -259,7 +289,8 @@ def test_datapage_name_changed(self): def test_instance_overdue(self): """When instance overdue date is set""" - self.parse(u""" + self.parse( + u""" @@ -275,7 +306,10 @@ def test_instance_overdue(self): -""".encode('ascii')) +""".encode( + "ascii" + ) + ) sc = self.context @@ -287,7 +321,8 @@ def test_instance_overdue(self): def test_protocol_deviation(self): """Protocol deviation creation""" - self.parse(u""" + self.parse( + u""" @@ -310,13 +345,19 @@ def test_protocol_deviation(self): -""".encode('ascii')) +""".encode( + "ascii" + ) + ) sc = self.context self.assertEqual("CreatePD", sc.subcategory) self.assertEqual("Insert", sc.protocol_deviation.transaction_type) - self.assertEqual("Body Mass Index is out of the prescribed range of LT 20 or GT 30", sc.protocol_deviation.value) + self.assertEqual( + "Body Mass Index is out of the prescribed range of LT 20 or GT 30", + sc.protocol_deviation.value, + ) self.assertEqual("Open", sc.protocol_deviation.status) self.assertEqual("Incl/Excl Criteria not met", sc.protocol_deviation.klass) self.assertEqual(218, sc.protocol_deviation.repeat_key) @@ -324,7 +365,8 @@ def test_protocol_deviation(self): def test_review(self): """Test for reviews""" - self.parse(u""" + self.parse( + u""" @@ -346,7 +388,10 @@ def test_review(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -356,7 +401,8 @@ def test_review(self): def test_verify(self): """Test data verification""" - self.parse(u""" + self.parse( + u""" @@ -377,7 +423,10 @@ def test_verify(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -385,7 +434,8 @@ def test_verify(self): def test_signature(self): """Test signatures""" - self.parse(u""" + self.parse( + u""" @@ -409,7 +459,10 @@ def test_signature(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -417,12 +470,15 @@ def test_signature(self): self.assertEqual("5", sc.signature.oid) self.assertEqual("1001", sc.signature.location_oid) self.assertEqual("mwissner.INV@gmail.com", sc.signature.user_oid) - self.assertEqual(datetime.datetime(2013, 8, 29, 16, 11, 31), sc.signature.datetimestamp) + self.assertEqual( + datetime.datetime(2013, 8, 29, 16, 11, 31), sc.signature.datetimestamp + ) def test_form_datapage_id(self): """Test data entered with folder refs, reasons for change etc""" - self.parse(u""" + self.parse( + u""" @@ -444,7 +500,10 @@ def test_form_datapage_id(self): - """.encode('ascii')) + """.encode( + "ascii" + ) + ) sc = self.context @@ -454,5 +513,6 @@ def test_form_datapage_id(self): self.assertEqual("VISIT", sc.form.oid) self.assertEqual(123, sc.form.datapage_id) -if __name__ == '__main__': + +if __name__ == "__main__": unittest.main() diff --git a/rwslib/tests/test_rwslib.py b/rwslib/tests/test_rwslib.py index 5011092..0b927b8 100644 --- a/rwslib/tests/test_rwslib.py +++ b/rwslib/tests/test_rwslib.py @@ -1,141 +1,157 @@ from mock import mock -__author__ = 'isparks' +__author__ = "isparks" import unittest import rwslib import httpretty import requests -import socket -import errno + # TODO: per the Repository, httpretty is not supporting Python3 - do we need to replace? class TestVersion(unittest.TestCase): """Test for the version method""" + @httpretty.activate def test_version(self): """A simple test, patching the get request so that it does not hit a website""" httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=200, - body="1.0.0") + body="1.0.0", + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual(v, '1.0.0') - self.assertEqual(rave.last_result.status_code,200) + self.assertEqual(v, "1.0.0") + self.assertEqual(rave.last_result.status_code, 200) def test_connection_failure(self): """Test we get a failure if we do not retry""" with mock.patch("requests.sessions.Session.get") as mock_get: mock_get.side_effect = requests.exceptions.ConnectionError() - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(requests.exceptions.ConnectionError) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) """Test with only mdsol sub-domain""" + @httpretty.activate def test_sub_domain(self): """A simple test, patching the get request so that it does not hit a website""" httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=200, - body="1.0.0") + body="1.0.0", + ) - #Now my test - rave = rwslib.RWSConnection('innovate') + # Now my test + rave = rwslib.RWSConnection("innovate") v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual(v, '1.0.0') + self.assertEqual(v, "1.0.0") self.assertEqual(rave.domain, "https://innovate.mdsol.com") - self.assertEqual(rave.last_result.status_code,200) - + self.assertEqual(rave.last_result.status_code, 200) """Test for overriding the virtual directory""" + @httpretty.activate def test_virtual_directory(self): """A simple test, patching the get request so that it does not hit a website""" httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RWS/version", + httpretty.GET, + "https://innovate.mdsol.com/RWS/version", status=200, - body="1.0.0") + body="1.0.0", + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com', virtual_dir='RWS') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com", virtual_dir="RWS") v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual(v, '1.0.0') - self.assertEqual(rave.last_result.status_code,200) + self.assertEqual(v, "1.0.0") + self.assertEqual(rave.last_result.status_code, 200) class TestMustBeRWSRequestSubclass(unittest.TestCase): """Test that request object passed must be RWSRequest subclass""" + def test_basic(self): """Must be rwssubclass or ValueError""" def do(): - rave = rwslib.RWSConnection('test') + rave = rwslib.RWSConnection("test") v = rave.send_request(object()) - self.assertRaises(ValueError, do) class TestRequestTime(unittest.TestCase): """Test for the last request time property""" + @httpretty.activate def test_request_time(self): """A simple test, patching the get request so that it does not hit a website""" httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=200, - body="1.0.0") + body="1.0.0", + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") v = rave.send_request(rwslib.rws_requests.VersionRequest()) request_time = rave.request_time - self.assertIs(type(request_time),float) + self.assertIs(type(request_time), float) -class TestErrorResponse(unittest.TestCase): +class TestErrorResponse(unittest.TestCase): @httpretty.activate def test_503_error(self): """Test that when we don't attempt to XMLParse a non-xml response""" httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=503, - body='HTTP 503 Service Temporarily Unavailable') - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + body="HTTP 503 Service Temporarily Unavailable", + ) + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual('HTTP 503 Service Temporarily Unavailable', exc.exception.rws_error) - self.assertEqual('Unexpected Status Code (503)', str(exc.exception)) + self.assertEqual( + "HTTP 503 Service Temporarily Unavailable", exc.exception.rws_error + ) + self.assertEqual("Unexpected Status Code (503)", str(exc.exception)) @httpretty.activate def test_500_error(self): """Test that when we don't attempt to XMLParse a non-xml response""" httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=500, - body='HTTP 500.13 Web server is too busy.') - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + body="HTTP 500.13 Web server is too busy.", + ) + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual('HTTP 500.13 Web server is too busy.', exc.exception.rws_error) - self.assertEqual('Server Error (500)', str(exc.exception)) + self.assertEqual("HTTP 500.13 Web server is too busy.", exc.exception.rws_error) + self.assertEqual("Server Error (500)", str(exc.exception)) @httpretty.activate def test_400_error_error_response(self): @@ -152,15 +168,17 @@ def test_400_error_error_response(self): """ httpretty.register_uri( - httpretty.POST, "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", + httpretty.POST, + "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", status=400, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.PostDataRequest("")) - self.assertEqual('Subject already exists.', str(exc.exception)) + self.assertEqual("Subject already exists.", str(exc.exception)) @httpretty.activate def test_400_error_iis_error(self): @@ -180,15 +198,17 @@ def test_400_error_iis_error(self): """ httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=400, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual('IIS Error', str(exc.exception)) + self.assertEqual("IIS Error", str(exc.exception)) @httpretty.activate def test_400_error_ODM_error(self): @@ -207,15 +227,19 @@ def test_400_error_ODM_error(self): """ httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=400, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual('Incorrect login and password combination. [RWS00008]', str(exc.exception)) + self.assertEqual( + "Incorrect login and password combination. [RWS00008]", str(exc.exception) + ) @httpretty.activate def test_401_error_error_response_no_header(self): @@ -224,12 +248,14 @@ def test_401_error_error_response_no_header(self): text = u"Authorization Header not provided" httpretty.register_uri( - httpretty.POST, "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", + httpretty.POST, + "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", status=401, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.AuthorizationException) as exc: v = rave.send_request(rwslib.rws_requests.PostDataRequest("")) self.assertEqual(text, str(exc.exception)) @@ -241,12 +267,14 @@ def test_401_error_error_response_unauthorized(self): text = u"

HTTP Error 401.0 - Unauthorized

" httpretty.register_uri( - httpretty.POST, "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", + httpretty.POST, + "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", status=401, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.PostDataRequest("")) self.assertEqual("Unauthorized.", str(exc.exception)) @@ -265,13 +293,15 @@ def test_401_error_error_response_unauthorized_but_wonky(self): """ httpretty.register_uri( - httpretty.POST, "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", + httpretty.POST, + "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", status=401, body=text, - content_type="text/xml") + content_type="text/xml", + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.PostDataRequest("")) self.assertEqual("You shall not pass", str(exc.exception)) @@ -290,12 +320,14 @@ def test_401_error_error_response_unauthorized_without_content_type(self): """ httpretty.register_uri( - httpretty.POST, "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", + httpretty.POST, + "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", status=401, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.PostDataRequest("")) self.assertEqual("You shall not pass", str(exc.exception)) @@ -314,12 +346,14 @@ def test_405_error_error_response_response_object(self): """ httpretty.register_uri( - httpretty.POST, "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", + httpretty.POST, + "https://innovate.mdsol.com/RaveWebServices/webservice.aspx?PostODMClinicalData", status=405, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.PostDataRequest("")) self.assertEqual("You shall not pass", str(exc.exception)) @@ -342,15 +376,19 @@ def test_405_error_ODM_error(self): """ httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=405, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual('Incorrect login and password combination. [RWS00008]', str(exc.exception)) + self.assertEqual( + "Incorrect login and password combination. [RWS00008]", str(exc.exception) + ) @httpretty.activate def test_405_error_iis_error(self): @@ -370,17 +408,18 @@ def test_405_error_iis_error(self): """ httpretty.register_uri( - httpretty.GET, "https://innovate.mdsol.com/RaveWebServices/version", + httpretty.GET, + "https://innovate.mdsol.com/RaveWebServices/version", status=405, - body=text) + body=text, + ) - #Now my test - rave = rwslib.RWSConnection('https://innovate.mdsol.com') + # Now my test + rave = rwslib.RWSConnection("https://innovate.mdsol.com") with self.assertRaises(rwslib.RWSException) as exc: v = rave.send_request(rwslib.rws_requests.VersionRequest()) - self.assertEqual('Unexpected Status Code (405)', str(exc.exception)) + self.assertEqual("Unexpected Status Code (405)", str(exc.exception)) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main() - diff --git a/setup.py b/setup.py index 70d3619..ec521e4 100644 --- a/setup.py +++ b/setup.py @@ -23,8 +23,8 @@ ] rwsinit = open('rwslib/__init__.py').read() -author = re.search("__author__ = '([^']+)'", rwsinit).group(1) -version = re.search("__version__ = '([^']+)'", rwsinit).group(1) +author = re.search("__author__ = \"([^\"]+)\"", rwsinit).group(1) +version = re.search("__version__ = \"([^\"]+)\"", rwsinit).group(1) setup( name='rwslib', @@ -36,15 +36,14 @@ packages=packages, package_dir={'rwslib': 'rwslib'}, include_package_data=True, - install_requires=('requests', + install_requires=['requests', 'lxml', - 'httpretty', 'six', 'click', 'faker', "enum34; python_version < '3.4'", - ), - tests_require=['mock'], + ], + tests_require=['mock', 'httpretty'], license=open('LICENSE.txt').read(), url='https://github.com/mdsol/rwslib/', zip_safe=False, @@ -56,9 +55,9 @@ 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: Implementation :: PyPy', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', ), entry_points=''' [console_scripts] diff --git a/tox.ini b/tox.ini index f9d7794..db84bc2 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ # and then run "tox" from this directory. [tox] -envlist = clean, py27, py35, py36, stats +envlist = clean, py27, py35, py36, py37, stats recreate = true [testenv] @@ -15,6 +15,7 @@ deps= setuptools coverage mock + httpretty [testenv:clean] commands=