def test_schema_match_their_examples(self, schema_path_with_example): schema = Schema.get_schema(schema_path_with_example) validator = Schema.get_validator(schema_path_with_example) examples = schema["examples"] for example in examples: validator.validate_all(example)
class CreateGroupMembership(JSONAPIData): """The data to add a user to a group.""" validator = Schema.get_validator( "bulk_api/command/create_group_membership.json") @classmethod def create(cls, user_ref, group_ref): # pylint: disable=arguments-differ """Create a create group membership body for adding users to groups. :param user_ref: Custom user reference :param group_ref: Custom group reference :return: A CreateGroupMembership instance """ return super().create( DataType.GROUP_MEMBERSHIP, relationships={ "member": { "data": { "type": DataType.USER.value, "id": { "$ref": user_ref } } }, "group": { "data": { "type": DataType.GROUP.value, "id": { "$ref": group_ref } } }, }, ) @property def member(self): """Get the user which is a member of this group. :return: A value object with `id` and `ref` properties. """ return _IdRef(self.relationships["member"]["data"]["id"]) @property def group(self): """Get the group which this user is a member of. :return: A value object with `id` and `ref` properties. """ return _IdRef(self.relationships["group"]["data"]["id"])
def schema_with_examples(): for file_name in schema_file_names(): schema = Schema.get_schema(file_name) if "examples" in schema: yield file_name defs = schema.get("$defs") if not defs: continue for key, sub_schema in defs.items(): if "examples" in sub_schema: yield f"{file_name}#/$defs/{key}"
class Command(Model): """A single abstract command provided to the API.""" validator = Schema.get_validator("bulk_api/wrapper.json") validation_error_title = "Cannot interpret command as the wrapper is malformed" def validate(self): # pylint: disable=arguments-differ """Validate this object and it's body meet their declared schema.""" super().validate() if isinstance(self.body, Model): self.body.validate() @classmethod def create(cls, type_, body): """Create a command. :param type_: The CommandType of the command :param body: The payload for the command :return: An instance of Command """ return cls([CommandType(type_).value, cls.extract_raw(body)]) @property def type(self): """Get the command type. :return: The CommandType of this command """ return CommandType(self.raw[0]) @property def body(self): """Get the body of this command. :return: The raw body """ return self.raw[1] def __repr__(self): return f"<{self.__class__.__name__} {self.body}>"
class UpsertGroup(UpsertBody): """The data to upsert a group.""" validator = Schema.get_validator("bulk_api/command/upsert_group.json") data_type = DataType.GROUP query_fields = ["authority", "authority_provided_id"]
class UpsertUser(UpsertBody): """The data to upsert a user.""" validator = Schema.get_validator("bulk_api/command/upsert_user.json") data_type = DataType.USER query_fields = ["authority", "username"]
def test_schema_is_a_valid_schema(self, schema_path): schema = Schema.get_schema(schema_path) Draft7Validator.check_schema(schema)
def get_schema_example(schema_path): return deepcopy(Schema.get_schema(schema_path)["examples"][0])
class Configuration(Model): """Configuration settings for a Bulk API request.""" validator = Schema.get_validator("bulk_api/command/configuration.json") WILD_CARD = "*" @classmethod def create(cls, effective_user, total_instructions, view=None): """Create a configuration object. :param effective_user: User to execute the command as :param total_instructions: Number of instructions (including this) :param view: Return style requested by the client :return: A Configuration object """ return cls({ "view": ViewType(view).value, "user": { "effective": effective_user }, "instructions": { "total": int(total_instructions) }, "defaults": [ ["create", "*", { "on_duplicate": "continue" }], ["upsert", "*", { "merge_query": True }], ], }) @property def view(self): """Get the return type of view requested by the user.""" return ViewType(self.raw["view"]) @property def effective_user(self): """Get the user to execute the request as.""" return self.raw["user"]["effective"] @property def total_instructions(self): """Get the number of instructions in the request. This count includes configuration commands. """ return self.raw["instructions"]["total"] def defaults_for(self, command_type, data_type): """Provide default configuration for the given command and data type. This will use any wild card options first, overlaying more specific defaults as they are found. :param command_type: Type of modification (e.g. Types.UPSERT) :param data_type: Data type being modified :return: A dict of config """ defaults = self._command_defaults config = {} wild = defaults.get(self.WILD_CARD, {}) specific = defaults.get(CommandType(command_type), {}) data_type = DataType(data_type) for container in (wild, specific): if self.WILD_CARD in container: config.update(container[self.WILD_CARD]) if data_type in container: config.update(container[data_type]) return config @property @lru_cache(1) def _command_defaults(self): config = defaultdict(dict) for command_type, data_type, defaults in self.raw["defaults"]: if command_type != self.WILD_CARD: command_type = CommandType(command_type) if data_type != self.WILD_CARD: data_type = DataType(data_type) config[command_type][data_type] = defaults return config