class_docstr: Store a sequence of fields, reading multipart/form-data.
  
  This class provides naming, typing, files stored on disk, and
  more.  At the top level, it is accessible like a dictionary, whose
  keys are the field names.  (Note: None can occur as a field name.)
  The items are either a Python list (if there's multiple values) or
  another FieldStorage or MiniFieldStorage object.  If it's a single
  object, it has the following attributes:
  
  name: the field name, if specified; otherwise None
  
  filename: the filename, if specified; otherwise None; this is the
      client side filename, *not* the file name on which it is
      stored (that's a temporary file you don't deal with)
  
  value: the value as a *string*; for file uploads, this
      transparently reads the file every time you request the value
      and returns *bytes*
  
  file: the file(-like) object from which you can read the data *as
      bytes* ; None if the data is stored a simple string
  
  type: the content-type, or None if not specified
  
  type_options: dictionary of options specified on the content-type
      line
  
  disposition: content-disposition, or None if not specified
  
  disposition_options: dictionary of corresponding options
  
  headers: a dictionary(-like) object (sometimes email.message.Message or a
      subclass thereof) containing *all* headers
  
  The class is subclassable, mostly for the purpose of overriding
  the make_file() method, which is called internally to come up with
  a file open for reading and writing.  This makes it possible to
  override the default choice of storing all files in a temporary
  directory and unlinking them as soon as they have been opened.
class_docstr_tok: ["Store","a","sequence","of","fields",",","reading","multipart\/form-data",".","This","class","provides","naming",",","typing",",","files","stored","on","disk",",","and","more",".","At","the","top","level",",","it","is","accessible","like","a","dictionary",",","whose","keys","are","the","field","names",".","(","Note",":","None","can","occur","as","a","field","name",".",")","The","items","are","either","a","Python","list","(","if","there","'s","multiple","values",")","or","another","FieldStorage","or","MiniFieldStorage","object",".","If","it","'s","a","single","object",",","it","has","the","following","attributes",":","name",":","the","field","name",",","if","specified",";","otherwise","None","filename",":","the","filename",",","if","specified",";","otherwise","None",";","this","is","the","client","side","filename",",","*","not","*","the","file","name","on","which","it","is","stored","(","that","'s","a","temporary","file","you","do","n't","deal","with",")","value",":","the","value","as","a","*","string","*",";","for","file","uploads",",","this","transparently","reads","the","file","every","time","you","request","the","value","and","returns","*","bytes","*","file",":","the","file","(","-like",")","object","from","which","you","can","read","the","data","*","as","bytes","*",";","None","if","the","data","is","stored","a","simple","string","type",":","the","content-type",",","or","None","if","not","specified","type_options",":","dictionary","of","options","specified","on","the","content-type","line","disposition",":","content-disposition",",","or","None","if","not","specified","disposition_options",":","dictionary","of","corresponding","options","headers",":","a","dictionary","(","-like",")","object","(","sometimes","email.message.Message","or","a","subclass","thereof",")","containing","*","all","*","headers","The","class","is","subclassable",",","mostly","for","the","purpose","of","overriding","the","make_file","(",")","method",",","which","is","called","internally","to","come","up","with","a","file","open","for","reading","and","writing",".","This","makes","it","possible","to","override","the","default","choice","of","storing","all","files","in","a","temporary","directory","and","unlinking","them","as","soon","as","they","have","been","opened","."]
docstr: Internal: read a part that is itself multipart.
docstr_tok: ["Internal",":","read","a","part","that","is","itself","multipart","."]
code: def read_multi(self, environ, keep_blank_values, strict_parsing):
      """Internal: read a part that is itself multipart."""
      ib = self.innerboundary
      if not valid_boundary(ib):
          raise ValueError(
              "Invalid boundary in multipart form: %r" % (ib,)
          )
      self.list = []
      if self.qs_on_post:
          query = urllib.parse.parse_qsl(
              self.qs_on_post,
              self.keep_blank_values,
              self.strict_parsing,
              encoding=self.encoding,
              errors=self.errors,
              max_num_fields=self.max_num_fields,
              separator=self.separator,
          )
          self.list.extend(
              MiniFieldStorage(key, value) for key, value in query
          )
  
      klass = self.FieldStorageClass or self.__class__
      first_line = self.fp.readline()  # bytes
      if not isinstance(first_line, bytes):
          raise ValueError(
              "%s should return bytes, got %s"
              % (self.fp, type(first_line).__name__)
          )
      self.bytes_read += len(first_line)
  
      # Ensure that we consume the file until we've hit our inner boundary
      while (
          first_line.strip() != (b"--" + self.innerboundary)
          and first_line
      ):
          first_line = self.fp.readline()
          self.bytes_read += len(first_line)
  
      # Propagate max_num_fields into the sub class appropriately
      max_num_fields = self.max_num_fields
      if max_num_fields is not None:
          max_num_fields -= len(self.list)
  
      while True:
          parser = FeedParser()
          hdr_text = b""
          while True:
              data = self.fp.readline()
              hdr_text += data
              if not data.strip():
                  break
          if not hdr_text:
              break
          # parser takes strings, not bytes
          self.bytes_read += len(hdr_text)
          parser.feed(hdr_text.decode(self.encoding, self.errors))
          headers = parser.close()
  
          # Some clients add Content-Length for part headers, ignore them
          if "content-length" in headers:
              del headers["content-length"]
  
          limit = (
              None
              if self.limit is None
              else self.limit - self.bytes_read
          )
          part = klass(
              self.fp,
              headers,
              ib,
              environ,
              keep_blank_values,
              strict_parsing,
              limit,
              self.encoding,
              self.errors,
              max_num_fields,
              self.separator,
          )
  
          if max_num_fields is not None:
              max_num_fields -= 1
              if part.list:
                  max_num_fields -= len(part.list)
              if max_num_fields < 0:
                  raise ValueError("Max number of fields exceeded")
  
          self.bytes_read += part.bytes_read
          self.list.append(part)
          if part.done or self.bytes_read >= self.length > 0:
              break
      self.skip_lines()
  
imports: from io import StringIO, BytesIO, TextIOWrapper
  from collections.abc import Mapping
  import sys
  import os
  import urllib.parse
  from email.parser import FeedParser
  from email.message import Message
  import html
  import locale
  import tempfile
  import warnings
label_desc: Use image node_id 17 for calling the FieldStorage obj's underlying member method code with example usage: obj.read_multi(environ, keep_blank_values, strict_parsing) without return types