class Pagination(PartialSchema): get_total = fields.Boolean( required=False, description="Request the total number of elements" ) page = fields.Int( required=False, description="Current page number", validate=validate.Range(min=1), ) size = fields.Int( required=False, description="Number of elements to retrieve", validate=validate.Range(min=1, max=100), ) sort_order = fields.Str( validate=validate.OneOf(["asc", "desc"]), required=False, missing="asc" ) sort_by = fields.Str(required=False, missing=None) input_filter = fields.Str(required=False, missing=None) @post_load def verify_parameters(self, data, **kwargs): if "get_total" in data: data["page"] = None data["size"] = None else: data.setdefault("get_total", False) data.setdefault("page", 1) data.setdefault("size", 20) return data
def getInputSchema(request: FlaskRequest, is_post: bool) -> Type[Schema]: graph = neo4j.get_instance() # as defined in Marshmallow.schema.from_dict attributes: Dict[str, Union[fields.Field, type]] = {} attributes["name"] = fields.Str(required=True) attributes["age"] = fields.Integer(allow_none=True, validate=validate.Range(min=0)) attributes["sex"] = fields.Str( required=True, validate=validate.OneOf(SEX), metadata={"description": ""} ) attributes["hpo"] = fields.List( fields.Str(), metadata={ "label": "HPO", "autocomplete_endpoint": "/api/hpo", "autocomplete_show_id": True, "autocomplete_id_bind": "hpo_id", "autocomplete_label_bind": "label", }, ) geodata_keys = [] geodata_labels = [] for g in graph.GeoData.nodes.all(): geodata_keys.append(g.uuid) geodata_labels.append(g.province) if len(geodata_keys) == 1: default_geodata = geodata_keys[0] else: default_geodata = None attributes["birth_place"] = fields.Str( required=False, allow_none=True, metadata={ "label": "Birth Place", "description": "", }, dump_default=default_geodata, validate=validate.OneOf(choices=geodata_keys, labels=geodata_labels), ) return Schema.from_dict(attributes, name="PhenotypeDefinition")
class TechmetaPutSchema(Schema): name = fields.Str(required=False) sequencing_date = fields.Date(format=DATE_FORMAT) platform = fields.Str(allow_none=True, validate=validate.OneOf(PLATFORMS)) enrichment_kit = fields.Str() @pre_load def null_platform(self, data: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: if "platform" in data and data["platform"] == "": data["platform"] = None return data
class PhenotypeOutputSchema(Schema): uuid = fields.Str(required=True) name = fields.Str(required=True) age = fields.Integer() sex = fields.Str(required=True, validate=validate.OneOf(SEX)) hpo = fields.List(fields.Nested(Hpo), required=False) birth_place = fields.Nested(GeoData, required=False) relationships = fields.Nested( Relationships, metadata={"description": "family relationships between phenotypes"}, )
def admin_user_input(request: FlaskRequest, is_post: bool) -> Type[Schema]: is_admin = HTTPTokenAuth.is_session_user_admin(request, auth) attributes: MarshmallowSchema = {} if is_post: # This is because Email is not typed on marshmallow attributes["email"] = fields.Email( # type: ignore required=is_post, validate=validate.Length(max=100)) attributes["name"] = fields.Str( required=is_post, validate=validate.Length(min=1), metadata={"label": "First Name"}, ) attributes["surname"] = fields.Str( required=is_post, validate=validate.Length(min=1), metadata={"label": "Last Name"}, ) attributes["password"] = fields.Str( required=is_post, validate=validate.Length(min=auth.MIN_PASSWORD_LENGTH), metadata={"password": True}, ) if Connector.check_availability("smtp"): attributes["email_notification"] = fields.Bool( metadata={"label": "Notify password by email"}) attributes["is_active"] = fields.Bool( dump_default=True, required=False, metadata={"label": "Activate user"}, ) roles = {r.name: r.description for r in auth.get_roles()} if not is_admin and RoleEnum.ADMIN.value in roles: roles.pop(RoleEnum.ADMIN.value) attributes["roles"] = fields.List( fields.Str(validate=validate.OneOf( choices=[r for r in roles.keys()], labels=[r for r in roles.values()], )), dump_default=[auth.default_role], required=False, unique=True, metadata={ "label": "Roles", "description": "", "extra_descriptions": auth.role_descriptions, }, ) group_keys = [] group_labels = [] for g in auth.get_groups(): group_keys.append(g.uuid) group_labels.append(f"{g.shortname} - {g.fullname}") if len(group_keys) == 1: default_group = group_keys[0] else: default_group = None attributes["group"] = fields.Str( required=is_post, dump_default=default_group, validate=validate.OneOf(choices=group_keys, labels=group_labels), metadata={ "label": "Group", "description": "The group to which the user belongs", }, ) attributes["expiration"] = fields.DateTime( required=False, allow_none=True, metadata={ "label": "Account expiration", "description": "This user will be blocked after this date", }, ) if custom_fields := mem.customizer.get_custom_input_fields( request=request, scope=mem.customizer.ADMIN): attributes.update(custom_fields)
class TechmetaInputSchema(Schema): name = fields.Str(required=True) sequencing_date = fields.Date(format=DATE_FORMAT) platform = fields.Str(validate=validate.OneOf(PLATFORMS)) enrichment_kit = fields.Str()
def getInputSchema(request, is_post): # as defined in Marshmallow.schema.from_dict attributes: Dict[str, Union[fields.Field, type]] = {} if is_post: attributes["email"] = fields.Email(required=is_post) attributes["name"] = fields.Str(required=is_post, validate=validate.Length(min=1)) attributes["surname"] = fields.Str(required=is_post, validate=validate.Length(min=1)) attributes["password"] = fields.Str( required=is_post, password=True, validate=validate.Length(min=auth.MIN_PASSWORD_LENGTH), ) if Connector.check_availability("smtp"): attributes["email_notification"] = fields.Bool( label="Notify password by email") attributes["is_active"] = fields.Bool(label="Activate user", default=True, required=False) roles = {r.name: r.description for r in auth.get_roles()} attributes["roles"] = AdvancedList( fields.Str(validate=validate.OneOf( choices=[r for r in roles.keys()], labels=[r for r in roles.values()], )), required=False, label="Roles", description="", unique=True, multiple=True, ) group_keys = [] group_labels = [] for g in auth.get_groups(): group_keys.append(g.uuid) group_labels.append(f"{g.shortname} - {g.fullname}") if len(group_keys) == 1: default_group = group_keys[0] else: default_group = None attributes["group"] = fields.Str( label="Group", description="The group to which the user belongs", required=is_post, default=default_group, validate=validate.OneOf(choices=group_keys, labels=group_labels), ) attributes["expiration"] = fields.DateTime( required=False, allow_none=True, label="Account expiration", description="This user will be blocked after this date", ) if custom_fields := mem.customizer.get_custom_input_fields( request=request, scope=mem.customizer.ADMIN): attributes.update(custom_fields)
def getInputSchema(request: FlaskRequest, is_post: bool) -> Type[Schema]: graph = neo4j.get_instance() # as defined in Marshmallow.schema.from_dict attributes: Dict[str, Union[fields.Field, type]] = {} attributes["name"] = fields.Str(required=is_post) attributes["description"] = fields.Str(required=is_post) if request: if is_post: study_uuid = request.view_args["uuid"] study = graph.Study.nodes.get_or_none(uuid=study_uuid) else: dataset_uuid = request.view_args["uuid"] dataset = graph.Dataset.nodes.get_or_none(uuid=dataset_uuid) study = dataset.parent_study.single() phenotype_keys = [] phenotype_labels = [] for p in study.phenotypes.all(): phenotype_keys.append(p.uuid) phenotype_labels.append(p.name) if len(phenotype_keys) == 1: default_phenotype = phenotype_keys[0] else: default_phenotype = None if not is_post: # add option to remove the technical phenotype_keys.append("-1") phenotype_labels.append(" - ") attributes["phenotype"] = fields.Str( required=False, allow_none=True, dump_default=default_phenotype, validate=validate.OneOf(choices=phenotype_keys, labels=phenotype_labels), ) techmeta_keys = [] techmeta_labels = [] for t in study.technicals.all(): techmeta_keys.append(t.uuid) techmeta_labels.append(t.name) if len(techmeta_keys) == 1: default_techmeta = techmeta_keys[0] else: default_techmeta = None if not is_post: # add option to remove the technical techmeta_keys.append("-1") techmeta_labels.append(" - ") attributes["technical"] = fields.Str( required=False, allow_none=True, dump_default=default_techmeta, validate=validate.OneOf(choices=techmeta_keys, labels=techmeta_labels), ) return Schema.from_dict(attributes, name="DatasetDefinition")
path="/dataset/<uuid>", summary="Modify the status of a dataset", responses={ 200: "Status successfully modified", 400: "Status can't be modified", 404: "This dataset cannot be found or you are not authorized to access", }, ) @decorators.preload(callback=verify_dataset_status_update) @decorators.use_kwargs({ "status": fields.Str(required=True, validate=validate.OneOf(["UPLOAD COMPLETED", "-1"])) }) @decorators.database_transaction def patch( self, uuid: str, study: Any, dataset: Any, status: str, user: User, ) -> Response: # patch can only be done on dataset with status UPLOAD COMPLETED if (dataset.status and dataset.status != "UPLOAD COMPLETED" and not self.auth.is_admin(user)): raise BadRequest(
class InputSchema(Schema): # lowercase key without label defined. label will be key.title() in schema mystr = fields.Str(required=True, validate=validate.Length(min=4)) # non-lowercase key without label defined. label will be == to key in schema MYDATE = fields.Date(required=True) MYDATETIME = fields.AwareDateTime( required=True, format=ISO8601UTC, default_timezone=pytz.utc, validate=validate.Range( max=datetime.now(pytz.utc).replace(hour=23, minute=59, second=59), min=datetime(1900, 1, 1, tzinfo=pytz.utc), max_inclusive=True, error="Invalid date", ), ) myint_exclusive = fields.Int( required=True, # Explicit label definition... but missing description validate=validate.Range( min=1, max=10, min_inclusive=False, max_inclusive=False ), metadata={ "label": "Int exclusive field", }, ) myint_inclusive = fields.Int( required=True, # Both label and description explicit definition validate=validate.Range(min=1, max=10), metadata={ "label": "Int inclusive field", "description": "This field accepts values in a defined range", }, ) myselect = fields.Str( required=True, validate=validate.OneOf(choices=["a", "b"], labels=["A", "B"]), ) myselect2 = fields.Str( required=True, # Wrong definition, number labels < number of choices # Labels will be ignored and replaced by choices validate=validate.OneOf(choices=["a", "b"], labels=["A"]), ) mymaxstr = fields.Str(required=True, validate=validate.Length(max=7)) myequalstr = fields.Str(required=True, validate=validate.Length(equal=6)) # Note: requests (from pytest) has to json-dump the arrays and objects, # but the normal Marshmallow fields does not json-load the inputs # fields.Nested is a replacement of the default Nested field with the ability # to receive json dumped data from requests or pytest mynested = fields.Nested(Nested, required=True) mynullablenested = fields.Nested(Nested, required=True, allow_none=True) # fields.List is a replacement of the default List field with the ability # to receive json dumped data from requests or pytest # In json model the type of this field will be resolved as string[] mylist = fields.List(fields.Str(), required=True) # In json model the type of this field will be resolved as int[] mylist2 = fields.List(CustomInt, required=True) # In json model the type of this field will be resolved as mylist3[] # The type is key[] ... should be something more explicative like FieldName[] mylist3 = fields.List(CustomGenericField, required=True)