aboutsummaryrefslogtreecommitdiff
path: root/venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py
diff options
context:
space:
mode:
authorsotech117 <michael_foiani@brown.edu>2025-07-31 17:27:24 -0400
committersotech117 <michael_foiani@brown.edu>2025-07-31 17:27:24 -0400
commit5bf22fc7e3c392c8bd44315ca2d06d7dca7d084e (patch)
tree8dacb0f195df1c0788d36dd0064f6bbaa3143ede /venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py
parentb832d364da8c2efe09e3f75828caf73c50d01ce3 (diff)
add code for analysis of data
Diffstat (limited to 'venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py')
-rw-r--r--venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py180
1 files changed, 180 insertions, 0 deletions
diff --git a/venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py b/venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py
new file mode 100644
index 0000000..7011ea4
--- /dev/null
+++ b/venv/lib/python3.8/site-packages/werkzeug/datastructures/range.py
@@ -0,0 +1,180 @@
+from __future__ import annotations
+
+
+class IfRange:
+ """Very simple object that represents the `If-Range` header in parsed
+ form. It will either have neither a etag or date or one of either but
+ never both.
+
+ .. versionadded:: 0.7
+ """
+
+ def __init__(self, etag=None, date=None):
+ #: The etag parsed and unquoted. Ranges always operate on strong
+ #: etags so the weakness information is not necessary.
+ self.etag = etag
+ #: The date in parsed format or `None`.
+ self.date = date
+
+ def to_header(self):
+ """Converts the object back into an HTTP header."""
+ if self.date is not None:
+ return http.http_date(self.date)
+ if self.etag is not None:
+ return http.quote_etag(self.etag)
+ return ""
+
+ def __str__(self):
+ return self.to_header()
+
+ def __repr__(self):
+ return f"<{type(self).__name__} {str(self)!r}>"
+
+
+class Range:
+ """Represents a ``Range`` header. All methods only support only
+ bytes as the unit. Stores a list of ranges if given, but the methods
+ only work if only one range is provided.
+
+ :raise ValueError: If the ranges provided are invalid.
+
+ .. versionchanged:: 0.15
+ The ranges passed in are validated.
+
+ .. versionadded:: 0.7
+ """
+
+ def __init__(self, units, ranges):
+ #: The units of this range. Usually "bytes".
+ self.units = units
+ #: A list of ``(begin, end)`` tuples for the range header provided.
+ #: The ranges are non-inclusive.
+ self.ranges = ranges
+
+ for start, end in ranges:
+ if start is None or (end is not None and (start < 0 or start >= end)):
+ raise ValueError(f"{(start, end)} is not a valid range.")
+
+ def range_for_length(self, length):
+ """If the range is for bytes, the length is not None and there is
+ exactly one range and it is satisfiable it returns a ``(start, stop)``
+ tuple, otherwise `None`.
+ """
+ if self.units != "bytes" or length is None or len(self.ranges) != 1:
+ return None
+ start, end = self.ranges[0]
+ if end is None:
+ end = length
+ if start < 0:
+ start += length
+ if http.is_byte_range_valid(start, end, length):
+ return start, min(end, length)
+ return None
+
+ def make_content_range(self, length):
+ """Creates a :class:`~werkzeug.datastructures.ContentRange` object
+ from the current range and given content length.
+ """
+ rng = self.range_for_length(length)
+ if rng is not None:
+ return ContentRange(self.units, rng[0], rng[1], length)
+ return None
+
+ def to_header(self):
+ """Converts the object back into an HTTP header."""
+ ranges = []
+ for begin, end in self.ranges:
+ if end is None:
+ ranges.append(f"{begin}-" if begin >= 0 else str(begin))
+ else:
+ ranges.append(f"{begin}-{end - 1}")
+ return f"{self.units}={','.join(ranges)}"
+
+ def to_content_range_header(self, length):
+ """Converts the object into `Content-Range` HTTP header,
+ based on given length
+ """
+ range = self.range_for_length(length)
+ if range is not None:
+ return f"{self.units} {range[0]}-{range[1] - 1}/{length}"
+ return None
+
+ def __str__(self):
+ return self.to_header()
+
+ def __repr__(self):
+ return f"<{type(self).__name__} {str(self)!r}>"
+
+
+def _callback_property(name):
+ def fget(self):
+ return getattr(self, name)
+
+ def fset(self, value):
+ setattr(self, name, value)
+ if self.on_update is not None:
+ self.on_update(self)
+
+ return property(fget, fset)
+
+
+class ContentRange:
+ """Represents the content range header.
+
+ .. versionadded:: 0.7
+ """
+
+ def __init__(self, units, start, stop, length=None, on_update=None):
+ assert http.is_byte_range_valid(start, stop, length), "Bad range provided"
+ self.on_update = on_update
+ self.set(start, stop, length, units)
+
+ #: The units to use, usually "bytes"
+ units = _callback_property("_units")
+ #: The start point of the range or `None`.
+ start = _callback_property("_start")
+ #: The stop point of the range (non-inclusive) or `None`. Can only be
+ #: `None` if also start is `None`.
+ stop = _callback_property("_stop")
+ #: The length of the range or `None`.
+ length = _callback_property("_length")
+
+ def set(self, start, stop, length=None, units="bytes"):
+ """Simple method to update the ranges."""
+ assert http.is_byte_range_valid(start, stop, length), "Bad range provided"
+ self._units = units
+ self._start = start
+ self._stop = stop
+ self._length = length
+ if self.on_update is not None:
+ self.on_update(self)
+
+ def unset(self):
+ """Sets the units to `None` which indicates that the header should
+ no longer be used.
+ """
+ self.set(None, None, units=None)
+
+ def to_header(self):
+ if self.units is None:
+ return ""
+ if self.length is None:
+ length = "*"
+ else:
+ length = self.length
+ if self.start is None:
+ return f"{self.units} */{length}"
+ return f"{self.units} {self.start}-{self.stop - 1}/{length}"
+
+ def __bool__(self):
+ return self.units is not None
+
+ def __str__(self):
+ return self.to_header()
+
+ def __repr__(self):
+ return f"<{type(self).__name__} {str(self)!r}>"
+
+
+# circular dependencies
+from .. import http