@@ -1543,59 +1543,113 @@ def DetectTarBombArchiveFileArray(listarrayfiles,
15431543 }
15441544
15451545
1546- def MkTempFile(data=None, inmem=__use_inmemfile__, isbytes=True, prefix=__project__,
1547- delete=True, encoding="utf-8"):
1546+ def _normalize_initial_data(data, isbytes, encoding):
15481547 """
1549- Return a file-like handle.
1550- - If inmem=True: returns StringIO (text) or BytesIO (bytes).
1551- - If inmem=False: returns a NamedTemporaryFile opened in text or binary mode.
1552- Args:
1553- data: optional initial content; if provided, it's written and the handle is seek(0)
1554- inmem: bool — return in-memory handle if True
1555- isbytes: bool — choose bytes (True) or text (False)
1556- prefix: str — tempfile prefix
1557- delete: bool — whether the tempfile is deleted on close (NamedTemporaryFile)
1558- encoding: str — used for text mode (and for conversions when needed)
1548+ Coerce `data` to the correct type for the chosen mode:
1549+ - bytes mode: return `bytes` (Py2: str; Py3: bytes)
1550+ - text mode : return unicode/str (Py2: unicode; Py3: str)
15591551 """
1560- init = _normalize_initial_data(data, isbytes, encoding)
1561-
1562- if inmem:
1563- buf = BytesIO() if isbytes else StringIO()
1564- if init is not None:
1565- buf.write(init)
1566- buf.seek(0)
1567- return buf
1568-
1569- mode = "wb+" if isbytes else "w+"
1570- kwargs = {"prefix": prefix or "", "delete": delete, "mode": mode}
1552+ if data is None:
1553+ return None
15711554
1572- # Only Python 3's text-mode files accept encoding/newline explicitly
1573- if not isbytes and sys.version_info[0] >= 3:
1574- kwargs["encoding"] = encoding
1575- kwargs["newline"] = ""
1555+ if isbytes:
1556+ # Need a byte sequence
1557+ if isinstance(data, bytes):
1558+ return data
1559+ if isinstance(data, bytearray):
1560+ return bytes(data)
1561+ # memoryview may not exist on very old Py2 builds; guard dynamically
1562+ mv_t = getattr(__builtins__, 'memoryview', type(None))
1563+ if isinstance(data, mv_t):
1564+ return bytes(data)
1565+ if isinstance(data, str):
1566+ # Py2 str is already bytes; Py3 str must be encoded
1567+ return data if PY2 else data.encode(encoding)
1568+ if PY2 and isinstance(data, unicode): # noqa: F821 (unicode only in Py2)
1569+ return data.encode(encoding)
1570+ raise TypeError("data must be bytes-like or text for isbytes=True (got %r)" % (type(data),))
1571+ else:
1572+ # Need text (unicode in Py2, str in Py3)
1573+ if PY2:
1574+ if isinstance(data, unicode): # noqa: F821
1575+ return data
1576+ if isinstance(data, str):
1577+ return data.decode(encoding)
1578+ if isinstance(data, bytearray):
1579+ return bytes(data).decode(encoding)
1580+ mv_t = getattr(__builtins__, 'memoryview', type(None))
1581+ if isinstance(data, mv_t):
1582+ return bytes(data).decode(encoding)
1583+ raise TypeError("data must be unicode or bytes-like for text mode (got %r)" % (type(data),))
1584+ else:
1585+ if isinstance(data, str):
1586+ return data
1587+ if isinstance(data, (bytes, bytearray, memoryview)):
1588+ return bytes(data).decode(encoding)
1589+ raise TypeError("data must be str or bytes-like for text mode (got %r)" % (type(data),))
1590+
1591+ def MkTempFile(data=None,
1592+ inmem=True,
1593+ isbytes=True,
1594+ prefix="",
1595+ delete=True,
1596+ encoding="utf-8",
1597+ newline=None, # Py3 text only; ignored by Py2 temp classes
1598+ dir=None,
1599+ suffix="",
1600+ # spooled option (RAM until threshold, then rolls to disk)
1601+ use_spool=False,
1602+ spool_max=8 * 1024 * 1024,
1603+ spool_dir=None):
1604+ """
1605+ Return a file-like handle with consistent behavior on Py2.7 and Py3.x.
15761606
1577- f = tempfile.NamedTemporaryFile(**kwargs)
1607+ - inmem=True -> BytesIO (bytes) or StringIO (text)
1608+ - inmem=False, use_spool=True -> SpooledTemporaryFile (RAM -> disk after spool_max)
1609+ - inmem=False, use_spool=False -> NamedTemporaryFile (on disk)
15781610
1579- if init is not None:
1580- f.write(init)
1581- f.seek(0)
1582- return f
1611+ If `data` is provided, it's written and the handle is rewound to position 0.
1612+ """
1613+ init = _normalize_initial_data(data, isbytes, encoding)
15831614
1615+ # -------- In-memory --------
1616+ if inmem:
1617+ if isbytes:
1618+ return BytesIO(init if init is not None else b"")
1619+ else:
1620+ # Py2 needs unicode literal for empty default
1621+ return StringIO(init if init is not None else (u"" if PY2 else ""))
15841622
1585- def MkTempFileSmart(data=None, isbytes=True, prefix=__project__, max_mem=1024*1024, encoding="utf-8"):
1586- """
1587- Spooled temp file: starts in memory and spills to disk past max_mem.
1588- Behaves like BytesIO/StringIO for small data, with the same preload+seek(0) behavior.
1589- """
1590- mode = "wb+" if isbytes else "w+"
1591- kwargs = {"mode": mode, "max_size": max_mem, "prefix": prefix or ""}
1592- if not isbytes and sys.version_info[0] >= 3:
1593- kwargs["encoding"] = encoding
1594- kwargs["newline"] = ""
1623+ # -------- Spooled (RAM then disk) --------
1624+ if use_spool:
1625+ if isbytes:
1626+ f = tempfile.SpooledTemporaryFile(max_size=spool_max, mode="w+b", dir=spool_dir)
1627+ else:
1628+ if PY2:
1629+ # Py2 SpooledTemporaryFile doesn't accept encoding/newline
1630+ f = tempfile.SpooledTemporaryFile(max_size=spool_max, mode="w+", dir=spool_dir)
1631+ else:
1632+ f = tempfile.SpooledTemporaryFile(max_size=spool_max, mode="w+",
1633+ dir=spool_dir, encoding=encoding, newline=newline)
1634+ if init is not None:
1635+ f.write(init)
1636+ f.seek(0)
1637+ return f
15951638
1596- f = tempfile.SpooledTemporaryFile(**kwargs)
1639+ # -------- On-disk temp --------
1640+ if isbytes:
1641+ f = tempfile.NamedTemporaryFile(mode="w+b", prefix=prefix or "", suffix=suffix,
1642+ dir=dir, delete=delete)
1643+ else:
1644+ if PY2:
1645+ # Py2 temp files don't accept encoding/newline; writes of unicode will be encoded
1646+ # using the default encoding. If you need strict control, wrap with codecs/io.open.
1647+ f = tempfile.NamedTemporaryFile(mode="w+", prefix=prefix or "", suffix=suffix,
1648+ dir=dir, delete=delete)
1649+ else:
1650+ f = tempfile.NamedTemporaryFile(mode="w+", prefix=prefix or "", suffix=suffix,
1651+ dir=dir, delete=delete, encoding=encoding, newline=newline)
15971652
1598- init = _normalize_initial_data(data, isbytes, encoding)
15991653 if init is not None:
16001654 f.write(init)
16011655 f.seek(0)
0 commit comments