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!

digraph inheritancee41c9c23a4 { bgcolor=transparent; rankdir=LR; size="8.0, 12.0"; "torrent_models.info.InfoDictHybrid" [URL="#torrent_models.info.InfoDictHybrid",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="An infodict of a valid v1/v2 hybrid torrent"]; "torrent_models.info.InfoDictV2" -> "torrent_models.info.InfoDictHybrid" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV1" -> "torrent_models.info.InfoDictHybrid" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictHybridCreate" [URL="#torrent_models.info.InfoDictHybridCreate",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="An infodict of a hybrid torrent that may or may not have its pieces hashed yet"]; "torrent_models.info.InfoDictV1Create" -> "torrent_models.info.InfoDictHybridCreate" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV2Create" -> "torrent_models.info.InfoDictHybridCreate" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictRoot" [URL="#torrent_models.info.InfoDictRoot",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="Fields shared by v1 and v2 infodicts"]; "torrent_models.info.InfoDictV1" [URL="#torrent_models.info.InfoDictV1",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="An infodict from a valid V1 torrent"]; "torrent_models.info.InfoDictV1Base" -> "torrent_models.info.InfoDictV1" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV1Base" [URL="#torrent_models.info.InfoDictV1Base",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "torrent_models.info.InfoDictRoot" -> "torrent_models.info.InfoDictV1Base" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV1Create" [URL="#torrent_models.info.InfoDictV1Create",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="v1 Infodict that may or may not have its pieces hashed yet"]; "torrent_models.info.InfoDictV1Base" -> "torrent_models.info.InfoDictV1Create" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV2" [URL="#torrent_models.info.InfoDictV2",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top",tooltip="An infodict from a valid V2 torrent"]; "torrent_models.info.InfoDictV2Base" -> "torrent_models.info.InfoDictV2" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV2Base" [URL="#torrent_models.info.InfoDictV2Base",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "torrent_models.info.InfoDictRoot" -> "torrent_models.info.InfoDictV2Base" [arrowsize=0.5,style="setlinewidth(0.5)"]; "torrent_models.info.InfoDictV2Create" [URL="#torrent_models.info.InfoDictV2Create",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=10,height=0.25,shape=box,style="setlinewidth(0.5),filled",target="_top"]; "torrent_models.info.InfoDictV2Base" -> "torrent_models.info.InfoDictV2Create" [arrowsize=0.5,style="setlinewidth(0.5)"]; }
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:
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

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 v1_infohash: str | None
property v2_infohash: str | None
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:
field files: Annotated[list[FileItem], MinLen(min_length=1)] | None = None
Validated by:
field length: Annotated[int, Ge(ge=0)] | None = None
Validated by:
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

property total_length: int

Total length of all files, in bytes

property v1_infohash: str

hex-encoded SHA-1 hash of the infodict

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:
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:
validator length_xor_files  »  all fields[source]

There is also a key length or a key files, but not both or neither. If length is present then the download represents a single file, otherwise it represents a set of files which go in a directory structure.

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.

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:

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.

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:
field file_tree: Annotated[_FileTreeType, AfterValidator(func=_sort_keys)] | None = None (alias 'file tree')
Validated by:
field meta_version: int = 2 (alias 'meta version')
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

property total_length: int

Total length of all files, in bytes.

property v2_infohash: str

hex-encoded SHA-256 hash of the infodict

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:
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.

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:

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.

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:
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:
validator disallowed_fields  »  all fields[source]

hybrids can have any additional fields

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.

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:
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 disallowed_fields  »  all fields[source]

hybrids can have any additional fields

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