info¶
Infodict models!!
Each of the flavors of infodict have a version intended to validate
and represent already-created torrent files,
and a Create version used while creating torrents!
- pydantic model InfoDictRoot[source]¶
Fields shared by v1 and v2 infodicts
Show JSON schema
{ "title": "InfoDictRoot", "description": "Fields shared by v1 and v2 infodicts", "type": "object", "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Name" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" } }, "additionalProperties": true }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
keys_as_strings»all fields
- field name: Annotated[str, PlainSerializer(func=_to_bytes, return_type=PydanticUndefined, when_used=always)] | None = None¶
- Validated by:
- field source: Annotated[str, PlainSerializer(func=_to_bytes, return_type=PydanticUndefined, when_used=always)] | None = None¶
- Validated by:
- validator keys_as_strings » all fields[source]¶
bencoded data comes as bytes, if we are trying to create directly from a bytestring dict, decode to strings first
- pydantic model InfoDictV1Base[source]¶
Show JSON schema
{ "title": "InfoDictV1Base", "type": "object", "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Name" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "pieces": { "anyOf": [ { "items": { "format": "binary", "maxLength": 20, "minLength": 20, "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "title": "Pieces" }, "length": { "anyOf": [ { "minimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "title": "Length" }, "files": { "anyOf": [ { "items": { "$ref": "#/$defs/FileItem" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "title": "Files" }, "piece length": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Piece Length" } }, "$defs": { "FileItem": { "additionalProperties": true, "properties": { "length": { "minimum": 0, "title": "Length", "type": "integer" }, "path": { "items": { "type": "string" }, "title": "Path", "type": "array" }, "attr": { "anyOf": [ { "format": "binary", "type": "string" }, { "type": "null" } ], "default": null, "title": "Attr" } }, "required": [ "length", "path" ], "title": "FileItem", "type": "object" } }, "additionalProperties": true, "required": [ "piece length" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
disallowed_fields»all fieldsexpected_n_pieces»all fieldspadfile_alignment»all fields
- field piece_length: Annotated[int, AfterValidator(func=_power_of_two)] | None [Required] (alias 'piece length')¶
- Validated by:
- field pieces: Annotated[list[Annotated[bytes, Len(min_length=20, max_length=20), PlainSerializer(func=_serialize_hash, return_type=PydanticUndefined, when_used=always)]], BeforeValidator(func=_validate_pieces, json_schema_input_type=PydanticUndefined), PlainSerializer(func=_serialize_pieces, return_type=PydanticUndefined, when_used=always)] | None = None¶
- Validated by:
- validator disallowed_fields » all fields[source]¶
We allow extra fields, but not those in v2 infodicts, in order to make them discriminable
- validator expected_n_pieces » all fields[source]¶
We have the expected number of pieces given the sizes implied by our file dict
- model_post_init(context: Any, /) None¶
This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- Parameters:
self – The BaseModel instance.
context – The context.
- validator padfile_alignment » all fields[source]¶
If padfiles are present in the files list, the sum of a file and its padfile’s sizes must be a multiple of the piece size.
Note
V1-only vs hybrid differences
Some clients do not pad every non-aligned file in v1-only torrents, which defeats the purpose of padding, but it happens. The default behavior for v1-only is to ignore padfile validation. To ensure global padding for v1-only torrents, use pydantic’s strict validation mode, or pass context = {“padding”: “strict”}.
Hybrid torrents must have their v1 files list padded, and the padding must be globally correct.
Note
Possible Validation Variations
The behavior of this validator can be changed by passing padding to the context argument of model_validate - See
ValidationContext
- pydantic model InfoDictV1[source]¶
An infodict from a valid V1 torrent
Show JSON schema
{ "title": "InfoDictV1", "description": "An infodict from a valid V1 torrent", "type": "object", "properties": { "name": { "title": "Name", "type": "string" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "pieces": { "items": { "format": "binary", "maxLength": 20, "minLength": 20, "type": "string" }, "title": "Pieces", "type": "array" }, "length": { "anyOf": [ { "minimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "title": "Length" }, "files": { "anyOf": [ { "items": { "$ref": "#/$defs/FileItem" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "title": "Files" }, "piece length": { "title": "Piece Length", "type": "integer" } }, "$defs": { "FileItem": { "additionalProperties": true, "properties": { "length": { "minimum": 0, "title": "Length", "type": "integer" }, "path": { "items": { "type": "string" }, "title": "Path", "type": "array" }, "attr": { "anyOf": [ { "format": "binary", "type": "string" }, { "type": "null" } ], "default": null, "title": "Attr" } }, "required": [ "length", "path" ], "title": "FileItem", "type": "object" } }, "additionalProperties": true, "required": [ "name", "pieces", "piece length" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
length_xor_files»all fields
- field name: Annotated[str, PlainSerializer(func=_to_bytes, return_type=PydanticUndefined, when_used=always)] [Required]¶
- Constraints:
func = <function _to_bytes at 0x70dff2da7380>
return_type = PydanticUndefined
when_used = always
- Validated by:
- field piece_length: Annotated[int, AfterValidator(func=_power_of_two)] [Required] (alias 'piece length')¶
- Constraints:
func = <function _power_of_two at 0x70dff2da7600>
- Validated by:
- field pieces: Annotated[list[Annotated[bytes, Len(min_length=20, max_length=20), PlainSerializer(func=_serialize_hash, return_type=PydanticUndefined, when_used=always)]], BeforeValidator(func=_validate_pieces, json_schema_input_type=PydanticUndefined), PlainSerializer(func=_serialize_pieces, return_type=PydanticUndefined, when_used=always)] [Required]¶
- Constraints:
func = <function _serialize_pieces at 0x70dff2da7ba0>
json_schema_input_type = PydanticUndefined
return_type = PydanticUndefined
when_used = always
- Validated by:
- pydantic model InfoDictV1Create[source]¶
v1 Infodict that may or may not have its pieces hashed yet
Show JSON schema
{ "title": "InfoDictV1Create", "description": "v1 Infodict that may or may not have its pieces hashed yet", "type": "object", "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Name" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "pieces": { "anyOf": [ { "items": { "format": "binary", "maxLength": 20, "minLength": 20, "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "title": "Pieces" }, "length": { "anyOf": [ { "minimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "title": "Length" }, "files": { "anyOf": [ { "items": { "$ref": "#/$defs/FileItem" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "title": "Files" }, "piece length": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Piece Length" } }, "$defs": { "FileItem": { "additionalProperties": true, "properties": { "length": { "minimum": 0, "title": "Length", "type": "integer" }, "path": { "items": { "type": "string" }, "title": "Path", "type": "array" }, "attr": { "anyOf": [ { "format": "binary", "type": "string" }, { "type": "null" } ], "default": null, "title": "Attr" } }, "required": [ "length", "path" ], "title": "FileItem", "type": "object" } }, "additionalProperties": true, "required": [ "piece length" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
- pydantic model InfoDictV2Base[source]¶
Show JSON schema
{ "title": "InfoDictV2Base", "type": "object", "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Name" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "meta version": { "default": 2, "title": "Meta Version", "type": "integer" }, "file tree": { "anyOf": [ { "$ref": "#/$defs/_FileTreeType" }, { "type": "null" } ], "default": null }, "piece length": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Piece Length" } }, "$defs": { "FileTreeItem": { "properties": { "length": { "title": "Length", "type": "integer" }, "pieces root": { "format": "binary", "maxLength": 32, "minLength": 32, "title": "Pieces Root", "type": "string" } }, "required": [ "length" ], "title": "FileTreeItem", "type": "object" }, "_FileTreeType": { "additionalProperties": { "anyOf": [ { "additionalProperties": { "$ref": "#/$defs/FileTreeItem" }, "propertyNames": { "const": "" }, "type": "object" }, { "$ref": "#/$defs/_FileTreeType" } ] }, "propertyNames": { "format": "binary" }, "type": "object" } }, "additionalProperties": true, "required": [ "piece length" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
disallowed_fields»all fields
- field file_tree: Annotated[_FileTreeType, AfterValidator(func=_sort_keys)] | None = None (alias 'file tree')¶
- Validated by:
- field piece_length: Annotated[int, AfterValidator(func=_divisible_by_16kib), AfterValidator(func=_power_of_two)] | None [Required] (alias 'piece length')¶
- Validated by:
- validator disallowed_fields » all fields[source]¶
We allow extra fields, but not those in v1 infodicts, in order to make them discriminable
- model_post_init(context: Any, /) None¶
This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- Parameters:
self – The BaseModel instance.
context – The context.
- property flat_tree: dict[str, FileTreeItem]¶
Flattened file tree! mapping full paths to tree items
- pydantic model InfoDictV2[source]¶
An infodict from a valid V2 torrent
Show JSON schema
{ "title": "InfoDictV2", "description": "An infodict from a valid V2 torrent", "type": "object", "properties": { "name": { "title": "Name", "type": "string" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "meta version": { "default": 2, "title": "Meta Version", "type": "integer" }, "file tree": { "$ref": "#/$defs/_FileTreeType" }, "piece length": { "title": "Piece Length", "type": "integer" } }, "$defs": { "FileTreeItem": { "properties": { "length": { "title": "Length", "type": "integer" }, "pieces root": { "format": "binary", "maxLength": 32, "minLength": 32, "title": "Pieces Root", "type": "string" } }, "required": [ "length" ], "title": "FileTreeItem", "type": "object" }, "_FileTreeType": { "additionalProperties": { "anyOf": [ { "additionalProperties": { "$ref": "#/$defs/FileTreeItem" }, "propertyNames": { "const": "" }, "type": "object" }, { "$ref": "#/$defs/_FileTreeType" } ] }, "propertyNames": { "format": "binary" }, "type": "object" } }, "additionalProperties": true, "required": [ "name", "file tree", "piece length" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
- field file_tree: Annotated[_FileTreeType, AfterValidator(func=_sort_keys)] [Required] (alias 'file tree')¶
- Constraints:
func = <function _sort_keys at 0x70dff2db4220>
- Validated by:
- field name: Annotated[str, PlainSerializer(func=_to_bytes, return_type=PydanticUndefined, when_used=always)] [Required]¶
- Constraints:
func = <function _to_bytes at 0x70dff2da7380>
return_type = PydanticUndefined
when_used = always
- Validated by:
- field piece_length: Annotated[int, AfterValidator(func=_divisible_by_16kib), AfterValidator(func=_power_of_two)] [Required] (alias 'piece length')¶
- Constraints:
func = <function _power_of_two at 0x70dff2da7600>
- Validated by:
- pydantic model InfoDictV2Create[source]¶
Show JSON schema
{ "title": "InfoDictV2Create", "type": "object", "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Name" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "meta version": { "default": 2, "title": "Meta Version", "type": "integer" }, "file tree": { "anyOf": [ { "$ref": "#/$defs/_FileTreeType" }, { "type": "null" } ], "default": null }, "piece length": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Piece Length" } }, "$defs": { "FileTreeItem": { "properties": { "length": { "title": "Length", "type": "integer" }, "pieces root": { "format": "binary", "maxLength": 32, "minLength": 32, "title": "Pieces Root", "type": "string" } }, "required": [ "length" ], "title": "FileTreeItem", "type": "object" }, "_FileTreeType": { "additionalProperties": { "anyOf": [ { "additionalProperties": { "$ref": "#/$defs/FileTreeItem" }, "propertyNames": { "const": "" }, "type": "object" }, { "$ref": "#/$defs/_FileTreeType" } ] }, "propertyNames": { "format": "binary" }, "type": "object" } }, "additionalProperties": true, "required": [ "piece length" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
- pydantic model InfoDictHybridCreate[source]¶
An infodict of a hybrid torrent that may or may not have its pieces hashed yet
Show JSON schema
{ "title": "InfoDictHybridCreate", "description": "An infodict of a hybrid torrent that may or may not have its pieces hashed yet", "type": "object", "properties": { "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Name" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "meta version": { "default": 2, "title": "Meta Version", "type": "integer" }, "file tree": { "anyOf": [ { "$ref": "#/$defs/_FileTreeType" }, { "type": "null" } ], "default": null }, "piece length": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Piece Length" }, "pieces": { "anyOf": [ { "items": { "format": "binary", "maxLength": 20, "minLength": 20, "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "title": "Pieces" }, "length": { "anyOf": [ { "minimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "title": "Length" }, "files": { "anyOf": [ { "items": { "$ref": "#/$defs/FileItem" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "title": "Files" } }, "$defs": { "FileItem": { "additionalProperties": true, "properties": { "length": { "minimum": 0, "title": "Length", "type": "integer" }, "path": { "items": { "type": "string" }, "title": "Path", "type": "array" }, "attr": { "anyOf": [ { "format": "binary", "type": "string" }, { "type": "null" } ], "default": null, "title": "Attr" } }, "required": [ "length", "path" ], "title": "FileItem", "type": "object" }, "FileTreeItem": { "properties": { "length": { "title": "Length", "type": "integer" }, "pieces root": { "format": "binary", "maxLength": 32, "minLength": 32, "title": "Pieces Root", "type": "string" } }, "required": [ "length" ], "title": "FileTreeItem", "type": "object" }, "_FileTreeType": { "additionalProperties": { "anyOf": [ { "additionalProperties": { "$ref": "#/$defs/FileTreeItem" }, "propertyNames": { "const": "" }, "type": "object" }, { "$ref": "#/$defs/_FileTreeType" } ] }, "propertyNames": { "format": "binary" }, "type": "object" } }, "additionalProperties": true }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
disallowed_fields»all fields
- field name: Annotated[str, PlainSerializer(func=_to_bytes, return_type=PydanticUndefined, when_used=always)] | None = None¶
- Validated by:
- field piece_length: Annotated[int, AfterValidator(func=_power_of_two)] | Annotated[int, AfterValidator(func=_divisible_by_16kib), AfterValidator(func=_power_of_two)] | None = None (alias 'piece length')¶
- Validated by:
- pydantic model InfoDictHybrid[source]¶
An infodict of a valid v1/v2 hybrid torrent
Show JSON schema
{ "title": "InfoDictHybrid", "description": "An infodict of a valid v1/v2 hybrid torrent", "type": "object", "properties": { "name": { "title": "Name", "type": "string" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "title": "Source" }, "pieces": { "items": { "format": "binary", "maxLength": 20, "minLength": 20, "type": "string" }, "title": "Pieces", "type": "array" }, "length": { "anyOf": [ { "minimum": 0, "type": "integer" }, { "type": "null" } ], "default": null, "title": "Length" }, "files": { "anyOf": [ { "items": { "$ref": "#/$defs/FileItem" }, "minItems": 1, "type": "array" }, { "type": "null" } ], "default": null, "title": "Files" }, "piece length": { "title": "Piece Length", "type": "integer" }, "meta version": { "default": 2, "title": "Meta Version", "type": "integer" }, "file tree": { "$ref": "#/$defs/_FileTreeType" } }, "$defs": { "FileItem": { "additionalProperties": true, "properties": { "length": { "minimum": 0, "title": "Length", "type": "integer" }, "path": { "items": { "type": "string" }, "title": "Path", "type": "array" }, "attr": { "anyOf": [ { "format": "binary", "type": "string" }, { "type": "null" } ], "default": null, "title": "Attr" } }, "required": [ "length", "path" ], "title": "FileItem", "type": "object" }, "FileTreeItem": { "properties": { "length": { "title": "Length", "type": "integer" }, "pieces root": { "format": "binary", "maxLength": 32, "minLength": 32, "title": "Pieces Root", "type": "string" } }, "required": [ "length" ], "title": "FileTreeItem", "type": "object" }, "_FileTreeType": { "additionalProperties": { "anyOf": [ { "additionalProperties": { "$ref": "#/$defs/FileTreeItem" }, "propertyNames": { "const": "" }, "type": "object" }, { "$ref": "#/$defs/_FileTreeType" } ] }, "propertyNames": { "format": "binary" }, "type": "object" } }, "additionalProperties": true, "required": [ "name", "pieces", "piece length", "file tree" ] }
- Config:
populate_by_name: bool = True
extra: str = allow
validate_by_alias: bool = True
validate_by_name: bool = True
- Fields:
- Validators:
disallowed_fields»all fieldsexpected_n_pieces»all fieldsv1_v2_files_match»all fields
- field piece_length: Annotated[int, AfterValidator(func=_divisible_by_16kib), AfterValidator(func=_power_of_two)] [Required] (alias 'piece length')¶
- Constraints:
func = <function _power_of_two at 0x70dff2da7600>
- Validated by:
- validator expected_n_pieces » all fields[source]¶
We have the expected number of pieces given the sizes implied by our file dict.
Overrides the v1 to account for expected padding in hybrids
- model_post_init(context: Any, /) None¶
This function is meant to behave like a BaseModel method to initialise private attributes.
It takes context as an argument since that’s what pydantic-core passes when calling it.
- Parameters:
self – The BaseModel instance.
context – The context.
- validator v1_v2_files_match » all fields[source]¶
From BEP 052:
> … the ‘pieces’ field and ‘files’ or ‘length’ in the info dictionary > must be generated to describe the same data in the same order. > … Before doing so they must validate that the content > (file names, order, piece alignment) is identical.
file names, sizes, and order must match (ignoring padfiles).
- infodict_discriminator(v: Any) str | None[source]¶
Discriminator function to use when detecting torrent version, and thus which infodict model to validate against.
Use this instead of standard union discrimination for clearer error messages- if there is a validation error in the infodict, since all infodict types will have been tried, trivial errors from the two invalid infodict models will also be shown.
References
https://docs.pydantic.dev/latest/concepts/unions/#discriminated-unions-with-callable-discriminator