H", ifd_data[:2])[0]):
+ ifd_tag, typ, count, data = struct.unpack(
+ ">HHL4s", ifd_data[i * 12 + 2 : (i + 1) * 12 + 2]
+ )
+ if ifd_tag == 0x1101:
+ # CameraInfo
+ (offset,) = struct.unpack(">L", data)
+ self.fp.seek(offset)
+
+ camerainfo = {"ModelID": self.fp.read(4)}
+
+ self.fp.read(4)
+ # Seconds since 2000
+ camerainfo["TimeStamp"] = i32le(self.fp.read(12))
+
+ self.fp.read(4)
+ camerainfo["InternalSerialNumber"] = self.fp.read(4)
+
+ self.fp.read(12)
+ parallax = self.fp.read(4)
+ handler = ImageFileDirectory_v2._load_dispatch[
+ TiffTags.FLOAT
+ ][1]
+ camerainfo["Parallax"] = handler(
+ ImageFileDirectory_v2(), parallax, False
+ )
+
+ self.fp.read(4)
+ camerainfo["Category"] = self.fp.read(2)
+
+ makernote = {0x1101: dict(self._fixup_dict(camerainfo))}
+ self._ifds[0x927C] = makernote
+ return self._ifds.get(tag, {})
+
+ def __str__(self):
+ if self._info is not None:
+ # Load all keys into self._data
+ for tag in self._info.keys():
+ self[tag]
+
+ return str(self._data)
+
+ def __len__(self):
+ keys = set(self._data)
+ if self._info is not None:
+ keys.update(self._info)
+ return len(keys)
+
+ def __getitem__(self, tag):
+ if self._info is not None and tag not in self._data and tag in self._info:
+ self._data[tag] = self._fixup(self._info[tag])
+ if tag == 0x8825:
+ self._data[tag] = self.get_ifd(tag)
+ del self._info[tag]
+ return self._data[tag]
+
+ def __contains__(self, tag):
+ return tag in self._data or (self._info is not None and tag in self._info)
+
+ def __setitem__(self, tag, value):
+ if self._info is not None and tag in self._info:
+ del self._info[tag]
+ self._data[tag] = value
+
+ def __delitem__(self, tag):
+ if self._info is not None and tag in self._info:
+ del self._info[tag]
+ else:
+ del self._data[tag]
+
+ def __iter__(self):
+ keys = set(self._data)
+ if self._info is not None:
+ keys.update(self._info)
+ return iter(keys)
diff --git a/venv/Lib/site-packages/PIL/ImageChops.py b/venv/Lib/site-packages/PIL/ImageChops.py
new file mode 100644
index 0000000..61d3a29
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageChops.py
@@ -0,0 +1,328 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard channel operations
+#
+# History:
+# 1996-03-24 fl Created
+# 1996-08-13 fl Added logical operations (for "1" images)
+# 2000-10-12 fl Added offset method (from Image.py)
+#
+# Copyright (c) 1997-2000 by Secret Labs AB
+# Copyright (c) 1996-2000 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+
+def constant(image, value):
+ """Fill a channel with a given grey level.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return Image.new("L", image.size, value)
+
+
+def duplicate(image):
+ """Copy a channel. Alias for :py:meth:`PIL.Image.Image.copy`.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return image.copy()
+
+
+def invert(image):
+ """
+ Invert an image (channel).
+
+ .. code-block:: python
+
+ out = MAX - image
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image.load()
+ return image._new(image.im.chop_invert())
+
+
+def lighter(image1, image2):
+ """
+ Compares the two images, pixel by pixel, and returns a new image containing
+ the lighter values.
+
+ .. code-block:: python
+
+ out = max(image1, image2)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_lighter(image2.im))
+
+
+def darker(image1, image2):
+ """
+ Compares the two images, pixel by pixel, and returns a new image containing
+ the darker values.
+
+ .. code-block:: python
+
+ out = min(image1, image2)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_darker(image2.im))
+
+
+def difference(image1, image2):
+ """
+ Returns the absolute value of the pixel-by-pixel difference between the two
+ images.
+
+ .. code-block:: python
+
+ out = abs(image1 - image2)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_difference(image2.im))
+
+
+def multiply(image1, image2):
+ """
+ Superimposes two images on top of each other.
+
+ If you multiply an image with a solid black image, the result is black. If
+ you multiply with a solid white image, the image is unaffected.
+
+ .. code-block:: python
+
+ out = image1 * image2 / MAX
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_multiply(image2.im))
+
+
+def screen(image1, image2):
+ """
+ Superimposes two inverted images on top of each other.
+
+ .. code-block:: python
+
+ out = MAX - ((MAX - image1) * (MAX - image2) / MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_screen(image2.im))
+
+
+def soft_light(image1, image2):
+ """
+ Superimposes two images on top of each other using the Soft Light algorithm
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_soft_light(image2.im))
+
+
+def hard_light(image1, image2):
+ """
+ Superimposes two images on top of each other using the Hard Light algorithm
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_hard_light(image2.im))
+
+
+def overlay(image1, image2):
+ """
+ Superimposes two images on top of each other using the Overlay algorithm
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_overlay(image2.im))
+
+
+def add(image1, image2, scale=1.0, offset=0):
+ """
+ Adds two images, dividing the result by scale and adding the
+ offset. If omitted, scale defaults to 1.0, and offset to 0.0.
+
+ .. code-block:: python
+
+ out = ((image1 + image2) / scale + offset)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_add(image2.im, scale, offset))
+
+
+def subtract(image1, image2, scale=1.0, offset=0):
+ """
+ Subtracts two images, dividing the result by scale and adding the offset.
+ If omitted, scale defaults to 1.0, and offset to 0.0.
+
+ .. code-block:: python
+
+ out = ((image1 - image2) / scale + offset)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_subtract(image2.im, scale, offset))
+
+
+def add_modulo(image1, image2):
+ """Add two images, without clipping the result.
+
+ .. code-block:: python
+
+ out = ((image1 + image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_add_modulo(image2.im))
+
+
+def subtract_modulo(image1, image2):
+ """Subtract two images, without clipping the result.
+
+ .. code-block:: python
+
+ out = ((image1 - image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_subtract_modulo(image2.im))
+
+
+def logical_and(image1, image2):
+ """Logical AND between two images.
+
+ Both of the images must have mode "1". If you would like to perform a
+ logical AND on an image with a mode other than "1", try
+ :py:meth:`~PIL.ImageChops.multiply` instead, using a black-and-white mask
+ as the second image.
+
+ .. code-block:: python
+
+ out = ((image1 and image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_and(image2.im))
+
+
+def logical_or(image1, image2):
+ """Logical OR between two images.
+
+ Both of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = ((image1 or image2) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_or(image2.im))
+
+
+def logical_xor(image1, image2):
+ """Logical XOR between two images.
+
+ Both of the images must have mode "1".
+
+ .. code-block:: python
+
+ out = ((bool(image1) != bool(image2)) % MAX)
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ image1.load()
+ image2.load()
+ return image1._new(image1.im.chop_xor(image2.im))
+
+
+def blend(image1, image2, alpha):
+ """Blend images using constant transparency weight. Alias for
+ :py:func:`PIL.Image.blend`.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return Image.blend(image1, image2, alpha)
+
+
+def composite(image1, image2, mask):
+ """Create composite using transparency mask. Alias for
+ :py:func:`PIL.Image.composite`.
+
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ return Image.composite(image1, image2, mask)
+
+
+def offset(image, xoffset, yoffset=None):
+ """Returns a copy of the image where data has been offset by the given
+ distances. Data wraps around the edges. If ``yoffset`` is omitted, it
+ is assumed to be equal to ``xoffset``.
+
+ :param xoffset: The horizontal distance.
+ :param yoffset: The vertical distance. If omitted, both
+ distances are set to the same value.
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+
+ if yoffset is None:
+ yoffset = xoffset
+ image.load()
+ return image._new(image.im.offset(xoffset, yoffset))
diff --git a/venv/Lib/site-packages/PIL/ImageCms.py b/venv/Lib/site-packages/PIL/ImageCms.py
new file mode 100644
index 0000000..8c4740d
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageCms.py
@@ -0,0 +1,999 @@
+# The Python Imaging Library.
+# $Id$
+
+# Optional color management support, based on Kevin Cazabon's PyCMS
+# library.
+
+# History:
+
+# 2009-03-08 fl Added to PIL.
+
+# Copyright (C) 2002-2003 Kevin Cazabon
+# Copyright (c) 2009 by Fredrik Lundh
+# Copyright (c) 2013 by Eric Soroos
+
+# See the README file for information on usage and redistribution. See
+# below for the original description.
+
+import sys
+
+from PIL import Image
+
+try:
+ from PIL import _imagingcms
+except ImportError as ex:
+ # Allow error import for doc purposes, but error out when accessing
+ # anything in core.
+ from ._util import deferred_error
+
+ _imagingcms = deferred_error(ex)
+
+DESCRIPTION = """
+pyCMS
+
+ a Python / PIL interface to the littleCMS ICC Color Management System
+ Copyright (C) 2002-2003 Kevin Cazabon
+ kevin@cazabon.com
+ http://www.cazabon.com
+
+ pyCMS home page: http://www.cazabon.com/pyCMS
+ littleCMS home page: http://www.littlecms.com
+ (littleCMS is Copyright (C) 1998-2001 Marti Maria)
+
+ Originally released under LGPL. Graciously donated to PIL in
+ March 2009, for distribution under the standard PIL license
+
+ The pyCMS.py module provides a "clean" interface between Python/PIL and
+ pyCMSdll, taking care of some of the more complex handling of the direct
+ pyCMSdll functions, as well as error-checking and making sure that all
+ relevant data is kept together.
+
+ While it is possible to call pyCMSdll functions directly, it's not highly
+ recommended.
+
+ Version History:
+
+ 1.0.0 pil Oct 2013 Port to LCMS 2.
+
+ 0.1.0 pil mod March 10, 2009
+
+ Renamed display profile to proof profile. The proof
+ profile is the profile of the device that is being
+ simulated, not the profile of the device which is
+ actually used to display/print the final simulation
+ (that'd be the output profile) - also see LCMSAPI.txt
+ input colorspace -> using 'renderingIntent' -> proof
+ colorspace -> using 'proofRenderingIntent' -> output
+ colorspace
+
+ Added LCMS FLAGS support.
+ Added FLAGS["SOFTPROOFING"] as default flag for
+ buildProofTransform (otherwise the proof profile/intent
+ would be ignored).
+
+ 0.1.0 pil March 2009 - added to PIL, as PIL.ImageCms
+
+ 0.0.2 alpha Jan 6, 2002
+
+ Added try/except statements around type() checks of
+ potential CObjects... Python won't let you use type()
+ on them, and raises a TypeError (stupid, if you ask
+ me!)
+
+ Added buildProofTransformFromOpenProfiles() function.
+ Additional fixes in DLL, see DLL code for details.
+
+ 0.0.1 alpha first public release, Dec. 26, 2002
+
+ Known to-do list with current version (of Python interface, not pyCMSdll):
+
+ none
+
+"""
+
+VERSION = "1.0.0 pil"
+
+# --------------------------------------------------------------------.
+
+core = _imagingcms
+
+#
+# intent/direction values
+
+INTENT_PERCEPTUAL = 0
+INTENT_RELATIVE_COLORIMETRIC = 1
+INTENT_SATURATION = 2
+INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+DIRECTION_INPUT = 0
+DIRECTION_OUTPUT = 1
+DIRECTION_PROOF = 2
+
+#
+# flags
+
+FLAGS = {
+ "MATRIXINPUT": 1,
+ "MATRIXOUTPUT": 2,
+ "MATRIXONLY": (1 | 2),
+ "NOWHITEONWHITEFIXUP": 4, # Don't hot fix scum dot
+ # Don't create prelinearization tables on precalculated transforms
+ # (internal use):
+ "NOPRELINEARIZATION": 16,
+ "GUESSDEVICECLASS": 32, # Guess device class (for transform2devicelink)
+ "NOTCACHE": 64, # Inhibit 1-pixel cache
+ "NOTPRECALC": 256,
+ "NULLTRANSFORM": 512, # Don't transform anyway
+ "HIGHRESPRECALC": 1024, # Use more memory to give better accuracy
+ "LOWRESPRECALC": 2048, # Use less memory to minimize resources
+ "WHITEBLACKCOMPENSATION": 8192,
+ "BLACKPOINTCOMPENSATION": 8192,
+ "GAMUTCHECK": 4096, # Out of Gamut alarm
+ "SOFTPROOFING": 16384, # Do softproofing
+ "PRESERVEBLACK": 32768, # Black preservation
+ "NODEFAULTRESOURCEDEF": 16777216, # CRD special
+ "GRIDPOINTS": lambda n: ((n) & 0xFF) << 16, # Gridpoints
+}
+
+_MAX_FLAG = 0
+for flag in FLAGS.values():
+ if isinstance(flag, int):
+ _MAX_FLAG = _MAX_FLAG | flag
+
+
+# --------------------------------------------------------------------.
+# Experimental PIL-level API
+# --------------------------------------------------------------------.
+
+##
+# Profile.
+
+
+class ImageCmsProfile:
+ def __init__(self, profile):
+ """
+ :param profile: Either a string representing a filename,
+ a file like object containing a profile or a
+ low-level profile object
+
+ """
+
+ if isinstance(profile, str):
+ if sys.platform == "win32":
+ profile_bytes_path = profile.encode()
+ try:
+ profile_bytes_path.decode("ascii")
+ except UnicodeDecodeError:
+ with open(profile, "rb") as f:
+ self._set(core.profile_frombytes(f.read()))
+ return
+ self._set(core.profile_open(profile), profile)
+ elif hasattr(profile, "read"):
+ self._set(core.profile_frombytes(profile.read()))
+ elif isinstance(profile, _imagingcms.CmsProfile):
+ self._set(profile)
+ else:
+ raise TypeError("Invalid type for Profile")
+
+ def _set(self, profile, filename=None):
+ self.profile = profile
+ self.filename = filename
+ if profile:
+ self.product_name = None # profile.product_name
+ self.product_info = None # profile.product_info
+ else:
+ self.product_name = None
+ self.product_info = None
+
+ def tobytes(self):
+ """
+ Returns the profile in a format suitable for embedding in
+ saved images.
+
+ :returns: a bytes object containing the ICC profile.
+ """
+
+ return core.profile_tobytes(self.profile)
+
+
+class ImageCmsTransform(Image.ImagePointHandler):
+
+ """
+ Transform. This can be used with the procedural API, or with the standard
+ :py:func:`~PIL.Image.Image.point` method.
+
+ Will return the output profile in the ``output.info['icc_profile']``.
+ """
+
+ def __init__(
+ self,
+ input,
+ output,
+ input_mode,
+ output_mode,
+ intent=INTENT_PERCEPTUAL,
+ proof=None,
+ proof_intent=INTENT_ABSOLUTE_COLORIMETRIC,
+ flags=0,
+ ):
+ if proof is None:
+ self.transform = core.buildTransform(
+ input.profile, output.profile, input_mode, output_mode, intent, flags
+ )
+ else:
+ self.transform = core.buildProofTransform(
+ input.profile,
+ output.profile,
+ proof.profile,
+ input_mode,
+ output_mode,
+ intent,
+ proof_intent,
+ flags,
+ )
+ # Note: inputMode and outputMode are for pyCMS compatibility only
+ self.input_mode = self.inputMode = input_mode
+ self.output_mode = self.outputMode = output_mode
+
+ self.output_profile = output
+
+ def point(self, im):
+ return self.apply(im)
+
+ def apply(self, im, imOut=None):
+ im.load()
+ if imOut is None:
+ imOut = Image.new(self.output_mode, im.size, None)
+ self.transform.apply(im.im.id, imOut.im.id)
+ imOut.info["icc_profile"] = self.output_profile.tobytes()
+ return imOut
+
+ def apply_in_place(self, im):
+ im.load()
+ if im.mode != self.output_mode:
+ raise ValueError("mode mismatch") # wrong output mode
+ self.transform.apply(im.im.id, im.im.id)
+ im.info["icc_profile"] = self.output_profile.tobytes()
+ return im
+
+
+def get_display_profile(handle=None):
+ """
+ (experimental) Fetches the profile for the current display device.
+
+ :returns: ``None`` if the profile is not known.
+ """
+
+ if sys.platform != "win32":
+ return None
+
+ from PIL import ImageWin
+
+ if isinstance(handle, ImageWin.HDC):
+ profile = core.get_display_profile_win32(handle, 1)
+ else:
+ profile = core.get_display_profile_win32(handle or 0)
+ if profile is None:
+ return None
+ return ImageCmsProfile(profile)
+
+
+# --------------------------------------------------------------------.
+# pyCMS compatible layer
+# --------------------------------------------------------------------.
+
+
+class PyCMSError(Exception):
+
+ """(pyCMS) Exception class.
+ This is used for all errors in the pyCMS API."""
+
+ pass
+
+
+def profileToProfile(
+ im,
+ inputProfile,
+ outputProfile,
+ renderingIntent=INTENT_PERCEPTUAL,
+ outputMode=None,
+ inPlace=False,
+ flags=0,
+):
+ """
+ (pyCMS) Applies an ICC transformation to a given image, mapping from
+ ``inputProfile`` to ``outputProfile``.
+
+ If the input or output profiles specified are not valid filenames, a
+ :exc:`PyCMSError` will be raised. If ``inPlace`` is ``True`` and
+ ``outputMode != im.mode``, a :exc:`PyCMSError` will be raised.
+ If an error occurs during application of the profiles,
+ a :exc:`PyCMSError` will be raised.
+ If ``outputMode`` is not a mode supported by the ``outputProfile`` (or by pyCMS),
+ a :exc:`PyCMSError` will be raised.
+
+ This function applies an ICC transformation to im from ``inputProfile``'s
+ color space to ``outputProfile``'s color space using the specified rendering
+ intent to decide how to handle out-of-gamut colors.
+
+ ``outputMode`` can be used to specify that a color mode conversion is to
+ be done using these profiles, but the specified profiles must be able
+ to handle that mode. I.e., if converting im from RGB to CMYK using
+ profiles, the input profile must handle RGB data, and the output
+ profile must handle CMYK data.
+
+ :param im: An open :py:class:`~PIL.Image.Image` object (i.e. Image.new(...)
+ or Image.open(...), etc.)
+ :param inputProfile: String, as a valid filename path to the ICC input
+ profile you wish to use for this image, or a profile object
+ :param outputProfile: String, as a valid filename path to the ICC output
+ profile you wish to use for this image, or a profile object
+ :param renderingIntent: Integer (0-3) specifying the rendering intent you
+ wish to use for the transform
+
+ ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
+ ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
+ ImageCms.INTENT_SATURATION = 2
+ ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+ see the pyCMS documentation for details on rendering intents and what
+ they do.
+ :param outputMode: A valid PIL mode for the output image (i.e. "RGB",
+ "CMYK", etc.). Note: if rendering the image "inPlace", outputMode
+ MUST be the same mode as the input, or omitted completely. If
+ omitted, the outputMode will be the same as the mode of the input
+ image (im.mode)
+ :param inPlace: Boolean. If ``True``, the original image is modified in-place,
+ and ``None`` is returned. If ``False`` (default), a new
+ :py:class:`~PIL.Image.Image` object is returned with the transform applied.
+ :param flags: Integer (0-...) specifying additional flags
+ :returns: Either None or a new :py:class:`~PIL.Image.Image` object, depending on
+ the value of ``inPlace``
+ :exception PyCMSError:
+ """
+
+ if outputMode is None:
+ outputMode = im.mode
+
+ if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
+ raise PyCMSError("renderingIntent must be an integer between 0 and 3")
+
+ if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
+ raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
+
+ try:
+ if not isinstance(inputProfile, ImageCmsProfile):
+ inputProfile = ImageCmsProfile(inputProfile)
+ if not isinstance(outputProfile, ImageCmsProfile):
+ outputProfile = ImageCmsProfile(outputProfile)
+ transform = ImageCmsTransform(
+ inputProfile,
+ outputProfile,
+ im.mode,
+ outputMode,
+ renderingIntent,
+ flags=flags,
+ )
+ if inPlace:
+ transform.apply_in_place(im)
+ imOut = None
+ else:
+ imOut = transform.apply(im)
+ except (OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+ return imOut
+
+
+def getOpenProfile(profileFilename):
+ """
+ (pyCMS) Opens an ICC profile file.
+
+ The PyCMSProfile object can be passed back into pyCMS for use in creating
+ transforms and such (as in ImageCms.buildTransformFromOpenProfiles()).
+
+ If ``profileFilename`` is not a valid filename for an ICC profile,
+ a :exc:`PyCMSError` will be raised.
+
+ :param profileFilename: String, as a valid filename path to the ICC profile
+ you wish to open, or a file-like object.
+ :returns: A CmsProfile class object.
+ :exception PyCMSError:
+ """
+
+ try:
+ return ImageCmsProfile(profileFilename)
+ except (OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def buildTransform(
+ inputProfile,
+ outputProfile,
+ inMode,
+ outMode,
+ renderingIntent=INTENT_PERCEPTUAL,
+ flags=0,
+):
+ """
+ (pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
+ ``outputProfile``. Use applyTransform to apply the transform to a given
+ image.
+
+ If the input or output profiles specified are not valid filenames, a
+ :exc:`PyCMSError` will be raised. If an error occurs during creation
+ of the transform, a :exc:`PyCMSError` will be raised.
+
+ If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile``
+ (or by pyCMS), a :exc:`PyCMSError` will be raised.
+
+ This function builds and returns an ICC transform from the ``inputProfile``
+ to the ``outputProfile`` using the ``renderingIntent`` to determine what to do
+ with out-of-gamut colors. It will ONLY work for converting images that
+ are in ``inMode`` to images that are in ``outMode`` color format (PIL mode,
+ i.e. "RGB", "RGBA", "CMYK", etc.).
+
+ Building the transform is a fair part of the overhead in
+ ImageCms.profileToProfile(), so if you're planning on converting multiple
+ images using the same input/output settings, this can save you time.
+ Once you have a transform object, it can be used with
+ ImageCms.applyProfile() to convert images without the need to re-compute
+ the lookup table for the transform.
+
+ The reason pyCMS returns a class object rather than a handle directly
+ to the transform is that it needs to keep track of the PIL input/output
+ modes that the transform is meant for. These attributes are stored in
+ the ``inMode`` and ``outMode`` attributes of the object (which can be
+ manually overridden if you really want to, but I don't know of any
+ time that would be of use, or would even work).
+
+ :param inputProfile: String, as a valid filename path to the ICC input
+ profile you wish to use for this transform, or a profile object
+ :param outputProfile: String, as a valid filename path to the ICC output
+ profile you wish to use for this transform, or a profile object
+ :param inMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param outMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param renderingIntent: Integer (0-3) specifying the rendering intent you
+ wish to use for the transform
+
+ ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
+ ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
+ ImageCms.INTENT_SATURATION = 2
+ ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+ see the pyCMS documentation for details on rendering intents and what
+ they do.
+ :param flags: Integer (0-...) specifying additional flags
+ :returns: A CmsTransform class object.
+ :exception PyCMSError:
+ """
+
+ if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
+ raise PyCMSError("renderingIntent must be an integer between 0 and 3")
+
+ if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
+ raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
+
+ try:
+ if not isinstance(inputProfile, ImageCmsProfile):
+ inputProfile = ImageCmsProfile(inputProfile)
+ if not isinstance(outputProfile, ImageCmsProfile):
+ outputProfile = ImageCmsProfile(outputProfile)
+ return ImageCmsTransform(
+ inputProfile, outputProfile, inMode, outMode, renderingIntent, flags=flags
+ )
+ except (OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def buildProofTransform(
+ inputProfile,
+ outputProfile,
+ proofProfile,
+ inMode,
+ outMode,
+ renderingIntent=INTENT_PERCEPTUAL,
+ proofRenderingIntent=INTENT_ABSOLUTE_COLORIMETRIC,
+ flags=FLAGS["SOFTPROOFING"],
+):
+ """
+ (pyCMS) Builds an ICC transform mapping from the ``inputProfile`` to the
+ ``outputProfile``, but tries to simulate the result that would be
+ obtained on the ``proofProfile`` device.
+
+ If the input, output, or proof profiles specified are not valid
+ filenames, a :exc:`PyCMSError` will be raised.
+
+ If an error occurs during creation of the transform,
+ a :exc:`PyCMSError` will be raised.
+
+ If ``inMode`` or ``outMode`` are not a mode supported by the ``outputProfile``
+ (or by pyCMS), a :exc:`PyCMSError` will be raised.
+
+ This function builds and returns an ICC transform from the ``inputProfile``
+ to the ``outputProfile``, but tries to simulate the result that would be
+ obtained on the ``proofProfile`` device using ``renderingIntent`` and
+ ``proofRenderingIntent`` to determine what to do with out-of-gamut
+ colors. This is known as "soft-proofing". It will ONLY work for
+ converting images that are in ``inMode`` to images that are in outMode
+ color format (PIL mode, i.e. "RGB", "RGBA", "CMYK", etc.).
+
+ Usage of the resulting transform object is exactly the same as with
+ ImageCms.buildTransform().
+
+ Proof profiling is generally used when using an output device to get a
+ good idea of what the final printed/displayed image would look like on
+ the ``proofProfile`` device when it's quicker and easier to use the
+ output device for judging color. Generally, this means that the
+ output device is a monitor, or a dye-sub printer (etc.), and the simulated
+ device is something more expensive, complicated, or time consuming
+ (making it difficult to make a real print for color judgement purposes).
+
+ Soft-proofing basically functions by adjusting the colors on the
+ output device to match the colors of the device being simulated. However,
+ when the simulated device has a much wider gamut than the output
+ device, you may obtain marginal results.
+
+ :param inputProfile: String, as a valid filename path to the ICC input
+ profile you wish to use for this transform, or a profile object
+ :param outputProfile: String, as a valid filename path to the ICC output
+ (monitor, usually) profile you wish to use for this transform, or a
+ profile object
+ :param proofProfile: String, as a valid filename path to the ICC proof
+ profile you wish to use for this transform, or a profile object
+ :param inMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param outMode: String, as a valid PIL mode that the appropriate profile
+ also supports (i.e. "RGB", "RGBA", "CMYK", etc.)
+ :param renderingIntent: Integer (0-3) specifying the rendering intent you
+ wish to use for the input->proof (simulated) transform
+
+ ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
+ ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
+ ImageCms.INTENT_SATURATION = 2
+ ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+ see the pyCMS documentation for details on rendering intents and what
+ they do.
+ :param proofRenderingIntent: Integer (0-3) specifying the rendering intent
+ you wish to use for proof->output transform
+
+ ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
+ ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
+ ImageCms.INTENT_SATURATION = 2
+ ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+ see the pyCMS documentation for details on rendering intents and what
+ they do.
+ :param flags: Integer (0-...) specifying additional flags
+ :returns: A CmsTransform class object.
+ :exception PyCMSError:
+ """
+
+ if not isinstance(renderingIntent, int) or not (0 <= renderingIntent <= 3):
+ raise PyCMSError("renderingIntent must be an integer between 0 and 3")
+
+ if not isinstance(flags, int) or not (0 <= flags <= _MAX_FLAG):
+ raise PyCMSError("flags must be an integer between 0 and %s" + _MAX_FLAG)
+
+ try:
+ if not isinstance(inputProfile, ImageCmsProfile):
+ inputProfile = ImageCmsProfile(inputProfile)
+ if not isinstance(outputProfile, ImageCmsProfile):
+ outputProfile = ImageCmsProfile(outputProfile)
+ if not isinstance(proofProfile, ImageCmsProfile):
+ proofProfile = ImageCmsProfile(proofProfile)
+ return ImageCmsTransform(
+ inputProfile,
+ outputProfile,
+ inMode,
+ outMode,
+ renderingIntent,
+ proofProfile,
+ proofRenderingIntent,
+ flags,
+ )
+ except (OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+buildTransformFromOpenProfiles = buildTransform
+buildProofTransformFromOpenProfiles = buildProofTransform
+
+
+def applyTransform(im, transform, inPlace=False):
+ """
+ (pyCMS) Applies a transform to a given image.
+
+ If ``im.mode != transform.inMode``, a :exc:`PyCMSError` is raised.
+
+ If ``inPlace`` is ``True`` and ``transform.inMode != transform.outMode``, a
+ :exc:`PyCMSError` is raised.
+
+ If ``im.mode``, ``transform.inMode`` or ``transform.outMode`` is not
+ supported by pyCMSdll or the profiles you used for the transform, a
+ :exc:`PyCMSError` is raised.
+
+ If an error occurs while the transform is being applied,
+ a :exc:`PyCMSError` is raised.
+
+ This function applies a pre-calculated transform (from
+ ImageCms.buildTransform() or ImageCms.buildTransformFromOpenProfiles())
+ to an image. The transform can be used for multiple images, saving
+ considerable calculation time if doing the same conversion multiple times.
+
+ If you want to modify im in-place instead of receiving a new image as
+ the return value, set ``inPlace`` to ``True``. This can only be done if
+ ``transform.inMode`` and ``transform.outMode`` are the same, because we can't
+ change the mode in-place (the buffer sizes for some modes are
+ different). The default behavior is to return a new :py:class:`~PIL.Image.Image`
+ object of the same dimensions in mode ``transform.outMode``.
+
+ :param im: An :py:class:`~PIL.Image.Image` object, and im.mode must be the same
+ as the ``inMode`` supported by the transform.
+ :param transform: A valid CmsTransform class object
+ :param inPlace: Bool. If ``True``, ``im`` is modified in place and ``None`` is
+ returned, if ``False``, a new :py:class:`~PIL.Image.Image` object with the
+ transform applied is returned (and ``im`` is not changed). The default is
+ ``False``.
+ :returns: Either ``None``, or a new :py:class:`~PIL.Image.Image` object,
+ depending on the value of ``inPlace``. The profile will be returned in
+ the image's ``info['icc_profile']``.
+ :exception PyCMSError:
+ """
+
+ try:
+ if inPlace:
+ transform.apply_in_place(im)
+ imOut = None
+ else:
+ imOut = transform.apply(im)
+ except (TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+ return imOut
+
+
+def createProfile(colorSpace, colorTemp=-1):
+ """
+ (pyCMS) Creates a profile.
+
+ If colorSpace not in ``["LAB", "XYZ", "sRGB"]``,
+ a :exc:`PyCMSError` is raised.
+
+ If using LAB and ``colorTemp`` is not a positive integer,
+ a :exc:`PyCMSError` is raised.
+
+ If an error occurs while creating the profile,
+ a :exc:`PyCMSError` is raised.
+
+ Use this function to create common profiles on-the-fly instead of
+ having to supply a profile on disk and knowing the path to it. It
+ returns a normal CmsProfile object that can be passed to
+ ImageCms.buildTransformFromOpenProfiles() to create a transform to apply
+ to images.
+
+ :param colorSpace: String, the color space of the profile you wish to
+ create.
+ Currently only "LAB", "XYZ", and "sRGB" are supported.
+ :param colorTemp: Positive integer for the white point for the profile, in
+ degrees Kelvin (i.e. 5000, 6500, 9600, etc.). The default is for D50
+ illuminant if omitted (5000k). colorTemp is ONLY applied to LAB
+ profiles, and is ignored for XYZ and sRGB.
+ :returns: A CmsProfile class object
+ :exception PyCMSError:
+ """
+
+ if colorSpace not in ["LAB", "XYZ", "sRGB"]:
+ raise PyCMSError(
+ f"Color space not supported for on-the-fly profile creation ({colorSpace})"
+ )
+
+ if colorSpace == "LAB":
+ try:
+ colorTemp = float(colorTemp)
+ except (TypeError, ValueError) as e:
+ raise PyCMSError(
+ f'Color temperature must be numeric, "{colorTemp}" not valid'
+ ) from e
+
+ try:
+ return core.createProfile(colorSpace, colorTemp)
+ except (TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getProfileName(profile):
+ """
+
+ (pyCMS) Gets the internal product name for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile,
+ a :exc:`PyCMSError` is raised If an error occurs while trying
+ to obtain the name tag, a :exc:`PyCMSError` is raised.
+
+ Use this function to obtain the INTERNAL name of the profile (stored
+ in an ICC tag in the profile itself), usually the one used when the
+ profile was originally created. Sometimes this tag also contains
+ additional information supplied by the creator.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal name of the profile as stored
+ in an ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ # do it in python, not c.
+ # // name was "%s - %s" (model, manufacturer) || Description ,
+ # // but if the Model and Manufacturer were the same or the model
+ # // was long, Just the model, in 1.x
+ model = profile.profile.model
+ manufacturer = profile.profile.manufacturer
+
+ if not (model or manufacturer):
+ return (profile.profile.profile_description or "") + "\n"
+ if not manufacturer or len(model) > 30:
+ return model + "\n"
+ return f"{model} - {manufacturer}\n"
+
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getProfileInfo(profile):
+ """
+ (pyCMS) Gets the internal product information for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile,
+ a :exc:`PyCMSError` is raised.
+
+ If an error occurs while trying to obtain the info tag,
+ a :exc:`PyCMSError` is raised.
+
+ Use this function to obtain the information stored in the profile's
+ info tag. This often contains details about the profile, and how it
+ was created, as supplied by the creator.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ # add an extra newline to preserve pyCMS compatibility
+ # Python, not C. the white point bits weren't working well,
+ # so skipping.
+ # info was description \r\n\r\n copyright \r\n\r\n K007 tag \r\n\r\n whitepoint
+ description = profile.profile.profile_description
+ cpright = profile.profile.copyright
+ arr = []
+ for elt in (description, cpright):
+ if elt:
+ arr.append(elt)
+ return "\r\n\r\n".join(arr) + "\r\n\r\n"
+
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getProfileCopyright(profile):
+ """
+ (pyCMS) Gets the copyright for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
+ :exc:`PyCMSError` is raised.
+
+ If an error occurs while trying to obtain the copyright tag,
+ a :exc:`PyCMSError` is raised.
+
+ Use this function to obtain the information stored in the profile's
+ copyright tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.copyright or "") + "\n"
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getProfileManufacturer(profile):
+ """
+ (pyCMS) Gets the manufacturer for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
+ :exc:`PyCMSError` is raised.
+
+ If an error occurs while trying to obtain the manufacturer tag, a
+ :exc:`PyCMSError` is raised.
+
+ Use this function to obtain the information stored in the profile's
+ manufacturer tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.manufacturer or "") + "\n"
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getProfileModel(profile):
+ """
+ (pyCMS) Gets the model for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
+ :exc:`PyCMSError` is raised.
+
+ If an error occurs while trying to obtain the model tag,
+ a :exc:`PyCMSError` is raised.
+
+ Use this function to obtain the information stored in the profile's
+ model tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in
+ an ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.model or "") + "\n"
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getProfileDescription(profile):
+ """
+ (pyCMS) Gets the description for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
+ :exc:`PyCMSError` is raised.
+
+ If an error occurs while trying to obtain the description tag,
+ a :exc:`PyCMSError` is raised.
+
+ Use this function to obtain the information stored in the profile's
+ description tag.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: A string containing the internal profile information stored in an
+ ICC tag.
+ :exception PyCMSError:
+ """
+
+ try:
+ # add an extra newline to preserve pyCMS compatibility
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return (profile.profile.profile_description or "") + "\n"
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def getDefaultIntent(profile):
+ """
+ (pyCMS) Gets the default intent name for the given profile.
+
+ If ``profile`` isn't a valid CmsProfile object or filename to a profile, a
+ :exc:`PyCMSError` is raised.
+
+ If an error occurs while trying to obtain the default intent, a
+ :exc:`PyCMSError` is raised.
+
+ Use this function to determine the default (and usually best optimized)
+ rendering intent for this profile. Most profiles support multiple
+ rendering intents, but are intended mostly for one type of conversion.
+ If you wish to use a different intent than returned, use
+ ImageCms.isIntentSupported() to verify it will work first.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :returns: Integer 0-3 specifying the default rendering intent for this
+ profile.
+
+ ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
+ ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
+ ImageCms.INTENT_SATURATION = 2
+ ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+ see the pyCMS documentation for details on rendering intents and what
+ they do.
+ :exception PyCMSError:
+ """
+
+ try:
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ return profile.profile.rendering_intent
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def isIntentSupported(profile, intent, direction):
+ """
+ (pyCMS) Checks if a given intent is supported.
+
+ Use this function to verify that you can use your desired
+ ``intent`` with ``profile``, and that ``profile`` can be used for the
+ input/output/proof profile as you desire.
+
+ Some profiles are created specifically for one "direction", can cannot
+ be used for others. Some profiles can only be used for certain
+ rendering intents, so it's best to either verify this before trying
+ to create a transform with them (using this function), or catch the
+ potential :exc:`PyCMSError` that will occur if they don't
+ support the modes you select.
+
+ :param profile: EITHER a valid CmsProfile object, OR a string of the
+ filename of an ICC profile.
+ :param intent: Integer (0-3) specifying the rendering intent you wish to
+ use with this profile
+
+ ImageCms.INTENT_PERCEPTUAL = 0 (DEFAULT)
+ ImageCms.INTENT_RELATIVE_COLORIMETRIC = 1
+ ImageCms.INTENT_SATURATION = 2
+ ImageCms.INTENT_ABSOLUTE_COLORIMETRIC = 3
+
+ see the pyCMS documentation for details on rendering intents and what
+ they do.
+ :param direction: Integer specifying if the profile is to be used for
+ input, output, or proof
+
+ INPUT = 0 (or use ImageCms.DIRECTION_INPUT)
+ OUTPUT = 1 (or use ImageCms.DIRECTION_OUTPUT)
+ PROOF = 2 (or use ImageCms.DIRECTION_PROOF)
+
+ :returns: 1 if the intent/direction are supported, -1 if they are not.
+ :exception PyCMSError:
+ """
+
+ try:
+ if not isinstance(profile, ImageCmsProfile):
+ profile = ImageCmsProfile(profile)
+ # FIXME: I get different results for the same data w. different
+ # compilers. Bug in LittleCMS or in the binding?
+ if profile.profile.is_intent_supported(intent, direction):
+ return 1
+ else:
+ return -1
+ except (AttributeError, OSError, TypeError, ValueError) as v:
+ raise PyCMSError(v) from v
+
+
+def versions():
+ """
+ (pyCMS) Fetches versions.
+ """
+
+ return (VERSION, core.littlecms_version, sys.version.split()[0], Image.__version__)
diff --git a/venv/Lib/site-packages/PIL/ImageColor.py b/venv/Lib/site-packages/PIL/ImageColor.py
new file mode 100644
index 0000000..9091174
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageColor.py
@@ -0,0 +1,300 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# map CSS3-style colour description strings to RGB
+#
+# History:
+# 2002-10-24 fl Added support for CSS-style color strings
+# 2002-12-15 fl Added RGBA support
+# 2004-03-27 fl Fixed remaining int() problems for Python 1.5.2
+# 2004-07-19 fl Fixed gray/grey spelling issues
+# 2009-03-05 fl Fixed rounding error in grayscale calculation
+#
+# Copyright (c) 2002-2004 by Secret Labs AB
+# Copyright (c) 2002-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import re
+
+from . import Image
+
+
+def getrgb(color):
+ """
+ Convert a color string to an RGB tuple. If the string cannot be parsed,
+ this function raises a :py:exc:`ValueError` exception.
+
+ .. versionadded:: 1.1.4
+
+ :param color: A color string
+ :return: ``(red, green, blue[, alpha])``
+ """
+ color = color.lower()
+
+ rgb = colormap.get(color, None)
+ if rgb:
+ if isinstance(rgb, tuple):
+ return rgb
+ colormap[color] = rgb = getrgb(rgb)
+ return rgb
+
+ # check for known string formats
+ if re.match("#[a-f0-9]{3}$", color):
+ return (int(color[1] * 2, 16), int(color[2] * 2, 16), int(color[3] * 2, 16))
+
+ if re.match("#[a-f0-9]{4}$", color):
+ return (
+ int(color[1] * 2, 16),
+ int(color[2] * 2, 16),
+ int(color[3] * 2, 16),
+ int(color[4] * 2, 16),
+ )
+
+ if re.match("#[a-f0-9]{6}$", color):
+ return (int(color[1:3], 16), int(color[3:5], 16), int(color[5:7], 16))
+
+ if re.match("#[a-f0-9]{8}$", color):
+ return (
+ int(color[1:3], 16),
+ int(color[3:5], 16),
+ int(color[5:7], 16),
+ int(color[7:9], 16),
+ )
+
+ m = re.match(r"rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
+ if m:
+ return (int(m.group(1)), int(m.group(2)), int(m.group(3)))
+
+ m = re.match(r"rgb\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)$", color)
+ if m:
+ return (
+ int((int(m.group(1)) * 255) / 100.0 + 0.5),
+ int((int(m.group(2)) * 255) / 100.0 + 0.5),
+ int((int(m.group(3)) * 255) / 100.0 + 0.5),
+ )
+
+ m = re.match(
+ r"hsl\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
+ )
+ if m:
+ from colorsys import hls_to_rgb
+
+ rgb = hls_to_rgb(
+ float(m.group(1)) / 360.0,
+ float(m.group(3)) / 100.0,
+ float(m.group(2)) / 100.0,
+ )
+ return (
+ int(rgb[0] * 255 + 0.5),
+ int(rgb[1] * 255 + 0.5),
+ int(rgb[2] * 255 + 0.5),
+ )
+
+ m = re.match(
+ r"hs[bv]\(\s*(\d+\.?\d*)\s*,\s*(\d+\.?\d*)%\s*,\s*(\d+\.?\d*)%\s*\)$", color
+ )
+ if m:
+ from colorsys import hsv_to_rgb
+
+ rgb = hsv_to_rgb(
+ float(m.group(1)) / 360.0,
+ float(m.group(2)) / 100.0,
+ float(m.group(3)) / 100.0,
+ )
+ return (
+ int(rgb[0] * 255 + 0.5),
+ int(rgb[1] * 255 + 0.5),
+ int(rgb[2] * 255 + 0.5),
+ )
+
+ m = re.match(r"rgba\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$", color)
+ if m:
+ return (int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)))
+ raise ValueError(f"unknown color specifier: {repr(color)}")
+
+
+def getcolor(color, mode):
+ """
+ Same as :py:func:`~PIL.ImageColor.getrgb`, but converts the RGB value to a
+ greyscale value if the mode is not color or a palette image. If the string
+ cannot be parsed, this function raises a :py:exc:`ValueError` exception.
+
+ .. versionadded:: 1.1.4
+
+ :param color: A color string
+ :return: ``(graylevel [, alpha]) or (red, green, blue[, alpha])``
+ """
+ # same as getrgb, but converts the result to the given mode
+ color, alpha = getrgb(color), 255
+ if len(color) == 4:
+ color, alpha = color[0:3], color[3]
+
+ if Image.getmodebase(mode) == "L":
+ r, g, b = color
+ # ITU-R Recommendation 601-2 for nonlinear RGB
+ # scaled to 24 bits to match the convert's implementation.
+ color = (r * 19595 + g * 38470 + b * 7471 + 0x8000) >> 16
+ if mode[-1] == "A":
+ return (color, alpha)
+ else:
+ if mode[-1] == "A":
+ return color + (alpha,)
+ return color
+
+
+colormap = {
+ # X11 colour table from https://drafts.csswg.org/css-color-4/, with
+ # gray/grey spelling issues fixed. This is a superset of HTML 4.0
+ # colour names used in CSS 1.
+ "aliceblue": "#f0f8ff",
+ "antiquewhite": "#faebd7",
+ "aqua": "#00ffff",
+ "aquamarine": "#7fffd4",
+ "azure": "#f0ffff",
+ "beige": "#f5f5dc",
+ "bisque": "#ffe4c4",
+ "black": "#000000",
+ "blanchedalmond": "#ffebcd",
+ "blue": "#0000ff",
+ "blueviolet": "#8a2be2",
+ "brown": "#a52a2a",
+ "burlywood": "#deb887",
+ "cadetblue": "#5f9ea0",
+ "chartreuse": "#7fff00",
+ "chocolate": "#d2691e",
+ "coral": "#ff7f50",
+ "cornflowerblue": "#6495ed",
+ "cornsilk": "#fff8dc",
+ "crimson": "#dc143c",
+ "cyan": "#00ffff",
+ "darkblue": "#00008b",
+ "darkcyan": "#008b8b",
+ "darkgoldenrod": "#b8860b",
+ "darkgray": "#a9a9a9",
+ "darkgrey": "#a9a9a9",
+ "darkgreen": "#006400",
+ "darkkhaki": "#bdb76b",
+ "darkmagenta": "#8b008b",
+ "darkolivegreen": "#556b2f",
+ "darkorange": "#ff8c00",
+ "darkorchid": "#9932cc",
+ "darkred": "#8b0000",
+ "darksalmon": "#e9967a",
+ "darkseagreen": "#8fbc8f",
+ "darkslateblue": "#483d8b",
+ "darkslategray": "#2f4f4f",
+ "darkslategrey": "#2f4f4f",
+ "darkturquoise": "#00ced1",
+ "darkviolet": "#9400d3",
+ "deeppink": "#ff1493",
+ "deepskyblue": "#00bfff",
+ "dimgray": "#696969",
+ "dimgrey": "#696969",
+ "dodgerblue": "#1e90ff",
+ "firebrick": "#b22222",
+ "floralwhite": "#fffaf0",
+ "forestgreen": "#228b22",
+ "fuchsia": "#ff00ff",
+ "gainsboro": "#dcdcdc",
+ "ghostwhite": "#f8f8ff",
+ "gold": "#ffd700",
+ "goldenrod": "#daa520",
+ "gray": "#808080",
+ "grey": "#808080",
+ "green": "#008000",
+ "greenyellow": "#adff2f",
+ "honeydew": "#f0fff0",
+ "hotpink": "#ff69b4",
+ "indianred": "#cd5c5c",
+ "indigo": "#4b0082",
+ "ivory": "#fffff0",
+ "khaki": "#f0e68c",
+ "lavender": "#e6e6fa",
+ "lavenderblush": "#fff0f5",
+ "lawngreen": "#7cfc00",
+ "lemonchiffon": "#fffacd",
+ "lightblue": "#add8e6",
+ "lightcoral": "#f08080",
+ "lightcyan": "#e0ffff",
+ "lightgoldenrodyellow": "#fafad2",
+ "lightgreen": "#90ee90",
+ "lightgray": "#d3d3d3",
+ "lightgrey": "#d3d3d3",
+ "lightpink": "#ffb6c1",
+ "lightsalmon": "#ffa07a",
+ "lightseagreen": "#20b2aa",
+ "lightskyblue": "#87cefa",
+ "lightslategray": "#778899",
+ "lightslategrey": "#778899",
+ "lightsteelblue": "#b0c4de",
+ "lightyellow": "#ffffe0",
+ "lime": "#00ff00",
+ "limegreen": "#32cd32",
+ "linen": "#faf0e6",
+ "magenta": "#ff00ff",
+ "maroon": "#800000",
+ "mediumaquamarine": "#66cdaa",
+ "mediumblue": "#0000cd",
+ "mediumorchid": "#ba55d3",
+ "mediumpurple": "#9370db",
+ "mediumseagreen": "#3cb371",
+ "mediumslateblue": "#7b68ee",
+ "mediumspringgreen": "#00fa9a",
+ "mediumturquoise": "#48d1cc",
+ "mediumvioletred": "#c71585",
+ "midnightblue": "#191970",
+ "mintcream": "#f5fffa",
+ "mistyrose": "#ffe4e1",
+ "moccasin": "#ffe4b5",
+ "navajowhite": "#ffdead",
+ "navy": "#000080",
+ "oldlace": "#fdf5e6",
+ "olive": "#808000",
+ "olivedrab": "#6b8e23",
+ "orange": "#ffa500",
+ "orangered": "#ff4500",
+ "orchid": "#da70d6",
+ "palegoldenrod": "#eee8aa",
+ "palegreen": "#98fb98",
+ "paleturquoise": "#afeeee",
+ "palevioletred": "#db7093",
+ "papayawhip": "#ffefd5",
+ "peachpuff": "#ffdab9",
+ "peru": "#cd853f",
+ "pink": "#ffc0cb",
+ "plum": "#dda0dd",
+ "powderblue": "#b0e0e6",
+ "purple": "#800080",
+ "rebeccapurple": "#663399",
+ "red": "#ff0000",
+ "rosybrown": "#bc8f8f",
+ "royalblue": "#4169e1",
+ "saddlebrown": "#8b4513",
+ "salmon": "#fa8072",
+ "sandybrown": "#f4a460",
+ "seagreen": "#2e8b57",
+ "seashell": "#fff5ee",
+ "sienna": "#a0522d",
+ "silver": "#c0c0c0",
+ "skyblue": "#87ceeb",
+ "slateblue": "#6a5acd",
+ "slategray": "#708090",
+ "slategrey": "#708090",
+ "snow": "#fffafa",
+ "springgreen": "#00ff7f",
+ "steelblue": "#4682b4",
+ "tan": "#d2b48c",
+ "teal": "#008080",
+ "thistle": "#d8bfd8",
+ "tomato": "#ff6347",
+ "turquoise": "#40e0d0",
+ "violet": "#ee82ee",
+ "wheat": "#f5deb3",
+ "white": "#ffffff",
+ "whitesmoke": "#f5f5f5",
+ "yellow": "#ffff00",
+ "yellowgreen": "#9acd32",
+}
diff --git a/venv/Lib/site-packages/PIL/ImageDraw.py b/venv/Lib/site-packages/PIL/ImageDraw.py
new file mode 100644
index 0000000..b823be9
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageDraw.py
@@ -0,0 +1,898 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# drawing interface operations
+#
+# History:
+# 1996-04-13 fl Created (experimental)
+# 1996-08-07 fl Filled polygons, ellipses.
+# 1996-08-13 fl Added text support
+# 1998-06-28 fl Handle I and F images
+# 1998-12-29 fl Added arc; use arc primitive to draw ellipses
+# 1999-01-10 fl Added shape stuff (experimental)
+# 1999-02-06 fl Added bitmap support
+# 1999-02-11 fl Changed all primitives to take options
+# 1999-02-20 fl Fixed backwards compatibility
+# 2000-10-12 fl Copy on write, when necessary
+# 2001-02-18 fl Use default ink for bitmap/text also in fill mode
+# 2002-10-24 fl Added support for CSS-style color strings
+# 2002-12-10 fl Added experimental support for RGBA-on-RGB drawing
+# 2002-12-11 fl Refactored low-level drawing API (work in progress)
+# 2004-08-26 fl Made Draw() a factory function, added getdraw() support
+# 2004-09-04 fl Added width support to line primitive
+# 2004-09-10 fl Added font mode handling
+# 2006-06-19 fl Added font bearing support (getmask2)
+#
+# Copyright (c) 1997-2006 by Secret Labs AB
+# Copyright (c) 1996-2006 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import math
+import numbers
+
+from . import Image, ImageColor
+
+"""
+A simple 2D drawing interface for PIL images.
+
+Application code should use the Draw factory, instead of
+directly.
+"""
+
+
+class ImageDraw:
+ def __init__(self, im, mode=None):
+ """
+ Create a drawing instance.
+
+ :param im: The image to draw in.
+ :param mode: Optional mode to use for color values. For RGB
+ images, this argument can be RGB or RGBA (to blend the
+ drawing into the image). For all other modes, this argument
+ must be the same as the image mode. If omitted, the mode
+ defaults to the mode of the image.
+ """
+ im.load()
+ if im.readonly:
+ im._copy() # make it writeable
+ blend = 0
+ if mode is None:
+ mode = im.mode
+ if mode != im.mode:
+ if mode == "RGBA" and im.mode == "RGB":
+ blend = 1
+ else:
+ raise ValueError("mode mismatch")
+ if mode == "P":
+ self.palette = im.palette
+ else:
+ self.palette = None
+ self.im = im.im
+ self.draw = Image.core.draw(self.im, blend)
+ self.mode = mode
+ if mode in ("I", "F"):
+ self.ink = self.draw.draw_ink(1)
+ else:
+ self.ink = self.draw.draw_ink(-1)
+ if mode in ("1", "P", "I", "F"):
+ # FIXME: fix Fill2 to properly support matte for I+F images
+ self.fontmode = "1"
+ else:
+ self.fontmode = "L" # aliasing is okay for other modes
+ self.fill = 0
+ self.font = None
+
+ def getfont(self):
+ """
+ Get the current default font.
+
+ :returns: An image font."""
+ if not self.font:
+ # FIXME: should add a font repository
+ from . import ImageFont
+
+ self.font = ImageFont.load_default()
+ return self.font
+
+ def _getink(self, ink, fill=None):
+ if ink is None and fill is None:
+ if self.fill:
+ fill = self.ink
+ else:
+ ink = self.ink
+ else:
+ if ink is not None:
+ if isinstance(ink, str):
+ ink = ImageColor.getcolor(ink, self.mode)
+ if self.palette and not isinstance(ink, numbers.Number):
+ ink = self.palette.getcolor(ink)
+ ink = self.draw.draw_ink(ink)
+ if fill is not None:
+ if isinstance(fill, str):
+ fill = ImageColor.getcolor(fill, self.mode)
+ if self.palette and not isinstance(fill, numbers.Number):
+ fill = self.palette.getcolor(fill)
+ fill = self.draw.draw_ink(fill)
+ return ink, fill
+
+ def arc(self, xy, start, end, fill=None, width=1):
+ """Draw an arc."""
+ ink, fill = self._getink(fill)
+ if ink is not None:
+ self.draw.draw_arc(xy, start, end, ink, width)
+
+ def bitmap(self, xy, bitmap, fill=None):
+ """Draw a bitmap."""
+ bitmap.load()
+ ink, fill = self._getink(fill)
+ if ink is None:
+ ink = fill
+ if ink is not None:
+ self.draw.draw_bitmap(xy, bitmap.im, ink)
+
+ def chord(self, xy, start, end, fill=None, outline=None, width=1):
+ """Draw a chord."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_chord(xy, start, end, fill, 1)
+ if ink is not None and ink != fill and width != 0:
+ self.draw.draw_chord(xy, start, end, ink, 0, width)
+
+ def ellipse(self, xy, fill=None, outline=None, width=1):
+ """Draw an ellipse."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_ellipse(xy, fill, 1)
+ if ink is not None and ink != fill and width != 0:
+ self.draw.draw_ellipse(xy, ink, 0, width)
+
+ def line(self, xy, fill=None, width=0, joint=None):
+ """Draw a line, or a connected sequence of line segments."""
+ ink = self._getink(fill)[0]
+ if ink is not None:
+ self.draw.draw_lines(xy, ink, width)
+ if joint == "curve" and width > 4:
+ if not isinstance(xy[0], (list, tuple)):
+ xy = [tuple(xy[i : i + 2]) for i in range(0, len(xy), 2)]
+ for i in range(1, len(xy) - 1):
+ point = xy[i]
+ angles = [
+ math.degrees(math.atan2(end[0] - start[0], start[1] - end[1]))
+ % 360
+ for start, end in ((xy[i - 1], point), (point, xy[i + 1]))
+ ]
+ if angles[0] == angles[1]:
+ # This is a straight line, so no joint is required
+ continue
+
+ def coord_at_angle(coord, angle):
+ x, y = coord
+ angle -= 90
+ distance = width / 2 - 1
+ return tuple(
+ [
+ p + (math.floor(p_d) if p_d > 0 else math.ceil(p_d))
+ for p, p_d in (
+ (x, distance * math.cos(math.radians(angle))),
+ (y, distance * math.sin(math.radians(angle))),
+ )
+ ]
+ )
+
+ flipped = (
+ angles[1] > angles[0] and angles[1] - 180 > angles[0]
+ ) or (angles[1] < angles[0] and angles[1] + 180 > angles[0])
+ coords = [
+ (point[0] - width / 2 + 1, point[1] - width / 2 + 1),
+ (point[0] + width / 2 - 1, point[1] + width / 2 - 1),
+ ]
+ if flipped:
+ start, end = (angles[1] + 90, angles[0] + 90)
+ else:
+ start, end = (angles[0] - 90, angles[1] - 90)
+ self.pieslice(coords, start - 90, end - 90, fill)
+
+ if width > 8:
+ # Cover potential gaps between the line and the joint
+ if flipped:
+ gapCoords = [
+ coord_at_angle(point, angles[0] + 90),
+ point,
+ coord_at_angle(point, angles[1] + 90),
+ ]
+ else:
+ gapCoords = [
+ coord_at_angle(point, angles[0] - 90),
+ point,
+ coord_at_angle(point, angles[1] - 90),
+ ]
+ self.line(gapCoords, fill, width=3)
+
+ def shape(self, shape, fill=None, outline=None):
+ """(Experimental) Draw a shape."""
+ shape.close()
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_outline(shape, fill, 1)
+ if ink is not None and ink != fill:
+ self.draw.draw_outline(shape, ink, 0)
+
+ def pieslice(self, xy, start, end, fill=None, outline=None, width=1):
+ """Draw a pieslice."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_pieslice(xy, start, end, fill, 1)
+ if ink is not None and ink != fill and width != 0:
+ self.draw.draw_pieslice(xy, start, end, ink, 0, width)
+
+ def point(self, xy, fill=None):
+ """Draw one or more individual pixels."""
+ ink, fill = self._getink(fill)
+ if ink is not None:
+ self.draw.draw_points(xy, ink)
+
+ def polygon(self, xy, fill=None, outline=None):
+ """Draw a polygon."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_polygon(xy, fill, 1)
+ if ink is not None and ink != fill:
+ self.draw.draw_polygon(xy, ink, 0)
+
+ def regular_polygon(
+ self, bounding_circle, n_sides, rotation=0, fill=None, outline=None
+ ):
+ """Draw a regular polygon."""
+ xy = _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation)
+ self.polygon(xy, fill, outline)
+
+ def rectangle(self, xy, fill=None, outline=None, width=1):
+ """Draw a rectangle."""
+ ink, fill = self._getink(outline, fill)
+ if fill is not None:
+ self.draw.draw_rectangle(xy, fill, 1)
+ if ink is not None and ink != fill and width != 0:
+ self.draw.draw_rectangle(xy, ink, 0, width)
+
+ def _multiline_check(self, text):
+ """Draw text."""
+ split_character = "\n" if isinstance(text, str) else b"\n"
+
+ return split_character in text
+
+ def _multiline_split(self, text):
+ split_character = "\n" if isinstance(text, str) else b"\n"
+
+ return text.split(split_character)
+
+ def text(
+ self,
+ xy,
+ text,
+ fill=None,
+ font=None,
+ anchor=None,
+ spacing=4,
+ align="left",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ stroke_fill=None,
+ embedded_color=False,
+ *args,
+ **kwargs,
+ ):
+ if self._multiline_check(text):
+ return self.multiline_text(
+ xy,
+ text,
+ fill,
+ font,
+ anchor,
+ spacing,
+ align,
+ direction,
+ features,
+ language,
+ stroke_width,
+ stroke_fill,
+ embedded_color,
+ )
+
+ if embedded_color and self.mode not in ("RGB", "RGBA"):
+ raise ValueError("Embedded color supported only in RGB and RGBA modes")
+
+ if font is None:
+ font = self.getfont()
+
+ def getink(fill):
+ ink, fill = self._getink(fill)
+ if ink is None:
+ return fill
+ return ink
+
+ def draw_text(ink, stroke_width=0, stroke_offset=None):
+ mode = self.fontmode
+ if stroke_width == 0 and embedded_color:
+ mode = "RGBA"
+ coord = xy
+ try:
+ mask, offset = font.getmask2(
+ text,
+ mode,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ anchor=anchor,
+ ink=ink,
+ *args,
+ **kwargs,
+ )
+ coord = coord[0] + offset[0], coord[1] + offset[1]
+ except AttributeError:
+ try:
+ mask = font.getmask(
+ text,
+ mode,
+ direction,
+ features,
+ language,
+ stroke_width,
+ anchor,
+ ink,
+ *args,
+ **kwargs,
+ )
+ except TypeError:
+ mask = font.getmask(text)
+ if stroke_offset:
+ coord = coord[0] + stroke_offset[0], coord[1] + stroke_offset[1]
+ if mode == "RGBA":
+ # font.getmask2(mode="RGBA") returns color in RGB bands and mask in A
+ # extract mask and set text alpha
+ color, mask = mask, mask.getband(3)
+ color.fillband(3, (ink >> 24) & 0xFF)
+ coord2 = coord[0] + mask.size[0], coord[1] + mask.size[1]
+ self.im.paste(color, coord + coord2, mask)
+ else:
+ self.draw.draw_bitmap(coord, mask, ink)
+
+ ink = getink(fill)
+ if ink is not None:
+ stroke_ink = None
+ if stroke_width:
+ stroke_ink = getink(stroke_fill) if stroke_fill is not None else ink
+
+ if stroke_ink is not None:
+ # Draw stroked text
+ draw_text(stroke_ink, stroke_width)
+
+ # Draw normal text
+ draw_text(ink, 0)
+ else:
+ # Only draw normal text
+ draw_text(ink)
+
+ def multiline_text(
+ self,
+ xy,
+ text,
+ fill=None,
+ font=None,
+ anchor=None,
+ spacing=4,
+ align="left",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ stroke_fill=None,
+ embedded_color=False,
+ ):
+ if direction == "ttb":
+ raise ValueError("ttb direction is unsupported for multiline text")
+
+ if anchor is None:
+ anchor = "la"
+ elif len(anchor) != 2:
+ raise ValueError("anchor must be a 2 character string")
+ elif anchor[1] in "tb":
+ raise ValueError("anchor not supported for multiline text")
+
+ widths = []
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = (
+ self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
+ )
+ for line in lines:
+ line_width = self.textlength(
+ line, font, direction=direction, features=features, language=language
+ )
+ widths.append(line_width)
+ max_width = max(max_width, line_width)
+
+ top = xy[1]
+ if anchor[1] == "m":
+ top -= (len(lines) - 1) * line_spacing / 2.0
+ elif anchor[1] == "d":
+ top -= (len(lines) - 1) * line_spacing
+
+ for idx, line in enumerate(lines):
+ left = xy[0]
+ width_difference = max_width - widths[idx]
+
+ # first align left by anchor
+ if anchor[0] == "m":
+ left -= width_difference / 2.0
+ elif anchor[0] == "r":
+ left -= width_difference
+
+ # then align by align parameter
+ if align == "left":
+ pass
+ elif align == "center":
+ left += width_difference / 2.0
+ elif align == "right":
+ left += width_difference
+ else:
+ raise ValueError('align must be "left", "center" or "right"')
+
+ self.text(
+ (left, top),
+ line,
+ fill,
+ font,
+ anchor,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ stroke_fill=stroke_fill,
+ embedded_color=embedded_color,
+ )
+ top += line_spacing
+
+ def textsize(
+ self,
+ text,
+ font=None,
+ spacing=4,
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ """Get the size of a given string, in pixels."""
+ if self._multiline_check(text):
+ return self.multiline_textsize(
+ text, font, spacing, direction, features, language, stroke_width
+ )
+
+ if font is None:
+ font = self.getfont()
+ return font.getsize(text, direction, features, language, stroke_width)
+
+ def multiline_textsize(
+ self,
+ text,
+ font=None,
+ spacing=4,
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = (
+ self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
+ )
+ for line in lines:
+ line_width, line_height = self.textsize(
+ line, font, spacing, direction, features, language, stroke_width
+ )
+ max_width = max(max_width, line_width)
+ return max_width, len(lines) * line_spacing - spacing
+
+ def textlength(
+ self,
+ text,
+ font=None,
+ direction=None,
+ features=None,
+ language=None,
+ embedded_color=False,
+ ):
+ """Get the length of a given string, in pixels with 1/64 precision."""
+ if self._multiline_check(text):
+ raise ValueError("can't measure length of multiline text")
+ if embedded_color and self.mode not in ("RGB", "RGBA"):
+ raise ValueError("Embedded color supported only in RGB and RGBA modes")
+
+ if font is None:
+ font = self.getfont()
+ mode = "RGBA" if embedded_color else self.fontmode
+ try:
+ return font.getlength(text, mode, direction, features, language)
+ except AttributeError:
+ size = self.textsize(
+ text, font, direction=direction, features=features, language=language
+ )
+ if direction == "ttb":
+ return size[1]
+ return size[0]
+
+ def textbbox(
+ self,
+ xy,
+ text,
+ font=None,
+ anchor=None,
+ spacing=4,
+ align="left",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ embedded_color=False,
+ ):
+ """Get the bounding box of a given string, in pixels."""
+ if embedded_color and self.mode not in ("RGB", "RGBA"):
+ raise ValueError("Embedded color supported only in RGB and RGBA modes")
+
+ if self._multiline_check(text):
+ return self.multiline_textbbox(
+ xy,
+ text,
+ font,
+ anchor,
+ spacing,
+ align,
+ direction,
+ features,
+ language,
+ stroke_width,
+ embedded_color,
+ )
+
+ if font is None:
+ font = self.getfont()
+ mode = "RGBA" if embedded_color else self.fontmode
+ bbox = font.getbbox(
+ text, mode, direction, features, language, stroke_width, anchor
+ )
+ return bbox[0] + xy[0], bbox[1] + xy[1], bbox[2] + xy[0], bbox[3] + xy[1]
+
+ def multiline_textbbox(
+ self,
+ xy,
+ text,
+ font=None,
+ anchor=None,
+ spacing=4,
+ align="left",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ embedded_color=False,
+ ):
+ if direction == "ttb":
+ raise ValueError("ttb direction is unsupported for multiline text")
+
+ if anchor is None:
+ anchor = "la"
+ elif len(anchor) != 2:
+ raise ValueError("anchor must be a 2 character string")
+ elif anchor[1] in "tb":
+ raise ValueError("anchor not supported for multiline text")
+
+ widths = []
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = (
+ self.textsize("A", font=font, stroke_width=stroke_width)[1] + spacing
+ )
+ for line in lines:
+ line_width = self.textlength(
+ line,
+ font,
+ direction=direction,
+ features=features,
+ language=language,
+ embedded_color=embedded_color,
+ )
+ widths.append(line_width)
+ max_width = max(max_width, line_width)
+
+ top = xy[1]
+ if anchor[1] == "m":
+ top -= (len(lines) - 1) * line_spacing / 2.0
+ elif anchor[1] == "d":
+ top -= (len(lines) - 1) * line_spacing
+
+ bbox = None
+
+ for idx, line in enumerate(lines):
+ left = xy[0]
+ width_difference = max_width - widths[idx]
+
+ # first align left by anchor
+ if anchor[0] == "m":
+ left -= width_difference / 2.0
+ elif anchor[0] == "r":
+ left -= width_difference
+
+ # then align by align parameter
+ if align == "left":
+ pass
+ elif align == "center":
+ left += width_difference / 2.0
+ elif align == "right":
+ left += width_difference
+ else:
+ raise ValueError('align must be "left", "center" or "right"')
+
+ bbox_line = self.textbbox(
+ (left, top),
+ line,
+ font,
+ anchor,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ embedded_color=embedded_color,
+ )
+ if bbox is None:
+ bbox = bbox_line
+ else:
+ bbox = (
+ min(bbox[0], bbox_line[0]),
+ min(bbox[1], bbox_line[1]),
+ max(bbox[2], bbox_line[2]),
+ max(bbox[3], bbox_line[3]),
+ )
+
+ top += line_spacing
+
+ if bbox is None:
+ return xy[0], xy[1], xy[0], xy[1]
+ return bbox
+
+
+def Draw(im, mode=None):
+ """
+ A simple 2D drawing interface for PIL images.
+
+ :param im: The image to draw in.
+ :param mode: Optional mode to use for color values. For RGB
+ images, this argument can be RGB or RGBA (to blend the
+ drawing into the image). For all other modes, this argument
+ must be the same as the image mode. If omitted, the mode
+ defaults to the mode of the image.
+ """
+ try:
+ return im.getdraw(mode)
+ except AttributeError:
+ return ImageDraw(im, mode)
+
+
+# experimental access to the outline API
+try:
+ Outline = Image.core.outline
+except AttributeError:
+ Outline = None
+
+
+def getdraw(im=None, hints=None):
+ """
+ (Experimental) A more advanced 2D drawing interface for PIL images,
+ based on the WCK interface.
+
+ :param im: The image to draw in.
+ :param hints: An optional list of hints.
+ :returns: A (drawing context, drawing resource factory) tuple.
+ """
+ # FIXME: this needs more work!
+ # FIXME: come up with a better 'hints' scheme.
+ handler = None
+ if not hints or "nicest" in hints:
+ try:
+ from . import _imagingagg as handler
+ except ImportError:
+ pass
+ if handler is None:
+ from . import ImageDraw2 as handler
+ if im:
+ im = handler.Draw(im)
+ return im, handler
+
+
+def floodfill(image, xy, value, border=None, thresh=0):
+ """
+ (experimental) Fills a bounded region with a given color.
+
+ :param image: Target image.
+ :param xy: Seed position (a 2-item coordinate tuple). See
+ :ref:`coordinate-system`.
+ :param value: Fill color.
+ :param border: Optional border value. If given, the region consists of
+ pixels with a color different from the border color. If not given,
+ the region consists of pixels having the same color as the seed
+ pixel.
+ :param thresh: Optional threshold value which specifies a maximum
+ tolerable difference of a pixel value from the 'background' in
+ order for it to be replaced. Useful for filling regions of
+ non-homogeneous, but similar, colors.
+ """
+ # based on an implementation by Eric S. Raymond
+ # amended by yo1995 @20180806
+ pixel = image.load()
+ x, y = xy
+ try:
+ background = pixel[x, y]
+ if _color_diff(value, background) <= thresh:
+ return # seed point already has fill color
+ pixel[x, y] = value
+ except (ValueError, IndexError):
+ return # seed point outside image
+ edge = {(x, y)}
+ # use a set to keep record of current and previous edge pixels
+ # to reduce memory consumption
+ full_edge = set()
+ while edge:
+ new_edge = set()
+ for (x, y) in edge: # 4 adjacent method
+ for (s, t) in ((x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)):
+ # If already processed, or if a coordinate is negative, skip
+ if (s, t) in full_edge or s < 0 or t < 0:
+ continue
+ try:
+ p = pixel[s, t]
+ except (ValueError, IndexError):
+ pass
+ else:
+ full_edge.add((s, t))
+ if border is None:
+ fill = _color_diff(p, background) <= thresh
+ else:
+ fill = p != value and p != border
+ if fill:
+ pixel[s, t] = value
+ new_edge.add((s, t))
+ full_edge = edge # discard pixels processed
+ edge = new_edge
+
+
+def _compute_regular_polygon_vertices(bounding_circle, n_sides, rotation):
+ """
+ Generate a list of vertices for a 2D regular polygon.
+
+ :param bounding_circle: The bounding circle is a tuple defined
+ by a point and radius. The polygon is inscribed in this circle.
+ (e.g. ``bounding_circle=(x, y, r)`` or ``((x, y), r)``)
+ :param n_sides: Number of sides
+ (e.g. ``n_sides=3`` for a triangle, ``6`` for a hexagon)
+ :param rotation: Apply an arbitrary rotation to the polygon
+ (e.g. ``rotation=90``, applies a 90 degree rotation)
+ :return: List of regular polygon vertices
+ (e.g. ``[(25, 50), (50, 50), (50, 25), (25, 25)]``)
+
+ How are the vertices computed?
+ 1. Compute the following variables
+ - theta: Angle between the apothem & the nearest polygon vertex
+ - side_length: Length of each polygon edge
+ - centroid: Center of bounding circle (1st, 2nd elements of bounding_circle)
+ - polygon_radius: Polygon radius (last element of bounding_circle)
+ - angles: Location of each polygon vertex in polar grid
+ (e.g. A square with 0 degree rotation => [225.0, 315.0, 45.0, 135.0])
+
+ 2. For each angle in angles, get the polygon vertex at that angle
+ The vertex is computed using the equation below.
+ X= xcos(φ) + ysin(φ)
+ Y= −xsin(φ) + ycos(φ)
+
+ Note:
+ φ = angle in degrees
+ x = 0
+ y = polygon_radius
+
+ The formula above assumes rotation around the origin.
+ In our case, we are rotating around the centroid.
+ To account for this, we use the formula below
+ X = xcos(φ) + ysin(φ) + centroid_x
+ Y = −xsin(φ) + ycos(φ) + centroid_y
+ """
+ # 1. Error Handling
+ # 1.1 Check `n_sides` has an appropriate value
+ if not isinstance(n_sides, int):
+ raise TypeError("n_sides should be an int")
+ if n_sides < 3:
+ raise ValueError("n_sides should be an int > 2")
+
+ # 1.2 Check `bounding_circle` has an appropriate value
+ if not isinstance(bounding_circle, (list, tuple)):
+ raise TypeError("bounding_circle should be a tuple")
+
+ if len(bounding_circle) == 3:
+ *centroid, polygon_radius = bounding_circle
+ elif len(bounding_circle) == 2:
+ centroid, polygon_radius = bounding_circle
+ else:
+ raise ValueError(
+ "bounding_circle should contain 2D coordinates "
+ "and a radius (e.g. (x, y, r) or ((x, y), r) )"
+ )
+
+ if not all(isinstance(i, (int, float)) for i in (*centroid, polygon_radius)):
+ raise ValueError("bounding_circle should only contain numeric data")
+
+ if not len(centroid) == 2:
+ raise ValueError(
+ "bounding_circle centre should contain 2D coordinates (e.g. (x, y))"
+ )
+
+ if polygon_radius <= 0:
+ raise ValueError("bounding_circle radius should be > 0")
+
+ # 1.3 Check `rotation` has an appropriate value
+ if not isinstance(rotation, (int, float)):
+ raise ValueError("rotation should be an int or float")
+
+ # 2. Define Helper Functions
+ def _apply_rotation(point, degrees, centroid):
+ return (
+ round(
+ point[0] * math.cos(math.radians(360 - degrees))
+ - point[1] * math.sin(math.radians(360 - degrees))
+ + centroid[0],
+ 2,
+ ),
+ round(
+ point[1] * math.cos(math.radians(360 - degrees))
+ + point[0] * math.sin(math.radians(360 - degrees))
+ + centroid[1],
+ 2,
+ ),
+ )
+
+ def _compute_polygon_vertex(centroid, polygon_radius, angle):
+ start_point = [polygon_radius, 0]
+ return _apply_rotation(start_point, angle, centroid)
+
+ def _get_angles(n_sides, rotation):
+ angles = []
+ degrees = 360 / n_sides
+ # Start with the bottom left polygon vertex
+ current_angle = (270 - 0.5 * degrees) + rotation
+ for _ in range(0, n_sides):
+ angles.append(current_angle)
+ current_angle += degrees
+ if current_angle > 360:
+ current_angle -= 360
+ return angles
+
+ # 3. Variable Declarations
+ angles = _get_angles(n_sides, rotation)
+
+ # 4. Compute Vertices
+ return [
+ _compute_polygon_vertex(centroid, polygon_radius, angle) for angle in angles
+ ]
+
+
+def _color_diff(color1, color2):
+ """
+ Uses 1-norm distance to calculate difference between two values.
+ """
+ if isinstance(color2, tuple):
+ return sum([abs(color1[i] - color2[i]) for i in range(0, len(color2))])
+ else:
+ return abs(color1 - color2)
diff --git a/venv/Lib/site-packages/PIL/ImageDraw2.py b/venv/Lib/site-packages/PIL/ImageDraw2.py
new file mode 100644
index 0000000..1f63110
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageDraw2.py
@@ -0,0 +1,179 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# WCK-style drawing interface operations
+#
+# History:
+# 2003-12-07 fl created
+# 2005-05-15 fl updated; added to PIL as ImageDraw2
+# 2005-05-15 fl added text support
+# 2005-05-20 fl added arc/chord/pieslice support
+#
+# Copyright (c) 2003-2005 by Secret Labs AB
+# Copyright (c) 2003-2005 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+"""
+(Experimental) WCK-style drawing interface operations
+
+.. seealso:: :py:mod:`PIL.ImageDraw`
+"""
+
+
+from . import Image, ImageColor, ImageDraw, ImageFont, ImagePath
+
+
+class Pen:
+ """Stores an outline color and width."""
+
+ def __init__(self, color, width=1, opacity=255):
+ self.color = ImageColor.getrgb(color)
+ self.width = width
+
+
+class Brush:
+ """Stores a fill color"""
+
+ def __init__(self, color, opacity=255):
+ self.color = ImageColor.getrgb(color)
+
+
+class Font:
+ """Stores a TrueType font and color"""
+
+ def __init__(self, color, file, size=12):
+ # FIXME: add support for bitmap fonts
+ self.color = ImageColor.getrgb(color)
+ self.font = ImageFont.truetype(file, size)
+
+
+class Draw:
+ """
+ (Experimental) WCK-style drawing interface
+ """
+
+ def __init__(self, image, size=None, color=None):
+ if not hasattr(image, "im"):
+ image = Image.new(image, size, color)
+ self.draw = ImageDraw.Draw(image)
+ self.image = image
+ self.transform = None
+
+ def flush(self):
+ return self.image
+
+ def render(self, op, xy, pen, brush=None):
+ # handle color arguments
+ outline = fill = None
+ width = 1
+ if isinstance(pen, Pen):
+ outline = pen.color
+ width = pen.width
+ elif isinstance(brush, Pen):
+ outline = brush.color
+ width = brush.width
+ if isinstance(brush, Brush):
+ fill = brush.color
+ elif isinstance(pen, Brush):
+ fill = pen.color
+ # handle transformation
+ if self.transform:
+ xy = ImagePath.Path(xy)
+ xy.transform(self.transform)
+ # render the item
+ if op == "line":
+ self.draw.line(xy, fill=outline, width=width)
+ else:
+ getattr(self.draw, op)(xy, fill=fill, outline=outline)
+
+ def settransform(self, offset):
+ """Sets a transformation offset."""
+ (xoffset, yoffset) = offset
+ self.transform = (1, 0, xoffset, 0, 1, yoffset)
+
+ def arc(self, xy, start, end, *options):
+ """
+ Draws an arc (a portion of a circle outline) between the start and end
+ angles, inside the given bounding box.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.arc`
+ """
+ self.render("arc", xy, start, end, *options)
+
+ def chord(self, xy, start, end, *options):
+ """
+ Same as :py:meth:`~PIL.ImageDraw2.Draw.arc`, but connects the end points
+ with a straight line.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.chord`
+ """
+ self.render("chord", xy, start, end, *options)
+
+ def ellipse(self, xy, *options):
+ """
+ Draws an ellipse inside the given bounding box.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.ellipse`
+ """
+ self.render("ellipse", xy, *options)
+
+ def line(self, xy, *options):
+ """
+ Draws a line between the coordinates in the ``xy`` list.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.line`
+ """
+ self.render("line", xy, *options)
+
+ def pieslice(self, xy, start, end, *options):
+ """
+ Same as arc, but also draws straight lines between the end points and the
+ center of the bounding box.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.pieslice`
+ """
+ self.render("pieslice", xy, start, end, *options)
+
+ def polygon(self, xy, *options):
+ """
+ Draws a polygon.
+
+ The polygon outline consists of straight lines between the given
+ coordinates, plus a straight line between the last and the first
+ coordinate.
+
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.polygon`
+ """
+ self.render("polygon", xy, *options)
+
+ def rectangle(self, xy, *options):
+ """
+ Draws a rectangle.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.rectangle`
+ """
+ self.render("rectangle", xy, *options)
+
+ def text(self, xy, text, font):
+ """
+ Draws the string at the given position.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.text`
+ """
+ if self.transform:
+ xy = ImagePath.Path(xy)
+ xy.transform(self.transform)
+ self.draw.text(xy, text, font=font.font, fill=font.color)
+
+ def textsize(self, text, font):
+ """
+ Return the size of the given string, in pixels.
+
+ .. seealso:: :py:meth:`PIL.ImageDraw.ImageDraw.textsize`
+ """
+ return self.draw.textsize(text, font=font.font)
diff --git a/venv/Lib/site-packages/PIL/ImageEnhance.py b/venv/Lib/site-packages/PIL/ImageEnhance.py
new file mode 100644
index 0000000..3b79d5c
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageEnhance.py
@@ -0,0 +1,103 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# image enhancement classes
+#
+# For a background, see "Image Processing By Interpolation and
+# Extrapolation", Paul Haeberli and Douglas Voorhies. Available
+# at http://www.graficaobscura.com/interp/index.html
+#
+# History:
+# 1996-03-23 fl Created
+# 2009-06-16 fl Fixed mean calculation
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFilter, ImageStat
+
+
+class _Enhance:
+ def enhance(self, factor):
+ """
+ Returns an enhanced image.
+
+ :param factor: A floating point value controlling the enhancement.
+ Factor 1.0 always returns a copy of the original image,
+ lower factors mean less color (brightness, contrast,
+ etc), and higher values more. There are no restrictions
+ on this value.
+ :rtype: :py:class:`~PIL.Image.Image`
+ """
+ return Image.blend(self.degenerate, self.image, factor)
+
+
+class Color(_Enhance):
+ """Adjust image color balance.
+
+ This class can be used to adjust the colour balance of an image, in
+ a manner similar to the controls on a colour TV set. An enhancement
+ factor of 0.0 gives a black and white image. A factor of 1.0 gives
+ the original image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ self.intermediate_mode = "L"
+ if "A" in image.getbands():
+ self.intermediate_mode = "LA"
+
+ self.degenerate = image.convert(self.intermediate_mode).convert(image.mode)
+
+
+class Contrast(_Enhance):
+ """Adjust image contrast.
+
+ This class can be used to control the contrast of an image, similar
+ to the contrast control on a TV set. An enhancement factor of 0.0
+ gives a solid grey image. A factor of 1.0 gives the original image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ mean = int(ImageStat.Stat(image.convert("L")).mean[0] + 0.5)
+ self.degenerate = Image.new("L", image.size, mean).convert(image.mode)
+
+ if "A" in image.getbands():
+ self.degenerate.putalpha(image.getchannel("A"))
+
+
+class Brightness(_Enhance):
+ """Adjust image brightness.
+
+ This class can be used to control the brightness of an image. An
+ enhancement factor of 0.0 gives a black image. A factor of 1.0 gives the
+ original image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ self.degenerate = Image.new(image.mode, image.size, 0)
+
+ if "A" in image.getbands():
+ self.degenerate.putalpha(image.getchannel("A"))
+
+
+class Sharpness(_Enhance):
+ """Adjust image sharpness.
+
+ This class can be used to adjust the sharpness of an image. An
+ enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives the
+ original image, and a factor of 2.0 gives a sharpened image.
+ """
+
+ def __init__(self, image):
+ self.image = image
+ self.degenerate = image.filter(ImageFilter.SMOOTH)
+
+ if "A" in image.getbands():
+ self.degenerate.putalpha(image.getchannel("A"))
diff --git a/venv/Lib/site-packages/PIL/ImageFile.py b/venv/Lib/site-packages/PIL/ImageFile.py
new file mode 100644
index 0000000..f2a55cb
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageFile.py
@@ -0,0 +1,697 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# base class for image file handlers
+#
+# history:
+# 1995-09-09 fl Created
+# 1996-03-11 fl Fixed load mechanism.
+# 1996-04-15 fl Added pcx/xbm decoders.
+# 1996-04-30 fl Added encoders.
+# 1996-12-14 fl Added load helpers
+# 1997-01-11 fl Use encode_to_file where possible
+# 1997-08-27 fl Flush output in _save
+# 1998-03-05 fl Use memory mapping for some modes
+# 1999-02-04 fl Use memory mapping also for "I;16" and "I;16B"
+# 1999-05-31 fl Added image parser
+# 2000-10-12 fl Set readonly flag on memory-mapped images
+# 2002-03-20 fl Use better messages for common decoder errors
+# 2003-04-21 fl Fall back on mmap/map_buffer if map is not available
+# 2003-10-30 fl Added StubImageFile class
+# 2004-02-25 fl Made incremental parser more robust
+#
+# Copyright (c) 1997-2004 by Secret Labs AB
+# Copyright (c) 1995-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import struct
+import sys
+import warnings
+
+from . import Image
+from ._util import isPath
+
+MAXBLOCK = 65536
+
+SAFEBLOCK = 1024 * 1024
+
+LOAD_TRUNCATED_IMAGES = False
+"""Whether or not to load truncated image files. User code may change this."""
+
+ERRORS = {
+ -1: "image buffer overrun error",
+ -2: "decoding error",
+ -3: "unknown error",
+ -8: "bad configuration",
+ -9: "out of memory error",
+}
+"""Dict of known error codes returned from :meth:`.PyDecoder.decode`."""
+
+
+#
+# --------------------------------------------------------------------
+# Helpers
+
+
+def raise_oserror(error):
+ try:
+ message = Image.core.getcodecstatus(error)
+ except AttributeError:
+ message = ERRORS.get(error)
+ if not message:
+ message = f"decoder error {error}"
+ raise OSError(message + " when reading image file")
+
+
+def raise_ioerror(error):
+ warnings.warn(
+ "raise_ioerror is deprecated and will be removed in Pillow 9 (2022-01-02). "
+ "Use raise_oserror instead.",
+ DeprecationWarning,
+ )
+ return raise_oserror(error)
+
+
+def _tilesort(t):
+ # sort on offset
+ return t[2]
+
+
+#
+# --------------------------------------------------------------------
+# ImageFile base class
+
+
+class ImageFile(Image.Image):
+ """Base class for image file format handlers."""
+
+ def __init__(self, fp=None, filename=None):
+ super().__init__()
+
+ self._min_frame = 0
+
+ self.custom_mimetype = None
+
+ self.tile = None
+ """ A list of tile descriptors, or ``None`` """
+
+ self.readonly = 1 # until we know better
+
+ self.decoderconfig = ()
+ self.decodermaxblock = MAXBLOCK
+
+ if isPath(fp):
+ # filename
+ self.fp = open(fp, "rb")
+ self.filename = fp
+ self._exclusive_fp = True
+ else:
+ # stream
+ self.fp = fp
+ self.filename = filename
+ # can be overridden
+ self._exclusive_fp = None
+
+ try:
+ try:
+ self._open()
+ except (
+ IndexError, # end of data
+ TypeError, # end of data (ord)
+ KeyError, # unsupported mode
+ EOFError, # got header but not the first frame
+ struct.error,
+ ) as v:
+ raise SyntaxError(v) from v
+
+ if not self.mode or self.size[0] <= 0:
+ raise SyntaxError("not identified by this driver")
+ except BaseException:
+ # close the file only if we have opened it this constructor
+ if self._exclusive_fp:
+ self.fp.close()
+ raise
+
+ def get_format_mimetype(self):
+ if self.custom_mimetype:
+ return self.custom_mimetype
+ if self.format is not None:
+ return Image.MIME.get(self.format.upper())
+
+ def verify(self):
+ """Check file integrity"""
+
+ # raise exception if something's wrong. must be called
+ # directly after open, and closes file when finished.
+ if self._exclusive_fp:
+ self.fp.close()
+ self.fp = None
+
+ def load(self):
+ """Load image data based on tile list"""
+
+ if self.tile is None:
+ raise OSError("cannot load this image")
+
+ pixel = Image.Image.load(self)
+ if not self.tile:
+ return pixel
+
+ self.map = None
+ use_mmap = self.filename and len(self.tile) == 1
+ # As of pypy 2.1.0, memory mapping was failing here.
+ use_mmap = use_mmap and not hasattr(sys, "pypy_version_info")
+
+ readonly = 0
+
+ # look for read/seek overrides
+ try:
+ read = self.load_read
+ # don't use mmap if there are custom read/seek functions
+ use_mmap = False
+ except AttributeError:
+ read = self.fp.read
+
+ try:
+ seek = self.load_seek
+ use_mmap = False
+ except AttributeError:
+ seek = self.fp.seek
+
+ if use_mmap:
+ # try memory mapping
+ decoder_name, extents, offset, args = self.tile[0]
+ if (
+ decoder_name == "raw"
+ and len(args) >= 3
+ and args[0] == self.mode
+ and args[0] in Image._MAPMODES
+ ):
+ try:
+ if hasattr(Image.core, "map"):
+ # use built-in mapper WIN32 only
+ self.map = Image.core.map(self.filename)
+ self.map.seek(offset)
+ self.im = self.map.readimage(
+ self.mode, self.size, args[1], args[2]
+ )
+ else:
+ # use mmap, if possible
+ import mmap
+
+ with open(self.filename) as fp:
+ self.map = mmap.mmap(
+ fp.fileno(), 0, access=mmap.ACCESS_READ
+ )
+ self.im = Image.core.map_buffer(
+ self.map, self.size, decoder_name, offset, args
+ )
+ readonly = 1
+ # After trashing self.im,
+ # we might need to reload the palette data.
+ if self.palette:
+ self.palette.dirty = 1
+ except (AttributeError, OSError, ImportError):
+ self.map = None
+
+ self.load_prepare()
+ err_code = -3 # initialize to unknown error
+ if not self.map:
+ # sort tiles in file order
+ self.tile.sort(key=_tilesort)
+
+ try:
+ # FIXME: This is a hack to handle TIFF's JpegTables tag.
+ prefix = self.tile_prefix
+ except AttributeError:
+ prefix = b""
+
+ for decoder_name, extents, offset, args in self.tile:
+ decoder = Image._getdecoder(
+ self.mode, decoder_name, args, self.decoderconfig
+ )
+ try:
+ seek(offset)
+ decoder.setimage(self.im, extents)
+ if decoder.pulls_fd:
+ decoder.setfd(self.fp)
+ status, err_code = decoder.decode(b"")
+ else:
+ b = prefix
+ while True:
+ try:
+ s = read(self.decodermaxblock)
+ except (IndexError, struct.error) as e:
+ # truncated png/gif
+ if LOAD_TRUNCATED_IMAGES:
+ break
+ else:
+ raise OSError("image file is truncated") from e
+
+ if not s: # truncated jpeg
+ if LOAD_TRUNCATED_IMAGES:
+ break
+ else:
+ raise OSError(
+ "image file is truncated "
+ f"({len(b)} bytes not processed)"
+ )
+
+ b = b + s
+ n, err_code = decoder.decode(b)
+ if n < 0:
+ break
+ b = b[n:]
+ finally:
+ # Need to cleanup here to prevent leaks
+ decoder.cleanup()
+
+ self.tile = []
+ self.readonly = readonly
+
+ self.load_end()
+
+ if self._exclusive_fp and self._close_exclusive_fp_after_loading:
+ self.fp.close()
+ self.fp = None
+
+ if not self.map and not LOAD_TRUNCATED_IMAGES and err_code < 0:
+ # still raised if decoder fails to return anything
+ raise_oserror(err_code)
+
+ return Image.Image.load(self)
+
+ def load_prepare(self):
+ # create image memory if necessary
+ if not self.im or self.im.mode != self.mode or self.im.size != self.size:
+ self.im = Image.core.new(self.mode, self.size)
+ # create palette (optional)
+ if self.mode == "P":
+ Image.Image.load(self)
+
+ def load_end(self):
+ # may be overridden
+ pass
+
+ # may be defined for contained formats
+ # def load_seek(self, pos):
+ # pass
+
+ # may be defined for blocked formats (e.g. PNG)
+ # def load_read(self, bytes):
+ # pass
+
+ def _seek_check(self, frame):
+ if (
+ frame < self._min_frame
+ # Only check upper limit on frames if additional seek operations
+ # are not required to do so
+ or (
+ not (hasattr(self, "_n_frames") and self._n_frames is None)
+ and frame >= self.n_frames + self._min_frame
+ )
+ ):
+ raise EOFError("attempt to seek outside sequence")
+
+ return self.tell() != frame
+
+
+class StubImageFile(ImageFile):
+ """
+ Base class for stub image loaders.
+
+ A stub loader is an image loader that can identify files of a
+ certain format, but relies on external code to load the file.
+ """
+
+ def _open(self):
+ raise NotImplementedError("StubImageFile subclass must implement _open")
+
+ def load(self):
+ loader = self._load()
+ if loader is None:
+ raise OSError(f"cannot find loader for this {self.format} file")
+ image = loader.load(self)
+ assert image is not None
+ # become the other object (!)
+ self.__class__ = image.__class__
+ self.__dict__ = image.__dict__
+
+ def _load(self):
+ """(Hook) Find actual image loader."""
+ raise NotImplementedError("StubImageFile subclass must implement _load")
+
+
+class Parser:
+ """
+ Incremental image parser. This class implements the standard
+ feed/close consumer interface.
+ """
+
+ incremental = None
+ image = None
+ data = None
+ decoder = None
+ offset = 0
+ finished = 0
+
+ def reset(self):
+ """
+ (Consumer) Reset the parser. Note that you can only call this
+ method immediately after you've created a parser; parser
+ instances cannot be reused.
+ """
+ assert self.data is None, "cannot reuse parsers"
+
+ def feed(self, data):
+ """
+ (Consumer) Feed data to the parser.
+
+ :param data: A string buffer.
+ :exception OSError: If the parser failed to parse the image file.
+ """
+ # collect data
+
+ if self.finished:
+ return
+
+ if self.data is None:
+ self.data = data
+ else:
+ self.data = self.data + data
+
+ # parse what we have
+ if self.decoder:
+
+ if self.offset > 0:
+ # skip header
+ skip = min(len(self.data), self.offset)
+ self.data = self.data[skip:]
+ self.offset = self.offset - skip
+ if self.offset > 0 or not self.data:
+ return
+
+ n, e = self.decoder.decode(self.data)
+
+ if n < 0:
+ # end of stream
+ self.data = None
+ self.finished = 1
+ if e < 0:
+ # decoding error
+ self.image = None
+ raise_oserror(e)
+ else:
+ # end of image
+ return
+ self.data = self.data[n:]
+
+ elif self.image:
+
+ # if we end up here with no decoder, this file cannot
+ # be incrementally parsed. wait until we've gotten all
+ # available data
+ pass
+
+ else:
+
+ # attempt to open this file
+ try:
+ with io.BytesIO(self.data) as fp:
+ im = Image.open(fp)
+ except OSError:
+ # traceback.print_exc()
+ pass # not enough data
+ else:
+ flag = hasattr(im, "load_seek") or hasattr(im, "load_read")
+ if flag or len(im.tile) != 1:
+ # custom load code, or multiple tiles
+ self.decode = None
+ else:
+ # initialize decoder
+ im.load_prepare()
+ d, e, o, a = im.tile[0]
+ im.tile = []
+ self.decoder = Image._getdecoder(im.mode, d, a, im.decoderconfig)
+ self.decoder.setimage(im.im, e)
+
+ # calculate decoder offset
+ self.offset = o
+ if self.offset <= len(self.data):
+ self.data = self.data[self.offset :]
+ self.offset = 0
+
+ self.image = im
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def close(self):
+ """
+ (Consumer) Close the stream.
+
+ :returns: An image object.
+ :exception OSError: If the parser failed to parse the image file either
+ because it cannot be identified or cannot be
+ decoded.
+ """
+ # finish decoding
+ if self.decoder:
+ # get rid of what's left in the buffers
+ self.feed(b"")
+ self.data = self.decoder = None
+ if not self.finished:
+ raise OSError("image was incomplete")
+ if not self.image:
+ raise OSError("cannot parse this image")
+ if self.data:
+ # incremental parsing not possible; reopen the file
+ # not that we have all data
+ with io.BytesIO(self.data) as fp:
+ try:
+ self.image = Image.open(fp)
+ finally:
+ self.image.load()
+ return self.image
+
+
+# --------------------------------------------------------------------
+
+
+def _save(im, fp, tile, bufsize=0):
+ """Helper to save image based on tile list
+
+ :param im: Image object.
+ :param fp: File object.
+ :param tile: Tile list.
+ :param bufsize: Optional buffer size
+ """
+
+ im.load()
+ if not hasattr(im, "encoderconfig"):
+ im.encoderconfig = ()
+ tile.sort(key=_tilesort)
+ # FIXME: make MAXBLOCK a configuration parameter
+ # It would be great if we could have the encoder specify what it needs
+ # But, it would need at least the image size in most cases. RawEncode is
+ # a tricky case.
+ bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4) # see RawEncode.c
+ if fp == sys.stdout:
+ fp.flush()
+ return
+ try:
+ fh = fp.fileno()
+ fp.flush()
+ except (AttributeError, io.UnsupportedOperation) as exc:
+ # compress to Python file-compatible object
+ for e, b, o, a in tile:
+ e = Image._getencoder(im.mode, e, a, im.encoderconfig)
+ if o > 0:
+ fp.seek(o)
+ e.setimage(im.im, b)
+ if e.pushes_fd:
+ e.setfd(fp)
+ l, s = e.encode_to_pyfd()
+ else:
+ while True:
+ l, s, d = e.encode(bufsize)
+ fp.write(d)
+ if s:
+ break
+ if s < 0:
+ raise OSError(f"encoder error {s} when writing image file") from exc
+ e.cleanup()
+ else:
+ # slight speedup: compress to real file object
+ for e, b, o, a in tile:
+ e = Image._getencoder(im.mode, e, a, im.encoderconfig)
+ if o > 0:
+ fp.seek(o)
+ e.setimage(im.im, b)
+ if e.pushes_fd:
+ e.setfd(fp)
+ l, s = e.encode_to_pyfd()
+ else:
+ s = e.encode_to_file(fh, bufsize)
+ if s < 0:
+ raise OSError(f"encoder error {s} when writing image file")
+ e.cleanup()
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+def _safe_read(fp, size):
+ """
+ Reads large blocks in a safe way. Unlike fp.read(n), this function
+ doesn't trust the user. If the requested size is larger than
+ SAFEBLOCK, the file is read block by block.
+
+ :param fp: File handle. Must implement a read method.
+ :param size: Number of bytes to read.
+ :returns: A string containing up to size bytes of data.
+ """
+ if size <= 0:
+ return b""
+ if size <= SAFEBLOCK:
+ return fp.read(size)
+ data = []
+ while size > 0:
+ block = fp.read(min(size, SAFEBLOCK))
+ if not block:
+ break
+ data.append(block)
+ size -= len(block)
+ return b"".join(data)
+
+
+class PyCodecState:
+ def __init__(self):
+ self.xsize = 0
+ self.ysize = 0
+ self.xoff = 0
+ self.yoff = 0
+
+ def extents(self):
+ return (self.xoff, self.yoff, self.xoff + self.xsize, self.yoff + self.ysize)
+
+
+class PyDecoder:
+ """
+ Python implementation of a format decoder. Override this class and
+ add the decoding logic in the :meth:`decode` method.
+
+ See :ref:`Writing Your Own File Decoder in Python`
+ """
+
+ _pulls_fd = False
+
+ def __init__(self, mode, *args):
+ self.im = None
+ self.state = PyCodecState()
+ self.fd = None
+ self.mode = mode
+ self.init(args)
+
+ def init(self, args):
+ """
+ Override to perform decoder specific initialization
+
+ :param args: Array of args items from the tile entry
+ :returns: None
+ """
+ self.args = args
+
+ @property
+ def pulls_fd(self):
+ return self._pulls_fd
+
+ def decode(self, buffer):
+ """
+ Override to perform the decoding process.
+
+ :param buffer: A bytes object with the data to be decoded.
+ :returns: A tuple of ``(bytes consumed, errcode)``.
+ If finished with decoding return <0 for the bytes consumed.
+ Err codes are from :data:`.ImageFile.ERRORS`.
+ """
+ raise NotImplementedError()
+
+ def cleanup(self):
+ """
+ Override to perform decoder specific cleanup
+
+ :returns: None
+ """
+ pass
+
+ def setfd(self, fd):
+ """
+ Called from ImageFile to set the python file-like object
+
+ :param fd: A python file-like object
+ :returns: None
+ """
+ self.fd = fd
+
+ def setimage(self, im, extents=None):
+ """
+ Called from ImageFile to set the core output image for the decoder
+
+ :param im: A core image object
+ :param extents: a 4 tuple of (x0, y0, x1, y1) defining the rectangle
+ for this tile
+ :returns: None
+ """
+
+ # following c code
+ self.im = im
+
+ if extents:
+ (x0, y0, x1, y1) = extents
+ else:
+ (x0, y0, x1, y1) = (0, 0, 0, 0)
+
+ if x0 == 0 and x1 == 0:
+ self.state.xsize, self.state.ysize = self.im.size
+ else:
+ self.state.xoff = x0
+ self.state.yoff = y0
+ self.state.xsize = x1 - x0
+ self.state.ysize = y1 - y0
+
+ if self.state.xsize <= 0 or self.state.ysize <= 0:
+ raise ValueError("Size cannot be negative")
+
+ if (
+ self.state.xsize + self.state.xoff > self.im.size[0]
+ or self.state.ysize + self.state.yoff > self.im.size[1]
+ ):
+ raise ValueError("Tile cannot extend outside image")
+
+ def set_as_raw(self, data, rawmode=None):
+ """
+ Convenience method to set the internal image from a stream of raw data
+
+ :param data: Bytes to be set
+ :param rawmode: The rawmode to be used for the decoder.
+ If not specified, it will default to the mode of the image
+ :returns: None
+ """
+
+ if not rawmode:
+ rawmode = self.mode
+ d = Image._getdecoder(self.mode, "raw", (rawmode))
+ d.setimage(self.im, self.state.extents())
+ s = d.decode(data)
+
+ if s[0] >= 0:
+ raise ValueError("not enough image data")
+ if s[1] != 0:
+ raise ValueError("cannot decode image data")
diff --git a/venv/Lib/site-packages/PIL/ImageFilter.py b/venv/Lib/site-packages/PIL/ImageFilter.py
new file mode 100644
index 0000000..9ca17d9
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageFilter.py
@@ -0,0 +1,534 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard filters
+#
+# History:
+# 1995-11-27 fl Created
+# 2002-06-08 fl Added rank and mode filters
+# 2003-09-15 fl Fixed rank calculation in rank filter; added expand call
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2002 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+import functools
+
+try:
+ import numpy
+except ImportError: # pragma: no cover
+ numpy = None
+
+
+class Filter:
+ pass
+
+
+class MultibandFilter(Filter):
+ pass
+
+
+class BuiltinFilter(MultibandFilter):
+ def filter(self, image):
+ if image.mode == "P":
+ raise ValueError("cannot filter palette images")
+ return image.filter(*self.filterargs)
+
+
+class Kernel(BuiltinFilter):
+ """
+ Create a convolution kernel. The current version only
+ supports 3x3 and 5x5 integer and floating point kernels.
+
+ In the current version, kernels can only be applied to
+ "L" and "RGB" images.
+
+ :param size: Kernel size, given as (width, height). In the current
+ version, this must be (3,3) or (5,5).
+ :param kernel: A sequence containing kernel weights.
+ :param scale: Scale factor. If given, the result for each pixel is
+ divided by this value. The default is the sum of the
+ kernel weights.
+ :param offset: Offset. If given, this value is added to the result,
+ after it has been divided by the scale factor.
+ """
+
+ name = "Kernel"
+
+ def __init__(self, size, kernel, scale=None, offset=0):
+ if scale is None:
+ # default scale is sum of kernel
+ scale = functools.reduce(lambda a, b: a + b, kernel)
+ if size[0] * size[1] != len(kernel):
+ raise ValueError("not enough coefficients in kernel")
+ self.filterargs = size, scale, offset, kernel
+
+
+class RankFilter(Filter):
+ """
+ Create a rank filter. The rank filter sorts all pixels in
+ a window of the given size, and returns the ``rank``'th value.
+
+ :param size: The kernel size, in pixels.
+ :param rank: What pixel value to pick. Use 0 for a min filter,
+ ``size * size / 2`` for a median filter, ``size * size - 1``
+ for a max filter, etc.
+ """
+
+ name = "Rank"
+
+ def __init__(self, size, rank):
+ self.size = size
+ self.rank = rank
+
+ def filter(self, image):
+ if image.mode == "P":
+ raise ValueError("cannot filter palette images")
+ image = image.expand(self.size // 2, self.size // 2)
+ return image.rankfilter(self.size, self.rank)
+
+
+class MedianFilter(RankFilter):
+ """
+ Create a median filter. Picks the median pixel value in a window with the
+ given size.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Median"
+
+ def __init__(self, size=3):
+ self.size = size
+ self.rank = size * size // 2
+
+
+class MinFilter(RankFilter):
+ """
+ Create a min filter. Picks the lowest pixel value in a window with the
+ given size.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Min"
+
+ def __init__(self, size=3):
+ self.size = size
+ self.rank = 0
+
+
+class MaxFilter(RankFilter):
+ """
+ Create a max filter. Picks the largest pixel value in a window with the
+ given size.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Max"
+
+ def __init__(self, size=3):
+ self.size = size
+ self.rank = size * size - 1
+
+
+class ModeFilter(Filter):
+ """
+ Create a mode filter. Picks the most frequent pixel value in a box with the
+ given size. Pixel values that occur only once or twice are ignored; if no
+ pixel value occurs more than twice, the original pixel value is preserved.
+
+ :param size: The kernel size, in pixels.
+ """
+
+ name = "Mode"
+
+ def __init__(self, size=3):
+ self.size = size
+
+ def filter(self, image):
+ return image.modefilter(self.size)
+
+
+class GaussianBlur(MultibandFilter):
+ """Gaussian blur filter.
+
+ :param radius: Blur radius.
+ """
+
+ name = "GaussianBlur"
+
+ def __init__(self, radius=2):
+ self.radius = radius
+
+ def filter(self, image):
+ return image.gaussian_blur(self.radius)
+
+
+class BoxBlur(MultibandFilter):
+ """Blurs the image by setting each pixel to the average value of the pixels
+ in a square box extending radius pixels in each direction.
+ Supports float radius of arbitrary size. Uses an optimized implementation
+ which runs in linear time relative to the size of the image
+ for any radius value.
+
+ :param radius: Size of the box in one direction. Radius 0 does not blur,
+ returns an identical image. Radius 1 takes 1 pixel
+ in each direction, i.e. 9 pixels in total.
+ """
+
+ name = "BoxBlur"
+
+ def __init__(self, radius):
+ self.radius = radius
+
+ def filter(self, image):
+ return image.box_blur(self.radius)
+
+
+class UnsharpMask(MultibandFilter):
+ """Unsharp mask filter.
+
+ See Wikipedia's entry on `digital unsharp masking`_ for an explanation of
+ the parameters.
+
+ :param radius: Blur Radius
+ :param percent: Unsharp strength, in percent
+ :param threshold: Threshold controls the minimum brightness change that
+ will be sharpened
+
+ .. _digital unsharp masking: https://en.wikipedia.org/wiki/Unsharp_masking#Digital_unsharp_masking
+
+ """ # noqa: E501
+
+ name = "UnsharpMask"
+
+ def __init__(self, radius=2, percent=150, threshold=3):
+ self.radius = radius
+ self.percent = percent
+ self.threshold = threshold
+
+ def filter(self, image):
+ return image.unsharp_mask(self.radius, self.percent, self.threshold)
+
+
+class BLUR(BuiltinFilter):
+ name = "Blur"
+ # fmt: off
+ filterargs = (5, 5), 16, 0, (
+ 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 0, 0, 0, 1,
+ 1, 1, 1, 1, 1,
+ )
+ # fmt: on
+
+
+class CONTOUR(BuiltinFilter):
+ name = "Contour"
+ # fmt: off
+ filterargs = (3, 3), 1, 255, (
+ -1, -1, -1,
+ -1, 8, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class DETAIL(BuiltinFilter):
+ name = "Detail"
+ # fmt: off
+ filterargs = (3, 3), 6, 0, (
+ 0, -1, 0,
+ -1, 10, -1,
+ 0, -1, 0,
+ )
+ # fmt: on
+
+
+class EDGE_ENHANCE(BuiltinFilter):
+ name = "Edge-enhance"
+ # fmt: off
+ filterargs = (3, 3), 2, 0, (
+ -1, -1, -1,
+ -1, 10, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class EDGE_ENHANCE_MORE(BuiltinFilter):
+ name = "Edge-enhance More"
+ # fmt: off
+ filterargs = (3, 3), 1, 0, (
+ -1, -1, -1,
+ -1, 9, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class EMBOSS(BuiltinFilter):
+ name = "Emboss"
+ # fmt: off
+ filterargs = (3, 3), 1, 128, (
+ -1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 0,
+ )
+ # fmt: on
+
+
+class FIND_EDGES(BuiltinFilter):
+ name = "Find Edges"
+ # fmt: off
+ filterargs = (3, 3), 1, 0, (
+ -1, -1, -1,
+ -1, 8, -1,
+ -1, -1, -1,
+ )
+ # fmt: on
+
+
+class SHARPEN(BuiltinFilter):
+ name = "Sharpen"
+ # fmt: off
+ filterargs = (3, 3), 16, 0, (
+ -2, -2, -2,
+ -2, 32, -2,
+ -2, -2, -2,
+ )
+ # fmt: on
+
+
+class SMOOTH(BuiltinFilter):
+ name = "Smooth"
+ # fmt: off
+ filterargs = (3, 3), 13, 0, (
+ 1, 1, 1,
+ 1, 5, 1,
+ 1, 1, 1,
+ )
+ # fmt: on
+
+
+class SMOOTH_MORE(BuiltinFilter):
+ name = "Smooth More"
+ # fmt: off
+ filterargs = (5, 5), 100, 0, (
+ 1, 1, 1, 1, 1,
+ 1, 5, 5, 5, 1,
+ 1, 5, 44, 5, 1,
+ 1, 5, 5, 5, 1,
+ 1, 1, 1, 1, 1,
+ )
+ # fmt: on
+
+
+class Color3DLUT(MultibandFilter):
+ """Three-dimensional color lookup table.
+
+ Transforms 3-channel pixels using the values of the channels as coordinates
+ in the 3D lookup table and interpolating the nearest elements.
+
+ This method allows you to apply almost any color transformation
+ in constant time by using pre-calculated decimated tables.
+
+ .. versionadded:: 5.2.0
+
+ :param size: Size of the table. One int or tuple of (int, int, int).
+ Minimal size in any dimension is 2, maximum is 65.
+ :param table: Flat lookup table. A list of ``channels * size**3``
+ float elements or a list of ``size**3`` channels-sized
+ tuples with floats. Channels are changed first,
+ then first dimension, then second, then third.
+ Value 0.0 corresponds lowest value of output, 1.0 highest.
+ :param channels: Number of channels in the table. Could be 3 or 4.
+ Default is 3.
+ :param target_mode: A mode for the result image. Should have not less
+ than ``channels`` channels. Default is ``None``,
+ which means that mode wouldn't be changed.
+ """
+
+ name = "Color 3D LUT"
+
+ def __init__(self, size, table, channels=3, target_mode=None, **kwargs):
+ if channels not in (3, 4):
+ raise ValueError("Only 3 or 4 output channels are supported")
+ self.size = size = self._check_size(size)
+ self.channels = channels
+ self.mode = target_mode
+
+ # Hidden flag `_copy_table=False` could be used to avoid extra copying
+ # of the table if the table is specially made for the constructor.
+ copy_table = kwargs.get("_copy_table", True)
+ items = size[0] * size[1] * size[2]
+ wrong_size = False
+
+ if numpy and isinstance(table, numpy.ndarray):
+ if copy_table:
+ table = table.copy()
+
+ if table.shape in [
+ (items * channels,),
+ (items, channels),
+ (size[2], size[1], size[0], channels),
+ ]:
+ table = table.reshape(items * channels)
+ else:
+ wrong_size = True
+
+ else:
+ if copy_table:
+ table = list(table)
+
+ # Convert to a flat list
+ if table and isinstance(table[0], (list, tuple)):
+ table, raw_table = [], table
+ for pixel in raw_table:
+ if len(pixel) != channels:
+ raise ValueError(
+ "The elements of the table should "
+ "have a length of {}.".format(channels)
+ )
+ table.extend(pixel)
+
+ if wrong_size or len(table) != items * channels:
+ raise ValueError(
+ "The table should have either channels * size**3 float items "
+ "or size**3 items of channels-sized tuples with floats. "
+ f"Table should be: {channels}x{size[0]}x{size[1]}x{size[2]}. "
+ f"Actual length: {len(table)}"
+ )
+ self.table = table
+
+ @staticmethod
+ def _check_size(size):
+ try:
+ _, _, _ = size
+ except ValueError as e:
+ raise ValueError(
+ "Size should be either an integer or a tuple of three integers."
+ ) from e
+ except TypeError:
+ size = (size, size, size)
+ size = [int(x) for x in size]
+ for size1D in size:
+ if not 2 <= size1D <= 65:
+ raise ValueError("Size should be in [2, 65] range.")
+ return size
+
+ @classmethod
+ def generate(cls, size, callback, channels=3, target_mode=None):
+ """Generates new LUT using provided callback.
+
+ :param size: Size of the table. Passed to the constructor.
+ :param callback: Function with three parameters which correspond
+ three color channels. Will be called ``size**3``
+ times with values from 0.0 to 1.0 and should return
+ a tuple with ``channels`` elements.
+ :param channels: The number of channels which should return callback.
+ :param target_mode: Passed to the constructor of the resulting
+ lookup table.
+ """
+ size1D, size2D, size3D = cls._check_size(size)
+ if channels not in (3, 4):
+ raise ValueError("Only 3 or 4 output channels are supported")
+
+ table = [0] * (size1D * size2D * size3D * channels)
+ idx_out = 0
+ for b in range(size3D):
+ for g in range(size2D):
+ for r in range(size1D):
+ table[idx_out : idx_out + channels] = callback(
+ r / (size1D - 1), g / (size2D - 1), b / (size3D - 1)
+ )
+ idx_out += channels
+
+ return cls(
+ (size1D, size2D, size3D),
+ table,
+ channels=channels,
+ target_mode=target_mode,
+ _copy_table=False,
+ )
+
+ def transform(self, callback, with_normals=False, channels=None, target_mode=None):
+ """Transforms the table values using provided callback and returns
+ a new LUT with altered values.
+
+ :param callback: A function which takes old lookup table values
+ and returns a new set of values. The number
+ of arguments which function should take is
+ ``self.channels`` or ``3 + self.channels``
+ if ``with_normals`` flag is set.
+ Should return a tuple of ``self.channels`` or
+ ``channels`` elements if it is set.
+ :param with_normals: If true, ``callback`` will be called with
+ coordinates in the color cube as the first
+ three arguments. Otherwise, ``callback``
+ will be called only with actual color values.
+ :param channels: The number of channels in the resulting lookup table.
+ :param target_mode: Passed to the constructor of the resulting
+ lookup table.
+ """
+ if channels not in (None, 3, 4):
+ raise ValueError("Only 3 or 4 output channels are supported")
+ ch_in = self.channels
+ ch_out = channels or ch_in
+ size1D, size2D, size3D = self.size
+
+ table = [0] * (size1D * size2D * size3D * ch_out)
+ idx_in = 0
+ idx_out = 0
+ for b in range(size3D):
+ for g in range(size2D):
+ for r in range(size1D):
+ values = self.table[idx_in : idx_in + ch_in]
+ if with_normals:
+ values = callback(
+ r / (size1D - 1),
+ g / (size2D - 1),
+ b / (size3D - 1),
+ *values,
+ )
+ else:
+ values = callback(*values)
+ table[idx_out : idx_out + ch_out] = values
+ idx_in += ch_in
+ idx_out += ch_out
+
+ return type(self)(
+ self.size,
+ table,
+ channels=ch_out,
+ target_mode=target_mode or self.mode,
+ _copy_table=False,
+ )
+
+ def __repr__(self):
+ r = [
+ f"{self.__class__.__name__} from {self.table.__class__.__name__}",
+ "size={:d}x{:d}x{:d}".format(*self.size),
+ f"channels={self.channels:d}",
+ ]
+ if self.mode:
+ r.append(f"target_mode={self.mode}")
+ return "<{}>".format(" ".join(r))
+
+ def filter(self, image):
+ from . import Image
+
+ return image.color_lut_3d(
+ self.mode or image.mode,
+ Image.LINEAR,
+ self.channels,
+ self.size[0],
+ self.size[1],
+ self.size[2],
+ self.table,
+ )
diff --git a/venv/Lib/site-packages/PIL/ImageFont.py b/venv/Lib/site-packages/PIL/ImageFont.py
new file mode 100644
index 0000000..c48d898
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageFont.py
@@ -0,0 +1,1057 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PIL raster font management
+#
+# History:
+# 1996-08-07 fl created (experimental)
+# 1997-08-25 fl minor adjustments to handle fonts from pilfont 0.3
+# 1999-02-06 fl rewrote most font management stuff in C
+# 1999-03-17 fl take pth files into account in load_path (from Richard Jones)
+# 2001-02-17 fl added freetype support
+# 2001-05-09 fl added TransposedFont wrapper class
+# 2002-03-04 fl make sure we have a "L" or "1" font
+# 2002-12-04 fl skip non-directory entries in the system path
+# 2003-04-29 fl add embedded default font
+# 2003-09-27 fl added support for truetype charmap encodings
+#
+# Todo:
+# Adapt to PILFONT2 format (16-bit fonts, compressed, single file)
+#
+# Copyright (c) 1997-2003 by Secret Labs AB
+# Copyright (c) 1996-2003 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import base64
+import os
+import sys
+import warnings
+from io import BytesIO
+
+from . import Image, features
+from ._util import isDirectory, isPath
+
+LAYOUT_BASIC = 0
+LAYOUT_RAQM = 1
+
+
+class _imagingft_not_installed:
+ # module placeholder
+ def __getattr__(self, id):
+ raise ImportError("The _imagingft C module is not installed")
+
+
+try:
+ from . import _imagingft as core
+except ImportError:
+ core = _imagingft_not_installed()
+
+
+# FIXME: add support for pilfont2 format (see FontFile.py)
+
+# --------------------------------------------------------------------
+# Font metrics format:
+# "PILfont" LF
+# fontdescriptor LF
+# (optional) key=value... LF
+# "DATA" LF
+# binary data: 256*10*2 bytes (dx, dy, dstbox, srcbox)
+#
+# To place a character, cut out srcbox and paste at dstbox,
+# relative to the character position. Then move the character
+# position according to dx, dy.
+# --------------------------------------------------------------------
+
+
+class ImageFont:
+ "PIL font wrapper"
+
+ def _load_pilfont(self, filename):
+
+ with open(filename, "rb") as fp:
+ image = None
+ for ext in (".png", ".gif", ".pbm"):
+ if image:
+ image.close()
+ try:
+ fullname = os.path.splitext(filename)[0] + ext
+ image = Image.open(fullname)
+ except Exception:
+ pass
+ else:
+ if image and image.mode in ("1", "L"):
+ break
+ else:
+ if image:
+ image.close()
+ raise OSError("cannot find glyph data file")
+
+ self.file = fullname
+
+ self._load_pilfont_data(fp, image)
+ image.close()
+
+ def _load_pilfont_data(self, file, image):
+
+ # read PILfont header
+ if file.readline() != b"PILfont\n":
+ raise SyntaxError("Not a PILfont file")
+ file.readline().split(b";")
+ self.info = [] # FIXME: should be a dictionary
+ while True:
+ s = file.readline()
+ if not s or s == b"DATA\n":
+ break
+ self.info.append(s)
+
+ # read PILfont metrics
+ data = file.read(256 * 20)
+
+ # check image
+ if image.mode not in ("1", "L"):
+ raise TypeError("invalid font image mode")
+
+ image.load()
+
+ self.font = Image.core.font(image.im, data)
+
+ def getsize(self, text, *args, **kwargs):
+ """
+ Returns width and height (in pixels) of given text.
+
+ :param text: Text to measure.
+
+ :return: (width, height)
+ """
+ return self.font.getsize(text)
+
+ def getmask(self, text, mode="", *args, **kwargs):
+ """
+ Create a bitmap for the text.
+
+ If the font uses antialiasing, the bitmap should have mode ``L`` and use a
+ maximum value of 255. Otherwise, it should have mode ``1``.
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ .. versionadded:: 1.1.5
+
+ :return: An internal PIL storage memory instance as defined by the
+ :py:mod:`PIL.Image.core` interface module.
+ """
+ return self.font.getmask(text, mode)
+
+
+##
+# Wrapper for FreeType fonts. Application code should use the
+# truetype factory function to create font objects.
+
+
+class FreeTypeFont:
+ "FreeType font wrapper (requires _imagingft service)"
+
+ def __init__(self, font=None, size=10, index=0, encoding="", layout_engine=None):
+ # FIXME: use service provider instead
+
+ self.path = font
+ self.size = size
+ self.index = index
+ self.encoding = encoding
+
+ try:
+ from packaging.version import parse as parse_version
+ except ImportError:
+ pass
+ else:
+ freetype_version = parse_version(features.version_module("freetype2"))
+ if freetype_version < parse_version("2.8"):
+ warnings.warn(
+ "Support for FreeType 2.7 is deprecated and will be removed"
+ " in Pillow 9 (2022-01-02). Please upgrade to FreeType 2.8 "
+ "or newer, preferably FreeType 2.10.4 which fixes "
+ "CVE-2020-15999.",
+ DeprecationWarning,
+ )
+
+ if layout_engine not in (LAYOUT_BASIC, LAYOUT_RAQM):
+ layout_engine = LAYOUT_BASIC
+ if core.HAVE_RAQM:
+ layout_engine = LAYOUT_RAQM
+ elif layout_engine == LAYOUT_RAQM and not core.HAVE_RAQM:
+ layout_engine = LAYOUT_BASIC
+
+ self.layout_engine = layout_engine
+
+ def load_from_bytes(f):
+ self.font_bytes = f.read()
+ self.font = core.getfont(
+ "", size, index, encoding, self.font_bytes, layout_engine
+ )
+
+ if isPath(font):
+ if sys.platform == "win32":
+ font_bytes_path = font if isinstance(font, bytes) else font.encode()
+ try:
+ font_bytes_path.decode("ascii")
+ except UnicodeDecodeError:
+ # FreeType cannot load fonts with non-ASCII characters on Windows
+ # So load it into memory first
+ with open(font, "rb") as f:
+ load_from_bytes(f)
+ return
+ self.font = core.getfont(
+ font, size, index, encoding, layout_engine=layout_engine
+ )
+ else:
+ load_from_bytes(font)
+
+ def _multiline_split(self, text):
+ split_character = "\n" if isinstance(text, str) else b"\n"
+ return text.split(split_character)
+
+ def getname(self):
+ """
+ :return: A tuple of the font family (e.g. Helvetica) and the font style
+ (e.g. Bold)
+ """
+ return self.font.family, self.font.style
+
+ def getmetrics(self):
+ """
+ :return: A tuple of the font ascent (the distance from the baseline to
+ the highest outline point) and descent (the distance from the
+ baseline to the lowest outline point, a negative value)
+ """
+ return self.font.ascent, self.font.descent
+
+ def getlength(self, text, mode="", direction=None, features=None, language=None):
+ """
+ Returns length (in pixels with 1/64 precision) of given text when rendered
+ in font with provided direction, features, and language.
+
+ This is the amount by which following text should be offset.
+ Text bounding box may extend past the length in some fonts,
+ e.g. when using italics or accents.
+
+ The result is returned as a float; it is a whole number if using basic layout.
+
+ Note that the sum of two lengths may not equal the length of a concatenated
+ string due to kerning. If you need to adjust for kerning, include the following
+ character and subtract its length.
+
+ For example, instead of
+
+ .. code-block:: python
+
+ hello = font.getlength("Hello")
+ world = font.getlength("World")
+ hello_world = hello + world # not adjusted for kerning
+ assert hello_world == font.getlength("HelloWorld") # may fail
+
+ use
+
+ .. code-block:: python
+
+ hello = font.getlength("HelloW") - font.getlength("W") # adjusted for kerning
+ world = font.getlength("World")
+ hello_world = hello + world # adjusted for kerning
+ assert hello_world == font.getlength("HelloWorld") # True
+
+ or disable kerning with (requires libraqm)
+
+ .. code-block:: python
+
+ hello = draw.textlength("Hello", font, features=["-kern"])
+ world = draw.textlength("World", font, features=["-kern"])
+ hello_world = hello + world # kerning is disabled, no need to adjust
+ assert hello_world == draw.textlength("HelloWorld", font, features=["-kern"])
+
+ .. versionadded:: 8.0.0
+
+ :param text: Text to measure.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ `_
+ Requires libraqm.
+
+ :return: Width for horizontal, height for vertical text.
+ """
+ return self.font.getlength(text, mode, direction, features, language) / 64
+
+ def getbbox(
+ self,
+ text,
+ mode="",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ anchor=None,
+ ):
+ """
+ Returns bounding box (in pixels) of given text relative to given anchor
+ when rendered in font with provided direction, features, and language.
+
+ Use :py:meth:`getlength()` to get the offset of following text with
+ 1/64 pixel precision. The bounding box includes extra margins for
+ some fonts, e.g. italics or accents.
+
+ .. versionadded:: 8.0.0
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ `_
+ Requires libraqm.
+
+ :param stroke_width: The width of the text stroke.
+
+ :param anchor: The text anchor alignment. Determines the relative location of
+ the anchor to the text. The default alignment is top left.
+ See :ref:`text-anchors` for valid values.
+
+ :return: ``(left, top, right, bottom)`` bounding box
+ """
+ size, offset = self.font.getsize(
+ text, mode, direction, features, language, anchor
+ )
+ left, top = offset[0] - stroke_width, offset[1] - stroke_width
+ width, height = size[0] + 2 * stroke_width, size[1] + 2 * stroke_width
+ return left, top, left + width, top + height
+
+ def getsize(
+ self, text, direction=None, features=None, language=None, stroke_width=0
+ ):
+ """
+ Returns width and height (in pixels) of given text if rendered in font with
+ provided direction, features, and language.
+
+ Use :py:meth:`getlength()` to measure the offset of following text with
+ 1/64 pixel precision.
+ Use :py:meth:`getbbox()` to get the exact bounding box based on an anchor.
+
+ .. note:: For historical reasons this function measures text height from
+ the ascender line instead of the top, see :ref:`text-anchors`.
+ If you wish to measure text height from the top, it is recommended
+ to use the bottom value of :meth:`getbbox` with ``anchor='lt'`` instead.
+
+ :param text: Text to measure.
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ `_
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :return: (width, height)
+ """
+ # vertical offset is added for historical reasons
+ # see https://github.com/python-pillow/Pillow/pull/4910#discussion_r486682929
+ size, offset = self.font.getsize(text, "L", direction, features, language)
+ return (
+ size[0] + stroke_width * 2,
+ size[1] + stroke_width * 2 + offset[1],
+ )
+
+ def getsize_multiline(
+ self,
+ text,
+ direction=None,
+ spacing=4,
+ features=None,
+ language=None,
+ stroke_width=0,
+ ):
+ """
+ Returns width and height (in pixels) of given text if rendered in font
+ with provided direction, features, and language, while respecting
+ newline characters.
+
+ :param text: Text to measure.
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ :param spacing: The vertical gap between lines, defaulting to 4 pixels.
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ `_
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :return: (width, height)
+ """
+ max_width = 0
+ lines = self._multiline_split(text)
+ line_spacing = self.getsize("A", stroke_width=stroke_width)[1] + spacing
+ for line in lines:
+ line_width, line_height = self.getsize(
+ line, direction, features, language, stroke_width
+ )
+ max_width = max(max_width, line_width)
+
+ return max_width, len(lines) * line_spacing - spacing
+
+ def getoffset(self, text):
+ """
+ Returns the offset of given text. This is the gap between the
+ starting coordinate and the first marking. Note that this gap is
+ included in the result of :py:func:`~PIL.ImageFont.FreeTypeFont.getsize`.
+
+ :param text: Text to measure.
+
+ :return: A tuple of the x and y offset
+ """
+ return self.font.getsize(text)[1]
+
+ def getmask(
+ self,
+ text,
+ mode="",
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ anchor=None,
+ ink=0,
+ ):
+ """
+ Create a bitmap for the text.
+
+ If the font uses antialiasing, the bitmap should have mode ``L`` and use a
+ maximum value of 255. If the font has embedded color data, the bitmap
+ should have mode ``RGBA``. Otherwise, it should have mode ``1``.
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ .. versionadded:: 1.1.5
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ `_
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :param anchor: The text anchor alignment. Determines the relative location of
+ the anchor to the text. The default alignment is top left.
+ See :ref:`text-anchors` for valid values.
+
+ .. versionadded:: 8.0.0
+
+ :param ink: Foreground ink for rendering in RGBA mode.
+
+ .. versionadded:: 8.0.0
+
+ :return: An internal PIL storage memory instance as defined by the
+ :py:mod:`PIL.Image.core` interface module.
+ """
+ return self.getmask2(
+ text,
+ mode,
+ direction=direction,
+ features=features,
+ language=language,
+ stroke_width=stroke_width,
+ anchor=anchor,
+ ink=ink,
+ )[0]
+
+ def getmask2(
+ self,
+ text,
+ mode="",
+ fill=Image.core.fill,
+ direction=None,
+ features=None,
+ language=None,
+ stroke_width=0,
+ anchor=None,
+ ink=0,
+ *args,
+ **kwargs,
+ ):
+ """
+ Create a bitmap for the text.
+
+ If the font uses antialiasing, the bitmap should have mode ``L`` and use a
+ maximum value of 255. If the font has embedded color data, the bitmap
+ should have mode ``RGBA``. Otherwise, it should have mode ``1``.
+
+ :param text: Text to render.
+ :param mode: Used by some graphics drivers to indicate what mode the
+ driver prefers; if empty, the renderer may return either
+ mode. Note that the mode is always a string, to simplify
+ C-level implementations.
+
+ .. versionadded:: 1.1.5
+
+ :param direction: Direction of the text. It can be 'rtl' (right to
+ left), 'ltr' (left to right) or 'ttb' (top to bottom).
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param features: A list of OpenType font features to be used during text
+ layout. This is usually used to turn on optional
+ font features that are not enabled by default,
+ for example 'dlig' or 'ss01', but can be also
+ used to turn off default font features for
+ example '-liga' to disable ligatures or '-kern'
+ to disable kerning. To get all supported
+ features, see
+ https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
+ Requires libraqm.
+
+ .. versionadded:: 4.2.0
+
+ :param language: Language of the text. Different languages may use
+ different glyph shapes or ligatures. This parameter tells
+ the font which language the text is in, and to apply the
+ correct substitutions as appropriate, if available.
+ It should be a `BCP 47 language code
+ `_
+ Requires libraqm.
+
+ .. versionadded:: 6.0.0
+
+ :param stroke_width: The width of the text stroke.
+
+ .. versionadded:: 6.2.0
+
+ :param anchor: The text anchor alignment. Determines the relative location of
+ the anchor to the text. The default alignment is top left.
+ See :ref:`text-anchors` for valid values.
+
+ .. versionadded:: 8.0.0
+
+ :param ink: Foreground ink for rendering in RGBA mode.
+
+ .. versionadded:: 8.0.0
+
+ :return: A tuple of an internal PIL storage memory instance as defined by the
+ :py:mod:`PIL.Image.core` interface module, and the text offset, the
+ gap between the starting coordinate and the first marking
+ """
+ size, offset = self.font.getsize(
+ text, mode, direction, features, language, anchor
+ )
+ size = size[0] + stroke_width * 2, size[1] + stroke_width * 2
+ offset = offset[0] - stroke_width, offset[1] - stroke_width
+ im = fill("RGBA" if mode == "RGBA" else "L", size, 0)
+ self.font.render(
+ text, im.id, mode, direction, features, language, stroke_width, ink
+ )
+ return im, offset
+
+ def font_variant(
+ self, font=None, size=None, index=None, encoding=None, layout_engine=None
+ ):
+ """
+ Create a copy of this FreeTypeFont object,
+ using any specified arguments to override the settings.
+
+ Parameters are identical to the parameters used to initialize this
+ object.
+
+ :return: A FreeTypeFont object.
+ """
+ return FreeTypeFont(
+ font=self.path if font is None else font,
+ size=self.size if size is None else size,
+ index=self.index if index is None else index,
+ encoding=self.encoding if encoding is None else encoding,
+ layout_engine=layout_engine or self.layout_engine,
+ )
+
+ def get_variation_names(self):
+ """
+ :returns: A list of the named styles in a variation font.
+ :exception OSError: If the font is not a variation font.
+ """
+ try:
+ names = self.font.getvarnames()
+ except AttributeError as e:
+ raise NotImplementedError("FreeType 2.9.1 or greater is required") from e
+ return [name.replace(b"\x00", b"") for name in names]
+
+ def set_variation_by_name(self, name):
+ """
+ :param name: The name of the style.
+ :exception OSError: If the font is not a variation font.
+ """
+ names = self.get_variation_names()
+ if not isinstance(name, bytes):
+ name = name.encode()
+ index = names.index(name)
+
+ if index == getattr(self, "_last_variation_index", None):
+ # When the same name is set twice in a row,
+ # there is an 'unknown freetype error'
+ # https://savannah.nongnu.org/bugs/?56186
+ return
+ self._last_variation_index = index
+
+ self.font.setvarname(index)
+
+ def get_variation_axes(self):
+ """
+ :returns: A list of the axes in a variation font.
+ :exception OSError: If the font is not a variation font.
+ """
+ try:
+ axes = self.font.getvaraxes()
+ except AttributeError as e:
+ raise NotImplementedError("FreeType 2.9.1 or greater is required") from e
+ for axis in axes:
+ axis["name"] = axis["name"].replace(b"\x00", b"")
+ return axes
+
+ def set_variation_by_axes(self, axes):
+ """
+ :param axes: A list of values for each axis.
+ :exception OSError: If the font is not a variation font.
+ """
+ try:
+ self.font.setvaraxes(axes)
+ except AttributeError as e:
+ raise NotImplementedError("FreeType 2.9.1 or greater is required") from e
+
+
+class TransposedFont:
+ "Wrapper for writing rotated or mirrored text"
+
+ def __init__(self, font, orientation=None):
+ """
+ Wrapper that creates a transposed font from any existing font
+ object.
+
+ :param font: A font object.
+ :param orientation: An optional orientation. If given, this should
+ be one of Image.FLIP_LEFT_RIGHT, Image.FLIP_TOP_BOTTOM,
+ Image.ROTATE_90, Image.ROTATE_180, or Image.ROTATE_270.
+ """
+ self.font = font
+ self.orientation = orientation # any 'transpose' argument, or None
+
+ def getsize(self, text, *args, **kwargs):
+ w, h = self.font.getsize(text)
+ if self.orientation in (Image.ROTATE_90, Image.ROTATE_270):
+ return h, w
+ return w, h
+
+ def getmask(self, text, mode="", *args, **kwargs):
+ im = self.font.getmask(text, mode, *args, **kwargs)
+ if self.orientation is not None:
+ return im.transpose(self.orientation)
+ return im
+
+
+def load(filename):
+ """
+ Load a font file. This function loads a font object from the given
+ bitmap font file, and returns the corresponding font object.
+
+ :param filename: Name of font file.
+ :return: A font object.
+ :exception OSError: If the file could not be read.
+ """
+ f = ImageFont()
+ f._load_pilfont(filename)
+ return f
+
+
+def truetype(font=None, size=10, index=0, encoding="", layout_engine=None):
+ """
+ Load a TrueType or OpenType font from a file or file-like object,
+ and create a font object.
+ This function loads a font object from the given file or file-like
+ object, and creates a font object for a font of the given size.
+
+ Pillow uses FreeType to open font files. If you are opening many fonts
+ simultaneously on Windows, be aware that Windows limits the number of files
+ that can be open in C at once to 512. If you approach that limit, an
+ ``OSError`` may be thrown, reporting that FreeType "cannot open resource".
+
+ This function requires the _imagingft service.
+
+ :param font: A filename or file-like object containing a TrueType font.
+ If the file is not found in this filename, the loader may also
+ search in other directories, such as the :file:`fonts/`
+ directory on Windows or :file:`/Library/Fonts/`,
+ :file:`/System/Library/Fonts/` and :file:`~/Library/Fonts/` on
+ macOS.
+
+ :param size: The requested size, in points.
+ :param index: Which font face to load (default is first available face).
+ :param encoding: Which font encoding to use (default is Unicode). Possible
+ encodings include (see the FreeType documentation for more
+ information):
+
+ * "unic" (Unicode)
+ * "symb" (Microsoft Symbol)
+ * "ADOB" (Adobe Standard)
+ * "ADBE" (Adobe Expert)
+ * "ADBC" (Adobe Custom)
+ * "armn" (Apple Roman)
+ * "sjis" (Shift JIS)
+ * "gb " (PRC)
+ * "big5"
+ * "wans" (Extended Wansung)
+ * "joha" (Johab)
+ * "lat1" (Latin-1)
+
+ This specifies the character set to use. It does not alter the
+ encoding of any text provided in subsequent operations.
+ :param layout_engine: Which layout engine to use, if available:
+ :data:`.ImageFont.LAYOUT_BASIC` or :data:`.ImageFont.LAYOUT_RAQM`.
+
+ You can check support for Raqm layout using
+ :py:func:`PIL.features.check_feature` with ``feature="raqm"``.
+
+ .. versionadded:: 4.2.0
+ :return: A font object.
+ :exception OSError: If the file could not be read.
+ """
+
+ def freetype(font):
+ return FreeTypeFont(font, size, index, encoding, layout_engine)
+
+ try:
+ return freetype(font)
+ except OSError:
+ if not isPath(font):
+ raise
+ ttf_filename = os.path.basename(font)
+
+ dirs = []
+ if sys.platform == "win32":
+ # check the windows font repository
+ # NOTE: must use uppercase WINDIR, to work around bugs in
+ # 1.5.2's os.environ.get()
+ windir = os.environ.get("WINDIR")
+ if windir:
+ dirs.append(os.path.join(windir, "fonts"))
+ elif sys.platform in ("linux", "linux2"):
+ lindirs = os.environ.get("XDG_DATA_DIRS", "")
+ if not lindirs:
+ # According to the freedesktop spec, XDG_DATA_DIRS should
+ # default to /usr/share
+ lindirs = "/usr/share"
+ dirs += [os.path.join(lindir, "fonts") for lindir in lindirs.split(":")]
+ elif sys.platform == "darwin":
+ dirs += [
+ "/Library/Fonts",
+ "/System/Library/Fonts",
+ os.path.expanduser("~/Library/Fonts"),
+ ]
+
+ ext = os.path.splitext(ttf_filename)[1]
+ first_font_with_a_different_extension = None
+ for directory in dirs:
+ for walkroot, walkdir, walkfilenames in os.walk(directory):
+ for walkfilename in walkfilenames:
+ if ext and walkfilename == ttf_filename:
+ return freetype(os.path.join(walkroot, walkfilename))
+ elif not ext and os.path.splitext(walkfilename)[0] == ttf_filename:
+ fontpath = os.path.join(walkroot, walkfilename)
+ if os.path.splitext(fontpath)[1] == ".ttf":
+ return freetype(fontpath)
+ if not ext and first_font_with_a_different_extension is None:
+ first_font_with_a_different_extension = fontpath
+ if first_font_with_a_different_extension:
+ return freetype(first_font_with_a_different_extension)
+ raise
+
+
+def load_path(filename):
+ """
+ Load font file. Same as :py:func:`~PIL.ImageFont.load`, but searches for a
+ bitmap font along the Python path.
+
+ :param filename: Name of font file.
+ :return: A font object.
+ :exception OSError: If the file could not be read.
+ """
+ for directory in sys.path:
+ if isDirectory(directory):
+ if not isinstance(filename, str):
+ filename = filename.decode("utf-8")
+ try:
+ return load(os.path.join(directory, filename))
+ except OSError:
+ pass
+ raise OSError("cannot find font file")
+
+
+def load_default():
+ """Load a "better than nothing" default font.
+
+ .. versionadded:: 1.1.4
+
+ :return: A font object.
+ """
+ f = ImageFont()
+ f._load_pilfont_data(
+ # courB08
+ BytesIO(
+ base64.b64decode(
+ b"""
+UElMZm9udAo7Ozs7OzsxMDsKREFUQQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAA//8AAQAAAAAAAAABAAEA
+BgAAAAH/+gADAAAAAQAAAAMABgAGAAAAAf/6AAT//QADAAAABgADAAYAAAAA//kABQABAAYAAAAL
+AAgABgAAAAD/+AAFAAEACwAAABAACQAGAAAAAP/5AAUAAAAQAAAAFQAHAAYAAP////oABQAAABUA
+AAAbAAYABgAAAAH/+QAE//wAGwAAAB4AAwAGAAAAAf/5AAQAAQAeAAAAIQAIAAYAAAAB//kABAAB
+ACEAAAAkAAgABgAAAAD/+QAE//0AJAAAACgABAAGAAAAAP/6AAX//wAoAAAALQAFAAYAAAAB//8A
+BAACAC0AAAAwAAMABgAAAAD//AAF//0AMAAAADUAAQAGAAAAAf//AAMAAAA1AAAANwABAAYAAAAB
+//kABQABADcAAAA7AAgABgAAAAD/+QAFAAAAOwAAAEAABwAGAAAAAP/5AAYAAABAAAAARgAHAAYA
+AAAA//kABQAAAEYAAABLAAcABgAAAAD/+QAFAAAASwAAAFAABwAGAAAAAP/5AAYAAABQAAAAVgAH
+AAYAAAAA//kABQAAAFYAAABbAAcABgAAAAD/+QAFAAAAWwAAAGAABwAGAAAAAP/5AAUAAABgAAAA
+ZQAHAAYAAAAA//kABQAAAGUAAABqAAcABgAAAAD/+QAFAAAAagAAAG8ABwAGAAAAAf/8AAMAAABv
+AAAAcQAEAAYAAAAA//wAAwACAHEAAAB0AAYABgAAAAD/+gAE//8AdAAAAHgABQAGAAAAAP/7AAT/
+/gB4AAAAfAADAAYAAAAB//oABf//AHwAAACAAAUABgAAAAD/+gAFAAAAgAAAAIUABgAGAAAAAP/5
+AAYAAQCFAAAAiwAIAAYAAP////oABgAAAIsAAACSAAYABgAA////+gAFAAAAkgAAAJgABgAGAAAA
+AP/6AAUAAACYAAAAnQAGAAYAAP////oABQAAAJ0AAACjAAYABgAA////+gAFAAAAowAAAKkABgAG
+AAD////6AAUAAACpAAAArwAGAAYAAAAA//oABQAAAK8AAAC0AAYABgAA////+gAGAAAAtAAAALsA
+BgAGAAAAAP/6AAQAAAC7AAAAvwAGAAYAAP////oABQAAAL8AAADFAAYABgAA////+gAGAAAAxQAA
+AMwABgAGAAD////6AAUAAADMAAAA0gAGAAYAAP////oABQAAANIAAADYAAYABgAA////+gAGAAAA
+2AAAAN8ABgAGAAAAAP/6AAUAAADfAAAA5AAGAAYAAP////oABQAAAOQAAADqAAYABgAAAAD/+gAF
+AAEA6gAAAO8ABwAGAAD////6AAYAAADvAAAA9gAGAAYAAAAA//oABQAAAPYAAAD7AAYABgAA////
++gAFAAAA+wAAAQEABgAGAAD////6AAYAAAEBAAABCAAGAAYAAP////oABgAAAQgAAAEPAAYABgAA
+////+gAGAAABDwAAARYABgAGAAAAAP/6AAYAAAEWAAABHAAGAAYAAP////oABgAAARwAAAEjAAYA
+BgAAAAD/+gAFAAABIwAAASgABgAGAAAAAf/5AAQAAQEoAAABKwAIAAYAAAAA//kABAABASsAAAEv
+AAgABgAAAAH/+QAEAAEBLwAAATIACAAGAAAAAP/5AAX//AEyAAABNwADAAYAAAAAAAEABgACATcA
+AAE9AAEABgAAAAH/+QAE//wBPQAAAUAAAwAGAAAAAP/7AAYAAAFAAAABRgAFAAYAAP////kABQAA
+AUYAAAFMAAcABgAAAAD/+wAFAAABTAAAAVEABQAGAAAAAP/5AAYAAAFRAAABVwAHAAYAAAAA//sA
+BQAAAVcAAAFcAAUABgAAAAD/+QAFAAABXAAAAWEABwAGAAAAAP/7AAYAAgFhAAABZwAHAAYAAP//
+//kABQAAAWcAAAFtAAcABgAAAAD/+QAGAAABbQAAAXMABwAGAAAAAP/5AAQAAgFzAAABdwAJAAYA
+AP////kABgAAAXcAAAF+AAcABgAAAAD/+QAGAAABfgAAAYQABwAGAAD////7AAUAAAGEAAABigAF
+AAYAAP////sABQAAAYoAAAGQAAUABgAAAAD/+wAFAAABkAAAAZUABQAGAAD////7AAUAAgGVAAAB
+mwAHAAYAAAAA//sABgACAZsAAAGhAAcABgAAAAD/+wAGAAABoQAAAacABQAGAAAAAP/7AAYAAAGn
+AAABrQAFAAYAAAAA//kABgAAAa0AAAGzAAcABgAA////+wAGAAABswAAAboABQAGAAD////7AAUA
+AAG6AAABwAAFAAYAAP////sABgAAAcAAAAHHAAUABgAAAAD/+wAGAAABxwAAAc0ABQAGAAD////7
+AAYAAgHNAAAB1AAHAAYAAAAA//sABQAAAdQAAAHZAAUABgAAAAH/+QAFAAEB2QAAAd0ACAAGAAAA
+Av/6AAMAAQHdAAAB3gAHAAYAAAAA//kABAABAd4AAAHiAAgABgAAAAD/+wAF//0B4gAAAecAAgAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAB
+//sAAwACAecAAAHpAAcABgAAAAD/+QAFAAEB6QAAAe4ACAAGAAAAAP/5AAYAAAHuAAAB9AAHAAYA
+AAAA//oABf//AfQAAAH5AAUABgAAAAD/+QAGAAAB+QAAAf8ABwAGAAAAAv/5AAMAAgH/AAACAAAJ
+AAYAAAAA//kABQABAgAAAAIFAAgABgAAAAH/+gAE//sCBQAAAggAAQAGAAAAAP/5AAYAAAIIAAAC
+DgAHAAYAAAAB//kABf/+Ag4AAAISAAUABgAA////+wAGAAACEgAAAhkABQAGAAAAAP/7AAX//gIZ
+AAACHgADAAYAAAAA//wABf/9Ah4AAAIjAAEABgAAAAD/+QAHAAACIwAAAioABwAGAAAAAP/6AAT/
++wIqAAACLgABAAYAAAAA//kABP/8Ai4AAAIyAAMABgAAAAD/+gAFAAACMgAAAjcABgAGAAAAAf/5
+AAT//QI3AAACOgAEAAYAAAAB//kABP/9AjoAAAI9AAQABgAAAAL/+QAE//sCPQAAAj8AAgAGAAD/
+///7AAYAAgI/AAACRgAHAAYAAAAA//kABgABAkYAAAJMAAgABgAAAAH//AAD//0CTAAAAk4AAQAG
+AAAAAf//AAQAAgJOAAACUQADAAYAAAAB//kABP/9AlEAAAJUAAQABgAAAAH/+QAF//4CVAAAAlgA
+BQAGAAD////7AAYAAAJYAAACXwAFAAYAAP////kABgAAAl8AAAJmAAcABgAA////+QAGAAACZgAA
+Am0ABwAGAAD////5AAYAAAJtAAACdAAHAAYAAAAA//sABQACAnQAAAJ5AAcABgAA////9wAGAAAC
+eQAAAoAACQAGAAD////3AAYAAAKAAAAChwAJAAYAAP////cABgAAAocAAAKOAAkABgAA////9wAG
+AAACjgAAApUACQAGAAD////4AAYAAAKVAAACnAAIAAYAAP////cABgAAApwAAAKjAAkABgAA////
++gAGAAACowAAAqoABgAGAAAAAP/6AAUAAgKqAAACrwAIAAYAAP////cABQAAAq8AAAK1AAkABgAA
+////9wAFAAACtQAAArsACQAGAAD////3AAUAAAK7AAACwQAJAAYAAP////gABQAAAsEAAALHAAgA
+BgAAAAD/9wAEAAACxwAAAssACQAGAAAAAP/3AAQAAALLAAACzwAJAAYAAAAA//cABAAAAs8AAALT
+AAkABgAAAAD/+AAEAAAC0wAAAtcACAAGAAD////6AAUAAALXAAAC3QAGAAYAAP////cABgAAAt0A
+AALkAAkABgAAAAD/9wAFAAAC5AAAAukACQAGAAAAAP/3AAUAAALpAAAC7gAJAAYAAAAA//cABQAA
+Au4AAALzAAkABgAAAAD/9wAFAAAC8wAAAvgACQAGAAAAAP/4AAUAAAL4AAAC/QAIAAYAAAAA//oA
+Bf//Av0AAAMCAAUABgAA////+gAGAAADAgAAAwkABgAGAAD////3AAYAAAMJAAADEAAJAAYAAP//
+//cABgAAAxAAAAMXAAkABgAA////9wAGAAADFwAAAx4ACQAGAAD////4AAYAAAAAAAoABwASAAYA
+AP////cABgAAAAcACgAOABMABgAA////+gAFAAAADgAKABQAEAAGAAD////6AAYAAAAUAAoAGwAQ
+AAYAAAAA//gABgAAABsACgAhABIABgAAAAD/+AAGAAAAIQAKACcAEgAGAAAAAP/4AAYAAAAnAAoA
+LQASAAYAAAAA//gABgAAAC0ACgAzABIABgAAAAD/+QAGAAAAMwAKADkAEQAGAAAAAP/3AAYAAAA5
+AAoAPwATAAYAAP////sABQAAAD8ACgBFAA8ABgAAAAD/+wAFAAIARQAKAEoAEQAGAAAAAP/4AAUA
+AABKAAoATwASAAYAAAAA//gABQAAAE8ACgBUABIABgAAAAD/+AAFAAAAVAAKAFkAEgAGAAAAAP/5
+AAUAAABZAAoAXgARAAYAAAAA//gABgAAAF4ACgBkABIABgAAAAD/+AAGAAAAZAAKAGoAEgAGAAAA
+AP/4AAYAAABqAAoAcAASAAYAAAAA//kABgAAAHAACgB2ABEABgAAAAD/+AAFAAAAdgAKAHsAEgAG
+AAD////4AAYAAAB7AAoAggASAAYAAAAA//gABQAAAIIACgCHABIABgAAAAD/+AAFAAAAhwAKAIwA
+EgAGAAAAAP/4AAUAAACMAAoAkQASAAYAAAAA//gABQAAAJEACgCWABIABgAAAAD/+QAFAAAAlgAK
+AJsAEQAGAAAAAP/6AAX//wCbAAoAoAAPAAYAAAAA//oABQABAKAACgClABEABgAA////+AAGAAAA
+pQAKAKwAEgAGAAD////4AAYAAACsAAoAswASAAYAAP////gABgAAALMACgC6ABIABgAA////+QAG
+AAAAugAKAMEAEQAGAAD////4AAYAAgDBAAoAyAAUAAYAAP////kABQACAMgACgDOABMABgAA////
++QAGAAIAzgAKANUAEw==
+"""
+ )
+ ),
+ Image.open(
+ BytesIO(
+ base64.b64decode(
+ b"""
+iVBORw0KGgoAAAANSUhEUgAAAx4AAAAUAQAAAAArMtZoAAAEwElEQVR4nABlAJr/AHVE4czCI/4u
+Mc4b7vuds/xzjz5/3/7u/n9vMe7vnfH/9++vPn/xyf5zhxzjt8GHw8+2d83u8x27199/nxuQ6Od9
+M43/5z2I+9n9ZtmDBwMQECDRQw/eQIQohJXxpBCNVE6QCCAAAAD//wBlAJr/AgALyj1t/wINwq0g
+LeNZUworuN1cjTPIzrTX6ofHWeo3v336qPzfEwRmBnHTtf95/fglZK5N0PDgfRTslpGBvz7LFc4F
+IUXBWQGjQ5MGCx34EDFPwXiY4YbYxavpnhHFrk14CDAAAAD//wBlAJr/AgKqRooH2gAgPeggvUAA
+Bu2WfgPoAwzRAABAAAAAAACQgLz/3Uv4Gv+gX7BJgDeeGP6AAAD1NMDzKHD7ANWr3loYbxsAD791
+NAADfcoIDyP44K/jv4Y63/Z+t98Ovt+ub4T48LAAAAD//wBlAJr/AuplMlADJAAAAGuAphWpqhMx
+in0A/fRvAYBABPgBwBUgABBQ/sYAyv9g0bCHgOLoGAAAAAAAREAAwI7nr0ArYpow7aX8//9LaP/9
+SjdavWA8ePHeBIKB//81/83ndznOaXx379wAAAD//wBlAJr/AqDxW+D3AABAAbUh/QMnbQag/gAY
+AYDAAACgtgD/gOqAAAB5IA/8AAAk+n9w0AAA8AAAmFRJuPo27ciC0cD5oeW4E7KA/wD3ECMAn2tt
+y8PgwH8AfAxFzC0JzeAMtratAsC/ffwAAAD//wBlAJr/BGKAyCAA4AAAAvgeYTAwHd1kmQF5chkG
+ABoMIHcL5xVpTfQbUqzlAAAErwAQBgAAEOClA5D9il08AEh/tUzdCBsXkbgACED+woQg8Si9VeqY
+lODCn7lmF6NhnAEYgAAA/NMIAAAAAAD//2JgjLZgVGBg5Pv/Tvpc8hwGBjYGJADjHDrAwPzAjv/H
+/Wf3PzCwtzcwHmBgYGcwbZz8wHaCAQMDOwMDQ8MCBgYOC3W7mp+f0w+wHOYxO3OG+e376hsMZjk3
+AAAAAP//YmCMY2A4wMAIN5e5gQETPD6AZisDAwMDgzSDAAPjByiHcQMDAwMDg1nOze1lByRu5/47
+c4859311AYNZzg0AAAAA//9iYGDBYihOIIMuwIjGL39/fwffA8b//xv/P2BPtzzHwCBjUQAAAAD/
+/yLFBrIBAAAA//9i1HhcwdhizX7u8NZNzyLbvT97bfrMf/QHI8evOwcSqGUJAAAA//9iYBB81iSw
+pEE170Qrg5MIYydHqwdDQRMrAwcVrQAAAAD//2J4x7j9AAMDn8Q/BgYLBoaiAwwMjPdvMDBYM1Tv
+oJodAAAAAP//Yqo/83+dxePWlxl3npsel9lvLfPcqlE9725C+acfVLMEAAAA//9i+s9gwCoaaGMR
+evta/58PTEWzr21hufPjA8N+qlnBwAAAAAD//2JiWLci5v1+HmFXDqcnULE/MxgYGBj+f6CaJQAA
+AAD//2Ji2FrkY3iYpYC5qDeGgeEMAwPDvwQBBoYvcTwOVLMEAAAA//9isDBgkP///0EOg9z35v//
+Gc/eeW7BwPj5+QGZhANUswMAAAD//2JgqGBgYGBgqEMXlvhMPUsAAAAA//8iYDd1AAAAAP//AwDR
+w7IkEbzhVQAAAABJRU5ErkJggg==
+"""
+ )
+ )
+ ),
+ )
+ return f
diff --git a/venv/Lib/site-packages/PIL/ImageGrab.py b/venv/Lib/site-packages/PIL/ImageGrab.py
new file mode 100644
index 0000000..b93ec3f
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageGrab.py
@@ -0,0 +1,120 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# screen grabber
+#
+# History:
+# 2001-04-26 fl created
+# 2001-09-17 fl use builtin driver, if present
+# 2002-11-19 fl added grabclipboard support
+#
+# Copyright (c) 2001-2002 by Secret Labs AB
+# Copyright (c) 2001-2002 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import sys
+
+from . import Image
+
+if sys.platform == "darwin":
+ import os
+ import subprocess
+ import tempfile
+
+
+def grab(bbox=None, include_layered_windows=False, all_screens=False, xdisplay=None):
+ if xdisplay is None:
+ if sys.platform == "darwin":
+ fh, filepath = tempfile.mkstemp(".png")
+ os.close(fh)
+ subprocess.call(["screencapture", "-x", filepath])
+ im = Image.open(filepath)
+ im.load()
+ os.unlink(filepath)
+ if bbox:
+ im_cropped = im.crop(bbox)
+ im.close()
+ return im_cropped
+ return im
+ elif sys.platform == "win32":
+ offset, size, data = Image.core.grabscreen_win32(
+ include_layered_windows, all_screens
+ )
+ im = Image.frombytes(
+ "RGB",
+ size,
+ data,
+ # RGB, 32-bit line padding, origin lower left corner
+ "raw",
+ "BGR",
+ (size[0] * 3 + 3) & -4,
+ -1,
+ )
+ if bbox:
+ x0, y0 = offset
+ left, top, right, bottom = bbox
+ im = im.crop((left - x0, top - y0, right - x0, bottom - y0))
+ return im
+ # use xdisplay=None for default display on non-win32/macOS systems
+ if not Image.core.HAVE_XCB:
+ raise OSError("Pillow was built without XCB support")
+ size, data = Image.core.grabscreen_x11(xdisplay)
+ im = Image.frombytes("RGB", size, data, "raw", "BGRX", size[0] * 4, 1)
+ if bbox:
+ im = im.crop(bbox)
+ return im
+
+
+def grabclipboard():
+ if sys.platform == "darwin":
+ fh, filepath = tempfile.mkstemp(".jpg")
+ os.close(fh)
+ commands = [
+ 'set theFile to (open for access POSIX file "'
+ + filepath
+ + '" with write permission)',
+ "try",
+ " write (the clipboard as JPEG picture) to theFile",
+ "end try",
+ "close access theFile",
+ ]
+ script = ["osascript"]
+ for command in commands:
+ script += ["-e", command]
+ subprocess.call(script)
+
+ im = None
+ if os.stat(filepath).st_size != 0:
+ im = Image.open(filepath)
+ im.load()
+ os.unlink(filepath)
+ return im
+ elif sys.platform == "win32":
+ fmt, data = Image.core.grabclipboard_win32()
+ if fmt == "file": # CF_HDROP
+ import struct
+
+ o = struct.unpack_from("I", data)[0]
+ if data[16] != 0:
+ files = data[o:].decode("utf-16le").split("\0")
+ else:
+ files = data[o:].decode("mbcs").split("\0")
+ return files[: files.index("")]
+ if isinstance(data, bytes):
+ import io
+
+ data = io.BytesIO(data)
+ if fmt == "png":
+ from . import PngImagePlugin
+
+ return PngImagePlugin.PngImageFile(data)
+ elif fmt == "DIB":
+ from . import BmpImagePlugin
+
+ return BmpImagePlugin.DibImageFile(data)
+ return None
+ else:
+ raise NotImplementedError("ImageGrab.grabclipboard() is macOS and Windows only")
diff --git a/venv/Lib/site-packages/PIL/ImageMath.py b/venv/Lib/site-packages/PIL/ImageMath.py
new file mode 100644
index 0000000..7f9c88e
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageMath.py
@@ -0,0 +1,253 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# a simple math add-on for the Python Imaging Library
+#
+# History:
+# 1999-02-15 fl Original PIL Plus release
+# 2005-05-05 fl Simplified and cleaned up for PIL 1.1.6
+# 2005-09-12 fl Fixed int() and float() for Python 2.4.1
+#
+# Copyright (c) 1999-2005 by Secret Labs AB
+# Copyright (c) 2005 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import builtins
+
+from . import Image, _imagingmath
+
+VERBOSE = 0
+
+
+def _isconstant(v):
+ return isinstance(v, (int, float))
+
+
+class _Operand:
+ """Wraps an image operand, providing standard operators"""
+
+ def __init__(self, im):
+ self.im = im
+
+ def __fixup(self, im1):
+ # convert image to suitable mode
+ if isinstance(im1, _Operand):
+ # argument was an image.
+ if im1.im.mode in ("1", "L"):
+ return im1.im.convert("I")
+ elif im1.im.mode in ("I", "F"):
+ return im1.im
+ else:
+ raise ValueError(f"unsupported mode: {im1.im.mode}")
+ else:
+ # argument was a constant
+ if _isconstant(im1) and self.im.mode in ("1", "L", "I"):
+ return Image.new("I", self.im.size, im1)
+ else:
+ return Image.new("F", self.im.size, im1)
+
+ def apply(self, op, im1, im2=None, mode=None):
+ im1 = self.__fixup(im1)
+ if im2 is None:
+ # unary operation
+ out = Image.new(mode or im1.mode, im1.size, None)
+ im1.load()
+ try:
+ op = getattr(_imagingmath, op + "_" + im1.mode)
+ except AttributeError as e:
+ raise TypeError(f"bad operand type for '{op}'") from e
+ _imagingmath.unop(op, out.im.id, im1.im.id)
+ else:
+ # binary operation
+ im2 = self.__fixup(im2)
+ if im1.mode != im2.mode:
+ # convert both arguments to floating point
+ if im1.mode != "F":
+ im1 = im1.convert("F")
+ if im2.mode != "F":
+ im2 = im2.convert("F")
+ if im1.mode != im2.mode:
+ raise ValueError("mode mismatch")
+ if im1.size != im2.size:
+ # crop both arguments to a common size
+ size = (min(im1.size[0], im2.size[0]), min(im1.size[1], im2.size[1]))
+ if im1.size != size:
+ im1 = im1.crop((0, 0) + size)
+ if im2.size != size:
+ im2 = im2.crop((0, 0) + size)
+ out = Image.new(mode or im1.mode, size, None)
+ else:
+ out = Image.new(mode or im1.mode, im1.size, None)
+ im1.load()
+ im2.load()
+ try:
+ op = getattr(_imagingmath, op + "_" + im1.mode)
+ except AttributeError as e:
+ raise TypeError(f"bad operand type for '{op}'") from e
+ _imagingmath.binop(op, out.im.id, im1.im.id, im2.im.id)
+ return _Operand(out)
+
+ # unary operators
+ def __bool__(self):
+ # an image is "true" if it contains at least one non-zero pixel
+ return self.im.getbbox() is not None
+
+ def __abs__(self):
+ return self.apply("abs", self)
+
+ def __pos__(self):
+ return self
+
+ def __neg__(self):
+ return self.apply("neg", self)
+
+ # binary operators
+ def __add__(self, other):
+ return self.apply("add", self, other)
+
+ def __radd__(self, other):
+ return self.apply("add", other, self)
+
+ def __sub__(self, other):
+ return self.apply("sub", self, other)
+
+ def __rsub__(self, other):
+ return self.apply("sub", other, self)
+
+ def __mul__(self, other):
+ return self.apply("mul", self, other)
+
+ def __rmul__(self, other):
+ return self.apply("mul", other, self)
+
+ def __truediv__(self, other):
+ return self.apply("div", self, other)
+
+ def __rtruediv__(self, other):
+ return self.apply("div", other, self)
+
+ def __mod__(self, other):
+ return self.apply("mod", self, other)
+
+ def __rmod__(self, other):
+ return self.apply("mod", other, self)
+
+ def __pow__(self, other):
+ return self.apply("pow", self, other)
+
+ def __rpow__(self, other):
+ return self.apply("pow", other, self)
+
+ # bitwise
+ def __invert__(self):
+ return self.apply("invert", self)
+
+ def __and__(self, other):
+ return self.apply("and", self, other)
+
+ def __rand__(self, other):
+ return self.apply("and", other, self)
+
+ def __or__(self, other):
+ return self.apply("or", self, other)
+
+ def __ror__(self, other):
+ return self.apply("or", other, self)
+
+ def __xor__(self, other):
+ return self.apply("xor", self, other)
+
+ def __rxor__(self, other):
+ return self.apply("xor", other, self)
+
+ def __lshift__(self, other):
+ return self.apply("lshift", self, other)
+
+ def __rshift__(self, other):
+ return self.apply("rshift", self, other)
+
+ # logical
+ def __eq__(self, other):
+ return self.apply("eq", self, other)
+
+ def __ne__(self, other):
+ return self.apply("ne", self, other)
+
+ def __lt__(self, other):
+ return self.apply("lt", self, other)
+
+ def __le__(self, other):
+ return self.apply("le", self, other)
+
+ def __gt__(self, other):
+ return self.apply("gt", self, other)
+
+ def __ge__(self, other):
+ return self.apply("ge", self, other)
+
+
+# conversions
+def imagemath_int(self):
+ return _Operand(self.im.convert("I"))
+
+
+def imagemath_float(self):
+ return _Operand(self.im.convert("F"))
+
+
+# logical
+def imagemath_equal(self, other):
+ return self.apply("eq", self, other, mode="I")
+
+
+def imagemath_notequal(self, other):
+ return self.apply("ne", self, other, mode="I")
+
+
+def imagemath_min(self, other):
+ return self.apply("min", self, other)
+
+
+def imagemath_max(self, other):
+ return self.apply("max", self, other)
+
+
+def imagemath_convert(self, mode):
+ return _Operand(self.im.convert(mode))
+
+
+ops = {}
+for k, v in list(globals().items()):
+ if k[:10] == "imagemath_":
+ ops[k[10:]] = v
+
+
+def eval(expression, _dict={}, **kw):
+ """
+ Evaluates an image expression.
+
+ :param expression: A string containing a Python-style expression.
+ :param options: Values to add to the evaluation context. You
+ can either use a dictionary, or one or more keyword
+ arguments.
+ :return: The evaluated expression. This is usually an image object, but can
+ also be an integer, a floating point value, or a pixel tuple,
+ depending on the expression.
+ """
+
+ # build execution namespace
+ args = ops.copy()
+ args.update(_dict)
+ args.update(kw)
+ for k, v in list(args.items()):
+ if hasattr(v, "im"):
+ args[k] = _Operand(v)
+
+ out = builtins.eval(expression, args)
+ try:
+ return out.im
+ except AttributeError:
+ return out
diff --git a/venv/Lib/site-packages/PIL/ImageMode.py b/venv/Lib/site-packages/PIL/ImageMode.py
new file mode 100644
index 0000000..9882883
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageMode.py
@@ -0,0 +1,64 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard mode descriptors
+#
+# History:
+# 2006-03-20 fl Added
+#
+# Copyright (c) 2006 by Secret Labs AB.
+# Copyright (c) 2006 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+# mode descriptor cache
+_modes = None
+
+
+class ModeDescriptor:
+ """Wrapper for mode strings."""
+
+ def __init__(self, mode, bands, basemode, basetype):
+ self.mode = mode
+ self.bands = bands
+ self.basemode = basemode
+ self.basetype = basetype
+
+ def __str__(self):
+ return self.mode
+
+
+def getmode(mode):
+ """Gets a mode descriptor for the given mode."""
+ global _modes
+ if not _modes:
+ # initialize mode cache
+
+ from . import Image
+
+ modes = {}
+ # core modes
+ for m, (basemode, basetype, bands) in Image._MODEINFO.items():
+ modes[m] = ModeDescriptor(m, bands, basemode, basetype)
+ # extra experimental modes
+ modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L")
+ modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L")
+ modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L")
+ modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L")
+ # mapping modes
+ for i16mode in (
+ "I;16",
+ "I;16S",
+ "I;16L",
+ "I;16LS",
+ "I;16B",
+ "I;16BS",
+ "I;16N",
+ "I;16NS",
+ ):
+ modes[i16mode] = ModeDescriptor(i16mode, ("I",), "L", "L")
+ # set global mode cache atomically
+ _modes = modes
+ return _modes[mode]
diff --git a/venv/Lib/site-packages/PIL/ImageMorph.py b/venv/Lib/site-packages/PIL/ImageMorph.py
new file mode 100644
index 0000000..b76dfa0
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageMorph.py
@@ -0,0 +1,245 @@
+# A binary morphology add-on for the Python Imaging Library
+#
+# History:
+# 2014-06-04 Initial version.
+#
+# Copyright (c) 2014 Dov Grobgeld
+
+import re
+
+from . import Image, _imagingmorph
+
+LUT_SIZE = 1 << 9
+
+# fmt: off
+ROTATION_MATRIX = [
+ 6, 3, 0,
+ 7, 4, 1,
+ 8, 5, 2,
+]
+MIRROR_MATRIX = [
+ 2, 1, 0,
+ 5, 4, 3,
+ 8, 7, 6,
+]
+# fmt: on
+
+
+class LutBuilder:
+ """A class for building a MorphLut from a descriptive language
+
+ The input patterns is a list of a strings sequences like these::
+
+ 4:(...
+ .1.
+ 111)->1
+
+ (whitespaces including linebreaks are ignored). The option 4
+ describes a series of symmetry operations (in this case a
+ 4-rotation), the pattern is described by:
+
+ - . or X - Ignore
+ - 1 - Pixel is on
+ - 0 - Pixel is off
+
+ The result of the operation is described after "->" string.
+
+ The default is to return the current pixel value, which is
+ returned if no other match is found.
+
+ Operations:
+
+ - 4 - 4 way rotation
+ - N - Negate
+ - 1 - Dummy op for no other operation (an op must always be given)
+ - M - Mirroring
+
+ Example::
+
+ lb = LutBuilder(patterns = ["4:(... .1. 111)->1"])
+ lut = lb.build_lut()
+
+ """
+
+ def __init__(self, patterns=None, op_name=None):
+ if patterns is not None:
+ self.patterns = patterns
+ else:
+ self.patterns = []
+ self.lut = None
+ if op_name is not None:
+ known_patterns = {
+ "corner": ["1:(... ... ...)->0", "4:(00. 01. ...)->1"],
+ "dilation4": ["4:(... .0. .1.)->1"],
+ "dilation8": ["4:(... .0. .1.)->1", "4:(... .0. ..1)->1"],
+ "erosion4": ["4:(... .1. .0.)->0"],
+ "erosion8": ["4:(... .1. .0.)->0", "4:(... .1. ..0)->0"],
+ "edge": [
+ "1:(... ... ...)->0",
+ "4:(.0. .1. ...)->1",
+ "4:(01. .1. ...)->1",
+ ],
+ }
+ if op_name not in known_patterns:
+ raise Exception("Unknown pattern " + op_name + "!")
+
+ self.patterns = known_patterns[op_name]
+
+ def add_patterns(self, patterns):
+ self.patterns += patterns
+
+ def build_default_lut(self):
+ symbols = [0, 1]
+ m = 1 << 4 # pos of current pixel
+ self.lut = bytearray(symbols[(i & m) > 0] for i in range(LUT_SIZE))
+
+ def get_lut(self):
+ return self.lut
+
+ def _string_permute(self, pattern, permutation):
+ """string_permute takes a pattern and a permutation and returns the
+ string permuted according to the permutation list.
+ """
+ assert len(permutation) == 9
+ return "".join(pattern[p] for p in permutation)
+
+ def _pattern_permute(self, basic_pattern, options, basic_result):
+ """pattern_permute takes a basic pattern and its result and clones
+ the pattern according to the modifications described in the $options
+ parameter. It returns a list of all cloned patterns."""
+ patterns = [(basic_pattern, basic_result)]
+
+ # rotations
+ if "4" in options:
+ res = patterns[-1][1]
+ for i in range(4):
+ patterns.append(
+ (self._string_permute(patterns[-1][0], ROTATION_MATRIX), res)
+ )
+ # mirror
+ if "M" in options:
+ n = len(patterns)
+ for pattern, res in patterns[0:n]:
+ patterns.append((self._string_permute(pattern, MIRROR_MATRIX), res))
+
+ # negate
+ if "N" in options:
+ n = len(patterns)
+ for pattern, res in patterns[0:n]:
+ # Swap 0 and 1
+ pattern = pattern.replace("0", "Z").replace("1", "0").replace("Z", "1")
+ res = 1 - int(res)
+ patterns.append((pattern, res))
+
+ return patterns
+
+ def build_lut(self):
+ """Compile all patterns into a morphology lut.
+
+ TBD :Build based on (file) morphlut:modify_lut
+ """
+ self.build_default_lut()
+ patterns = []
+
+ # Parse and create symmetries of the patterns strings
+ for p in self.patterns:
+ m = re.search(r"(\w*):?\s*\((.+?)\)\s*->\s*(\d)", p.replace("\n", ""))
+ if not m:
+ raise Exception('Syntax error in pattern "' + p + '"')
+ options = m.group(1)
+ pattern = m.group(2)
+ result = int(m.group(3))
+
+ # Get rid of spaces
+ pattern = pattern.replace(" ", "").replace("\n", "")
+
+ patterns += self._pattern_permute(pattern, options, result)
+
+ # compile the patterns into regular expressions for speed
+ for i, pattern in enumerate(patterns):
+ p = pattern[0].replace(".", "X").replace("X", "[01]")
+ p = re.compile(p)
+ patterns[i] = (p, pattern[1])
+
+ # Step through table and find patterns that match.
+ # Note that all the patterns are searched. The last one
+ # caught overrides
+ for i in range(LUT_SIZE):
+ # Build the bit pattern
+ bitpattern = bin(i)[2:]
+ bitpattern = ("0" * (9 - len(bitpattern)) + bitpattern)[::-1]
+
+ for p, r in patterns:
+ if p.match(bitpattern):
+ self.lut[i] = [0, 1][r]
+
+ return self.lut
+
+
+class MorphOp:
+ """A class for binary morphological operators"""
+
+ def __init__(self, lut=None, op_name=None, patterns=None):
+ """Create a binary morphological operator"""
+ self.lut = lut
+ if op_name is not None:
+ self.lut = LutBuilder(op_name=op_name).build_lut()
+ elif patterns is not None:
+ self.lut = LutBuilder(patterns=patterns).build_lut()
+
+ def apply(self, image):
+ """Run a single morphological operation on an image
+
+ Returns a tuple of the number of changed pixels and the
+ morphed image"""
+ if self.lut is None:
+ raise Exception("No operator loaded")
+
+ if image.mode != "L":
+ raise Exception("Image must be binary, meaning it must use mode L")
+ outimage = Image.new(image.mode, image.size, None)
+ count = _imagingmorph.apply(bytes(self.lut), image.im.id, outimage.im.id)
+ return count, outimage
+
+ def match(self, image):
+ """Get a list of coordinates matching the morphological operation on
+ an image.
+
+ Returns a list of tuples of (x,y) coordinates
+ of all matching pixels. See :ref:`coordinate-system`."""
+ if self.lut is None:
+ raise Exception("No operator loaded")
+
+ if image.mode != "L":
+ raise Exception("Image must be binary, meaning it must use mode L")
+ return _imagingmorph.match(bytes(self.lut), image.im.id)
+
+ def get_on_pixels(self, image):
+ """Get a list of all turned on pixels in a binary image
+
+ Returns a list of tuples of (x,y) coordinates
+ of all matching pixels. See :ref:`coordinate-system`."""
+
+ if image.mode != "L":
+ raise Exception("Image must be binary, meaning it must use mode L")
+ return _imagingmorph.get_on_pixels(image.im.id)
+
+ def load_lut(self, filename):
+ """Load an operator from an mrl file"""
+ with open(filename, "rb") as f:
+ self.lut = bytearray(f.read())
+
+ if len(self.lut) != LUT_SIZE:
+ self.lut = None
+ raise Exception("Wrong size operator file!")
+
+ def save_lut(self, filename):
+ """Save an operator to an mrl file"""
+ if self.lut is None:
+ raise Exception("No operator loaded")
+ with open(filename, "wb") as f:
+ f.write(self.lut)
+
+ def set_lut(self, lut):
+ """Set the lut from an external source"""
+ self.lut = lut
diff --git a/venv/Lib/site-packages/PIL/ImageOps.py b/venv/Lib/site-packages/PIL/ImageOps.py
new file mode 100644
index 0000000..14602a5
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageOps.py
@@ -0,0 +1,558 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# standard image operations
+#
+# History:
+# 2001-10-20 fl Created
+# 2001-10-23 fl Added autocontrast operator
+# 2001-12-18 fl Added Kevin's fit operator
+# 2004-03-14 fl Fixed potential division by zero in equalize
+# 2005-05-05 fl Fixed equalize for low number of values
+#
+# Copyright (c) 2001-2004 by Secret Labs AB
+# Copyright (c) 2001-2004 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import functools
+import operator
+
+from . import Image
+
+#
+# helpers
+
+
+def _border(border):
+ if isinstance(border, tuple):
+ if len(border) == 2:
+ left, top = right, bottom = border
+ elif len(border) == 4:
+ left, top, right, bottom = border
+ else:
+ left = top = right = bottom = border
+ return left, top, right, bottom
+
+
+def _color(color, mode):
+ if isinstance(color, str):
+ from . import ImageColor
+
+ color = ImageColor.getcolor(color, mode)
+ return color
+
+
+def _lut(image, lut):
+ if image.mode == "P":
+ # FIXME: apply to lookup table, not image data
+ raise NotImplementedError("mode P support coming soon")
+ elif image.mode in ("L", "RGB"):
+ if image.mode == "RGB" and len(lut) == 256:
+ lut = lut + lut + lut
+ return image.point(lut)
+ else:
+ raise OSError("not supported for this image mode")
+
+
+#
+# actions
+
+
+def autocontrast(image, cutoff=0, ignore=None, mask=None):
+ """
+ Maximize (normalize) image contrast. This function calculates a
+ histogram of the input image (or mask region), removes ``cutoff`` percent of the
+ lightest and darkest pixels from the histogram, and remaps the image
+ so that the darkest pixel becomes black (0), and the lightest
+ becomes white (255).
+
+ :param image: The image to process.
+ :param cutoff: The percent to cut off from the histogram on the low and
+ high ends. Either a tuple of (low, high), or a single
+ number for both.
+ :param ignore: The background pixel value (use None for no background).
+ :param mask: Histogram used in contrast operation is computed using pixels
+ within the mask. If no mask is given the entire image is used
+ for histogram computation.
+ :return: An image.
+ """
+ histogram = image.histogram(mask)
+ lut = []
+ for layer in range(0, len(histogram), 256):
+ h = histogram[layer : layer + 256]
+ if ignore is not None:
+ # get rid of outliers
+ try:
+ h[ignore] = 0
+ except TypeError:
+ # assume sequence
+ for ix in ignore:
+ h[ix] = 0
+ if cutoff:
+ # cut off pixels from both ends of the histogram
+ if not isinstance(cutoff, tuple):
+ cutoff = (cutoff, cutoff)
+ # get number of pixels
+ n = 0
+ for ix in range(256):
+ n = n + h[ix]
+ # remove cutoff% pixels from the low end
+ cut = n * cutoff[0] // 100
+ for lo in range(256):
+ if cut > h[lo]:
+ cut = cut - h[lo]
+ h[lo] = 0
+ else:
+ h[lo] -= cut
+ cut = 0
+ if cut <= 0:
+ break
+ # remove cutoff% samples from the high end
+ cut = n * cutoff[1] // 100
+ for hi in range(255, -1, -1):
+ if cut > h[hi]:
+ cut = cut - h[hi]
+ h[hi] = 0
+ else:
+ h[hi] -= cut
+ cut = 0
+ if cut <= 0:
+ break
+ # find lowest/highest samples after preprocessing
+ for lo in range(256):
+ if h[lo]:
+ break
+ for hi in range(255, -1, -1):
+ if h[hi]:
+ break
+ if hi <= lo:
+ # don't bother
+ lut.extend(list(range(256)))
+ else:
+ scale = 255.0 / (hi - lo)
+ offset = -lo * scale
+ for ix in range(256):
+ ix = int(ix * scale + offset)
+ if ix < 0:
+ ix = 0
+ elif ix > 255:
+ ix = 255
+ lut.append(ix)
+ return _lut(image, lut)
+
+
+def colorize(image, black, white, mid=None, blackpoint=0, whitepoint=255, midpoint=127):
+ """
+ Colorize grayscale image.
+ This function calculates a color wedge which maps all black pixels in
+ the source image to the first color and all white pixels to the
+ second color. If ``mid`` is specified, it uses three-color mapping.
+ The ``black`` and ``white`` arguments should be RGB tuples or color names;
+ optionally you can use three-color mapping by also specifying ``mid``.
+ Mapping positions for any of the colors can be specified
+ (e.g. ``blackpoint``), where these parameters are the integer
+ value corresponding to where the corresponding color should be mapped.
+ These parameters must have logical order, such that
+ ``blackpoint <= midpoint <= whitepoint`` (if ``mid`` is specified).
+
+ :param image: The image to colorize.
+ :param black: The color to use for black input pixels.
+ :param white: The color to use for white input pixels.
+ :param mid: The color to use for midtone input pixels.
+ :param blackpoint: an int value [0, 255] for the black mapping.
+ :param whitepoint: an int value [0, 255] for the white mapping.
+ :param midpoint: an int value [0, 255] for the midtone mapping.
+ :return: An image.
+ """
+
+ # Initial asserts
+ assert image.mode == "L"
+ if mid is None:
+ assert 0 <= blackpoint <= whitepoint <= 255
+ else:
+ assert 0 <= blackpoint <= midpoint <= whitepoint <= 255
+
+ # Define colors from arguments
+ black = _color(black, "RGB")
+ white = _color(white, "RGB")
+ if mid is not None:
+ mid = _color(mid, "RGB")
+
+ # Empty lists for the mapping
+ red = []
+ green = []
+ blue = []
+
+ # Create the low-end values
+ for i in range(0, blackpoint):
+ red.append(black[0])
+ green.append(black[1])
+ blue.append(black[2])
+
+ # Create the mapping (2-color)
+ if mid is None:
+
+ range_map = range(0, whitepoint - blackpoint)
+
+ for i in range_map:
+ red.append(black[0] + i * (white[0] - black[0]) // len(range_map))
+ green.append(black[1] + i * (white[1] - black[1]) // len(range_map))
+ blue.append(black[2] + i * (white[2] - black[2]) // len(range_map))
+
+ # Create the mapping (3-color)
+ else:
+
+ range_map1 = range(0, midpoint - blackpoint)
+ range_map2 = range(0, whitepoint - midpoint)
+
+ for i in range_map1:
+ red.append(black[0] + i * (mid[0] - black[0]) // len(range_map1))
+ green.append(black[1] + i * (mid[1] - black[1]) // len(range_map1))
+ blue.append(black[2] + i * (mid[2] - black[2]) // len(range_map1))
+ for i in range_map2:
+ red.append(mid[0] + i * (white[0] - mid[0]) // len(range_map2))
+ green.append(mid[1] + i * (white[1] - mid[1]) // len(range_map2))
+ blue.append(mid[2] + i * (white[2] - mid[2]) // len(range_map2))
+
+ # Create the high-end values
+ for i in range(0, 256 - whitepoint):
+ red.append(white[0])
+ green.append(white[1])
+ blue.append(white[2])
+
+ # Return converted image
+ image = image.convert("RGB")
+ return _lut(image, red + green + blue)
+
+
+def pad(image, size, method=Image.BICUBIC, color=None, centering=(0.5, 0.5)):
+ """
+ Returns a sized and padded version of the image, expanded to fill the
+ requested aspect ratio and size.
+
+ :param image: The image to size and crop.
+ :param size: The requested output size in pixels, given as a
+ (width, height) tuple.
+ :param method: What resampling method to use. Default is
+ :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
+ :param color: The background color of the padded image.
+ :param centering: Control the position of the original image within the
+ padded version.
+
+ (0.5, 0.5) will keep the image centered
+ (0, 0) will keep the image aligned to the top left
+ (1, 1) will keep the image aligned to the bottom
+ right
+ :return: An image.
+ """
+
+ im_ratio = image.width / image.height
+ dest_ratio = size[0] / size[1]
+
+ if im_ratio == dest_ratio:
+ out = image.resize(size, resample=method)
+ else:
+ out = Image.new(image.mode, size, color)
+ if im_ratio > dest_ratio:
+ new_height = int(image.height / image.width * size[0])
+ if new_height != size[1]:
+ image = image.resize((size[0], new_height), resample=method)
+
+ y = int((size[1] - new_height) * max(0, min(centering[1], 1)))
+ out.paste(image, (0, y))
+ else:
+ new_width = int(image.width / image.height * size[1])
+ if new_width != size[0]:
+ image = image.resize((new_width, size[1]), resample=method)
+
+ x = int((size[0] - new_width) * max(0, min(centering[0], 1)))
+ out.paste(image, (x, 0))
+ return out
+
+
+def crop(image, border=0):
+ """
+ Remove border from image. The same amount of pixels are removed
+ from all four sides. This function works on all image modes.
+
+ .. seealso:: :py:meth:`~PIL.Image.Image.crop`
+
+ :param image: The image to crop.
+ :param border: The number of pixels to remove.
+ :return: An image.
+ """
+ left, top, right, bottom = _border(border)
+ return image.crop((left, top, image.size[0] - right, image.size[1] - bottom))
+
+
+def scale(image, factor, resample=Image.BICUBIC):
+ """
+ Returns a rescaled image by a specific factor given in parameter.
+ A factor greater than 1 expands the image, between 0 and 1 contracts the
+ image.
+
+ :param image: The image to rescale.
+ :param factor: The expansion factor, as a float.
+ :param resample: What resampling method to use. Default is
+ :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
+ :returns: An :py:class:`~PIL.Image.Image` object.
+ """
+ if factor == 1:
+ return image.copy()
+ elif factor <= 0:
+ raise ValueError("the factor must be greater than 0")
+ else:
+ size = (round(factor * image.width), round(factor * image.height))
+ return image.resize(size, resample)
+
+
+def deform(image, deformer, resample=Image.BILINEAR):
+ """
+ Deform the image.
+
+ :param image: The image to deform.
+ :param deformer: A deformer object. Any object that implements a
+ ``getmesh`` method can be used.
+ :param resample: An optional resampling filter. Same values possible as
+ in the PIL.Image.transform function.
+ :return: An image.
+ """
+ return image.transform(image.size, Image.MESH, deformer.getmesh(image), resample)
+
+
+def equalize(image, mask=None):
+ """
+ Equalize the image histogram. This function applies a non-linear
+ mapping to the input image, in order to create a uniform
+ distribution of grayscale values in the output image.
+
+ :param image: The image to equalize.
+ :param mask: An optional mask. If given, only the pixels selected by
+ the mask are included in the analysis.
+ :return: An image.
+ """
+ if image.mode == "P":
+ image = image.convert("RGB")
+ h = image.histogram(mask)
+ lut = []
+ for b in range(0, len(h), 256):
+ histo = [_f for _f in h[b : b + 256] if _f]
+ if len(histo) <= 1:
+ lut.extend(list(range(256)))
+ else:
+ step = (functools.reduce(operator.add, histo) - histo[-1]) // 255
+ if not step:
+ lut.extend(list(range(256)))
+ else:
+ n = step // 2
+ for i in range(256):
+ lut.append(n // step)
+ n = n + h[i + b]
+ return _lut(image, lut)
+
+
+def expand(image, border=0, fill=0):
+ """
+ Add border to the image
+
+ :param image: The image to expand.
+ :param border: Border width, in pixels.
+ :param fill: Pixel fill value (a color value). Default is 0 (black).
+ :return: An image.
+ """
+ left, top, right, bottom = _border(border)
+ width = left + image.size[0] + right
+ height = top + image.size[1] + bottom
+ out = Image.new(image.mode, (width, height), _color(fill, image.mode))
+ out.paste(image, (left, top))
+ return out
+
+
+def fit(image, size, method=Image.BICUBIC, bleed=0.0, centering=(0.5, 0.5)):
+ """
+ Returns a sized and cropped version of the image, cropped to the
+ requested aspect ratio and size.
+
+ This function was contributed by Kevin Cazabon.
+
+ :param image: The image to size and crop.
+ :param size: The requested output size in pixels, given as a
+ (width, height) tuple.
+ :param method: What resampling method to use. Default is
+ :py:attr:`PIL.Image.BICUBIC`. See :ref:`concept-filters`.
+ :param bleed: Remove a border around the outside of the image from all
+ four edges. The value is a decimal percentage (use 0.01 for
+ one percent). The default value is 0 (no border).
+ Cannot be greater than or equal to 0.5.
+ :param centering: Control the cropping position. Use (0.5, 0.5) for
+ center cropping (e.g. if cropping the width, take 50% off
+ of the left side, and therefore 50% off the right side).
+ (0.0, 0.0) will crop from the top left corner (i.e. if
+ cropping the width, take all of the crop off of the right
+ side, and if cropping the height, take all of it off the
+ bottom). (1.0, 0.0) will crop from the bottom left
+ corner, etc. (i.e. if cropping the width, take all of the
+ crop off the left side, and if cropping the height take
+ none from the top, and therefore all off the bottom).
+ :return: An image.
+ """
+
+ # by Kevin Cazabon, Feb 17/2000
+ # kevin@cazabon.com
+ # http://www.cazabon.com
+
+ # ensure centering is mutable
+ centering = list(centering)
+
+ if not 0.0 <= centering[0] <= 1.0:
+ centering[0] = 0.5
+ if not 0.0 <= centering[1] <= 1.0:
+ centering[1] = 0.5
+
+ if not 0.0 <= bleed < 0.5:
+ bleed = 0.0
+
+ # calculate the area to use for resizing and cropping, subtracting
+ # the 'bleed' around the edges
+
+ # number of pixels to trim off on Top and Bottom, Left and Right
+ bleed_pixels = (bleed * image.size[0], bleed * image.size[1])
+
+ live_size = (
+ image.size[0] - bleed_pixels[0] * 2,
+ image.size[1] - bleed_pixels[1] * 2,
+ )
+
+ # calculate the aspect ratio of the live_size
+ live_size_ratio = live_size[0] / live_size[1]
+
+ # calculate the aspect ratio of the output image
+ output_ratio = size[0] / size[1]
+
+ # figure out if the sides or top/bottom will be cropped off
+ if live_size_ratio == output_ratio:
+ # live_size is already the needed ratio
+ crop_width = live_size[0]
+ crop_height = live_size[1]
+ elif live_size_ratio >= output_ratio:
+ # live_size is wider than what's needed, crop the sides
+ crop_width = output_ratio * live_size[1]
+ crop_height = live_size[1]
+ else:
+ # live_size is taller than what's needed, crop the top and bottom
+ crop_width = live_size[0]
+ crop_height = live_size[0] / output_ratio
+
+ # make the crop
+ crop_left = bleed_pixels[0] + (live_size[0] - crop_width) * centering[0]
+ crop_top = bleed_pixels[1] + (live_size[1] - crop_height) * centering[1]
+
+ crop = (crop_left, crop_top, crop_left + crop_width, crop_top + crop_height)
+
+ # resize the image and return it
+ return image.resize(size, method, box=crop)
+
+
+def flip(image):
+ """
+ Flip the image vertically (top to bottom).
+
+ :param image: The image to flip.
+ :return: An image.
+ """
+ return image.transpose(Image.FLIP_TOP_BOTTOM)
+
+
+def grayscale(image):
+ """
+ Convert the image to grayscale.
+
+ :param image: The image to convert.
+ :return: An image.
+ """
+ return image.convert("L")
+
+
+def invert(image):
+ """
+ Invert (negate) the image.
+
+ :param image: The image to invert.
+ :return: An image.
+ """
+ lut = []
+ for i in range(256):
+ lut.append(255 - i)
+ return _lut(image, lut)
+
+
+def mirror(image):
+ """
+ Flip image horizontally (left to right).
+
+ :param image: The image to mirror.
+ :return: An image.
+ """
+ return image.transpose(Image.FLIP_LEFT_RIGHT)
+
+
+def posterize(image, bits):
+ """
+ Reduce the number of bits for each color channel.
+
+ :param image: The image to posterize.
+ :param bits: The number of bits to keep for each channel (1-8).
+ :return: An image.
+ """
+ lut = []
+ mask = ~(2 ** (8 - bits) - 1)
+ for i in range(256):
+ lut.append(i & mask)
+ return _lut(image, lut)
+
+
+def solarize(image, threshold=128):
+ """
+ Invert all pixel values above a threshold.
+
+ :param image: The image to solarize.
+ :param threshold: All pixels above this greyscale level are inverted.
+ :return: An image.
+ """
+ lut = []
+ for i in range(256):
+ if i < threshold:
+ lut.append(i)
+ else:
+ lut.append(255 - i)
+ return _lut(image, lut)
+
+
+def exif_transpose(image):
+ """
+ If an image has an EXIF Orientation tag, return a new image that is
+ transposed accordingly. Otherwise, return a copy of the image.
+
+ :param image: The image to transpose.
+ :return: An image.
+ """
+ exif = image.getexif()
+ orientation = exif.get(0x0112)
+ method = {
+ 2: Image.FLIP_LEFT_RIGHT,
+ 3: Image.ROTATE_180,
+ 4: Image.FLIP_TOP_BOTTOM,
+ 5: Image.TRANSPOSE,
+ 6: Image.ROTATE_270,
+ 7: Image.TRANSVERSE,
+ 8: Image.ROTATE_90,
+ }.get(orientation)
+ if method is not None:
+ transposed_image = image.transpose(method)
+ del exif[0x0112]
+ transposed_image.info["exif"] = exif.tobytes()
+ return transposed_image
+ return image.copy()
diff --git a/venv/Lib/site-packages/PIL/ImagePalette.py b/venv/Lib/site-packages/PIL/ImagePalette.py
new file mode 100644
index 0000000..d060411
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImagePalette.py
@@ -0,0 +1,221 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# image palette object
+#
+# History:
+# 1996-03-11 fl Rewritten.
+# 1997-01-03 fl Up and running.
+# 1997-08-23 fl Added load hack
+# 2001-04-16 fl Fixed randint shadow bug in random()
+#
+# Copyright (c) 1997-2001 by Secret Labs AB
+# Copyright (c) 1996-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import array
+
+from . import GimpGradientFile, GimpPaletteFile, ImageColor, PaletteFile
+
+
+class ImagePalette:
+ """
+ Color palette for palette mapped images
+
+ :param mode: The mode to use for the Palette. See:
+ :ref:`concept-modes`. Defaults to "RGB"
+ :param palette: An optional palette. If given, it must be a bytearray,
+ an array or a list of ints between 0-255 and of length ``size``
+ times the number of colors in ``mode``. The list must be aligned
+ by channel (All R values must be contiguous in the list before G
+ and B values.) Defaults to 0 through 255 per channel.
+ :param size: An optional palette size. If given, it cannot be equal to
+ or greater than 256. Defaults to 0.
+ """
+
+ def __init__(self, mode="RGB", palette=None, size=0):
+ self.mode = mode
+ self.rawmode = None # if set, palette contains raw data
+ self.palette = palette or bytearray(range(256)) * len(self.mode)
+ self.colors = {}
+ self.dirty = None
+ if (size == 0 and len(self.mode) * 256 != len(self.palette)) or (
+ size != 0 and size != len(self.palette)
+ ):
+ raise ValueError("wrong palette size")
+
+ def copy(self):
+ new = ImagePalette()
+
+ new.mode = self.mode
+ new.rawmode = self.rawmode
+ if self.palette is not None:
+ new.palette = self.palette[:]
+ new.colors = self.colors.copy()
+ new.dirty = self.dirty
+
+ return new
+
+ def getdata(self):
+ """
+ Get palette contents in format suitable for the low-level
+ ``im.putpalette`` primitive.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ return self.rawmode, self.palette
+ return self.mode + ";L", self.tobytes()
+
+ def tobytes(self):
+ """Convert palette to bytes.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ raise ValueError("palette contains raw palette data")
+ if isinstance(self.palette, bytes):
+ return self.palette
+ arr = array.array("B", self.palette)
+ if hasattr(arr, "tobytes"):
+ return arr.tobytes()
+ return arr.tostring()
+
+ # Declare tostring as an alias for tobytes
+ tostring = tobytes
+
+ def getcolor(self, color):
+ """Given an rgb tuple, allocate palette entry.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ raise ValueError("palette contains raw palette data")
+ if isinstance(color, tuple):
+ try:
+ return self.colors[color]
+ except KeyError as e:
+ # allocate new color slot
+ if isinstance(self.palette, bytes):
+ self.palette = bytearray(self.palette)
+ index = len(self.colors)
+ if index >= 256:
+ raise ValueError("cannot allocate more than 256 colors") from e
+ self.colors[color] = index
+ self.palette[index] = color[0]
+ self.palette[index + 256] = color[1]
+ self.palette[index + 512] = color[2]
+ self.dirty = 1
+ return index
+ else:
+ raise ValueError(f"unknown color specifier: {repr(color)}")
+
+ def save(self, fp):
+ """Save palette to text file.
+
+ .. warning:: This method is experimental.
+ """
+ if self.rawmode:
+ raise ValueError("palette contains raw palette data")
+ if isinstance(fp, str):
+ fp = open(fp, "w")
+ fp.write("# Palette\n")
+ fp.write(f"# Mode: {self.mode}\n")
+ for i in range(256):
+ fp.write(f"{i}")
+ for j in range(i * len(self.mode), (i + 1) * len(self.mode)):
+ try:
+ fp.write(f" {self.palette[j]}")
+ except IndexError:
+ fp.write(" 0")
+ fp.write("\n")
+ fp.close()
+
+
+# --------------------------------------------------------------------
+# Internal
+
+
+def raw(rawmode, data):
+ palette = ImagePalette()
+ palette.rawmode = rawmode
+ palette.palette = data
+ palette.dirty = 1
+ return palette
+
+
+# --------------------------------------------------------------------
+# Factories
+
+
+def make_linear_lut(black, white):
+ lut = []
+ if black == 0:
+ for i in range(256):
+ lut.append(white * i // 255)
+ else:
+ raise NotImplementedError # FIXME
+ return lut
+
+
+def make_gamma_lut(exp):
+ lut = []
+ for i in range(256):
+ lut.append(int(((i / 255.0) ** exp) * 255.0 + 0.5))
+ return lut
+
+
+def negative(mode="RGB"):
+ palette = list(range(256))
+ palette.reverse()
+ return ImagePalette(mode, palette * len(mode))
+
+
+def random(mode="RGB"):
+ from random import randint
+
+ palette = []
+ for i in range(256 * len(mode)):
+ palette.append(randint(0, 255))
+ return ImagePalette(mode, palette)
+
+
+def sepia(white="#fff0c0"):
+ r, g, b = ImageColor.getrgb(white)
+ r = make_linear_lut(0, r)
+ g = make_linear_lut(0, g)
+ b = make_linear_lut(0, b)
+ return ImagePalette("RGB", r + g + b)
+
+
+def wedge(mode="RGB"):
+ return ImagePalette(mode, list(range(256)) * len(mode))
+
+
+def load(filename):
+
+ # FIXME: supports GIMP gradients only
+
+ with open(filename, "rb") as fp:
+
+ for paletteHandler in [
+ GimpPaletteFile.GimpPaletteFile,
+ GimpGradientFile.GimpGradientFile,
+ PaletteFile.PaletteFile,
+ ]:
+ try:
+ fp.seek(0)
+ lut = paletteHandler(fp).getpalette()
+ if lut:
+ break
+ except (SyntaxError, ValueError):
+ # import traceback
+ # traceback.print_exc()
+ pass
+ else:
+ raise OSError("cannot load palette")
+
+ return lut # data, rawmode
diff --git a/venv/Lib/site-packages/PIL/ImagePath.py b/venv/Lib/site-packages/PIL/ImagePath.py
new file mode 100644
index 0000000..3d3538c
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImagePath.py
@@ -0,0 +1,19 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# path interface
+#
+# History:
+# 1996-11-04 fl Created
+# 2002-04-14 fl Added documentation stub class
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+Path = Image.core.path
diff --git a/venv/Lib/site-packages/PIL/ImageQt.py b/venv/Lib/site-packages/PIL/ImageQt.py
new file mode 100644
index 0000000..64f07be
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageQt.py
@@ -0,0 +1,202 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# a simple Qt image interface.
+#
+# history:
+# 2006-06-03 fl: created
+# 2006-06-04 fl: inherit from QImage instead of wrapping it
+# 2006-06-05 fl: removed toimage helper; move string support to ImageQt
+# 2013-11-13 fl: add support for Qt5 (aurelien.ballier@cyclonit.com)
+#
+# Copyright (c) 2006 by Secret Labs AB
+# Copyright (c) 2006 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import sys
+from io import BytesIO
+
+from . import Image
+from ._util import isPath
+
+qt_versions = [
+ ["side6", "PySide6"],
+ ["5", "PyQt5"],
+ ["side2", "PySide2"],
+]
+
+# If a version has already been imported, attempt it first
+qt_versions.sort(key=lambda qt_version: qt_version[1] in sys.modules, reverse=True)
+for qt_version, qt_module in qt_versions:
+ try:
+ if qt_module == "PySide6":
+ from PySide6.QtCore import QBuffer, QIODevice
+ from PySide6.QtGui import QImage, QPixmap, qRgba
+ elif qt_module == "PyQt5":
+ from PyQt5.QtCore import QBuffer, QIODevice
+ from PyQt5.QtGui import QImage, QPixmap, qRgba
+ elif qt_module == "PySide2":
+ from PySide2.QtCore import QBuffer, QIODevice
+ from PySide2.QtGui import QImage, QPixmap, qRgba
+ except (ImportError, RuntimeError):
+ continue
+ qt_is_installed = True
+ break
+else:
+ qt_is_installed = False
+ qt_version = None
+
+
+def rgb(r, g, b, a=255):
+ """(Internal) Turns an RGB color into a Qt compatible color integer."""
+ # use qRgb to pack the colors, and then turn the resulting long
+ # into a negative integer with the same bitpattern.
+ return qRgba(r, g, b, a) & 0xFFFFFFFF
+
+
+def fromqimage(im):
+ """
+ :param im: A PIL Image object, or a file name
+ (given either as Python string or a PyQt string object)
+ """
+ buffer = QBuffer()
+ buffer.open(QIODevice.ReadWrite)
+ # preserve alpha channel with png
+ # otherwise ppm is more friendly with Image.open
+ if im.hasAlphaChannel():
+ im.save(buffer, "png")
+ else:
+ im.save(buffer, "ppm")
+
+ b = BytesIO()
+ b.write(buffer.data())
+ buffer.close()
+ b.seek(0)
+
+ return Image.open(b)
+
+
+def fromqpixmap(im):
+ return fromqimage(im)
+ # buffer = QBuffer()
+ # buffer.open(QIODevice.ReadWrite)
+ # # im.save(buffer)
+ # # What if png doesn't support some image features like animation?
+ # im.save(buffer, 'ppm')
+ # bytes_io = BytesIO()
+ # bytes_io.write(buffer.data())
+ # buffer.close()
+ # bytes_io.seek(0)
+ # return Image.open(bytes_io)
+
+
+def align8to32(bytes, width, mode):
+ """
+ converts each scanline of data from 8 bit to 32 bit aligned
+ """
+
+ bits_per_pixel = {"1": 1, "L": 8, "P": 8}[mode]
+
+ # calculate bytes per line and the extra padding if needed
+ bits_per_line = bits_per_pixel * width
+ full_bytes_per_line, remaining_bits_per_line = divmod(bits_per_line, 8)
+ bytes_per_line = full_bytes_per_line + (1 if remaining_bits_per_line else 0)
+
+ extra_padding = -bytes_per_line % 4
+
+ # already 32 bit aligned by luck
+ if not extra_padding:
+ return bytes
+
+ new_data = []
+ for i in range(len(bytes) // bytes_per_line):
+ new_data.append(
+ bytes[i * bytes_per_line : (i + 1) * bytes_per_line]
+ + b"\x00" * extra_padding
+ )
+
+ return b"".join(new_data)
+
+
+def _toqclass_helper(im):
+ data = None
+ colortable = None
+
+ # handle filename, if given instead of image name
+ if hasattr(im, "toUtf8"):
+ # FIXME - is this really the best way to do this?
+ im = str(im.toUtf8(), "utf-8")
+ if isPath(im):
+ im = Image.open(im)
+
+ if im.mode == "1":
+ format = QImage.Format_Mono
+ elif im.mode == "L":
+ format = QImage.Format_Indexed8
+ colortable = []
+ for i in range(256):
+ colortable.append(rgb(i, i, i))
+ elif im.mode == "P":
+ format = QImage.Format_Indexed8
+ colortable = []
+ palette = im.getpalette()
+ for i in range(0, len(palette), 3):
+ colortable.append(rgb(*palette[i : i + 3]))
+ elif im.mode == "RGB":
+ data = im.tobytes("raw", "BGRX")
+ format = QImage.Format_RGB32
+ elif im.mode == "RGBA":
+ data = im.tobytes("raw", "BGRA")
+ format = QImage.Format_ARGB32
+ else:
+ raise ValueError(f"unsupported image mode {repr(im.mode)}")
+
+ __data = data or align8to32(im.tobytes(), im.size[0], im.mode)
+ return {"data": __data, "im": im, "format": format, "colortable": colortable}
+
+
+if qt_is_installed:
+
+ class ImageQt(QImage):
+ def __init__(self, im):
+ """
+ An PIL image wrapper for Qt. This is a subclass of PyQt's QImage
+ class.
+
+ :param im: A PIL Image object, or a file name (given either as
+ Python string or a PyQt string object).
+ """
+ im_data = _toqclass_helper(im)
+ # must keep a reference, or Qt will crash!
+ # All QImage constructors that take data operate on an existing
+ # buffer, so this buffer has to hang on for the life of the image.
+ # Fixes https://github.com/python-pillow/Pillow/issues/1370
+ self.__data = im_data["data"]
+ super().__init__(
+ self.__data,
+ im_data["im"].size[0],
+ im_data["im"].size[1],
+ im_data["format"],
+ )
+ if im_data["colortable"]:
+ self.setColorTable(im_data["colortable"])
+
+
+def toqimage(im):
+ return ImageQt(im)
+
+
+def toqpixmap(im):
+ # # This doesn't work. For now using a dumb approach.
+ # im_data = _toqclass_helper(im)
+ # result = QPixmap(im_data['im'].size[0], im_data['im'].size[1])
+ # result.loadFromData(im_data['data'])
+ # Fix some strange bug that causes
+ if im.mode == "RGB":
+ im = im.convert("RGBA")
+
+ qimage = toqimage(im)
+ return QPixmap.fromImage(qimage)
diff --git a/venv/Lib/site-packages/PIL/ImageSequence.py b/venv/Lib/site-packages/PIL/ImageSequence.py
new file mode 100644
index 0000000..9df910a
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageSequence.py
@@ -0,0 +1,75 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# sequence support classes
+#
+# history:
+# 1997-02-20 fl Created
+#
+# Copyright (c) 1997 by Secret Labs AB.
+# Copyright (c) 1997 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+
+
+class Iterator:
+ """
+ This class implements an iterator object that can be used to loop
+ over an image sequence.
+
+ You can use the ``[]`` operator to access elements by index. This operator
+ will raise an :py:exc:`IndexError` if you try to access a nonexistent
+ frame.
+
+ :param im: An image object.
+ """
+
+ def __init__(self, im):
+ if not hasattr(im, "seek"):
+ raise AttributeError("im must have seek method")
+ self.im = im
+ self.position = getattr(self.im, "_min_frame", 0)
+
+ def __getitem__(self, ix):
+ try:
+ self.im.seek(ix)
+ return self.im
+ except EOFError as e:
+ raise IndexError from e # end of sequence
+
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ try:
+ self.im.seek(self.position)
+ self.position += 1
+ return self.im
+ except EOFError as e:
+ raise StopIteration from e
+
+
+def all_frames(im, func=None):
+ """
+ Applies a given function to all frames in an image or a list of images.
+ The frames are returned as a list of separate images.
+
+ :param im: An image, or a list of images.
+ :param func: The function to apply to all of the image frames.
+ :returns: A list of images.
+ """
+ if not isinstance(im, list):
+ im = [im]
+
+ ims = []
+ for imSequence in im:
+ current = imSequence.tell()
+
+ ims += [im_frame.copy() for im_frame in Iterator(imSequence)]
+
+ imSequence.seek(current)
+ return [func(im) for im in ims] if func else ims
diff --git a/venv/Lib/site-packages/PIL/ImageShow.py b/venv/Lib/site-packages/PIL/ImageShow.py
new file mode 100644
index 0000000..1ada825
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageShow.py
@@ -0,0 +1,236 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# im.show() drivers
+#
+# History:
+# 2008-04-06 fl Created
+#
+# Copyright (c) Secret Labs AB 2008.
+#
+# See the README file for information on usage and redistribution.
+#
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+from shlex import quote
+
+from PIL import Image
+
+_viewers = []
+
+
+def register(viewer, order=1):
+ """
+ The :py:func:`register` function is used to register additional viewers.
+
+ :param viewer: The viewer to be registered.
+ :param order:
+ Zero or a negative integer to prepend this viewer to the list,
+ a positive integer to append it.
+ """
+ try:
+ if issubclass(viewer, Viewer):
+ viewer = viewer()
+ except TypeError:
+ pass # raised if viewer wasn't a class
+ if order > 0:
+ _viewers.append(viewer)
+ else:
+ _viewers.insert(0, viewer)
+
+
+def show(image, title=None, **options):
+ r"""
+ Display a given image.
+
+ :param image: An image object.
+ :param title: Optional title. Not all viewers can display the title.
+ :param \**options: Additional viewer options.
+ :returns: ``True`` if a suitable viewer was found, ``False`` otherwise.
+ """
+ for viewer in _viewers:
+ if viewer.show(image, title=title, **options):
+ return 1
+ return 0
+
+
+class Viewer:
+ """Base class for viewers."""
+
+ # main api
+
+ def show(self, image, **options):
+ """
+ The main function for displaying an image.
+ Converts the given image to the target format and displays it.
+ """
+
+ # save temporary image to disk
+ if not (
+ image.mode in ("1", "RGBA")
+ or (self.format == "PNG" and image.mode in ("I;16", "LA"))
+ ):
+ base = Image.getmodebase(image.mode)
+ if image.mode != base:
+ image = image.convert(base)
+
+ return self.show_image(image, **options)
+
+ # hook methods
+
+ format = None
+ """The format to convert the image into."""
+ options = {}
+ """Additional options used to convert the image."""
+
+ def get_format(self, image):
+ """Return format name, or ``None`` to save as PGM/PPM."""
+ return self.format
+
+ def get_command(self, file, **options):
+ """
+ Returns the command used to display the file.
+ Not implemented in the base class.
+ """
+ raise NotImplementedError
+
+ def save_image(self, image):
+ """Save to temporary file and return filename."""
+ return image._dump(format=self.get_format(image), **self.options)
+
+ def show_image(self, image, **options):
+ """Display the given image."""
+ return self.show_file(self.save_image(image), **options)
+
+ def show_file(self, file, **options):
+ """Display the given file."""
+ os.system(self.get_command(file, **options))
+ return 1
+
+
+# --------------------------------------------------------------------
+
+
+class WindowsViewer(Viewer):
+ """The default viewer on Windows is the default system application for PNG files."""
+
+ format = "PNG"
+ options = {"compress_level": 1}
+
+ def get_command(self, file, **options):
+ return (
+ f'start "Pillow" /WAIT "{file}" '
+ "&& ping -n 2 127.0.0.1 >NUL "
+ f'&& del /f "{file}"'
+ )
+
+
+if sys.platform == "win32":
+ register(WindowsViewer)
+
+
+class MacViewer(Viewer):
+ """The default viewer on MacOS using ``Preview.app``."""
+
+ format = "PNG"
+ options = {"compress_level": 1}
+
+ def get_command(self, file, **options):
+ # on darwin open returns immediately resulting in the temp
+ # file removal while app is opening
+ command = "open -a Preview.app"
+ command = f"({command} {quote(file)}; sleep 20; rm -f {quote(file)})&"
+ return command
+
+ def show_file(self, file, **options):
+ """Display given file"""
+ fd, path = tempfile.mkstemp()
+ with os.fdopen(fd, "w") as f:
+ f.write(file)
+ with open(path) as f:
+ subprocess.Popen(
+ ["im=$(cat); open -a Preview.app $im; sleep 20; rm -f $im"],
+ shell=True,
+ stdin=f,
+ )
+ os.remove(path)
+ return 1
+
+
+if sys.platform == "darwin":
+ register(MacViewer)
+
+
+class UnixViewer(Viewer):
+ format = "PNG"
+ options = {"compress_level": 1}
+
+ def get_command(self, file, **options):
+ command = self.get_command_ex(file, **options)[0]
+ return f"({command} {quote(file)}; rm -f {quote(file)})&"
+
+ def show_file(self, file, **options):
+ """Display given file"""
+ fd, path = tempfile.mkstemp()
+ with os.fdopen(fd, "w") as f:
+ f.write(file)
+ with open(path) as f:
+ command = self.get_command_ex(file, **options)[0]
+ subprocess.Popen(
+ ["im=$(cat);" + command + " $im; rm -f $im"], shell=True, stdin=f
+ )
+ os.remove(path)
+ return 1
+
+
+class DisplayViewer(UnixViewer):
+ """The ImageMagick ``display`` command."""
+
+ def get_command_ex(self, file, **options):
+ command = executable = "display"
+ return command, executable
+
+
+class EogViewer(UnixViewer):
+ """The GNOME Image Viewer ``eog`` command."""
+
+ def get_command_ex(self, file, **options):
+ command = executable = "eog"
+ return command, executable
+
+
+class XVViewer(UnixViewer):
+ """
+ The X Viewer ``xv`` command.
+ This viewer supports the ``title`` parameter.
+ """
+
+ def get_command_ex(self, file, title=None, **options):
+ # note: xv is pretty outdated. most modern systems have
+ # imagemagick's display command instead.
+ command = executable = "xv"
+ if title:
+ command += f" -name {quote(title)}"
+ return command, executable
+
+
+if sys.platform not in ("win32", "darwin"): # unixoids
+ if shutil.which("display"):
+ register(DisplayViewer)
+ if shutil.which("eog"):
+ register(EogViewer)
+ if shutil.which("xv"):
+ register(XVViewer)
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 2:
+ print("Syntax: python ImageShow.py imagefile [title]")
+ sys.exit()
+
+ with Image.open(sys.argv[1]) as im:
+ print(show(im, *sys.argv[2:]))
diff --git a/venv/Lib/site-packages/PIL/ImageStat.py b/venv/Lib/site-packages/PIL/ImageStat.py
new file mode 100644
index 0000000..50bafc9
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageStat.py
@@ -0,0 +1,147 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# global image statistics
+#
+# History:
+# 1996-04-05 fl Created
+# 1997-05-21 fl Added mask; added rms, var, stddev attributes
+# 1997-08-05 fl Added median
+# 1998-07-05 hk Fixed integer overflow error
+#
+# Notes:
+# This class shows how to implement delayed evaluation of attributes.
+# To get a certain value, simply access the corresponding attribute.
+# The __getattr__ dispatcher takes care of the rest.
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996-97.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import functools
+import math
+import operator
+
+
+class Stat:
+ def __init__(self, image_or_list, mask=None):
+ try:
+ if mask:
+ self.h = image_or_list.histogram(mask)
+ else:
+ self.h = image_or_list.histogram()
+ except AttributeError:
+ self.h = image_or_list # assume it to be a histogram list
+ if not isinstance(self.h, list):
+ raise TypeError("first argument must be image or list")
+ self.bands = list(range(len(self.h) // 256))
+
+ def __getattr__(self, id):
+ """Calculate missing attribute"""
+ if id[:4] == "_get":
+ raise AttributeError(id)
+ # calculate missing attribute
+ v = getattr(self, "_get" + id)()
+ setattr(self, id, v)
+ return v
+
+ def _getextrema(self):
+ """Get min/max values for each band in the image"""
+
+ def minmax(histogram):
+ n = 255
+ x = 0
+ for i in range(256):
+ if histogram[i]:
+ n = min(n, i)
+ x = max(x, i)
+ return n, x # returns (255, 0) if there's no data in the histogram
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ v.append(minmax(self.h[i:]))
+ return v
+
+ def _getcount(self):
+ """Get total number of pixels in each layer"""
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ v.append(functools.reduce(operator.add, self.h[i : i + 256]))
+ return v
+
+ def _getsum(self):
+ """Get sum of all pixels in each layer"""
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ layerSum = 0.0
+ for j in range(256):
+ layerSum += j * self.h[i + j]
+ v.append(layerSum)
+ return v
+
+ def _getsum2(self):
+ """Get squared sum of all pixels in each layer"""
+
+ v = []
+ for i in range(0, len(self.h), 256):
+ sum2 = 0.0
+ for j in range(256):
+ sum2 += (j ** 2) * float(self.h[i + j])
+ v.append(sum2)
+ return v
+
+ def _getmean(self):
+ """Get average pixel level for each layer"""
+
+ v = []
+ for i in self.bands:
+ v.append(self.sum[i] / self.count[i])
+ return v
+
+ def _getmedian(self):
+ """Get median pixel level for each layer"""
+
+ v = []
+ for i in self.bands:
+ s = 0
+ half = self.count[i] // 2
+ b = i * 256
+ for j in range(256):
+ s = s + self.h[b + j]
+ if s > half:
+ break
+ v.append(j)
+ return v
+
+ def _getrms(self):
+ """Get RMS for each layer"""
+
+ v = []
+ for i in self.bands:
+ v.append(math.sqrt(self.sum2[i] / self.count[i]))
+ return v
+
+ def _getvar(self):
+ """Get variance for each layer"""
+
+ v = []
+ for i in self.bands:
+ n = self.count[i]
+ v.append((self.sum2[i] - (self.sum[i] ** 2.0) / n) / n)
+ return v
+
+ def _getstddev(self):
+ """Get standard deviation for each layer"""
+
+ v = []
+ for i in self.bands:
+ v.append(math.sqrt(self.var[i]))
+ return v
+
+
+Global = Stat # compatibility
diff --git a/venv/Lib/site-packages/PIL/ImageTk.py b/venv/Lib/site-packages/PIL/ImageTk.py
new file mode 100644
index 0000000..62db7a7
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageTk.py
@@ -0,0 +1,300 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# a Tk display interface
+#
+# History:
+# 96-04-08 fl Created
+# 96-09-06 fl Added getimage method
+# 96-11-01 fl Rewritten, removed image attribute and crop method
+# 97-05-09 fl Use PyImagingPaste method instead of image type
+# 97-05-12 fl Minor tweaks to match the IFUNC95 interface
+# 97-05-17 fl Support the "pilbitmap" booster patch
+# 97-06-05 fl Added file= and data= argument to image constructors
+# 98-03-09 fl Added width and height methods to Image classes
+# 98-07-02 fl Use default mode for "P" images without palette attribute
+# 98-07-02 fl Explicitly destroy Tkinter image objects
+# 99-07-24 fl Support multiple Tk interpreters (from Greg Couch)
+# 99-07-26 fl Automatically hook into Tkinter (if possible)
+# 99-08-15 fl Hook uses _imagingtk instead of _imaging
+#
+# Copyright (c) 1997-1999 by Secret Labs AB
+# Copyright (c) 1996-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import tkinter
+from io import BytesIO
+
+from . import Image
+
+# --------------------------------------------------------------------
+# Check for Tkinter interface hooks
+
+_pilbitmap_ok = None
+
+
+def _pilbitmap_check():
+ global _pilbitmap_ok
+ if _pilbitmap_ok is None:
+ try:
+ im = Image.new("1", (1, 1))
+ tkinter.BitmapImage(data=f"PIL:{im.im.id}")
+ _pilbitmap_ok = 1
+ except tkinter.TclError:
+ _pilbitmap_ok = 0
+ return _pilbitmap_ok
+
+
+def _get_image_from_kw(kw):
+ source = None
+ if "file" in kw:
+ source = kw.pop("file")
+ elif "data" in kw:
+ source = BytesIO(kw.pop("data"))
+ if source:
+ return Image.open(source)
+
+
+# --------------------------------------------------------------------
+# PhotoImage
+
+
+class PhotoImage:
+ """
+ A Tkinter-compatible photo image. This can be used
+ everywhere Tkinter expects an image object. If the image is an RGBA
+ image, pixels having alpha 0 are treated as transparent.
+
+ The constructor takes either a PIL image, or a mode and a size.
+ Alternatively, you can use the ``file`` or ``data`` options to initialize
+ the photo image object.
+
+ :param image: Either a PIL image, or a mode string. If a mode string is
+ used, a size must also be given.
+ :param size: If the first argument is a mode string, this defines the size
+ of the image.
+ :keyword file: A filename to load the image from (using
+ ``Image.open(file)``).
+ :keyword data: An 8-bit string containing image data (as loaded from an
+ image file).
+ """
+
+ def __init__(self, image=None, size=None, **kw):
+
+ # Tk compatibility: file or data
+ if image is None:
+ image = _get_image_from_kw(kw)
+
+ if hasattr(image, "mode") and hasattr(image, "size"):
+ # got an image instead of a mode
+ mode = image.mode
+ if mode == "P":
+ # palette mapped data
+ image.load()
+ try:
+ mode = image.palette.mode
+ except AttributeError:
+ mode = "RGB" # default
+ size = image.size
+ kw["width"], kw["height"] = size
+ else:
+ mode = image
+ image = None
+
+ if mode not in ["1", "L", "RGB", "RGBA"]:
+ mode = Image.getmodebase(mode)
+
+ self.__mode = mode
+ self.__size = size
+ self.__photo = tkinter.PhotoImage(**kw)
+ self.tk = self.__photo.tk
+ if image:
+ self.paste(image)
+
+ def __del__(self):
+ name = self.__photo.name
+ self.__photo.name = None
+ try:
+ self.__photo.tk.call("image", "delete", name)
+ except Exception:
+ pass # ignore internal errors
+
+ def __str__(self):
+ """
+ Get the Tkinter photo image identifier. This method is automatically
+ called by Tkinter whenever a PhotoImage object is passed to a Tkinter
+ method.
+
+ :return: A Tkinter photo image identifier (a string).
+ """
+ return str(self.__photo)
+
+ def width(self):
+ """
+ Get the width of the image.
+
+ :return: The width, in pixels.
+ """
+ return self.__size[0]
+
+ def height(self):
+ """
+ Get the height of the image.
+
+ :return: The height, in pixels.
+ """
+ return self.__size[1]
+
+ def paste(self, im, box=None):
+ """
+ Paste a PIL image into the photo image. Note that this can
+ be very slow if the photo image is displayed.
+
+ :param im: A PIL image. The size must match the target region. If the
+ mode does not match, the image is converted to the mode of
+ the bitmap image.
+ :param box: A 4-tuple defining the left, upper, right, and lower pixel
+ coordinate. See :ref:`coordinate-system`. If None is given
+ instead of a tuple, all of the image is assumed.
+ """
+
+ # convert to blittable
+ im.load()
+ image = im.im
+ if image.isblock() and im.mode == self.__mode:
+ block = image
+ else:
+ block = image.new_block(self.__mode, im.size)
+ image.convert2(block, image) # convert directly between buffers
+
+ tk = self.__photo.tk
+
+ try:
+ tk.call("PyImagingPhoto", self.__photo, block.id)
+ except tkinter.TclError:
+ # activate Tkinter hook
+ try:
+ from . import _imagingtk
+
+ try:
+ if hasattr(tk, "interp"):
+ # Required for PyPy, which always has CFFI installed
+ from cffi import FFI
+
+ ffi = FFI()
+
+ # PyPy is using an FFI CDATA element
+ # (Pdb) self.tk.interp
+ #
+ _imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1)
+ else:
+ _imagingtk.tkinit(tk.interpaddr(), 1)
+ except AttributeError:
+ _imagingtk.tkinit(id(tk), 0)
+ tk.call("PyImagingPhoto", self.__photo, block.id)
+ except (ImportError, AttributeError, tkinter.TclError):
+ raise # configuration problem; cannot attach to Tkinter
+
+
+# --------------------------------------------------------------------
+# BitmapImage
+
+
+class BitmapImage:
+ """
+ A Tkinter-compatible bitmap image. This can be used everywhere Tkinter
+ expects an image object.
+
+ The given image must have mode "1". Pixels having value 0 are treated as
+ transparent. Options, if any, are passed on to Tkinter. The most commonly
+ used option is ``foreground``, which is used to specify the color for the
+ non-transparent parts. See the Tkinter documentation for information on
+ how to specify colours.
+
+ :param image: A PIL image.
+ """
+
+ def __init__(self, image=None, **kw):
+
+ # Tk compatibility: file or data
+ if image is None:
+ image = _get_image_from_kw(kw)
+
+ self.__mode = image.mode
+ self.__size = image.size
+
+ if _pilbitmap_check():
+ # fast way (requires the pilbitmap booster patch)
+ image.load()
+ kw["data"] = f"PIL:{image.im.id}"
+ self.__im = image # must keep a reference
+ else:
+ # slow but safe way
+ kw["data"] = image.tobitmap()
+ self.__photo = tkinter.BitmapImage(**kw)
+
+ def __del__(self):
+ name = self.__photo.name
+ self.__photo.name = None
+ try:
+ self.__photo.tk.call("image", "delete", name)
+ except Exception:
+ pass # ignore internal errors
+
+ def width(self):
+ """
+ Get the width of the image.
+
+ :return: The width, in pixels.
+ """
+ return self.__size[0]
+
+ def height(self):
+ """
+ Get the height of the image.
+
+ :return: The height, in pixels.
+ """
+ return self.__size[1]
+
+ def __str__(self):
+ """
+ Get the Tkinter bitmap image identifier. This method is automatically
+ called by Tkinter whenever a BitmapImage object is passed to a Tkinter
+ method.
+
+ :return: A Tkinter bitmap image identifier (a string).
+ """
+ return str(self.__photo)
+
+
+def getimage(photo):
+ """Copies the contents of a PhotoImage to a PIL image memory."""
+ im = Image.new("RGBA", (photo.width(), photo.height()))
+ block = im.im
+
+ photo.tk.call("PyImagingPhotoGet", photo, block.id)
+
+ return im
+
+
+def _show(image, title):
+ """Helper for the Image.show method."""
+
+ class UI(tkinter.Label):
+ def __init__(self, master, im):
+ if im.mode == "1":
+ self.image = BitmapImage(im, foreground="white", master=master)
+ else:
+ self.image = PhotoImage(im, master=master)
+ super().__init__(master, image=self.image, bg="black", bd=0)
+
+ if not tkinter._default_root:
+ raise OSError("tkinter not initialized")
+ top = tkinter.Toplevel()
+ if title:
+ top.title(title)
+ UI(top, image).pack()
diff --git a/venv/Lib/site-packages/PIL/ImageTransform.py b/venv/Lib/site-packages/PIL/ImageTransform.py
new file mode 100644
index 0000000..77791ab
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageTransform.py
@@ -0,0 +1,102 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# transform wrappers
+#
+# History:
+# 2002-04-08 fl Created
+#
+# Copyright (c) 2002 by Secret Labs AB
+# Copyright (c) 2002 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+
+class Transform(Image.ImageTransformHandler):
+ def __init__(self, data):
+ self.data = data
+
+ def getdata(self):
+ return self.method, self.data
+
+ def transform(self, size, image, **options):
+ # can be overridden
+ method, data = self.getdata()
+ return image.transform(size, method, data, **options)
+
+
+class AffineTransform(Transform):
+ """
+ Define an affine image transform.
+
+ This function takes a 6-tuple (a, b, c, d, e, f) which contain the first
+ two rows from an affine transform matrix. For each pixel (x, y) in the
+ output image, the new value is taken from a position (a x + b y + c,
+ d x + e y + f) in the input image, rounded to nearest pixel.
+
+ This function can be used to scale, translate, rotate, and shear the
+ original image.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param matrix: A 6-tuple (a, b, c, d, e, f) containing the first two rows
+ from an affine transform matrix.
+ """
+
+ method = Image.AFFINE
+
+
+class ExtentTransform(Transform):
+ """
+ Define a transform to extract a subregion from an image.
+
+ Maps a rectangle (defined by two corners) from the image to a rectangle of
+ the given size. The resulting image will contain data sampled from between
+ the corners, such that (x0, y0) in the input image will end up at (0,0) in
+ the output image, and (x1, y1) at size.
+
+ This method can be used to crop, stretch, shrink, or mirror an arbitrary
+ rectangle in the current image. It is slightly slower than crop, but about
+ as fast as a corresponding resize operation.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param bbox: A 4-tuple (x0, y0, x1, y1) which specifies two points in the
+ input image's coordinate system. See :ref:`coordinate-system`.
+ """
+
+ method = Image.EXTENT
+
+
+class QuadTransform(Transform):
+ """
+ Define a quad image transform.
+
+ Maps a quadrilateral (a region defined by four corners) from the image to a
+ rectangle of the given size.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param xy: An 8-tuple (x0, y0, x1, y1, x2, y2, x3, y3) which contain the
+ upper left, lower left, lower right, and upper right corner of the
+ source quadrilateral.
+ """
+
+ method = Image.QUAD
+
+
+class MeshTransform(Transform):
+ """
+ Define a mesh image transform. A mesh transform consists of one or more
+ individual quad transforms.
+
+ See :py:meth:`~PIL.Image.Image.transform`
+
+ :param data: A list of (bbox, quad) tuples.
+ """
+
+ method = Image.MESH
diff --git a/venv/Lib/site-packages/PIL/ImageWin.py b/venv/Lib/site-packages/PIL/ImageWin.py
new file mode 100644
index 0000000..ca9b14c
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImageWin.py
@@ -0,0 +1,230 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# a Windows DIB display interface
+#
+# History:
+# 1996-05-20 fl Created
+# 1996-09-20 fl Fixed subregion exposure
+# 1997-09-21 fl Added draw primitive (for tzPrint)
+# 2003-05-21 fl Added experimental Window/ImageWindow classes
+# 2003-09-05 fl Added fromstring/tostring methods
+#
+# Copyright (c) Secret Labs AB 1997-2003.
+# Copyright (c) Fredrik Lundh 1996-2003.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image
+
+
+class HDC:
+ """
+ Wraps an HDC integer. The resulting object can be passed to the
+ :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
+ methods.
+ """
+
+ def __init__(self, dc):
+ self.dc = dc
+
+ def __int__(self):
+ return self.dc
+
+
+class HWND:
+ """
+ Wraps an HWND integer. The resulting object can be passed to the
+ :py:meth:`~PIL.ImageWin.Dib.draw` and :py:meth:`~PIL.ImageWin.Dib.expose`
+ methods, instead of a DC.
+ """
+
+ def __init__(self, wnd):
+ self.wnd = wnd
+
+ def __int__(self):
+ return self.wnd
+
+
+class Dib:
+ """
+ A Windows bitmap with the given mode and size. The mode can be one of "1",
+ "L", "P", or "RGB".
+
+ If the display requires a palette, this constructor creates a suitable
+ palette and associates it with the image. For an "L" image, 128 greylevels
+ are allocated. For an "RGB" image, a 6x6x6 colour cube is used, together
+ with 20 greylevels.
+
+ To make sure that palettes work properly under Windows, you must call the
+ ``palette`` method upon certain events from Windows.
+
+ :param image: Either a PIL image, or a mode string. If a mode string is
+ used, a size must also be given. The mode can be one of "1",
+ "L", "P", or "RGB".
+ :param size: If the first argument is a mode string, this
+ defines the size of the image.
+ """
+
+ def __init__(self, image, size=None):
+ if hasattr(image, "mode") and hasattr(image, "size"):
+ mode = image.mode
+ size = image.size
+ else:
+ mode = image
+ image = None
+ if mode not in ["1", "L", "P", "RGB"]:
+ mode = Image.getmodebase(mode)
+ self.image = Image.core.display(mode, size)
+ self.mode = mode
+ self.size = size
+ if image:
+ self.paste(image)
+
+ def expose(self, handle):
+ """
+ Copy the bitmap contents to a device context.
+
+ :param handle: Device context (HDC), cast to a Python integer, or an
+ HDC or HWND instance. In PythonWin, you can use
+ ``CDC.GetHandleAttrib()`` to get a suitable handle.
+ """
+ if isinstance(handle, HWND):
+ dc = self.image.getdc(handle)
+ try:
+ result = self.image.expose(dc)
+ finally:
+ self.image.releasedc(handle, dc)
+ else:
+ result = self.image.expose(handle)
+ return result
+
+ def draw(self, handle, dst, src=None):
+ """
+ Same as expose, but allows you to specify where to draw the image, and
+ what part of it to draw.
+
+ The destination and source areas are given as 4-tuple rectangles. If
+ the source is omitted, the entire image is copied. If the source and
+ the destination have different sizes, the image is resized as
+ necessary.
+ """
+ if not src:
+ src = (0, 0) + self.size
+ if isinstance(handle, HWND):
+ dc = self.image.getdc(handle)
+ try:
+ result = self.image.draw(dc, dst, src)
+ finally:
+ self.image.releasedc(handle, dc)
+ else:
+ result = self.image.draw(handle, dst, src)
+ return result
+
+ def query_palette(self, handle):
+ """
+ Installs the palette associated with the image in the given device
+ context.
+
+ This method should be called upon **QUERYNEWPALETTE** and
+ **PALETTECHANGED** events from Windows. If this method returns a
+ non-zero value, one or more display palette entries were changed, and
+ the image should be redrawn.
+
+ :param handle: Device context (HDC), cast to a Python integer, or an
+ HDC or HWND instance.
+ :return: A true value if one or more entries were changed (this
+ indicates that the image should be redrawn).
+ """
+ if isinstance(handle, HWND):
+ handle = self.image.getdc(handle)
+ try:
+ result = self.image.query_palette(handle)
+ finally:
+ self.image.releasedc(handle, handle)
+ else:
+ result = self.image.query_palette(handle)
+ return result
+
+ def paste(self, im, box=None):
+ """
+ Paste a PIL image into the bitmap image.
+
+ :param im: A PIL image. The size must match the target region.
+ If the mode does not match, the image is converted to the
+ mode of the bitmap image.
+ :param box: A 4-tuple defining the left, upper, right, and
+ lower pixel coordinate. See :ref:`coordinate-system`. If
+ None is given instead of a tuple, all of the image is
+ assumed.
+ """
+ im.load()
+ if self.mode != im.mode:
+ im = im.convert(self.mode)
+ if box:
+ self.image.paste(im.im, box)
+ else:
+ self.image.paste(im.im)
+
+ def frombytes(self, buffer):
+ """
+ Load display memory contents from byte data.
+
+ :param buffer: A buffer containing display data (usually
+ data returned from :py:func:`~PIL.ImageWin.Dib.tobytes`)
+ """
+ return self.image.frombytes(buffer)
+
+ def tobytes(self):
+ """
+ Copy display memory contents to bytes object.
+
+ :return: A bytes object containing display data.
+ """
+ return self.image.tobytes()
+
+
+class Window:
+ """Create a Window with the given title size."""
+
+ def __init__(self, title="PIL", width=None, height=None):
+ self.hwnd = Image.core.createwindow(
+ title, self.__dispatcher, width or 0, height or 0
+ )
+
+ def __dispatcher(self, action, *args):
+ return getattr(self, "ui_handle_" + action)(*args)
+
+ def ui_handle_clear(self, dc, x0, y0, x1, y1):
+ pass
+
+ def ui_handle_damage(self, x0, y0, x1, y1):
+ pass
+
+ def ui_handle_destroy(self):
+ pass
+
+ def ui_handle_repair(self, dc, x0, y0, x1, y1):
+ pass
+
+ def ui_handle_resize(self, width, height):
+ pass
+
+ def mainloop(self):
+ Image.core.eventloop()
+
+
+class ImageWindow(Window):
+ """Create an image window which displays the given image."""
+
+ def __init__(self, image, title="PIL"):
+ if not isinstance(image, Dib):
+ image = Dib(image)
+ self.image = image
+ width, height = image.size
+ super().__init__(title, width=width, height=height)
+
+ def ui_handle_repair(self, dc, x0, y0, x1, y1):
+ self.image.draw(dc, (x0, y0, x1, y1))
diff --git a/venv/Lib/site-packages/PIL/ImtImagePlugin.py b/venv/Lib/site-packages/PIL/ImtImagePlugin.py
new file mode 100644
index 0000000..21ffd74
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/ImtImagePlugin.py
@@ -0,0 +1,93 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# IM Tools support for PIL
+#
+# history:
+# 1996-05-27 fl Created (read 8-bit images only)
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.2)
+#
+# Copyright (c) Secret Labs AB 1997-2001.
+# Copyright (c) Fredrik Lundh 1996-2001.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import re
+
+from . import Image, ImageFile
+
+#
+# --------------------------------------------------------------------
+
+field = re.compile(br"([a-z]*) ([^ \r\n]*)")
+
+
+##
+# Image plugin for IM Tools images.
+
+
+class ImtImageFile(ImageFile.ImageFile):
+
+ format = "IMT"
+ format_description = "IM Tools"
+
+ def _open(self):
+
+ # Quick rejection: if there's not a LF among the first
+ # 100 bytes, this is (probably) not a text header.
+
+ if b"\n" not in self.fp.read(100):
+ raise SyntaxError("not an IM file")
+ self.fp.seek(0)
+
+ xsize = ysize = 0
+
+ while True:
+
+ s = self.fp.read(1)
+ if not s:
+ break
+
+ if s == b"\x0C":
+
+ # image data begins
+ self.tile = [
+ ("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1))
+ ]
+
+ break
+
+ else:
+
+ # read key/value pair
+ # FIXME: dangerous, may read whole file
+ s = s + self.fp.readline()
+ if len(s) == 1 or len(s) > 100:
+ break
+ if s[0] == ord(b"*"):
+ continue # comment
+
+ m = field.match(s)
+ if not m:
+ break
+ k, v = m.group(1, 2)
+ if k == "width":
+ xsize = int(v)
+ self._size = xsize, ysize
+ elif k == "height":
+ ysize = int(v)
+ self._size = xsize, ysize
+ elif k == "pixel" and v == "n8":
+ self.mode = "L"
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(ImtImageFile.format, ImtImageFile)
+
+#
+# no extension registered (".im" is simply too common)
diff --git a/venv/Lib/site-packages/PIL/IptcImagePlugin.py b/venv/Lib/site-packages/PIL/IptcImagePlugin.py
new file mode 100644
index 0000000..0bbe506
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/IptcImagePlugin.py
@@ -0,0 +1,230 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# IPTC/NAA file handling
+#
+# history:
+# 1995-10-01 fl Created
+# 1998-03-09 fl Cleaned up and added to PIL
+# 2002-06-18 fl Added getiptcinfo helper
+#
+# Copyright (c) Secret Labs AB 1997-2002.
+# Copyright (c) Fredrik Lundh 1995.
+#
+# See the README file for information on usage and redistribution.
+#
+import os
+import tempfile
+
+from . import Image, ImageFile
+from ._binary import i8
+from ._binary import i16be as i16
+from ._binary import i32be as i32
+from ._binary import o8
+
+COMPRESSION = {1: "raw", 5: "jpeg"}
+
+PAD = o8(0) * 4
+
+
+#
+# Helpers
+
+
+def i(c):
+ return i32((PAD + c)[-4:])
+
+
+def dump(c):
+ for i in c:
+ print("%02x" % i8(i), end=" ")
+ print()
+
+
+##
+# Image plugin for IPTC/NAA datastreams. To read IPTC/NAA fields
+# from TIFF and JPEG files, use the getiptcinfo function.
+
+
+class IptcImageFile(ImageFile.ImageFile):
+
+ format = "IPTC"
+ format_description = "IPTC/NAA"
+
+ def getint(self, key):
+ return i(self.info[key])
+
+ def field(self):
+ #
+ # get a IPTC field header
+ s = self.fp.read(5)
+ if not len(s):
+ return None, 0
+
+ tag = s[1], s[2]
+
+ # syntax
+ if s[0] != 0x1C or tag[0] < 1 or tag[0] > 9:
+ raise SyntaxError("invalid IPTC/NAA file")
+
+ # field size
+ size = s[3]
+ if size > 132:
+ raise OSError("illegal field length in IPTC/NAA file")
+ elif size == 128:
+ size = 0
+ elif size > 128:
+ size = i(self.fp.read(size - 128))
+ else:
+ size = i16(s, 3)
+
+ return tag, size
+
+ def _open(self):
+
+ # load descriptive fields
+ while True:
+ offset = self.fp.tell()
+ tag, size = self.field()
+ if not tag or tag == (8, 10):
+ break
+ if size:
+ tagdata = self.fp.read(size)
+ else:
+ tagdata = None
+ if tag in self.info:
+ if isinstance(self.info[tag], list):
+ self.info[tag].append(tagdata)
+ else:
+ self.info[tag] = [self.info[tag], tagdata]
+ else:
+ self.info[tag] = tagdata
+
+ # mode
+ layers = i8(self.info[(3, 60)][0])
+ component = i8(self.info[(3, 60)][1])
+ if (3, 65) in self.info:
+ id = i8(self.info[(3, 65)][0]) - 1
+ else:
+ id = 0
+ if layers == 1 and not component:
+ self.mode = "L"
+ elif layers == 3 and component:
+ self.mode = "RGB"[id]
+ elif layers == 4 and component:
+ self.mode = "CMYK"[id]
+
+ # size
+ self._size = self.getint((3, 20)), self.getint((3, 30))
+
+ # compression
+ try:
+ compression = COMPRESSION[self.getint((3, 120))]
+ except KeyError as e:
+ raise OSError("Unknown IPTC image compression") from e
+
+ # tile
+ if tag == (8, 10):
+ self.tile = [
+ ("iptc", (compression, offset), (0, 0, self.size[0], self.size[1]))
+ ]
+
+ def load(self):
+
+ if len(self.tile) != 1 or self.tile[0][0] != "iptc":
+ return ImageFile.ImageFile.load(self)
+
+ type, tile, box = self.tile[0]
+
+ encoding, offset = tile
+
+ self.fp.seek(offset)
+
+ # Copy image data to temporary file
+ o_fd, outfile = tempfile.mkstemp(text=False)
+ o = os.fdopen(o_fd)
+ if encoding == "raw":
+ # To simplify access to the extracted file,
+ # prepend a PPM header
+ o.write("P5\n%d %d\n255\n" % self.size)
+ while True:
+ type, size = self.field()
+ if type != (8, 10):
+ break
+ while size > 0:
+ s = self.fp.read(min(size, 8192))
+ if not s:
+ break
+ o.write(s)
+ size -= len(s)
+ o.close()
+
+ try:
+ with Image.open(outfile) as _im:
+ _im.load()
+ self.im = _im.im
+ finally:
+ try:
+ os.unlink(outfile)
+ except OSError:
+ pass
+
+
+Image.register_open(IptcImageFile.format, IptcImageFile)
+
+Image.register_extension(IptcImageFile.format, ".iim")
+
+
+def getiptcinfo(im):
+ """
+ Get IPTC information from TIFF, JPEG, or IPTC file.
+
+ :param im: An image containing IPTC data.
+ :returns: A dictionary containing IPTC information, or None if
+ no IPTC information block was found.
+ """
+ import io
+
+ from . import JpegImagePlugin, TiffImagePlugin
+
+ data = None
+
+ if isinstance(im, IptcImageFile):
+ # return info dictionary right away
+ return im.info
+
+ elif isinstance(im, JpegImagePlugin.JpegImageFile):
+ # extract the IPTC/NAA resource
+ photoshop = im.info.get("photoshop")
+ if photoshop:
+ data = photoshop.get(0x0404)
+
+ elif isinstance(im, TiffImagePlugin.TiffImageFile):
+ # get raw data from the IPTC/NAA tag (PhotoShop tags the data
+ # as 4-byte integers, so we cannot use the get method...)
+ try:
+ data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
+ except (AttributeError, KeyError):
+ pass
+
+ if data is None:
+ return None # no properties
+
+ # create an IptcImagePlugin object without initializing it
+ class FakeImage:
+ pass
+
+ im = FakeImage()
+ im.__class__ = IptcImageFile
+
+ # parse the IPTC information chunk
+ im.info = {}
+ im.fp = io.BytesIO(data)
+
+ try:
+ im._open()
+ except (IndexError, KeyError):
+ pass # expected failure
+
+ return im.info
diff --git a/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py b/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py
new file mode 100644
index 0000000..0b0d433
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/Jpeg2KImagePlugin.py
@@ -0,0 +1,314 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# JPEG2000 file handling
+#
+# History:
+# 2014-03-12 ajh Created
+#
+# Copyright (c) 2014 Coriolis Systems Limited
+# Copyright (c) 2014 Alastair Houghton
+#
+# See the README file for information on usage and redistribution.
+#
+import io
+import os
+import struct
+
+from . import Image, ImageFile
+
+
+def _parse_codestream(fp):
+ """Parse the JPEG 2000 codestream to extract the size and component
+ count from the SIZ marker segment, returning a PIL (size, mode) tuple."""
+
+ hdr = fp.read(2)
+ lsiz = struct.unpack(">H", hdr)[0]
+ siz = hdr + fp.read(lsiz - 2)
+ lsiz, rsiz, xsiz, ysiz, xosiz, yosiz, _, _, _, _, csiz = struct.unpack_from(
+ ">HHIIIIIIIIH", siz
+ )
+ ssiz = [None] * csiz
+ xrsiz = [None] * csiz
+ yrsiz = [None] * csiz
+ for i in range(csiz):
+ ssiz[i], xrsiz[i], yrsiz[i] = struct.unpack_from(">BBB", siz, 36 + 3 * i)
+
+ size = (xsiz - xosiz, ysiz - yosiz)
+ if csiz == 1:
+ if (yrsiz[0] & 0x7F) > 8:
+ mode = "I;16"
+ else:
+ mode = "L"
+ elif csiz == 2:
+ mode = "LA"
+ elif csiz == 3:
+ mode = "RGB"
+ elif csiz == 4:
+ mode = "RGBA"
+ else:
+ mode = None
+
+ return (size, mode)
+
+
+def _parse_jp2_header(fp):
+ """Parse the JP2 header box to extract size, component count and
+ color space information, returning a (size, mode, mimetype) tuple."""
+
+ # Find the JP2 header box
+ header = None
+ mimetype = None
+ while True:
+ lbox, tbox = struct.unpack(">I4s", fp.read(8))
+ if lbox == 1:
+ lbox = struct.unpack(">Q", fp.read(8))[0]
+ hlen = 16
+ else:
+ hlen = 8
+
+ if lbox < hlen:
+ raise SyntaxError("Invalid JP2 header length")
+
+ if tbox == b"jp2h":
+ header = fp.read(lbox - hlen)
+ break
+ elif tbox == b"ftyp":
+ if fp.read(4) == b"jpx ":
+ mimetype = "image/jpx"
+ fp.seek(lbox - hlen - 4, os.SEEK_CUR)
+ else:
+ fp.seek(lbox - hlen, os.SEEK_CUR)
+
+ if header is None:
+ raise SyntaxError("could not find JP2 header")
+
+ size = None
+ mode = None
+ bpc = None
+ nc = None
+
+ hio = io.BytesIO(header)
+ while True:
+ lbox, tbox = struct.unpack(">I4s", hio.read(8))
+ if lbox == 1:
+ lbox = struct.unpack(">Q", hio.read(8))[0]
+ hlen = 16
+ else:
+ hlen = 8
+
+ content = hio.read(lbox - hlen)
+
+ if tbox == b"ihdr":
+ height, width, nc, bpc, c, unkc, ipr = struct.unpack(">IIHBBBB", content)
+ size = (width, height)
+ if unkc:
+ if nc == 1 and (bpc & 0x7F) > 8:
+ mode = "I;16"
+ elif nc == 1:
+ mode = "L"
+ elif nc == 2:
+ mode = "LA"
+ elif nc == 3:
+ mode = "RGB"
+ elif nc == 4:
+ mode = "RGBA"
+ break
+ elif tbox == b"colr":
+ meth, prec, approx = struct.unpack_from(">BBB", content)
+ if meth == 1:
+ cs = struct.unpack_from(">I", content, 3)[0]
+ if cs == 16: # sRGB
+ if nc == 1 and (bpc & 0x7F) > 8:
+ mode = "I;16"
+ elif nc == 1:
+ mode = "L"
+ elif nc == 3:
+ mode = "RGB"
+ elif nc == 4:
+ mode = "RGBA"
+ break
+ elif cs == 17: # grayscale
+ if nc == 1 and (bpc & 0x7F) > 8:
+ mode = "I;16"
+ elif nc == 1:
+ mode = "L"
+ elif nc == 2:
+ mode = "LA"
+ break
+ elif cs == 18: # sYCC
+ if nc == 3:
+ mode = "RGB"
+ elif nc == 4:
+ mode = "RGBA"
+ break
+
+ if size is None or mode is None:
+ raise SyntaxError("Malformed jp2 header")
+
+ return (size, mode, mimetype)
+
+
+##
+# Image plugin for JPEG2000 images.
+
+
+class Jpeg2KImageFile(ImageFile.ImageFile):
+ format = "JPEG2000"
+ format_description = "JPEG 2000 (ISO 15444)"
+
+ def _open(self):
+ sig = self.fp.read(4)
+ if sig == b"\xff\x4f\xff\x51":
+ self.codec = "j2k"
+ self._size, self.mode = _parse_codestream(self.fp)
+ else:
+ sig = sig + self.fp.read(8)
+
+ if sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a":
+ self.codec = "jp2"
+ header = _parse_jp2_header(self.fp)
+ self._size, self.mode, self.custom_mimetype = header
+ else:
+ raise SyntaxError("not a JPEG 2000 file")
+
+ if self.size is None or self.mode is None:
+ raise SyntaxError("unable to determine size/mode")
+
+ self._reduce = 0
+ self.layers = 0
+
+ fd = -1
+ length = -1
+
+ try:
+ fd = self.fp.fileno()
+ length = os.fstat(fd).st_size
+ except Exception:
+ fd = -1
+ try:
+ pos = self.fp.tell()
+ self.fp.seek(0, io.SEEK_END)
+ length = self.fp.tell()
+ self.fp.seek(pos)
+ except Exception:
+ length = -1
+
+ self.tile = [
+ (
+ "jpeg2k",
+ (0, 0) + self.size,
+ 0,
+ (self.codec, self._reduce, self.layers, fd, length),
+ )
+ ]
+
+ @property
+ def reduce(self):
+ # https://github.com/python-pillow/Pillow/issues/4343 found that the
+ # new Image 'reduce' method was shadowed by this plugin's 'reduce'
+ # property. This attempts to allow for both scenarios
+ return self._reduce or super().reduce
+
+ @reduce.setter
+ def reduce(self, value):
+ self._reduce = value
+
+ def load(self):
+ if self.tile and self._reduce:
+ power = 1 << self._reduce
+ adjust = power >> 1
+ self._size = (
+ int((self.size[0] + adjust) / power),
+ int((self.size[1] + adjust) / power),
+ )
+
+ # Update the reduce and layers settings
+ t = self.tile[0]
+ t3 = (t[3][0], self._reduce, self.layers, t[3][3], t[3][4])
+ self.tile = [(t[0], (0, 0) + self.size, t[2], t3)]
+
+ return ImageFile.ImageFile.load(self)
+
+
+def _accept(prefix):
+ return (
+ prefix[:4] == b"\xff\x4f\xff\x51"
+ or prefix[:12] == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a"
+ )
+
+
+# ------------------------------------------------------------
+# Save support
+
+
+def _save(im, fp, filename):
+ if filename.endswith(".j2k"):
+ kind = "j2k"
+ else:
+ kind = "jp2"
+
+ # Get the keyword arguments
+ info = im.encoderinfo
+
+ offset = info.get("offset", None)
+ tile_offset = info.get("tile_offset", None)
+ tile_size = info.get("tile_size", None)
+ quality_mode = info.get("quality_mode", "rates")
+ quality_layers = info.get("quality_layers", None)
+ if quality_layers is not None and not (
+ isinstance(quality_layers, (list, tuple))
+ and all(
+ [
+ isinstance(quality_layer, (int, float))
+ for quality_layer in quality_layers
+ ]
+ )
+ ):
+ raise ValueError("quality_layers must be a sequence of numbers")
+
+ num_resolutions = info.get("num_resolutions", 0)
+ cblk_size = info.get("codeblock_size", None)
+ precinct_size = info.get("precinct_size", None)
+ irreversible = info.get("irreversible", False)
+ progression = info.get("progression", "LRCP")
+ cinema_mode = info.get("cinema_mode", "no")
+ fd = -1
+
+ if hasattr(fp, "fileno"):
+ try:
+ fd = fp.fileno()
+ except Exception:
+ fd = -1
+
+ im.encoderconfig = (
+ offset,
+ tile_offset,
+ tile_size,
+ quality_mode,
+ quality_layers,
+ num_resolutions,
+ cblk_size,
+ precinct_size,
+ irreversible,
+ progression,
+ cinema_mode,
+ fd,
+ )
+
+ ImageFile._save(im, fp, [("jpeg2k", (0, 0) + im.size, 0, kind)])
+
+
+# ------------------------------------------------------------
+# Registry stuff
+
+
+Image.register_open(Jpeg2KImageFile.format, Jpeg2KImageFile, _accept)
+Image.register_save(Jpeg2KImageFile.format, _save)
+
+Image.register_extensions(
+ Jpeg2KImageFile.format, [".jp2", ".j2k", ".jpc", ".jpf", ".jpx", ".j2c"]
+)
+
+Image.register_mime(Jpeg2KImageFile.format, "image/jp2")
diff --git a/venv/Lib/site-packages/PIL/JpegImagePlugin.py b/venv/Lib/site-packages/PIL/JpegImagePlugin.py
new file mode 100644
index 0000000..054495e
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/JpegImagePlugin.py
@@ -0,0 +1,805 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# JPEG (JFIF) file handling
+#
+# See "Digital Compression and Coding of Continuous-Tone Still Images,
+# Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
+#
+# History:
+# 1995-09-09 fl Created
+# 1995-09-13 fl Added full parser
+# 1996-03-25 fl Added hack to use the IJG command line utilities
+# 1996-05-05 fl Workaround Photoshop 2.5 CMYK polarity bug
+# 1996-05-28 fl Added draft support, JFIF version (0.1)
+# 1996-12-30 fl Added encoder options, added progression property (0.2)
+# 1997-08-27 fl Save mode 1 images as BW (0.3)
+# 1998-07-12 fl Added YCbCr to draft and save methods (0.4)
+# 1998-10-19 fl Don't hang on files using 16-bit DQT's (0.4.1)
+# 2001-04-16 fl Extract DPI settings from JFIF files (0.4.2)
+# 2002-07-01 fl Skip pad bytes before markers; identify Exif files (0.4.3)
+# 2003-04-25 fl Added experimental EXIF decoder (0.5)
+# 2003-06-06 fl Added experimental EXIF GPSinfo decoder
+# 2003-09-13 fl Extract COM markers
+# 2009-09-06 fl Added icc_profile support (from Florian Hoech)
+# 2009-03-06 fl Changed CMYK handling; always use Adobe polarity (0.6)
+# 2009-03-08 fl Added subsampling support (from Justin Huff).
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-1996 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+import array
+import io
+import os
+import struct
+import subprocess
+import sys
+import tempfile
+import warnings
+
+from . import Image, ImageFile, TiffImagePlugin
+from ._binary import i16be as i16
+from ._binary import i32be as i32
+from ._binary import o8
+from .JpegPresets import presets
+
+#
+# Parser
+
+
+def Skip(self, marker):
+ n = i16(self.fp.read(2)) - 2
+ ImageFile._safe_read(self.fp, n)
+
+
+def APP(self, marker):
+ #
+ # Application marker. Store these in the APP dictionary.
+ # Also look for well-known application markers.
+
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+
+ app = "APP%d" % (marker & 15)
+
+ self.app[app] = s # compatibility
+ self.applist.append((app, s))
+
+ if marker == 0xFFE0 and s[:4] == b"JFIF":
+ # extract JFIF information
+ self.info["jfif"] = version = i16(s, 5) # version
+ self.info["jfif_version"] = divmod(version, 256)
+ # extract JFIF properties
+ try:
+ jfif_unit = s[7]
+ jfif_density = i16(s, 8), i16(s, 10)
+ except Exception:
+ pass
+ else:
+ if jfif_unit == 1:
+ self.info["dpi"] = jfif_density
+ self.info["jfif_unit"] = jfif_unit
+ self.info["jfif_density"] = jfif_density
+ elif marker == 0xFFE1 and s[:5] == b"Exif\0":
+ if "exif" not in self.info:
+ # extract EXIF information (incomplete)
+ self.info["exif"] = s # FIXME: value will change
+ elif marker == 0xFFE2 and s[:5] == b"FPXR\0":
+ # extract FlashPix information (incomplete)
+ self.info["flashpix"] = s # FIXME: value will change
+ elif marker == 0xFFE2 and s[:12] == b"ICC_PROFILE\0":
+ # Since an ICC profile can be larger than the maximum size of
+ # a JPEG marker (64K), we need provisions to split it into
+ # multiple markers. The format defined by the ICC specifies
+ # one or more APP2 markers containing the following data:
+ # Identifying string ASCII "ICC_PROFILE\0" (12 bytes)
+ # Marker sequence number 1, 2, etc (1 byte)
+ # Number of markers Total of APP2's used (1 byte)
+ # Profile data (remainder of APP2 data)
+ # Decoders should use the marker sequence numbers to
+ # reassemble the profile, rather than assuming that the APP2
+ # markers appear in the correct sequence.
+ self.icclist.append(s)
+ elif marker == 0xFFED and s[:14] == b"Photoshop 3.0\x00":
+ # parse the image resource block
+ offset = 14
+ photoshop = self.info.setdefault("photoshop", {})
+ while s[offset : offset + 4] == b"8BIM":
+ try:
+ offset += 4
+ # resource code
+ code = i16(s, offset)
+ offset += 2
+ # resource name (usually empty)
+ name_len = s[offset]
+ # name = s[offset+1:offset+1+name_len]
+ offset += 1 + name_len
+ offset += offset & 1 # align
+ # resource data block
+ size = i32(s, offset)
+ offset += 4
+ data = s[offset : offset + size]
+ if code == 0x03ED: # ResolutionInfo
+ data = {
+ "XResolution": i32(data, 0) / 65536,
+ "DisplayedUnitsX": i16(data, 4),
+ "YResolution": i32(data, 8) / 65536,
+ "DisplayedUnitsY": i16(data, 12),
+ }
+ photoshop[code] = data
+ offset += size
+ offset += offset & 1 # align
+ except struct.error:
+ break # insufficient data
+
+ elif marker == 0xFFEE and s[:5] == b"Adobe":
+ self.info["adobe"] = i16(s, 5)
+ # extract Adobe custom properties
+ try:
+ adobe_transform = s[1]
+ except Exception:
+ pass
+ else:
+ self.info["adobe_transform"] = adobe_transform
+ elif marker == 0xFFE2 and s[:4] == b"MPF\0":
+ # extract MPO information
+ self.info["mp"] = s[4:]
+ # offset is current location minus buffer size
+ # plus constant header size
+ self.info["mpoffset"] = self.fp.tell() - n + 4
+
+ # If DPI isn't in JPEG header, fetch from EXIF
+ if "dpi" not in self.info and "exif" in self.info:
+ try:
+ exif = self.getexif()
+ resolution_unit = exif[0x0128]
+ x_resolution = exif[0x011A]
+ try:
+ dpi = float(x_resolution[0]) / x_resolution[1]
+ except TypeError:
+ dpi = x_resolution
+ if resolution_unit == 3: # cm
+ # 1 dpcm = 2.54 dpi
+ dpi *= 2.54
+ self.info["dpi"] = int(dpi + 0.5), int(dpi + 0.5)
+ except (KeyError, SyntaxError, ValueError, ZeroDivisionError):
+ # SyntaxError for invalid/unreadable EXIF
+ # KeyError for dpi not included
+ # ZeroDivisionError for invalid dpi rational value
+ # ValueError for x_resolution[0] being an invalid float
+ self.info["dpi"] = 72, 72
+
+
+def COM(self, marker):
+ #
+ # Comment marker. Store these in the APP dictionary.
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+
+ self.info["comment"] = s
+ self.app["COM"] = s # compatibility
+ self.applist.append(("COM", s))
+
+
+def SOF(self, marker):
+ #
+ # Start of frame marker. Defines the size and mode of the
+ # image. JPEG is colour blind, so we use some simple
+ # heuristics to map the number of layers to an appropriate
+ # mode. Note that this could be made a bit brighter, by
+ # looking for JFIF and Adobe APP markers.
+
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+ self._size = i16(s, 3), i16(s, 1)
+
+ self.bits = s[0]
+ if self.bits != 8:
+ raise SyntaxError(f"cannot handle {self.bits}-bit layers")
+
+ self.layers = s[5]
+ if self.layers == 1:
+ self.mode = "L"
+ elif self.layers == 3:
+ self.mode = "RGB"
+ elif self.layers == 4:
+ self.mode = "CMYK"
+ else:
+ raise SyntaxError(f"cannot handle {self.layers}-layer images")
+
+ if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
+ self.info["progressive"] = self.info["progression"] = 1
+
+ if self.icclist:
+ # fixup icc profile
+ self.icclist.sort() # sort by sequence number
+ if self.icclist[0][13] == len(self.icclist):
+ profile = []
+ for p in self.icclist:
+ profile.append(p[14:])
+ icc_profile = b"".join(profile)
+ else:
+ icc_profile = None # wrong number of fragments
+ self.info["icc_profile"] = icc_profile
+ self.icclist = []
+
+ for i in range(6, len(s), 3):
+ t = s[i : i + 3]
+ # 4-tuples: id, vsamp, hsamp, qtable
+ self.layer.append((t[0], t[1] // 16, t[1] & 15, t[2]))
+
+
+def DQT(self, marker):
+ #
+ # Define quantization table. Note that there might be more
+ # than one table in each marker.
+
+ # FIXME: The quantization tables can be used to estimate the
+ # compression quality.
+
+ n = i16(self.fp.read(2)) - 2
+ s = ImageFile._safe_read(self.fp, n)
+ while len(s):
+ v = s[0]
+ precision = 1 if (v // 16 == 0) else 2 # in bytes
+ qt_length = 1 + precision * 64
+ if len(s) < qt_length:
+ raise SyntaxError("bad quantization table marker")
+ data = array.array("B" if precision == 1 else "H", s[1:qt_length])
+ if sys.byteorder == "little" and precision > 1:
+ data.byteswap() # the values are always big-endian
+ self.quantization[v & 15] = data
+ s = s[qt_length:]
+
+
+#
+# JPEG marker table
+
+MARKER = {
+ 0xFFC0: ("SOF0", "Baseline DCT", SOF),
+ 0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
+ 0xFFC2: ("SOF2", "Progressive DCT", SOF),
+ 0xFFC3: ("SOF3", "Spatial lossless", SOF),
+ 0xFFC4: ("DHT", "Define Huffman table", Skip),
+ 0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
+ 0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
+ 0xFFC7: ("SOF7", "Differential spatial", SOF),
+ 0xFFC8: ("JPG", "Extension", None),
+ 0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
+ 0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
+ 0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
+ 0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
+ 0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
+ 0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
+ 0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
+ 0xFFD0: ("RST0", "Restart 0", None),
+ 0xFFD1: ("RST1", "Restart 1", None),
+ 0xFFD2: ("RST2", "Restart 2", None),
+ 0xFFD3: ("RST3", "Restart 3", None),
+ 0xFFD4: ("RST4", "Restart 4", None),
+ 0xFFD5: ("RST5", "Restart 5", None),
+ 0xFFD6: ("RST6", "Restart 6", None),
+ 0xFFD7: ("RST7", "Restart 7", None),
+ 0xFFD8: ("SOI", "Start of image", None),
+ 0xFFD9: ("EOI", "End of image", None),
+ 0xFFDA: ("SOS", "Start of scan", Skip),
+ 0xFFDB: ("DQT", "Define quantization table", DQT),
+ 0xFFDC: ("DNL", "Define number of lines", Skip),
+ 0xFFDD: ("DRI", "Define restart interval", Skip),
+ 0xFFDE: ("DHP", "Define hierarchical progression", SOF),
+ 0xFFDF: ("EXP", "Expand reference component", Skip),
+ 0xFFE0: ("APP0", "Application segment 0", APP),
+ 0xFFE1: ("APP1", "Application segment 1", APP),
+ 0xFFE2: ("APP2", "Application segment 2", APP),
+ 0xFFE3: ("APP3", "Application segment 3", APP),
+ 0xFFE4: ("APP4", "Application segment 4", APP),
+ 0xFFE5: ("APP5", "Application segment 5", APP),
+ 0xFFE6: ("APP6", "Application segment 6", APP),
+ 0xFFE7: ("APP7", "Application segment 7", APP),
+ 0xFFE8: ("APP8", "Application segment 8", APP),
+ 0xFFE9: ("APP9", "Application segment 9", APP),
+ 0xFFEA: ("APP10", "Application segment 10", APP),
+ 0xFFEB: ("APP11", "Application segment 11", APP),
+ 0xFFEC: ("APP12", "Application segment 12", APP),
+ 0xFFED: ("APP13", "Application segment 13", APP),
+ 0xFFEE: ("APP14", "Application segment 14", APP),
+ 0xFFEF: ("APP15", "Application segment 15", APP),
+ 0xFFF0: ("JPG0", "Extension 0", None),
+ 0xFFF1: ("JPG1", "Extension 1", None),
+ 0xFFF2: ("JPG2", "Extension 2", None),
+ 0xFFF3: ("JPG3", "Extension 3", None),
+ 0xFFF4: ("JPG4", "Extension 4", None),
+ 0xFFF5: ("JPG5", "Extension 5", None),
+ 0xFFF6: ("JPG6", "Extension 6", None),
+ 0xFFF7: ("JPG7", "Extension 7", None),
+ 0xFFF8: ("JPG8", "Extension 8", None),
+ 0xFFF9: ("JPG9", "Extension 9", None),
+ 0xFFFA: ("JPG10", "Extension 10", None),
+ 0xFFFB: ("JPG11", "Extension 11", None),
+ 0xFFFC: ("JPG12", "Extension 12", None),
+ 0xFFFD: ("JPG13", "Extension 13", None),
+ 0xFFFE: ("COM", "Comment", COM),
+}
+
+
+def _accept(prefix):
+ # Magic number was taken from https://en.wikipedia.org/wiki/JPEG
+ return prefix[0:3] == b"\xFF\xD8\xFF"
+
+
+##
+# Image plugin for JPEG and JFIF images.
+
+
+class JpegImageFile(ImageFile.ImageFile):
+
+ format = "JPEG"
+ format_description = "JPEG (ISO 10918)"
+
+ def _open(self):
+
+ s = self.fp.read(3)
+
+ if not _accept(s):
+ raise SyntaxError("not a JPEG file")
+ s = b"\xFF"
+
+ # Create attributes
+ self.bits = self.layers = 0
+
+ # JPEG specifics (internal)
+ self.layer = []
+ self.huffman_dc = {}
+ self.huffman_ac = {}
+ self.quantization = {}
+ self.app = {} # compatibility
+ self.applist = []
+ self.icclist = []
+
+ while True:
+
+ i = s[0]
+ if i == 0xFF:
+ s = s + self.fp.read(1)
+ i = i16(s)
+ else:
+ # Skip non-0xFF junk
+ s = self.fp.read(1)
+ continue
+
+ if i in MARKER:
+ name, description, handler = MARKER[i]
+ if handler is not None:
+ handler(self, i)
+ if i == 0xFFDA: # start of scan
+ rawmode = self.mode
+ if self.mode == "CMYK":
+ rawmode = "CMYK;I" # assume adobe conventions
+ self.tile = [("jpeg", (0, 0) + self.size, 0, (rawmode, ""))]
+ # self.__offset = self.fp.tell()
+ break
+ s = self.fp.read(1)
+ elif i == 0 or i == 0xFFFF:
+ # padded marker or junk; move on
+ s = b"\xff"
+ elif i == 0xFF00: # Skip extraneous data (escaped 0xFF)
+ s = self.fp.read(1)
+ else:
+ raise SyntaxError("no marker found")
+
+ def load_read(self, read_bytes):
+ """
+ internal: read more image data
+ For premature EOF and LOAD_TRUNCATED_IMAGES adds EOI marker
+ so libjpeg can finish decoding
+ """
+ s = self.fp.read(read_bytes)
+
+ if not s and ImageFile.LOAD_TRUNCATED_IMAGES:
+ # Premature EOF.
+ # Pretend file is finished adding EOI marker
+ return b"\xFF\xD9"
+
+ return s
+
+ def draft(self, mode, size):
+
+ if len(self.tile) != 1:
+ return
+
+ # Protect from second call
+ if self.decoderconfig:
+ return
+
+ d, e, o, a = self.tile[0]
+ scale = 1
+ original_size = self.size
+
+ if a[0] == "RGB" and mode in ["L", "YCbCr"]:
+ self.mode = mode
+ a = mode, ""
+
+ if size:
+ scale = min(self.size[0] // size[0], self.size[1] // size[1])
+ for s in [8, 4, 2, 1]:
+ if scale >= s:
+ break
+ e = (
+ e[0],
+ e[1],
+ (e[2] - e[0] + s - 1) // s + e[0],
+ (e[3] - e[1] + s - 1) // s + e[1],
+ )
+ self._size = ((self.size[0] + s - 1) // s, (self.size[1] + s - 1) // s)
+ scale = s
+
+ self.tile = [(d, e, o, a)]
+ self.decoderconfig = (scale, 0)
+
+ box = (0, 0, original_size[0] / scale, original_size[1] / scale)
+ return (self.mode, box)
+
+ def load_djpeg(self):
+
+ # ALTERNATIVE: handle JPEGs via the IJG command line utilities
+
+ f, path = tempfile.mkstemp()
+ os.close(f)
+ if os.path.exists(self.filename):
+ subprocess.check_call(["djpeg", "-outfile", path, self.filename])
+ else:
+ raise ValueError("Invalid Filename")
+
+ try:
+ with Image.open(path) as _im:
+ _im.load()
+ self.im = _im.im
+ finally:
+ try:
+ os.unlink(path)
+ except OSError:
+ pass
+
+ self.mode = self.im.mode
+ self._size = self.im.size
+
+ self.tile = []
+
+ def _getexif(self):
+ return _getexif(self)
+
+ def _getmp(self):
+ return _getmp(self)
+
+
+def _getexif(self):
+ if "exif" not in self.info:
+ return None
+ return dict(self.getexif())
+
+
+def _getmp(self):
+ # Extract MP information. This method was inspired by the "highly
+ # experimental" _getexif version that's been in use for years now,
+ # itself based on the ImageFileDirectory class in the TIFF plugin.
+
+ # The MP record essentially consists of a TIFF file embedded in a JPEG
+ # application marker.
+ try:
+ data = self.info["mp"]
+ except KeyError:
+ return None
+ file_contents = io.BytesIO(data)
+ head = file_contents.read(8)
+ endianness = ">" if head[:4] == b"\x4d\x4d\x00\x2a" else "<"
+ # process dictionary
+ try:
+ info = TiffImagePlugin.ImageFileDirectory_v2(head)
+ file_contents.seek(info.next)
+ info.load(file_contents)
+ mp = dict(info)
+ except Exception as e:
+ raise SyntaxError("malformed MP Index (unreadable directory)") from e
+ # it's an error not to have a number of images
+ try:
+ quant = mp[0xB001]
+ except KeyError as e:
+ raise SyntaxError("malformed MP Index (no number of images)") from e
+ # get MP entries
+ mpentries = []
+ try:
+ rawmpentries = mp[0xB002]
+ for entrynum in range(0, quant):
+ unpackedentry = struct.unpack_from(
+ f"{endianness}LLLHH", rawmpentries, entrynum * 16
+ )
+ labels = ("Attribute", "Size", "DataOffset", "EntryNo1", "EntryNo2")
+ mpentry = dict(zip(labels, unpackedentry))
+ mpentryattr = {
+ "DependentParentImageFlag": bool(mpentry["Attribute"] & (1 << 31)),
+ "DependentChildImageFlag": bool(mpentry["Attribute"] & (1 << 30)),
+ "RepresentativeImageFlag": bool(mpentry["Attribute"] & (1 << 29)),
+ "Reserved": (mpentry["Attribute"] & (3 << 27)) >> 27,
+ "ImageDataFormat": (mpentry["Attribute"] & (7 << 24)) >> 24,
+ "MPType": mpentry["Attribute"] & 0x00FFFFFF,
+ }
+ if mpentryattr["ImageDataFormat"] == 0:
+ mpentryattr["ImageDataFormat"] = "JPEG"
+ else:
+ raise SyntaxError("unsupported picture format in MPO")
+ mptypemap = {
+ 0x000000: "Undefined",
+ 0x010001: "Large Thumbnail (VGA Equivalent)",
+ 0x010002: "Large Thumbnail (Full HD Equivalent)",
+ 0x020001: "Multi-Frame Image (Panorama)",
+ 0x020002: "Multi-Frame Image: (Disparity)",
+ 0x020003: "Multi-Frame Image: (Multi-Angle)",
+ 0x030000: "Baseline MP Primary Image",
+ }
+ mpentryattr["MPType"] = mptypemap.get(mpentryattr["MPType"], "Unknown")
+ mpentry["Attribute"] = mpentryattr
+ mpentries.append(mpentry)
+ mp[0xB002] = mpentries
+ except KeyError as e:
+ raise SyntaxError("malformed MP Index (bad MP Entry)") from e
+ # Next we should try and parse the individual image unique ID list;
+ # we don't because I've never seen this actually used in a real MPO
+ # file and so can't test it.
+ return mp
+
+
+# --------------------------------------------------------------------
+# stuff to save JPEG files
+
+RAWMODE = {
+ "1": "L",
+ "L": "L",
+ "RGB": "RGB",
+ "RGBX": "RGB",
+ "CMYK": "CMYK;I", # assume adobe conventions
+ "YCbCr": "YCbCr",
+}
+
+# fmt: off
+zigzag_index = (
+ 0, 1, 5, 6, 14, 15, 27, 28,
+ 2, 4, 7, 13, 16, 26, 29, 42,
+ 3, 8, 12, 17, 25, 30, 41, 43,
+ 9, 11, 18, 24, 31, 40, 44, 53,
+ 10, 19, 23, 32, 39, 45, 52, 54,
+ 20, 22, 33, 38, 46, 51, 55, 60,
+ 21, 34, 37, 47, 50, 56, 59, 61,
+ 35, 36, 48, 49, 57, 58, 62, 63,
+)
+
+samplings = {
+ (1, 1, 1, 1, 1, 1): 0,
+ (2, 1, 1, 1, 1, 1): 1,
+ (2, 2, 1, 1, 1, 1): 2,
+}
+# fmt: on
+
+
+def convert_dict_qtables(qtables):
+ qtables = [qtables[key] for key in range(len(qtables)) if key in qtables]
+ for idx, table in enumerate(qtables):
+ qtables[idx] = [table[i] for i in zigzag_index]
+ return qtables
+
+
+def get_sampling(im):
+ # There's no subsampling when images have only 1 layer
+ # (grayscale images) or when they are CMYK (4 layers),
+ # so set subsampling to the default value.
+ #
+ # NOTE: currently Pillow can't encode JPEG to YCCK format.
+ # If YCCK support is added in the future, subsampling code will have
+ # to be updated (here and in JpegEncode.c) to deal with 4 layers.
+ if not hasattr(im, "layers") or im.layers in (1, 4):
+ return -1
+ sampling = im.layer[0][1:3] + im.layer[1][1:3] + im.layer[2][1:3]
+ return samplings.get(sampling, -1)
+
+
+def _save(im, fp, filename):
+
+ try:
+ rawmode = RAWMODE[im.mode]
+ except KeyError as e:
+ raise OSError(f"cannot write mode {im.mode} as JPEG") from e
+
+ info = im.encoderinfo
+
+ dpi = [round(x) for x in info.get("dpi", (0, 0))]
+
+ quality = info.get("quality", -1)
+ subsampling = info.get("subsampling", -1)
+ qtables = info.get("qtables")
+
+ if quality == "keep":
+ quality = -1
+ subsampling = "keep"
+ qtables = "keep"
+ elif quality in presets:
+ preset = presets[quality]
+ quality = -1
+ subsampling = preset.get("subsampling", -1)
+ qtables = preset.get("quantization")
+ elif not isinstance(quality, int):
+ raise ValueError("Invalid quality setting")
+ else:
+ if subsampling in presets:
+ subsampling = presets[subsampling].get("subsampling", -1)
+ if isinstance(qtables, str) and qtables in presets:
+ qtables = presets[qtables].get("quantization")
+
+ if subsampling == "4:4:4":
+ subsampling = 0
+ elif subsampling == "4:2:2":
+ subsampling = 1
+ elif subsampling == "4:2:0":
+ subsampling = 2
+ elif subsampling == "4:1:1":
+ # For compatibility. Before Pillow 4.3, 4:1:1 actually meant 4:2:0.
+ # Set 4:2:0 if someone is still using that value.
+ subsampling = 2
+ elif subsampling == "keep":
+ if im.format != "JPEG":
+ raise ValueError("Cannot use 'keep' when original image is not a JPEG")
+ subsampling = get_sampling(im)
+
+ def validate_qtables(qtables):
+ if qtables is None:
+ return qtables
+ if isinstance(qtables, str):
+ try:
+ lines = [
+ int(num)
+ for line in qtables.splitlines()
+ for num in line.split("#", 1)[0].split()
+ ]
+ except ValueError as e:
+ raise ValueError("Invalid quantization table") from e
+ else:
+ qtables = [lines[s : s + 64] for s in range(0, len(lines), 64)]
+ if isinstance(qtables, (tuple, list, dict)):
+ if isinstance(qtables, dict):
+ qtables = convert_dict_qtables(qtables)
+ elif isinstance(qtables, tuple):
+ qtables = list(qtables)
+ if not (0 < len(qtables) < 5):
+ raise ValueError("None or too many quantization tables")
+ for idx, table in enumerate(qtables):
+ try:
+ if len(table) != 64:
+ raise TypeError
+ table = array.array("H", table)
+ except TypeError as e:
+ raise ValueError("Invalid quantization table") from e
+ else:
+ qtables[idx] = list(table)
+ return qtables
+
+ if qtables == "keep":
+ if im.format != "JPEG":
+ raise ValueError("Cannot use 'keep' when original image is not a JPEG")
+ qtables = getattr(im, "quantization", None)
+ qtables = validate_qtables(qtables)
+
+ extra = b""
+
+ icc_profile = info.get("icc_profile")
+ if icc_profile:
+ ICC_OVERHEAD_LEN = 14
+ MAX_BYTES_IN_MARKER = 65533
+ MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
+ markers = []
+ while icc_profile:
+ markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
+ icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
+ i = 1
+ for marker in markers:
+ size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
+ extra += (
+ b"\xFF\xE2"
+ + size
+ + b"ICC_PROFILE\0"
+ + o8(i)
+ + o8(len(markers))
+ + marker
+ )
+ i += 1
+
+ # "progressive" is the official name, but older documentation
+ # says "progression"
+ # FIXME: issue a warning if the wrong form is used (post-1.1.7)
+ progressive = info.get("progressive", False) or info.get("progression", False)
+
+ optimize = info.get("optimize", False)
+
+ exif = info.get("exif", b"")
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes()
+
+ # get keyword arguments
+ im.encoderconfig = (
+ quality,
+ progressive,
+ info.get("smooth", 0),
+ optimize,
+ info.get("streamtype", 0),
+ dpi[0],
+ dpi[1],
+ subsampling,
+ qtables,
+ extra,
+ exif,
+ )
+
+ # if we optimize, libjpeg needs a buffer big enough to hold the whole image
+ # in a shot. Guessing on the size, at im.size bytes. (raw pixel size is
+ # channels*size, this is a value that's been used in a django patch.
+ # https://github.com/matthewwithanm/django-imagekit/issues/50
+ bufsize = 0
+ if optimize or progressive:
+ # CMYK can be bigger
+ if im.mode == "CMYK":
+ bufsize = 4 * im.size[0] * im.size[1]
+ # keep sets quality to -1, but the actual value may be high.
+ elif quality >= 95 or quality == -1:
+ bufsize = 2 * im.size[0] * im.size[1]
+ else:
+ bufsize = im.size[0] * im.size[1]
+
+ # The EXIF info needs to be written as one block, + APP1, + one spare byte.
+ # Ensure that our buffer is big enough. Same with the icc_profile block.
+ bufsize = max(ImageFile.MAXBLOCK, bufsize, len(exif) + 5, len(extra) + 1)
+
+ ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
+
+
+def _save_cjpeg(im, fp, filename):
+ # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
+ tempfile = im._dump()
+ subprocess.check_call(["cjpeg", "-outfile", filename, tempfile])
+ try:
+ os.unlink(tempfile)
+ except OSError:
+ pass
+
+
+##
+# Factory for making JPEG and MPO instances
+def jpeg_factory(fp=None, filename=None):
+ im = JpegImageFile(fp, filename)
+ try:
+ mpheader = im._getmp()
+ if mpheader[45057] > 1:
+ # It's actually an MPO
+ from .MpoImagePlugin import MpoImageFile
+
+ # Don't reload everything, just convert it.
+ im = MpoImageFile.adopt(im, mpheader)
+ except (TypeError, IndexError):
+ # It is really a JPEG
+ pass
+ except SyntaxError:
+ warnings.warn(
+ "Image appears to be a malformed MPO file, it will be "
+ "interpreted as a base JPEG file"
+ )
+ return im
+
+
+# ---------------------------------------------------------------------
+# Registry stuff
+
+Image.register_open(JpegImageFile.format, jpeg_factory, _accept)
+Image.register_save(JpegImageFile.format, _save)
+
+Image.register_extensions(JpegImageFile.format, [".jfif", ".jpe", ".jpg", ".jpeg"])
+
+Image.register_mime(JpegImageFile.format, "image/jpeg")
diff --git a/venv/Lib/site-packages/PIL/JpegPresets.py b/venv/Lib/site-packages/PIL/JpegPresets.py
new file mode 100644
index 0000000..79d10eb
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/JpegPresets.py
@@ -0,0 +1,248 @@
+"""
+JPEG quality settings equivalent to the Photoshop settings.
+Can be used when saving JPEG files.
+
+The following presets are available by default:
+``web_low``, ``web_medium``, ``web_high``, ``web_very_high``, ``web_maximum``,
+``low``, ``medium``, ``high``, ``maximum``.
+More presets can be added to the :py:data:`presets` dict if needed.
+
+To apply the preset, specify::
+
+ quality="preset_name"
+
+To apply only the quantization table::
+
+ qtables="preset_name"
+
+To apply only the subsampling setting::
+
+ subsampling="preset_name"
+
+Example::
+
+ im.save("image_name.jpg", quality="web_high")
+
+Subsampling
+-----------
+
+Subsampling is the practice of encoding images by implementing less resolution
+for chroma information than for luma information.
+(ref.: https://en.wikipedia.org/wiki/Chroma_subsampling)
+
+Possible subsampling values are 0, 1 and 2 that correspond to 4:4:4, 4:2:2 and
+4:2:0.
+
+You can get the subsampling of a JPEG with the
+:func:`.JpegImagePlugin.get_sampling` function.
+
+In JPEG compressed data a JPEG marker is used instead of an EXIFÂ tag.
+(ref.: https://www.exiv2.org/tags.html)
+
+
+Quantization tables
+-------------------
+
+They are values use by the DCT (Discrete cosine transform) to remove
+*unnecessary* information from the image (the lossy part of the compression).
+(ref.: https://en.wikipedia.org/wiki/Quantization_matrix#Quantization_matrices,
+https://en.wikipedia.org/wiki/JPEG#Quantization)
+
+You can get the quantization tables of a JPEG with::
+
+ im.quantization
+
+This will return a dict with a number of arrays. You can pass this dict
+directly as the qtables argument when saving a JPEG.
+
+The tables format between im.quantization and quantization in presets differ in
+3 ways:
+
+1. The base container of the preset is a list with sublists instead of dict.
+ dict[0] -> list[0], dict[1] -> list[1], ...
+2. Each table in a preset is a list instead of an array.
+3. The zigzag order is remove in the preset (needed by libjpeg >= 6a).
+
+You can convert the dict format to the preset format with the
+:func:`.JpegImagePlugin.convert_dict_qtables()` function.
+
+Libjpeg ref.:
+https://web.archive.org/web/20120328125543/http://www.jpegcameras.com/libjpeg/libjpeg-3.html
+
+"""
+
+# fmt: off
+presets = {
+ 'web_low': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [20, 16, 25, 39, 50, 46, 62, 68,
+ 16, 18, 23, 38, 38, 53, 65, 68,
+ 25, 23, 31, 38, 53, 65, 68, 68,
+ 39, 38, 38, 53, 65, 68, 68, 68,
+ 50, 38, 53, 65, 68, 68, 68, 68,
+ 46, 53, 65, 68, 68, 68, 68, 68,
+ 62, 65, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68],
+ [21, 25, 32, 38, 54, 68, 68, 68,
+ 25, 28, 24, 38, 54, 68, 68, 68,
+ 32, 24, 32, 43, 66, 68, 68, 68,
+ 38, 38, 43, 53, 68, 68, 68, 68,
+ 54, 54, 66, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68]
+ ]},
+ 'web_medium': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [16, 11, 11, 16, 23, 27, 31, 30,
+ 11, 12, 12, 15, 20, 23, 23, 30,
+ 11, 12, 13, 16, 23, 26, 35, 47,
+ 16, 15, 16, 23, 26, 37, 47, 64,
+ 23, 20, 23, 26, 39, 51, 64, 64,
+ 27, 23, 26, 37, 51, 64, 64, 64,
+ 31, 23, 35, 47, 64, 64, 64, 64,
+ 30, 30, 47, 64, 64, 64, 64, 64],
+ [17, 15, 17, 21, 20, 26, 38, 48,
+ 15, 19, 18, 17, 20, 26, 35, 43,
+ 17, 18, 20, 22, 26, 30, 46, 53,
+ 21, 17, 22, 28, 30, 39, 53, 64,
+ 20, 20, 26, 30, 39, 48, 64, 64,
+ 26, 26, 30, 39, 48, 63, 64, 64,
+ 38, 35, 46, 53, 64, 64, 64, 64,
+ 48, 43, 53, 64, 64, 64, 64, 64]
+ ]},
+ 'web_high': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [6, 4, 4, 6, 9, 11, 12, 16,
+ 4, 5, 5, 6, 8, 10, 12, 12,
+ 4, 5, 5, 6, 10, 12, 14, 19,
+ 6, 6, 6, 11, 12, 15, 19, 28,
+ 9, 8, 10, 12, 16, 20, 27, 31,
+ 11, 10, 12, 15, 20, 27, 31, 31,
+ 12, 12, 14, 19, 27, 31, 31, 31,
+ 16, 12, 19, 28, 31, 31, 31, 31],
+ [7, 7, 13, 24, 26, 31, 31, 31,
+ 7, 12, 16, 21, 31, 31, 31, 31,
+ 13, 16, 17, 31, 31, 31, 31, 31,
+ 24, 21, 31, 31, 31, 31, 31, 31,
+ 26, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31,
+ 31, 31, 31, 31, 31, 31, 31, 31]
+ ]},
+ 'web_very_high': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 4, 5, 7, 9,
+ 2, 2, 2, 4, 5, 7, 9, 12,
+ 3, 3, 4, 5, 8, 10, 12, 12,
+ 4, 4, 5, 7, 10, 12, 12, 12,
+ 5, 5, 7, 9, 12, 12, 12, 12,
+ 6, 6, 9, 12, 12, 12, 12, 12],
+ [3, 3, 5, 9, 13, 15, 15, 15,
+ 3, 4, 6, 11, 14, 12, 12, 12,
+ 5, 6, 9, 14, 12, 12, 12, 12,
+ 9, 11, 14, 12, 12, 12, 12, 12,
+ 13, 14, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'web_maximum': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 1, 1, 1, 1, 1, 1, 2, 2,
+ 1, 1, 1, 1, 1, 2, 2, 3,
+ 1, 1, 1, 1, 2, 2, 3, 3,
+ 1, 1, 1, 2, 2, 3, 3, 3,
+ 1, 1, 2, 2, 3, 3, 3, 3],
+ [1, 1, 1, 2, 2, 3, 3, 3,
+ 1, 1, 1, 2, 3, 3, 3, 3,
+ 1, 1, 1, 3, 3, 3, 3, 3,
+ 2, 2, 3, 3, 3, 3, 3, 3,
+ 2, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3]
+ ]},
+ 'low': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [18, 14, 14, 21, 30, 35, 34, 17,
+ 14, 16, 16, 19, 26, 23, 12, 12,
+ 14, 16, 17, 21, 23, 12, 12, 12,
+ 21, 19, 21, 23, 12, 12, 12, 12,
+ 30, 26, 23, 12, 12, 12, 12, 12,
+ 35, 23, 12, 12, 12, 12, 12, 12,
+ 34, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12],
+ [20, 19, 22, 27, 20, 20, 17, 17,
+ 19, 25, 23, 14, 14, 12, 12, 12,
+ 22, 23, 14, 14, 12, 12, 12, 12,
+ 27, 14, 14, 12, 12, 12, 12, 12,
+ 20, 14, 12, 12, 12, 12, 12, 12,
+ 20, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'medium': {'subsampling': 2, # "4:2:0"
+ 'quantization': [
+ [12, 8, 8, 12, 17, 21, 24, 17,
+ 8, 9, 9, 11, 15, 19, 12, 12,
+ 8, 9, 10, 12, 19, 12, 12, 12,
+ 12, 11, 12, 21, 12, 12, 12, 12,
+ 17, 15, 19, 12, 12, 12, 12, 12,
+ 21, 19, 12, 12, 12, 12, 12, 12,
+ 24, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12],
+ [13, 11, 13, 16, 20, 20, 17, 17,
+ 11, 14, 14, 14, 14, 12, 12, 12,
+ 13, 14, 14, 14, 12, 12, 12, 12,
+ 16, 14, 14, 12, 12, 12, 12, 12,
+ 20, 14, 12, 12, 12, 12, 12, 12,
+ 20, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'high': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [6, 4, 4, 6, 9, 11, 12, 16,
+ 4, 5, 5, 6, 8, 10, 12, 12,
+ 4, 5, 5, 6, 10, 12, 12, 12,
+ 6, 6, 6, 11, 12, 12, 12, 12,
+ 9, 8, 10, 12, 12, 12, 12, 12,
+ 11, 10, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12,
+ 16, 12, 12, 12, 12, 12, 12, 12],
+ [7, 7, 13, 24, 20, 20, 17, 17,
+ 7, 12, 16, 14, 14, 12, 12, 12,
+ 13, 16, 14, 14, 12, 12, 12, 12,
+ 24, 14, 14, 12, 12, 12, 12, 12,
+ 20, 14, 12, 12, 12, 12, 12, 12,
+ 20, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12,
+ 17, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+ 'maximum': {'subsampling': 0, # "4:4:4"
+ 'quantization': [
+ [2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 3, 4, 5, 6,
+ 2, 2, 2, 2, 4, 5, 7, 9,
+ 2, 2, 2, 4, 5, 7, 9, 12,
+ 3, 3, 4, 5, 8, 10, 12, 12,
+ 4, 4, 5, 7, 10, 12, 12, 12,
+ 5, 5, 7, 9, 12, 12, 12, 12,
+ 6, 6, 9, 12, 12, 12, 12, 12],
+ [3, 3, 5, 9, 13, 15, 15, 15,
+ 3, 4, 6, 10, 14, 12, 12, 12,
+ 5, 6, 9, 14, 12, 12, 12, 12,
+ 9, 10, 14, 12, 12, 12, 12, 12,
+ 13, 14, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12,
+ 15, 12, 12, 12, 12, 12, 12, 12]
+ ]},
+}
+# fmt: on
diff --git a/venv/Lib/site-packages/PIL/McIdasImagePlugin.py b/venv/Lib/site-packages/PIL/McIdasImagePlugin.py
new file mode 100644
index 0000000..cd047fe
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/McIdasImagePlugin.py
@@ -0,0 +1,75 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Basic McIdas support for PIL
+#
+# History:
+# 1997-05-05 fl Created (8-bit images only)
+# 2009-03-08 fl Added 16/32-bit support.
+#
+# Thanks to Richard Jones and Craig Swank for specs and samples.
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import struct
+
+from . import Image, ImageFile
+
+
+def _accept(s):
+ return s[:8] == b"\x00\x00\x00\x00\x00\x00\x00\x04"
+
+
+##
+# Image plugin for McIdas area images.
+
+
+class McIdasImageFile(ImageFile.ImageFile):
+
+ format = "MCIDAS"
+ format_description = "McIdas area file"
+
+ def _open(self):
+
+ # parse area file directory
+ s = self.fp.read(256)
+ if not _accept(s) or len(s) != 256:
+ raise SyntaxError("not an McIdas area file")
+
+ self.area_descriptor_raw = s
+ self.area_descriptor = w = [0] + list(struct.unpack("!64i", s))
+
+ # get mode
+ if w[11] == 1:
+ mode = rawmode = "L"
+ elif w[11] == 2:
+ # FIXME: add memory map support
+ mode = "I"
+ rawmode = "I;16B"
+ elif w[11] == 4:
+ # FIXME: add memory map support
+ mode = "I"
+ rawmode = "I;32B"
+ else:
+ raise SyntaxError("unsupported McIdas format")
+
+ self.mode = mode
+ self._size = w[10], w[9]
+
+ offset = w[34] + w[15]
+ stride = w[15] + w[10] * w[11] * w[14]
+
+ self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride, 1))]
+
+
+# --------------------------------------------------------------------
+# registry
+
+Image.register_open(McIdasImageFile.format, McIdasImageFile, _accept)
+
+# no default extension
diff --git a/venv/Lib/site-packages/PIL/MicImagePlugin.py b/venv/Lib/site-packages/PIL/MicImagePlugin.py
new file mode 100644
index 0000000..2aed260
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/MicImagePlugin.py
@@ -0,0 +1,107 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Microsoft Image Composer support for PIL
+#
+# Notes:
+# uses TiffImagePlugin.py to read the actual image streams
+#
+# History:
+# 97-01-20 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import olefile
+
+from . import Image, TiffImagePlugin
+
+#
+# --------------------------------------------------------------------
+
+
+def _accept(prefix):
+ return prefix[:8] == olefile.MAGIC
+
+
+##
+# Image plugin for Microsoft's Image Composer file format.
+
+
+class MicImageFile(TiffImagePlugin.TiffImageFile):
+
+ format = "MIC"
+ format_description = "Microsoft Image Composer"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ # read the OLE directory and see if this is a likely
+ # to be a Microsoft Image Composer file
+
+ try:
+ self.ole = olefile.OleFileIO(self.fp)
+ except OSError as e:
+ raise SyntaxError("not an MIC file; invalid OLE file") from e
+
+ # find ACI subfiles with Image members (maybe not the
+ # best way to identify MIC files, but what the... ;-)
+
+ self.images = []
+ for path in self.ole.listdir():
+ if path[1:] and path[0][-4:] == ".ACI" and path[1] == "Image":
+ self.images.append(path)
+
+ # if we didn't find any images, this is probably not
+ # an MIC file.
+ if not self.images:
+ raise SyntaxError("not an MIC file; no image entries")
+
+ self.__fp = self.fp
+ self.frame = None
+ self._n_frames = len(self.images)
+ self.is_animated = self._n_frames > 1
+
+ if len(self.images) > 1:
+ self.category = Image.CONTAINER
+
+ self.seek(0)
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ try:
+ filename = self.images[frame]
+ except IndexError as e:
+ raise EOFError("no such frame") from e
+
+ self.fp = self.ole.openstream(filename)
+
+ TiffImagePlugin.TiffImageFile._open(self)
+
+ self.frame = frame
+
+ def tell(self):
+ return self.frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(MicImageFile.format, MicImageFile, _accept)
+
+Image.register_extension(MicImageFile.format, ".mic")
diff --git a/venv/Lib/site-packages/PIL/MpegImagePlugin.py b/venv/Lib/site-packages/PIL/MpegImagePlugin.py
new file mode 100644
index 0000000..a358dfd
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/MpegImagePlugin.py
@@ -0,0 +1,83 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# MPEG file handling
+#
+# History:
+# 95-09-09 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1995.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile
+from ._binary import i8
+
+#
+# Bitstream parser
+
+
+class BitStream:
+ def __init__(self, fp):
+ self.fp = fp
+ self.bits = 0
+ self.bitbuffer = 0
+
+ def next(self):
+ return i8(self.fp.read(1))
+
+ def peek(self, bits):
+ while self.bits < bits:
+ c = self.next()
+ if c < 0:
+ self.bits = 0
+ continue
+ self.bitbuffer = (self.bitbuffer << 8) + c
+ self.bits += 8
+ return self.bitbuffer >> (self.bits - bits) & (1 << bits) - 1
+
+ def skip(self, bits):
+ while self.bits < bits:
+ self.bitbuffer = (self.bitbuffer << 8) + i8(self.fp.read(1))
+ self.bits += 8
+ self.bits = self.bits - bits
+
+ def read(self, bits):
+ v = self.peek(bits)
+ self.bits = self.bits - bits
+ return v
+
+
+##
+# Image plugin for MPEG streams. This plugin can identify a stream,
+# but it cannot read it.
+
+
+class MpegImageFile(ImageFile.ImageFile):
+
+ format = "MPEG"
+ format_description = "MPEG"
+
+ def _open(self):
+
+ s = BitStream(self.fp)
+
+ if s.read(32) != 0x1B3:
+ raise SyntaxError("not an MPEG file")
+
+ self.mode = "RGB"
+ self._size = s.read(12), s.read(12)
+
+
+# --------------------------------------------------------------------
+# Registry stuff
+
+Image.register_open(MpegImageFile.format, MpegImageFile)
+
+Image.register_extensions(MpegImageFile.format, [".mpg", ".mpeg"])
+
+Image.register_mime(MpegImageFile.format, "video/mpeg")
diff --git a/venv/Lib/site-packages/PIL/MpoImagePlugin.py b/venv/Lib/site-packages/PIL/MpoImagePlugin.py
new file mode 100644
index 0000000..575cc9c
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/MpoImagePlugin.py
@@ -0,0 +1,134 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# MPO file handling
+#
+# See "Multi-Picture Format" (CIPA DC-007-Translation 2009, Standard of the
+# Camera & Imaging Products Association)
+#
+# The multi-picture object combines multiple JPEG images (with a modified EXIF
+# data format) into a single file. While it can theoretically be used much like
+# a GIF animation, it is commonly used to represent 3D photographs and is (as
+# of this writing) the most commonly used format by 3D cameras.
+#
+# History:
+# 2014-03-13 Feneric Created
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile, JpegImagePlugin
+from ._binary import i16be as i16
+
+
+def _accept(prefix):
+ return JpegImagePlugin._accept(prefix)
+
+
+def _save(im, fp, filename):
+ # Note that we can only save the current frame at present
+ return JpegImagePlugin._save(im, fp, filename)
+
+
+##
+# Image plugin for MPO images.
+
+
+class MpoImageFile(JpegImagePlugin.JpegImageFile):
+
+ format = "MPO"
+ format_description = "MPO (CIPA DC-007)"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+ self.fp.seek(0) # prep the fp in order to pass the JPEG test
+ JpegImagePlugin.JpegImageFile._open(self)
+ self._after_jpeg_open()
+
+ def _after_jpeg_open(self, mpheader=None):
+ self.mpinfo = mpheader if mpheader is not None else self._getmp()
+ self.n_frames = self.mpinfo[0xB001]
+ self.__mpoffsets = [
+ mpent["DataOffset"] + self.info["mpoffset"] for mpent in self.mpinfo[0xB002]
+ ]
+ self.__mpoffsets[0] = 0
+ # Note that the following assertion will only be invalid if something
+ # gets broken within JpegImagePlugin.
+ assert self.n_frames == len(self.__mpoffsets)
+ del self.info["mpoffset"] # no longer needed
+ self.is_animated = self.n_frames > 1
+ self.__fp = self.fp # FIXME: hack
+ self.__fp.seek(self.__mpoffsets[0]) # get ready to read first frame
+ self.__frame = 0
+ self.offset = 0
+ # for now we can only handle reading and individual frame extraction
+ self.readonly = 1
+
+ def load_seek(self, pos):
+ self.__fp.seek(pos)
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ self.fp = self.__fp
+ self.offset = self.__mpoffsets[frame]
+
+ self.fp.seek(self.offset + 2) # skip SOI marker
+ segment = self.fp.read(2)
+ if not segment:
+ raise ValueError("No data found for frame")
+ if i16(segment) == 0xFFE1: # APP1
+ n = i16(self.fp.read(2)) - 2
+ self.info["exif"] = ImageFile._safe_read(self.fp, n)
+
+ exif = self.getexif()
+ if 40962 in exif and 40963 in exif:
+ self._size = (exif[40962], exif[40963])
+ elif "exif" in self.info:
+ del self.info["exif"]
+
+ self.tile = [("jpeg", (0, 0) + self.size, self.offset, (self.mode, ""))]
+ self.__frame = frame
+
+ def tell(self):
+ return self.__frame
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+ @staticmethod
+ def adopt(jpeg_instance, mpheader=None):
+ """
+ Transform the instance of JpegImageFile into
+ an instance of MpoImageFile.
+ After the call, the JpegImageFile is extended
+ to be an MpoImageFile.
+
+ This is essentially useful when opening a JPEG
+ file that reveals itself as an MPO, to avoid
+ double call to _open.
+ """
+ jpeg_instance.__class__ = MpoImageFile
+ jpeg_instance._after_jpeg_open(mpheader)
+ return jpeg_instance
+
+
+# ---------------------------------------------------------------------
+# Registry stuff
+
+# Note that since MPO shares a factory with JPEG, we do not need to do a
+# separate registration for it here.
+# Image.register_open(MpoImageFile.format,
+# JpegImagePlugin.jpeg_factory, _accept)
+Image.register_save(MpoImageFile.format, _save)
+
+Image.register_extension(MpoImageFile.format, ".mpo")
+
+Image.register_mime(MpoImageFile.format, "image/mpo")
diff --git a/venv/Lib/site-packages/PIL/MspImagePlugin.py b/venv/Lib/site-packages/PIL/MspImagePlugin.py
new file mode 100644
index 0000000..e1fdc1f
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/MspImagePlugin.py
@@ -0,0 +1,194 @@
+#
+# The Python Imaging Library.
+#
+# MSP file handling
+#
+# This is the format used by the Paint program in Windows 1 and 2.
+#
+# History:
+# 95-09-05 fl Created
+# 97-01-03 fl Read/write MSP images
+# 17-02-21 es Fixed RLE interpretation
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1995-97.
+# Copyright (c) Eric Soroos 2017.
+#
+# See the README file for information on usage and redistribution.
+#
+# More info on this format: https://archive.org/details/gg243631
+# Page 313:
+# Figure 205. Windows Paint Version 1: "DanM" Format
+# Figure 206. Windows Paint Version 2: "LinS" Format. Used in Windows V2.03
+#
+# See also: http://www.fileformat.info/format/mspaint/egff.htm
+
+import io
+import struct
+
+from . import Image, ImageFile
+from ._binary import i16le as i16
+from ._binary import o16le as o16
+
+#
+# read MSP files
+
+
+def _accept(prefix):
+ return prefix[:4] in [b"DanM", b"LinS"]
+
+
+##
+# Image plugin for Windows MSP images. This plugin supports both
+# uncompressed (Windows 1.0).
+
+
+class MspImageFile(ImageFile.ImageFile):
+
+ format = "MSP"
+ format_description = "Windows Paint"
+
+ def _open(self):
+
+ # Header
+ s = self.fp.read(32)
+ if not _accept(s):
+ raise SyntaxError("not an MSP file")
+
+ # Header checksum
+ checksum = 0
+ for i in range(0, 32, 2):
+ checksum = checksum ^ i16(s, i)
+ if checksum != 0:
+ raise SyntaxError("bad MSP checksum")
+
+ self.mode = "1"
+ self._size = i16(s, 4), i16(s, 6)
+
+ if s[:4] == b"DanM":
+ self.tile = [("raw", (0, 0) + self.size, 32, ("1", 0, 1))]
+ else:
+ self.tile = [("MSP", (0, 0) + self.size, 32, None)]
+
+
+class MspDecoder(ImageFile.PyDecoder):
+ # The algo for the MSP decoder is from
+ # http://www.fileformat.info/format/mspaint/egff.htm
+ # cc-by-attribution -- That page references is taken from the
+ # Encyclopedia of Graphics File Formats and is licensed by
+ # O'Reilly under the Creative Common/Attribution license
+ #
+ # For RLE encoded files, the 32byte header is followed by a scan
+ # line map, encoded as one 16bit word of encoded byte length per
+ # line.
+ #
+ # NOTE: the encoded length of the line can be 0. This was not
+ # handled in the previous version of this encoder, and there's no
+ # mention of how to handle it in the documentation. From the few
+ # examples I've seen, I've assumed that it is a fill of the
+ # background color, in this case, white.
+ #
+ #
+ # Pseudocode of the decoder:
+ # Read a BYTE value as the RunType
+ # If the RunType value is zero
+ # Read next byte as the RunCount
+ # Read the next byte as the RunValue
+ # Write the RunValue byte RunCount times
+ # If the RunType value is non-zero
+ # Use this value as the RunCount
+ # Read and write the next RunCount bytes literally
+ #
+ # e.g.:
+ # 0x00 03 ff 05 00 01 02 03 04
+ # would yield the bytes:
+ # 0xff ff ff 00 01 02 03 04
+ #
+ # which are then interpreted as a bit packed mode '1' image
+
+ _pulls_fd = True
+
+ def decode(self, buffer):
+
+ img = io.BytesIO()
+ blank_line = bytearray((0xFF,) * ((self.state.xsize + 7) // 8))
+ try:
+ self.fd.seek(32)
+ rowmap = struct.unpack_from(
+ f"<{self.state.ysize}H", self.fd.read(self.state.ysize * 2)
+ )
+ except struct.error as e:
+ raise OSError("Truncated MSP file in row map") from e
+
+ for x, rowlen in enumerate(rowmap):
+ try:
+ if rowlen == 0:
+ img.write(blank_line)
+ continue
+ row = self.fd.read(rowlen)
+ if len(row) != rowlen:
+ raise OSError(
+ "Truncated MSP file, expected %d bytes on row %s", (rowlen, x)
+ )
+ idx = 0
+ while idx < rowlen:
+ runtype = row[idx]
+ idx += 1
+ if runtype == 0:
+ (runcount, runval) = struct.unpack_from("Bc", row, idx)
+ img.write(runval * runcount)
+ idx += 2
+ else:
+ runcount = runtype
+ img.write(row[idx : idx + runcount])
+ idx += runcount
+
+ except struct.error as e:
+ raise OSError(f"Corrupted MSP file in row {x}") from e
+
+ self.set_as_raw(img.getvalue(), ("1", 0, 1))
+
+ return 0, 0
+
+
+Image.register_decoder("MSP", MspDecoder)
+
+
+#
+# write MSP files (uncompressed only)
+
+
+def _save(im, fp, filename):
+
+ if im.mode != "1":
+ raise OSError(f"cannot write mode {im.mode} as MSP")
+
+ # create MSP header
+ header = [0] * 16
+
+ header[0], header[1] = i16(b"Da"), i16(b"nM") # version 1
+ header[2], header[3] = im.size
+ header[4], header[5] = 1, 1
+ header[6], header[7] = 1, 1
+ header[8], header[9] = im.size
+
+ checksum = 0
+ for h in header:
+ checksum = checksum ^ h
+ header[12] = checksum # FIXME: is this the right field?
+
+ # header
+ for h in header:
+ fp.write(o16(h))
+
+ # image body
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 32, ("1", 0, 1))])
+
+
+#
+# registry
+
+Image.register_open(MspImageFile.format, MspImageFile, _accept)
+Image.register_save(MspImageFile.format, _save)
+
+Image.register_extension(MspImageFile.format, ".msp")
diff --git a/venv/Lib/site-packages/PIL/PSDraw.py b/venv/Lib/site-packages/PIL/PSDraw.py
new file mode 100644
index 0000000..c1bd933
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PSDraw.py
@@ -0,0 +1,235 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# Simple PostScript graphics interface
+#
+# History:
+# 1996-04-20 fl Created
+# 1999-01-10 fl Added gsave/grestore to image method
+# 2005-05-04 fl Fixed floating point issue in image (from Eric Etheridge)
+#
+# Copyright (c) 1997-2005 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1996 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import sys
+
+from . import EpsImagePlugin
+
+##
+# Simple PostScript graphics interface.
+
+
+class PSDraw:
+ """
+ Sets up printing to the given file. If ``fp`` is omitted,
+ :py:data:`sys.stdout` is assumed.
+ """
+
+ def __init__(self, fp=None):
+ if not fp:
+ fp = sys.stdout
+ self.fp = fp
+
+ def _fp_write(self, to_write):
+ if self.fp == sys.stdout:
+ self.fp.write(to_write)
+ else:
+ self.fp.write(bytes(to_write, "UTF-8"))
+
+ def begin_document(self, id=None):
+ """Set up printing of a document. (Write PostScript DSC header.)"""
+ # FIXME: incomplete
+ self._fp_write(
+ "%!PS-Adobe-3.0\n"
+ "save\n"
+ "/showpage { } def\n"
+ "%%EndComments\n"
+ "%%BeginDocument\n"
+ )
+ # self._fp_write(ERROR_PS) # debugging!
+ self._fp_write(EDROFF_PS)
+ self._fp_write(VDI_PS)
+ self._fp_write("%%EndProlog\n")
+ self.isofont = {}
+
+ def end_document(self):
+ """Ends printing. (Write PostScript DSC footer.)"""
+ self._fp_write("%%EndDocument\nrestore showpage\n%%End\n")
+ if hasattr(self.fp, "flush"):
+ self.fp.flush()
+
+ def setfont(self, font, size):
+ """
+ Selects which font to use.
+
+ :param font: A PostScript font name
+ :param size: Size in points.
+ """
+ if font not in self.isofont:
+ # reencode font
+ self._fp_write(f"/PSDraw-{font} ISOLatin1Encoding /{font} E\n")
+ self.isofont[font] = 1
+ # rough
+ self._fp_write(f"/F0 {size} /PSDraw-{font} F\n")
+
+ def line(self, xy0, xy1):
+ """
+ Draws a line between the two points. Coordinates are given in
+ PostScript point coordinates (72 points per inch, (0, 0) is the lower
+ left corner of the page).
+ """
+ self._fp_write("%d %d %d %d Vl\n" % (*xy0, *xy1))
+
+ def rectangle(self, box):
+ """
+ Draws a rectangle.
+
+ :param box: A 4-tuple of integers whose order and function is currently
+ undocumented.
+
+ Hint: the tuple is passed into this format string:
+
+ .. code-block:: python
+
+ %d %d M %d %d 0 Vr\n
+ """
+ self._fp_write("%d %d M %d %d 0 Vr\n" % box)
+
+ def text(self, xy, text):
+ """
+ Draws text at the given position. You must use
+ :py:meth:`~PIL.PSDraw.PSDraw.setfont` before calling this method.
+ """
+ text = "\\(".join(text.split("("))
+ text = "\\)".join(text.split(")"))
+ self._fp_write(f"{xy[0]} {xy[1]} M ({text}) S\n")
+
+ def image(self, box, im, dpi=None):
+ """Draw a PIL image, centered in the given box."""
+ # default resolution depends on mode
+ if not dpi:
+ if im.mode == "1":
+ dpi = 200 # fax
+ else:
+ dpi = 100 # greyscale
+ # image size (on paper)
+ x = im.size[0] * 72 / dpi
+ y = im.size[1] * 72 / dpi
+ # max allowed size
+ xmax = float(box[2] - box[0])
+ ymax = float(box[3] - box[1])
+ if x > xmax:
+ y = y * xmax / x
+ x = xmax
+ if y > ymax:
+ x = x * ymax / y
+ y = ymax
+ dx = (xmax - x) / 2 + box[0]
+ dy = (ymax - y) / 2 + box[1]
+ self._fp_write(f"gsave\n{dx:f} {dy:f} translate\n")
+ if (x, y) != im.size:
+ # EpsImagePlugin._save prints the image at (0,0,xsize,ysize)
+ sx = x / im.size[0]
+ sy = y / im.size[1]
+ self._fp_write(f"{sx:f} {sy:f} scale\n")
+ EpsImagePlugin._save(im, self.fp, None, 0)
+ self._fp_write("\ngrestore\n")
+
+
+# --------------------------------------------------------------------
+# PostScript driver
+
+#
+# EDROFF.PS -- PostScript driver for Edroff 2
+#
+# History:
+# 94-01-25 fl: created (edroff 2.04)
+#
+# Copyright (c) Fredrik Lundh 1994.
+#
+
+
+EDROFF_PS = """\
+/S { show } bind def
+/P { moveto show } bind def
+/M { moveto } bind def
+/X { 0 rmoveto } bind def
+/Y { 0 exch rmoveto } bind def
+/E { findfont
+ dup maxlength dict begin
+ {
+ 1 index /FID ne { def } { pop pop } ifelse
+ } forall
+ /Encoding exch def
+ dup /FontName exch def
+ currentdict end definefont pop
+} bind def
+/F { findfont exch scalefont dup setfont
+ [ exch /setfont cvx ] cvx bind def
+} bind def
+"""
+
+#
+# VDI.PS -- PostScript driver for VDI meta commands
+#
+# History:
+# 94-01-25 fl: created (edroff 2.04)
+#
+# Copyright (c) Fredrik Lundh 1994.
+#
+
+VDI_PS = """\
+/Vm { moveto } bind def
+/Va { newpath arcn stroke } bind def
+/Vl { moveto lineto stroke } bind def
+/Vc { newpath 0 360 arc closepath } bind def
+/Vr { exch dup 0 rlineto
+ exch dup neg 0 exch rlineto
+ exch neg 0 rlineto
+ 0 exch rlineto
+ 100 div setgray fill 0 setgray } bind def
+/Tm matrix def
+/Ve { Tm currentmatrix pop
+ translate scale newpath 0 0 .5 0 360 arc closepath
+ Tm setmatrix
+} bind def
+/Vf { currentgray exch setgray fill setgray } bind def
+"""
+
+#
+# ERROR.PS -- Error handler
+#
+# History:
+# 89-11-21 fl: created (pslist 1.10)
+#
+
+ERROR_PS = """\
+/landscape false def
+/errorBUF 200 string def
+/errorNL { currentpoint 10 sub exch pop 72 exch moveto } def
+errordict begin /handleerror {
+ initmatrix /Courier findfont 10 scalefont setfont
+ newpath 72 720 moveto $error begin /newerror false def
+ (PostScript Error) show errorNL errorNL
+ (Error: ) show
+ /errorname load errorBUF cvs show errorNL errorNL
+ (Command: ) show
+ /command load dup type /stringtype ne { errorBUF cvs } if show
+ errorNL errorNL
+ (VMstatus: ) show
+ vmstatus errorBUF cvs show ( bytes available, ) show
+ errorBUF cvs show ( bytes used at level ) show
+ errorBUF cvs show errorNL errorNL
+ (Operand stargck: ) show errorNL /ostargck load {
+ dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
+ } forall errorNL
+ (Execution stargck: ) show errorNL /estargck load {
+ dup type /stringtype ne { errorBUF cvs } if 72 0 rmoveto show errorNL
+ } forall
+ end showpage
+} def end
+"""
diff --git a/venv/Lib/site-packages/PIL/PaletteFile.py b/venv/Lib/site-packages/PIL/PaletteFile.py
new file mode 100644
index 0000000..6ccaa1f
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PaletteFile.py
@@ -0,0 +1,53 @@
+#
+# Python Imaging Library
+# $Id$
+#
+# stuff to read simple, teragon-style palette files
+#
+# History:
+# 97-08-23 fl Created
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from ._binary import o8
+
+
+class PaletteFile:
+ """File handler for Teragon-style palette files."""
+
+ rawmode = "RGB"
+
+ def __init__(self, fp):
+
+ self.palette = [(i, i, i) for i in range(256)]
+
+ while True:
+
+ s = fp.readline()
+
+ if not s:
+ break
+ if s[0:1] == b"#":
+ continue
+ if len(s) > 100:
+ raise SyntaxError("bad palette file")
+
+ v = [int(x) for x in s.split()]
+ try:
+ [i, r, g, b] = v
+ except ValueError:
+ [i, r] = v
+ g = b = r
+
+ if 0 <= i <= 255:
+ self.palette[i] = o8(r) + o8(g) + o8(b)
+
+ self.palette = b"".join(self.palette)
+
+ def getpalette(self):
+
+ return self.palette, self.rawmode
diff --git a/venv/Lib/site-packages/PIL/PalmImagePlugin.py b/venv/Lib/site-packages/PIL/PalmImagePlugin.py
new file mode 100644
index 0000000..700f10e
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PalmImagePlugin.py
@@ -0,0 +1,227 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+
+##
+# Image plugin for Palm pixmap images (output only).
+##
+
+from . import Image, ImageFile
+from ._binary import o8
+from ._binary import o16be as o16b
+
+# fmt: off
+_Palm8BitColormapValues = (
+ (255, 255, 255), (255, 204, 255), (255, 153, 255), (255, 102, 255),
+ (255, 51, 255), (255, 0, 255), (255, 255, 204), (255, 204, 204),
+ (255, 153, 204), (255, 102, 204), (255, 51, 204), (255, 0, 204),
+ (255, 255, 153), (255, 204, 153), (255, 153, 153), (255, 102, 153),
+ (255, 51, 153), (255, 0, 153), (204, 255, 255), (204, 204, 255),
+ (204, 153, 255), (204, 102, 255), (204, 51, 255), (204, 0, 255),
+ (204, 255, 204), (204, 204, 204), (204, 153, 204), (204, 102, 204),
+ (204, 51, 204), (204, 0, 204), (204, 255, 153), (204, 204, 153),
+ (204, 153, 153), (204, 102, 153), (204, 51, 153), (204, 0, 153),
+ (153, 255, 255), (153, 204, 255), (153, 153, 255), (153, 102, 255),
+ (153, 51, 255), (153, 0, 255), (153, 255, 204), (153, 204, 204),
+ (153, 153, 204), (153, 102, 204), (153, 51, 204), (153, 0, 204),
+ (153, 255, 153), (153, 204, 153), (153, 153, 153), (153, 102, 153),
+ (153, 51, 153), (153, 0, 153), (102, 255, 255), (102, 204, 255),
+ (102, 153, 255), (102, 102, 255), (102, 51, 255), (102, 0, 255),
+ (102, 255, 204), (102, 204, 204), (102, 153, 204), (102, 102, 204),
+ (102, 51, 204), (102, 0, 204), (102, 255, 153), (102, 204, 153),
+ (102, 153, 153), (102, 102, 153), (102, 51, 153), (102, 0, 153),
+ (51, 255, 255), (51, 204, 255), (51, 153, 255), (51, 102, 255),
+ (51, 51, 255), (51, 0, 255), (51, 255, 204), (51, 204, 204),
+ (51, 153, 204), (51, 102, 204), (51, 51, 204), (51, 0, 204),
+ (51, 255, 153), (51, 204, 153), (51, 153, 153), (51, 102, 153),
+ (51, 51, 153), (51, 0, 153), (0, 255, 255), (0, 204, 255),
+ (0, 153, 255), (0, 102, 255), (0, 51, 255), (0, 0, 255),
+ (0, 255, 204), (0, 204, 204), (0, 153, 204), (0, 102, 204),
+ (0, 51, 204), (0, 0, 204), (0, 255, 153), (0, 204, 153),
+ (0, 153, 153), (0, 102, 153), (0, 51, 153), (0, 0, 153),
+ (255, 255, 102), (255, 204, 102), (255, 153, 102), (255, 102, 102),
+ (255, 51, 102), (255, 0, 102), (255, 255, 51), (255, 204, 51),
+ (255, 153, 51), (255, 102, 51), (255, 51, 51), (255, 0, 51),
+ (255, 255, 0), (255, 204, 0), (255, 153, 0), (255, 102, 0),
+ (255, 51, 0), (255, 0, 0), (204, 255, 102), (204, 204, 102),
+ (204, 153, 102), (204, 102, 102), (204, 51, 102), (204, 0, 102),
+ (204, 255, 51), (204, 204, 51), (204, 153, 51), (204, 102, 51),
+ (204, 51, 51), (204, 0, 51), (204, 255, 0), (204, 204, 0),
+ (204, 153, 0), (204, 102, 0), (204, 51, 0), (204, 0, 0),
+ (153, 255, 102), (153, 204, 102), (153, 153, 102), (153, 102, 102),
+ (153, 51, 102), (153, 0, 102), (153, 255, 51), (153, 204, 51),
+ (153, 153, 51), (153, 102, 51), (153, 51, 51), (153, 0, 51),
+ (153, 255, 0), (153, 204, 0), (153, 153, 0), (153, 102, 0),
+ (153, 51, 0), (153, 0, 0), (102, 255, 102), (102, 204, 102),
+ (102, 153, 102), (102, 102, 102), (102, 51, 102), (102, 0, 102),
+ (102, 255, 51), (102, 204, 51), (102, 153, 51), (102, 102, 51),
+ (102, 51, 51), (102, 0, 51), (102, 255, 0), (102, 204, 0),
+ (102, 153, 0), (102, 102, 0), (102, 51, 0), (102, 0, 0),
+ (51, 255, 102), (51, 204, 102), (51, 153, 102), (51, 102, 102),
+ (51, 51, 102), (51, 0, 102), (51, 255, 51), (51, 204, 51),
+ (51, 153, 51), (51, 102, 51), (51, 51, 51), (51, 0, 51),
+ (51, 255, 0), (51, 204, 0), (51, 153, 0), (51, 102, 0),
+ (51, 51, 0), (51, 0, 0), (0, 255, 102), (0, 204, 102),
+ (0, 153, 102), (0, 102, 102), (0, 51, 102), (0, 0, 102),
+ (0, 255, 51), (0, 204, 51), (0, 153, 51), (0, 102, 51),
+ (0, 51, 51), (0, 0, 51), (0, 255, 0), (0, 204, 0),
+ (0, 153, 0), (0, 102, 0), (0, 51, 0), (17, 17, 17),
+ (34, 34, 34), (68, 68, 68), (85, 85, 85), (119, 119, 119),
+ (136, 136, 136), (170, 170, 170), (187, 187, 187), (221, 221, 221),
+ (238, 238, 238), (192, 192, 192), (128, 0, 0), (128, 0, 128),
+ (0, 128, 0), (0, 128, 128), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0),
+ (0, 0, 0), (0, 0, 0), (0, 0, 0), (0, 0, 0))
+# fmt: on
+
+
+# so build a prototype image to be used for palette resampling
+def build_prototype_image():
+ image = Image.new("L", (1, len(_Palm8BitColormapValues)))
+ image.putdata(list(range(len(_Palm8BitColormapValues))))
+ palettedata = ()
+ for colormapValue in _Palm8BitColormapValues:
+ palettedata += colormapValue
+ palettedata += (0, 0, 0) * (256 - len(_Palm8BitColormapValues))
+ image.putpalette(palettedata)
+ return image
+
+
+Palm8BitColormapImage = build_prototype_image()
+
+# OK, we now have in Palm8BitColormapImage,
+# a "P"-mode image with the right palette
+#
+# --------------------------------------------------------------------
+
+_FLAGS = {"custom-colormap": 0x4000, "is-compressed": 0x8000, "has-transparent": 0x2000}
+
+_COMPRESSION_TYPES = {"none": 0xFF, "rle": 0x01, "scanline": 0x00}
+
+
+#
+# --------------------------------------------------------------------
+
+##
+# (Internal) Image save plugin for the Palm format.
+
+
+def _save(im, fp, filename):
+
+ if im.mode == "P":
+
+ # we assume this is a color Palm image with the standard colormap,
+ # unless the "info" dict has a "custom-colormap" field
+
+ rawmode = "P"
+ bpp = 8
+ version = 1
+
+ elif im.mode == "L":
+ if im.encoderinfo.get("bpp") in (1, 2, 4):
+ # this is 8-bit grayscale, so we shift it to get the high-order bits,
+ # and invert it because
+ # Palm does greyscale from white (0) to black (1)
+ bpp = im.encoderinfo["bpp"]
+ im = im.point(
+ lambda x, shift=8 - bpp, maxval=(1 << bpp) - 1: maxval - (x >> shift)
+ )
+ elif im.info.get("bpp") in (1, 2, 4):
+ # here we assume that even though the inherent mode is 8-bit grayscale,
+ # only the lower bpp bits are significant.
+ # We invert them to match the Palm.
+ bpp = im.info["bpp"]
+ im = im.point(lambda x, maxval=(1 << bpp) - 1: maxval - (x & maxval))
+ else:
+ raise OSError(f"cannot write mode {im.mode} as Palm")
+
+ # we ignore the palette here
+ im.mode = "P"
+ rawmode = "P;" + str(bpp)
+ version = 1
+
+ elif im.mode == "1":
+
+ # monochrome -- write it inverted, as is the Palm standard
+ rawmode = "1;I"
+ bpp = 1
+ version = 0
+
+ else:
+
+ raise OSError(f"cannot write mode {im.mode} as Palm")
+
+ #
+ # make sure image data is available
+ im.load()
+
+ # write header
+
+ cols = im.size[0]
+ rows = im.size[1]
+
+ rowbytes = int((cols + (16 // bpp - 1)) / (16 // bpp)) * 2
+ transparent_index = 0
+ compression_type = _COMPRESSION_TYPES["none"]
+
+ flags = 0
+ if im.mode == "P" and "custom-colormap" in im.info:
+ flags = flags & _FLAGS["custom-colormap"]
+ colormapsize = 4 * 256 + 2
+ colormapmode = im.palette.mode
+ colormap = im.getdata().getpalette()
+ else:
+ colormapsize = 0
+
+ if "offset" in im.info:
+ offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4
+ else:
+ offset = 0
+
+ fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags))
+ fp.write(o8(bpp))
+ fp.write(o8(version))
+ fp.write(o16b(offset))
+ fp.write(o8(transparent_index))
+ fp.write(o8(compression_type))
+ fp.write(o16b(0)) # reserved by Palm
+
+ # now write colormap if necessary
+
+ if colormapsize > 0:
+ fp.write(o16b(256))
+ for i in range(256):
+ fp.write(o8(i))
+ if colormapmode == "RGB":
+ fp.write(
+ o8(colormap[3 * i])
+ + o8(colormap[3 * i + 1])
+ + o8(colormap[3 * i + 2])
+ )
+ elif colormapmode == "RGBA":
+ fp.write(
+ o8(colormap[4 * i])
+ + o8(colormap[4 * i + 1])
+ + o8(colormap[4 * i + 2])
+ )
+
+ # now convert data to raw form
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, rowbytes, 1))])
+
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_save("Palm", _save)
+
+Image.register_extension("Palm", ".palm")
+
+Image.register_mime("Palm", "image/palm")
diff --git a/venv/Lib/site-packages/PIL/PcdImagePlugin.py b/venv/Lib/site-packages/PIL/PcdImagePlugin.py
new file mode 100644
index 0000000..38caf5c
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PcdImagePlugin.py
@@ -0,0 +1,63 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PCD file handling
+#
+# History:
+# 96-05-10 fl Created
+# 96-05-27 fl Added draft mode (128x192, 256x384)
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile
+
+##
+# Image plugin for PhotoCD images. This plugin only reads the 768x512
+# image from the file; higher resolutions are encoded in a proprietary
+# encoding.
+
+
+class PcdImageFile(ImageFile.ImageFile):
+
+ format = "PCD"
+ format_description = "Kodak PhotoCD"
+
+ def _open(self):
+
+ # rough
+ self.fp.seek(2048)
+ s = self.fp.read(2048)
+
+ if s[:4] != b"PCD_":
+ raise SyntaxError("not a PCD file")
+
+ orientation = s[1538] & 3
+ self.tile_post_rotate = None
+ if orientation == 1:
+ self.tile_post_rotate = 90
+ elif orientation == 3:
+ self.tile_post_rotate = -90
+
+ self.mode = "RGB"
+ self._size = 768, 512 # FIXME: not correct for rotated images!
+ self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)]
+
+ def load_end(self):
+ if self.tile_post_rotate:
+ # Handle rotated PCDs
+ self.im = self.im.rotate(self.tile_post_rotate)
+ self._size = self.im.size
+
+
+#
+# registry
+
+Image.register_open(PcdImageFile.format, PcdImageFile)
+
+Image.register_extension(PcdImageFile.format, ".pcd")
diff --git a/venv/Lib/site-packages/PIL/PcfFontFile.py b/venv/Lib/site-packages/PIL/PcfFontFile.py
new file mode 100644
index 0000000..6a4eb22
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PcfFontFile.py
@@ -0,0 +1,248 @@
+#
+# THIS IS WORK IN PROGRESS
+#
+# The Python Imaging Library
+# $Id$
+#
+# portable compiled font file parser
+#
+# history:
+# 1997-08-19 fl created
+# 2003-09-13 fl fixed loading of unicode fonts
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1997-2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+
+from . import FontFile, Image
+from ._binary import i8
+from ._binary import i16be as b16
+from ._binary import i16le as l16
+from ._binary import i32be as b32
+from ._binary import i32le as l32
+
+# --------------------------------------------------------------------
+# declarations
+
+PCF_MAGIC = 0x70636601 # "\x01fcp"
+
+PCF_PROPERTIES = 1 << 0
+PCF_ACCELERATORS = 1 << 1
+PCF_METRICS = 1 << 2
+PCF_BITMAPS = 1 << 3
+PCF_INK_METRICS = 1 << 4
+PCF_BDF_ENCODINGS = 1 << 5
+PCF_SWIDTHS = 1 << 6
+PCF_GLYPH_NAMES = 1 << 7
+PCF_BDF_ACCELERATORS = 1 << 8
+
+BYTES_PER_ROW = [
+ lambda bits: ((bits + 7) >> 3),
+ lambda bits: ((bits + 15) >> 3) & ~1,
+ lambda bits: ((bits + 31) >> 3) & ~3,
+ lambda bits: ((bits + 63) >> 3) & ~7,
+]
+
+
+def sz(s, o):
+ return s[o : s.index(b"\0", o)]
+
+
+class PcfFontFile(FontFile.FontFile):
+ """Font file plugin for the X11 PCF format."""
+
+ name = "name"
+
+ def __init__(self, fp, charset_encoding="iso8859-1"):
+
+ self.charset_encoding = charset_encoding
+
+ magic = l32(fp.read(4))
+ if magic != PCF_MAGIC:
+ raise SyntaxError("not a PCF file")
+
+ super().__init__()
+
+ count = l32(fp.read(4))
+ self.toc = {}
+ for i in range(count):
+ type = l32(fp.read(4))
+ self.toc[type] = l32(fp.read(4)), l32(fp.read(4)), l32(fp.read(4))
+
+ self.fp = fp
+
+ self.info = self._load_properties()
+
+ metrics = self._load_metrics()
+ bitmaps = self._load_bitmaps(metrics)
+ encoding = self._load_encoding()
+
+ #
+ # create glyph structure
+
+ for ch in range(256):
+ ix = encoding[ch]
+ if ix is not None:
+ x, y, l, r, w, a, d, f = metrics[ix]
+ glyph = (w, 0), (l, d - y, x + l, d), (0, 0, x, y), bitmaps[ix]
+ self.glyph[ch] = glyph
+
+ def _getformat(self, tag):
+
+ format, size, offset = self.toc[tag]
+
+ fp = self.fp
+ fp.seek(offset)
+
+ format = l32(fp.read(4))
+
+ if format & 4:
+ i16, i32 = b16, b32
+ else:
+ i16, i32 = l16, l32
+
+ return fp, format, i16, i32
+
+ def _load_properties(self):
+
+ #
+ # font properties
+
+ properties = {}
+
+ fp, format, i16, i32 = self._getformat(PCF_PROPERTIES)
+
+ nprops = i32(fp.read(4))
+
+ # read property description
+ p = []
+ for i in range(nprops):
+ p.append((i32(fp.read(4)), i8(fp.read(1)), i32(fp.read(4))))
+ if nprops & 3:
+ fp.seek(4 - (nprops & 3), io.SEEK_CUR) # pad
+
+ data = fp.read(i32(fp.read(4)))
+
+ for k, s, v in p:
+ k = sz(data, k)
+ if s:
+ v = sz(data, v)
+ properties[k] = v
+
+ return properties
+
+ def _load_metrics(self):
+
+ #
+ # font metrics
+
+ metrics = []
+
+ fp, format, i16, i32 = self._getformat(PCF_METRICS)
+
+ append = metrics.append
+
+ if (format & 0xFF00) == 0x100:
+
+ # "compressed" metrics
+ for i in range(i16(fp.read(2))):
+ left = i8(fp.read(1)) - 128
+ right = i8(fp.read(1)) - 128
+ width = i8(fp.read(1)) - 128
+ ascent = i8(fp.read(1)) - 128
+ descent = i8(fp.read(1)) - 128
+ xsize = right - left
+ ysize = ascent + descent
+ append((xsize, ysize, left, right, width, ascent, descent, 0))
+
+ else:
+
+ # "jumbo" metrics
+ for i in range(i32(fp.read(4))):
+ left = i16(fp.read(2))
+ right = i16(fp.read(2))
+ width = i16(fp.read(2))
+ ascent = i16(fp.read(2))
+ descent = i16(fp.read(2))
+ attributes = i16(fp.read(2))
+ xsize = right - left
+ ysize = ascent + descent
+ append((xsize, ysize, left, right, width, ascent, descent, attributes))
+
+ return metrics
+
+ def _load_bitmaps(self, metrics):
+
+ #
+ # bitmap data
+
+ bitmaps = []
+
+ fp, format, i16, i32 = self._getformat(PCF_BITMAPS)
+
+ nbitmaps = i32(fp.read(4))
+
+ if nbitmaps != len(metrics):
+ raise OSError("Wrong number of bitmaps")
+
+ offsets = []
+ for i in range(nbitmaps):
+ offsets.append(i32(fp.read(4)))
+
+ bitmapSizes = []
+ for i in range(4):
+ bitmapSizes.append(i32(fp.read(4)))
+
+ # byteorder = format & 4 # non-zero => MSB
+ bitorder = format & 8 # non-zero => MSB
+ padindex = format & 3
+
+ bitmapsize = bitmapSizes[padindex]
+ offsets.append(bitmapsize)
+
+ data = fp.read(bitmapsize)
+
+ pad = BYTES_PER_ROW[padindex]
+ mode = "1;R"
+ if bitorder:
+ mode = "1"
+
+ for i in range(nbitmaps):
+ x, y, l, r, w, a, d, f = metrics[i]
+ b, e = offsets[i], offsets[i + 1]
+ bitmaps.append(Image.frombytes("1", (x, y), data[b:e], "raw", mode, pad(x)))
+
+ return bitmaps
+
+ def _load_encoding(self):
+
+ # map character code to bitmap index
+ encoding = [None] * 256
+
+ fp, format, i16, i32 = self._getformat(PCF_BDF_ENCODINGS)
+
+ firstCol, lastCol = i16(fp.read(2)), i16(fp.read(2))
+ firstRow, lastRow = i16(fp.read(2)), i16(fp.read(2))
+
+ i16(fp.read(2)) # default
+
+ nencoding = (lastCol - firstCol + 1) * (lastRow - firstRow + 1)
+
+ encodingOffsets = [i16(fp.read(2)) for _ in range(nencoding)]
+
+ for i in range(firstCol, len(encoding)):
+ try:
+ encodingOffset = encodingOffsets[
+ ord(bytearray([i]).decode(self.charset_encoding))
+ ]
+ if encodingOffset != 0xFFFF:
+ encoding[i] = encodingOffset
+ except UnicodeDecodeError:
+ # character is not supported in selected encoding
+ pass
+
+ return encoding
diff --git a/venv/Lib/site-packages/PIL/PcxImagePlugin.py b/venv/Lib/site-packages/PIL/PcxImagePlugin.py
new file mode 100644
index 0000000..a24d44b
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PcxImagePlugin.py
@@ -0,0 +1,213 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PCX file handling
+#
+# This format was originally used by ZSoft's popular PaintBrush
+# program for the IBM PC. It is also supported by many MS-DOS and
+# Windows applications, including the Windows PaintBrush program in
+# Windows 3.
+#
+# history:
+# 1995-09-01 fl Created
+# 1996-05-20 fl Fixed RGB support
+# 1997-01-03 fl Fixed 2-bit and 4-bit support
+# 1999-02-03 fl Fixed 8-bit support (broken in 1.0b1)
+# 1999-02-07 fl Added write support
+# 2002-06-09 fl Made 2-bit and 4-bit support a bit more robust
+# 2002-07-30 fl Seek from to current position, not beginning of file
+# 2003-06-03 fl Extract DPI settings (info["dpi"])
+#
+# Copyright (c) 1997-2003 by Secret Labs AB.
+# Copyright (c) 1995-2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+import logging
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i16le as i16
+from ._binary import o8
+from ._binary import o16le as o16
+
+logger = logging.getLogger(__name__)
+
+
+def _accept(prefix):
+ return prefix[0] == 10 and prefix[1] in [0, 2, 3, 5]
+
+
+##
+# Image plugin for Paintbrush images.
+
+
+class PcxImageFile(ImageFile.ImageFile):
+
+ format = "PCX"
+ format_description = "Paintbrush"
+
+ def _open(self):
+
+ # header
+ s = self.fp.read(128)
+ if not _accept(s):
+ raise SyntaxError("not a PCX file")
+
+ # image
+ bbox = i16(s, 4), i16(s, 6), i16(s, 8) + 1, i16(s, 10) + 1
+ if bbox[2] <= bbox[0] or bbox[3] <= bbox[1]:
+ raise SyntaxError("bad PCX image size")
+ logger.debug("BBox: %s %s %s %s", *bbox)
+
+ # format
+ version = s[1]
+ bits = s[3]
+ planes = s[65]
+ ignored_stride = i16(s, 66)
+ logger.debug(
+ "PCX version %s, bits %s, planes %s, stride %s",
+ version,
+ bits,
+ planes,
+ ignored_stride,
+ )
+
+ self.info["dpi"] = i16(s, 12), i16(s, 14)
+
+ if bits == 1 and planes == 1:
+ mode = rawmode = "1"
+
+ elif bits == 1 and planes in (2, 4):
+ mode = "P"
+ rawmode = "P;%dL" % planes
+ self.palette = ImagePalette.raw("RGB", s[16:64])
+
+ elif version == 5 and bits == 8 and planes == 1:
+ mode = rawmode = "L"
+ # FIXME: hey, this doesn't work with the incremental loader !!!
+ self.fp.seek(-769, io.SEEK_END)
+ s = self.fp.read(769)
+ if len(s) == 769 and s[0] == 12:
+ # check if the palette is linear greyscale
+ for i in range(256):
+ if s[i * 3 + 1 : i * 3 + 4] != o8(i) * 3:
+ mode = rawmode = "P"
+ break
+ if mode == "P":
+ self.palette = ImagePalette.raw("RGB", s[1:])
+ self.fp.seek(128)
+
+ elif version == 5 and bits == 8 and planes == 3:
+ mode = "RGB"
+ rawmode = "RGB;L"
+
+ else:
+ raise OSError("unknown PCX mode")
+
+ self.mode = mode
+ self._size = bbox[2] - bbox[0], bbox[3] - bbox[1]
+
+ # don't trust the passed in stride. Calculate for ourselves.
+ # CVE-2020-35655
+ stride = (self._size[0] * bits + 7) // 8
+ stride += stride % 2
+
+ bbox = (0, 0) + self.size
+ logger.debug("size: %sx%s", *self.size)
+
+ self.tile = [("pcx", bbox, self.fp.tell(), (rawmode, planes * stride))]
+
+
+# --------------------------------------------------------------------
+# save PCX files
+
+
+SAVE = {
+ # mode: (version, bits, planes, raw mode)
+ "1": (2, 1, 1, "1"),
+ "L": (5, 8, 1, "L"),
+ "P": (5, 8, 1, "P"),
+ "RGB": (5, 8, 3, "RGB;L"),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ version, bits, planes, rawmode = SAVE[im.mode]
+ except KeyError as e:
+ raise ValueError(f"Cannot save {im.mode} images as PCX") from e
+
+ # bytes per plane
+ stride = (im.size[0] * bits + 7) // 8
+ # stride should be even
+ stride += stride % 2
+ # Stride needs to be kept in sync with the PcxEncode.c version.
+ # Ideally it should be passed in in the state, but the bytes value
+ # gets overwritten.
+
+ logger.debug(
+ "PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d",
+ im.size[0],
+ bits,
+ stride,
+ )
+
+ # under windows, we could determine the current screen size with
+ # "Image.core.display_mode()[1]", but I think that's overkill...
+
+ screen = im.size
+
+ dpi = 100, 100
+
+ # PCX header
+ fp.write(
+ o8(10)
+ + o8(version)
+ + o8(1)
+ + o8(bits)
+ + o16(0)
+ + o16(0)
+ + o16(im.size[0] - 1)
+ + o16(im.size[1] - 1)
+ + o16(dpi[0])
+ + o16(dpi[1])
+ + b"\0" * 24
+ + b"\xFF" * 24
+ + b"\0"
+ + o8(planes)
+ + o16(stride)
+ + o16(1)
+ + o16(screen[0])
+ + o16(screen[1])
+ + b"\0" * 54
+ )
+
+ assert fp.tell() == 128
+
+ ImageFile._save(im, fp, [("pcx", (0, 0) + im.size, 0, (rawmode, bits * planes))])
+
+ if im.mode == "P":
+ # colour palette
+ fp.write(o8(12))
+ fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
+ elif im.mode == "L":
+ # greyscale palette
+ fp.write(o8(12))
+ for i in range(256):
+ fp.write(o8(i) * 3)
+
+
+# --------------------------------------------------------------------
+# registry
+
+
+Image.register_open(PcxImageFile.format, PcxImageFile, _accept)
+Image.register_save(PcxImageFile.format, _save)
+
+Image.register_extension(PcxImageFile.format, ".pcx")
+
+Image.register_mime(PcxImageFile.format, "image/x-pcx")
diff --git a/venv/Lib/site-packages/PIL/PdfImagePlugin.py b/venv/Lib/site-packages/PIL/PdfImagePlugin.py
new file mode 100644
index 0000000..36c8fb8
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PdfImagePlugin.py
@@ -0,0 +1,246 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PDF (Acrobat) file handling
+#
+# History:
+# 1996-07-16 fl Created
+# 1997-01-18 fl Fixed header
+# 2004-02-21 fl Fixes for 1/L/CMYK images, etc.
+# 2004-02-24 fl Fixes for 1 and P images.
+#
+# Copyright (c) 1997-2004 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1996-1997 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+# Image plugin for PDF images (output only).
+##
+
+import io
+import os
+import time
+
+from . import Image, ImageFile, ImageSequence, PdfParser, __version__
+
+#
+# --------------------------------------------------------------------
+
+# object ids:
+# 1. catalogue
+# 2. pages
+# 3. image
+# 4. page
+# 5. page contents
+
+
+def _save_all(im, fp, filename):
+ _save(im, fp, filename, save_all=True)
+
+
+##
+# (Internal) Image save plugin for the PDF format.
+
+
+def _save(im, fp, filename, save_all=False):
+ is_appending = im.encoderinfo.get("append", False)
+ if is_appending:
+ existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="r+b")
+ else:
+ existing_pdf = PdfParser.PdfParser(f=fp, filename=filename, mode="w+b")
+
+ resolution = im.encoderinfo.get("resolution", 72.0)
+
+ info = {
+ "title": None
+ if is_appending
+ else os.path.splitext(os.path.basename(filename))[0],
+ "author": None,
+ "subject": None,
+ "keywords": None,
+ "creator": None,
+ "producer": None,
+ "creationDate": None if is_appending else time.gmtime(),
+ "modDate": None if is_appending else time.gmtime(),
+ }
+ for k, default in info.items():
+ v = im.encoderinfo.get(k) if k in im.encoderinfo else default
+ if v:
+ existing_pdf.info[k[0].upper() + k[1:]] = v
+
+ #
+ # make sure image data is available
+ im.load()
+
+ existing_pdf.start_writing()
+ existing_pdf.write_header()
+ existing_pdf.write_comment(f"created by Pillow {__version__} PDF driver")
+
+ #
+ # pages
+ ims = [im]
+ if save_all:
+ append_images = im.encoderinfo.get("append_images", [])
+ for append_im in append_images:
+ append_im.encoderinfo = im.encoderinfo.copy()
+ ims.append(append_im)
+ numberOfPages = 0
+ image_refs = []
+ page_refs = []
+ contents_refs = []
+ for im in ims:
+ im_numberOfPages = 1
+ if save_all:
+ try:
+ im_numberOfPages = im.n_frames
+ except AttributeError:
+ # Image format does not have n_frames.
+ # It is a single frame image
+ pass
+ numberOfPages += im_numberOfPages
+ for i in range(im_numberOfPages):
+ image_refs.append(existing_pdf.next_object_id(0))
+ page_refs.append(existing_pdf.next_object_id(0))
+ contents_refs.append(existing_pdf.next_object_id(0))
+ existing_pdf.pages.append(page_refs[-1])
+
+ #
+ # catalog and list of pages
+ existing_pdf.write_catalog()
+
+ pageNumber = 0
+ for imSequence in ims:
+ im_pages = ImageSequence.Iterator(imSequence) if save_all else [imSequence]
+ for im in im_pages:
+ # FIXME: Should replace ASCIIHexDecode with RunLengthDecode
+ # (packbits) or LZWDecode (tiff/lzw compression). Note that
+ # PDF 1.2 also supports Flatedecode (zip compression).
+
+ bits = 8
+ params = None
+ decode = None
+
+ if im.mode == "1":
+ filter = "ASCIIHexDecode"
+ colorspace = PdfParser.PdfName("DeviceGray")
+ procset = "ImageB" # grayscale
+ bits = 1
+ elif im.mode == "L":
+ filter = "DCTDecode"
+ # params = f"<< /Predictor 15 /Columns {width-2} >>"
+ colorspace = PdfParser.PdfName("DeviceGray")
+ procset = "ImageB" # grayscale
+ elif im.mode == "P":
+ filter = "ASCIIHexDecode"
+ palette = im.im.getpalette("RGB")
+ colorspace = [
+ PdfParser.PdfName("Indexed"),
+ PdfParser.PdfName("DeviceRGB"),
+ 255,
+ PdfParser.PdfBinary(palette),
+ ]
+ procset = "ImageI" # indexed color
+ elif im.mode == "RGB":
+ filter = "DCTDecode"
+ colorspace = PdfParser.PdfName("DeviceRGB")
+ procset = "ImageC" # color images
+ elif im.mode == "CMYK":
+ filter = "DCTDecode"
+ colorspace = PdfParser.PdfName("DeviceCMYK")
+ procset = "ImageC" # color images
+ decode = [1, 0, 1, 0, 1, 0, 1, 0]
+ else:
+ raise ValueError(f"cannot save mode {im.mode}")
+
+ #
+ # image
+
+ op = io.BytesIO()
+
+ if filter == "ASCIIHexDecode":
+ if bits == 1:
+ # FIXME: the hex encoder doesn't support packed 1-bit
+ # images; do things the hard way...
+ data = im.tobytes("raw", "1")
+ im = Image.new("L", im.size)
+ im.putdata(data)
+ ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
+ elif filter == "DCTDecode":
+ Image.SAVE["JPEG"](im, op, filename)
+ elif filter == "FlateDecode":
+ ImageFile._save(im, op, [("zip", (0, 0) + im.size, 0, im.mode)])
+ elif filter == "RunLengthDecode":
+ ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)])
+ else:
+ raise ValueError(f"unsupported PDF filter ({filter})")
+
+ #
+ # Get image characteristics
+
+ width, height = im.size
+
+ existing_pdf.write_obj(
+ image_refs[pageNumber],
+ stream=op.getvalue(),
+ Type=PdfParser.PdfName("XObject"),
+ Subtype=PdfParser.PdfName("Image"),
+ Width=width, # * 72.0 / resolution,
+ Height=height, # * 72.0 / resolution,
+ Filter=PdfParser.PdfName(filter),
+ BitsPerComponent=bits,
+ Decode=decode,
+ DecodeParams=params,
+ ColorSpace=colorspace,
+ )
+
+ #
+ # page
+
+ existing_pdf.write_page(
+ page_refs[pageNumber],
+ Resources=PdfParser.PdfDict(
+ ProcSet=[PdfParser.PdfName("PDF"), PdfParser.PdfName(procset)],
+ XObject=PdfParser.PdfDict(image=image_refs[pageNumber]),
+ ),
+ MediaBox=[
+ 0,
+ 0,
+ int(width * 72.0 / resolution),
+ int(height * 72.0 / resolution),
+ ],
+ Contents=contents_refs[pageNumber],
+ )
+
+ #
+ # page contents
+
+ page_contents = b"q %d 0 0 %d 0 0 cm /image Do Q\n" % (
+ int(width * 72.0 / resolution),
+ int(height * 72.0 / resolution),
+ )
+
+ existing_pdf.write_obj(contents_refs[pageNumber], stream=page_contents)
+
+ pageNumber += 1
+
+ #
+ # trailer
+ existing_pdf.write_xref_and_trailer()
+ if hasattr(fp, "flush"):
+ fp.flush()
+ existing_pdf.close()
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_save("PDF", _save)
+Image.register_save_all("PDF", _save_all)
+
+Image.register_extension("PDF", ".pdf")
+
+Image.register_mime("PDF", "application/pdf")
diff --git a/venv/Lib/site-packages/PIL/PdfParser.py b/venv/Lib/site-packages/PIL/PdfParser.py
new file mode 100644
index 0000000..86d78a9
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PdfParser.py
@@ -0,0 +1,995 @@
+import calendar
+import codecs
+import collections
+import mmap
+import os
+import re
+import time
+import zlib
+
+
+# see 7.9.2.2 Text String Type on page 86 and D.3 PDFDocEncoding Character Set
+# on page 656
+def encode_text(s):
+ return codecs.BOM_UTF16_BE + s.encode("utf_16_be")
+
+
+PDFDocEncoding = {
+ 0x16: "\u0017",
+ 0x18: "\u02D8",
+ 0x19: "\u02C7",
+ 0x1A: "\u02C6",
+ 0x1B: "\u02D9",
+ 0x1C: "\u02DD",
+ 0x1D: "\u02DB",
+ 0x1E: "\u02DA",
+ 0x1F: "\u02DC",
+ 0x80: "\u2022",
+ 0x81: "\u2020",
+ 0x82: "\u2021",
+ 0x83: "\u2026",
+ 0x84: "\u2014",
+ 0x85: "\u2013",
+ 0x86: "\u0192",
+ 0x87: "\u2044",
+ 0x88: "\u2039",
+ 0x89: "\u203A",
+ 0x8A: "\u2212",
+ 0x8B: "\u2030",
+ 0x8C: "\u201E",
+ 0x8D: "\u201C",
+ 0x8E: "\u201D",
+ 0x8F: "\u2018",
+ 0x90: "\u2019",
+ 0x91: "\u201A",
+ 0x92: "\u2122",
+ 0x93: "\uFB01",
+ 0x94: "\uFB02",
+ 0x95: "\u0141",
+ 0x96: "\u0152",
+ 0x97: "\u0160",
+ 0x98: "\u0178",
+ 0x99: "\u017D",
+ 0x9A: "\u0131",
+ 0x9B: "\u0142",
+ 0x9C: "\u0153",
+ 0x9D: "\u0161",
+ 0x9E: "\u017E",
+ 0xA0: "\u20AC",
+}
+
+
+def decode_text(b):
+ if b[: len(codecs.BOM_UTF16_BE)] == codecs.BOM_UTF16_BE:
+ return b[len(codecs.BOM_UTF16_BE) :].decode("utf_16_be")
+ else:
+ return "".join(PDFDocEncoding.get(byte, chr(byte)) for byte in b)
+
+
+class PdfFormatError(RuntimeError):
+ """An error that probably indicates a syntactic or semantic error in the
+ PDF file structure"""
+
+ pass
+
+
+def check_format_condition(condition, error_message):
+ if not condition:
+ raise PdfFormatError(error_message)
+
+
+class IndirectReference(
+ collections.namedtuple("IndirectReferenceTuple", ["object_id", "generation"])
+):
+ def __str__(self):
+ return "%s %s R" % self
+
+ def __bytes__(self):
+ return self.__str__().encode("us-ascii")
+
+ def __eq__(self, other):
+ return (
+ other.__class__ is self.__class__
+ and other.object_id == self.object_id
+ and other.generation == self.generation
+ )
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def __hash__(self):
+ return hash((self.object_id, self.generation))
+
+
+class IndirectObjectDef(IndirectReference):
+ def __str__(self):
+ return "%s %s obj" % self
+
+
+class XrefTable:
+ def __init__(self):
+ self.existing_entries = {} # object ID => (offset, generation)
+ self.new_entries = {} # object ID => (offset, generation)
+ self.deleted_entries = {0: 65536} # object ID => generation
+ self.reading_finished = False
+
+ def __setitem__(self, key, value):
+ if self.reading_finished:
+ self.new_entries[key] = value
+ else:
+ self.existing_entries[key] = value
+ if key in self.deleted_entries:
+ del self.deleted_entries[key]
+
+ def __getitem__(self, key):
+ try:
+ return self.new_entries[key]
+ except KeyError:
+ return self.existing_entries[key]
+
+ def __delitem__(self, key):
+ if key in self.new_entries:
+ generation = self.new_entries[key][1] + 1
+ del self.new_entries[key]
+ self.deleted_entries[key] = generation
+ elif key in self.existing_entries:
+ generation = self.existing_entries[key][1] + 1
+ self.deleted_entries[key] = generation
+ elif key in self.deleted_entries:
+ generation = self.deleted_entries[key]
+ else:
+ raise IndexError(
+ "object ID " + str(key) + " cannot be deleted because it doesn't exist"
+ )
+
+ def __contains__(self, key):
+ return key in self.existing_entries or key in self.new_entries
+
+ def __len__(self):
+ return len(
+ set(self.existing_entries.keys())
+ | set(self.new_entries.keys())
+ | set(self.deleted_entries.keys())
+ )
+
+ def keys(self):
+ return (
+ set(self.existing_entries.keys()) - set(self.deleted_entries.keys())
+ ) | set(self.new_entries.keys())
+
+ def write(self, f):
+ keys = sorted(set(self.new_entries.keys()) | set(self.deleted_entries.keys()))
+ deleted_keys = sorted(set(self.deleted_entries.keys()))
+ startxref = f.tell()
+ f.write(b"xref\n")
+ while keys:
+ # find a contiguous sequence of object IDs
+ prev = None
+ for index, key in enumerate(keys):
+ if prev is None or prev + 1 == key:
+ prev = key
+ else:
+ contiguous_keys = keys[:index]
+ keys = keys[index:]
+ break
+ else:
+ contiguous_keys = keys
+ keys = None
+ f.write(b"%d %d\n" % (contiguous_keys[0], len(contiguous_keys)))
+ for object_id in contiguous_keys:
+ if object_id in self.new_entries:
+ f.write(b"%010d %05d n \n" % self.new_entries[object_id])
+ else:
+ this_deleted_object_id = deleted_keys.pop(0)
+ check_format_condition(
+ object_id == this_deleted_object_id,
+ f"expected the next deleted object ID to be {object_id}, "
+ f"instead found {this_deleted_object_id}",
+ )
+ try:
+ next_in_linked_list = deleted_keys[0]
+ except IndexError:
+ next_in_linked_list = 0
+ f.write(
+ b"%010d %05d f \n"
+ % (next_in_linked_list, self.deleted_entries[object_id])
+ )
+ return startxref
+
+
+class PdfName:
+ def __init__(self, name):
+ if isinstance(name, PdfName):
+ self.name = name.name
+ elif isinstance(name, bytes):
+ self.name = name
+ else:
+ self.name = name.encode("us-ascii")
+
+ def name_as_str(self):
+ return self.name.decode("us-ascii")
+
+ def __eq__(self, other):
+ return (
+ isinstance(other, PdfName) and other.name == self.name
+ ) or other == self.name
+
+ def __hash__(self):
+ return hash(self.name)
+
+ def __repr__(self):
+ return f"PdfName({repr(self.name)})"
+
+ @classmethod
+ def from_pdf_stream(cls, data):
+ return cls(PdfParser.interpret_name(data))
+
+ allowed_chars = set(range(33, 127)) - {ord(c) for c in "#%/()<>[]{}"}
+
+ def __bytes__(self):
+ result = bytearray(b"/")
+ for b in self.name:
+ if b in self.allowed_chars:
+ result.append(b)
+ else:
+ result.extend(b"#%02X" % b)
+ return bytes(result)
+
+
+class PdfArray(list):
+ def __bytes__(self):
+ return b"[ " + b" ".join(pdf_repr(x) for x in self) + b" ]"
+
+
+class PdfDict(collections.UserDict):
+ def __setattr__(self, key, value):
+ if key == "data":
+ collections.UserDict.__setattr__(self, key, value)
+ else:
+ self[key.encode("us-ascii")] = value
+
+ def __getattr__(self, key):
+ try:
+ value = self[key.encode("us-ascii")]
+ except KeyError as e:
+ raise AttributeError(key) from e
+ if isinstance(value, bytes):
+ value = decode_text(value)
+ if key.endswith("Date"):
+ if value.startswith("D:"):
+ value = value[2:]
+
+ relationship = "Z"
+ if len(value) > 17:
+ relationship = value[14]
+ offset = int(value[15:17]) * 60
+ if len(value) > 20:
+ offset += int(value[18:20])
+
+ format = "%Y%m%d%H%M%S"[: len(value) - 2]
+ value = time.strptime(value[: len(format) + 2], format)
+ if relationship in ["+", "-"]:
+ offset *= 60
+ if relationship == "+":
+ offset *= -1
+ value = time.gmtime(calendar.timegm(value) + offset)
+ return value
+
+ def __bytes__(self):
+ out = bytearray(b"<<")
+ for key, value in self.items():
+ if value is None:
+ continue
+ value = pdf_repr(value)
+ out.extend(b"\n")
+ out.extend(bytes(PdfName(key)))
+ out.extend(b" ")
+ out.extend(value)
+ out.extend(b"\n>>")
+ return bytes(out)
+
+
+class PdfBinary:
+ def __init__(self, data):
+ self.data = data
+
+ def __bytes__(self):
+ return b"<%s>" % b"".join(b"%02X" % b for b in self.data)
+
+
+class PdfStream:
+ def __init__(self, dictionary, buf):
+ self.dictionary = dictionary
+ self.buf = buf
+
+ def decode(self):
+ try:
+ filter = self.dictionary.Filter
+ except AttributeError:
+ return self.buf
+ if filter == b"FlateDecode":
+ try:
+ expected_length = self.dictionary.DL
+ except AttributeError:
+ expected_length = self.dictionary.Length
+ return zlib.decompress(self.buf, bufsize=int(expected_length))
+ else:
+ raise NotImplementedError(
+ f"stream filter {repr(self.dictionary.Filter)} unknown/unsupported"
+ )
+
+
+def pdf_repr(x):
+ if x is True:
+ return b"true"
+ elif x is False:
+ return b"false"
+ elif x is None:
+ return b"null"
+ elif isinstance(x, (PdfName, PdfDict, PdfArray, PdfBinary)):
+ return bytes(x)
+ elif isinstance(x, int):
+ return str(x).encode("us-ascii")
+ elif isinstance(x, time.struct_time):
+ return b"(D:" + time.strftime("%Y%m%d%H%M%SZ", x).encode("us-ascii") + b")"
+ elif isinstance(x, dict):
+ return bytes(PdfDict(x))
+ elif isinstance(x, list):
+ return bytes(PdfArray(x))
+ elif isinstance(x, str):
+ return pdf_repr(encode_text(x))
+ elif isinstance(x, bytes):
+ # XXX escape more chars? handle binary garbage
+ x = x.replace(b"\\", b"\\\\")
+ x = x.replace(b"(", b"\\(")
+ x = x.replace(b")", b"\\)")
+ return b"(" + x + b")"
+ else:
+ return bytes(x)
+
+
+class PdfParser:
+ """Based on
+ https://www.adobe.com/content/dam/acom/en/devnet/acrobat/pdfs/PDF32000_2008.pdf
+ Supports PDF up to 1.4
+ """
+
+ def __init__(self, filename=None, f=None, buf=None, start_offset=0, mode="rb"):
+ if buf and f:
+ raise RuntimeError("specify buf or f or filename, but not both buf and f")
+ self.filename = filename
+ self.buf = buf
+ self.f = f
+ self.start_offset = start_offset
+ self.should_close_buf = False
+ self.should_close_file = False
+ if filename is not None and f is None:
+ self.f = f = open(filename, mode)
+ self.should_close_file = True
+ if f is not None:
+ self.buf = buf = self.get_buf_from_file(f)
+ self.should_close_buf = True
+ if not filename and hasattr(f, "name"):
+ self.filename = f.name
+ self.cached_objects = {}
+ if buf:
+ self.read_pdf_info()
+ else:
+ self.file_size_total = self.file_size_this = 0
+ self.root = PdfDict()
+ self.root_ref = None
+ self.info = PdfDict()
+ self.info_ref = None
+ self.page_tree_root = {}
+ self.pages = []
+ self.orig_pages = []
+ self.pages_ref = None
+ self.last_xref_section_offset = None
+ self.trailer_dict = {}
+ self.xref_table = XrefTable()
+ self.xref_table.reading_finished = True
+ if f:
+ self.seek_end()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ self.close()
+ return False # do not suppress exceptions
+
+ def start_writing(self):
+ self.close_buf()
+ self.seek_end()
+
+ def close_buf(self):
+ try:
+ self.buf.close()
+ except AttributeError:
+ pass
+ self.buf = None
+
+ def close(self):
+ if self.should_close_buf:
+ self.close_buf()
+ if self.f is not None and self.should_close_file:
+ self.f.close()
+ self.f = None
+
+ def seek_end(self):
+ self.f.seek(0, os.SEEK_END)
+
+ def write_header(self):
+ self.f.write(b"%PDF-1.4\n")
+
+ def write_comment(self, s):
+ self.f.write(f"% {s}\n".encode("utf-8"))
+
+ def write_catalog(self):
+ self.del_root()
+ self.root_ref = self.next_object_id(self.f.tell())
+ self.pages_ref = self.next_object_id(0)
+ self.rewrite_pages()
+ self.write_obj(self.root_ref, Type=PdfName(b"Catalog"), Pages=self.pages_ref)
+ self.write_obj(
+ self.pages_ref,
+ Type=PdfName(b"Pages"),
+ Count=len(self.pages),
+ Kids=self.pages,
+ )
+ return self.root_ref
+
+ def rewrite_pages(self):
+ pages_tree_nodes_to_delete = []
+ for i, page_ref in enumerate(self.orig_pages):
+ page_info = self.cached_objects[page_ref]
+ del self.xref_table[page_ref.object_id]
+ pages_tree_nodes_to_delete.append(page_info[PdfName(b"Parent")])
+ if page_ref not in self.pages:
+ # the page has been deleted
+ continue
+ # make dict keys into strings for passing to write_page
+ stringified_page_info = {}
+ for key, value in page_info.items():
+ # key should be a PdfName
+ stringified_page_info[key.name_as_str()] = value
+ stringified_page_info["Parent"] = self.pages_ref
+ new_page_ref = self.write_page(None, **stringified_page_info)
+ for j, cur_page_ref in enumerate(self.pages):
+ if cur_page_ref == page_ref:
+ # replace the page reference with the new one
+ self.pages[j] = new_page_ref
+ # delete redundant Pages tree nodes from xref table
+ for pages_tree_node_ref in pages_tree_nodes_to_delete:
+ while pages_tree_node_ref:
+ pages_tree_node = self.cached_objects[pages_tree_node_ref]
+ if pages_tree_node_ref.object_id in self.xref_table:
+ del self.xref_table[pages_tree_node_ref.object_id]
+ pages_tree_node_ref = pages_tree_node.get(b"Parent", None)
+ self.orig_pages = []
+
+ def write_xref_and_trailer(self, new_root_ref=None):
+ if new_root_ref:
+ self.del_root()
+ self.root_ref = new_root_ref
+ if self.info:
+ self.info_ref = self.write_obj(None, self.info)
+ start_xref = self.xref_table.write(self.f)
+ num_entries = len(self.xref_table)
+ trailer_dict = {b"Root": self.root_ref, b"Size": num_entries}
+ if self.last_xref_section_offset is not None:
+ trailer_dict[b"Prev"] = self.last_xref_section_offset
+ if self.info:
+ trailer_dict[b"Info"] = self.info_ref
+ self.last_xref_section_offset = start_xref
+ self.f.write(
+ b"trailer\n"
+ + bytes(PdfDict(trailer_dict))
+ + b"\nstartxref\n%d\n%%%%EOF" % start_xref
+ )
+
+ def write_page(self, ref, *objs, **dict_obj):
+ if isinstance(ref, int):
+ ref = self.pages[ref]
+ if "Type" not in dict_obj:
+ dict_obj["Type"] = PdfName(b"Page")
+ if "Parent" not in dict_obj:
+ dict_obj["Parent"] = self.pages_ref
+ return self.write_obj(ref, *objs, **dict_obj)
+
+ def write_obj(self, ref, *objs, **dict_obj):
+ f = self.f
+ if ref is None:
+ ref = self.next_object_id(f.tell())
+ else:
+ self.xref_table[ref.object_id] = (f.tell(), ref.generation)
+ f.write(bytes(IndirectObjectDef(*ref)))
+ stream = dict_obj.pop("stream", None)
+ if stream is not None:
+ dict_obj["Length"] = len(stream)
+ if dict_obj:
+ f.write(pdf_repr(dict_obj))
+ for obj in objs:
+ f.write(pdf_repr(obj))
+ if stream is not None:
+ f.write(b"stream\n")
+ f.write(stream)
+ f.write(b"\nendstream\n")
+ f.write(b"endobj\n")
+ return ref
+
+ def del_root(self):
+ if self.root_ref is None:
+ return
+ del self.xref_table[self.root_ref.object_id]
+ del self.xref_table[self.root[b"Pages"].object_id]
+
+ @staticmethod
+ def get_buf_from_file(f):
+ if hasattr(f, "getbuffer"):
+ return f.getbuffer()
+ elif hasattr(f, "getvalue"):
+ return f.getvalue()
+ else:
+ try:
+ return mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
+ except ValueError: # cannot mmap an empty file
+ return b""
+
+ def read_pdf_info(self):
+ self.file_size_total = len(self.buf)
+ self.file_size_this = self.file_size_total - self.start_offset
+ self.read_trailer()
+ self.root_ref = self.trailer_dict[b"Root"]
+ self.info_ref = self.trailer_dict.get(b"Info", None)
+ self.root = PdfDict(self.read_indirect(self.root_ref))
+ if self.info_ref is None:
+ self.info = PdfDict()
+ else:
+ self.info = PdfDict(self.read_indirect(self.info_ref))
+ check_format_condition(b"Type" in self.root, "/Type missing in Root")
+ check_format_condition(
+ self.root[b"Type"] == b"Catalog", "/Type in Root is not /Catalog"
+ )
+ check_format_condition(b"Pages" in self.root, "/Pages missing in Root")
+ check_format_condition(
+ isinstance(self.root[b"Pages"], IndirectReference),
+ "/Pages in Root is not an indirect reference",
+ )
+ self.pages_ref = self.root[b"Pages"]
+ self.page_tree_root = self.read_indirect(self.pages_ref)
+ self.pages = self.linearize_page_tree(self.page_tree_root)
+ # save the original list of page references
+ # in case the user modifies, adds or deletes some pages
+ # and we need to rewrite the pages and their list
+ self.orig_pages = self.pages[:]
+
+ def next_object_id(self, offset=None):
+ try:
+ # TODO: support reuse of deleted objects
+ reference = IndirectReference(max(self.xref_table.keys()) + 1, 0)
+ except ValueError:
+ reference = IndirectReference(1, 0)
+ if offset is not None:
+ self.xref_table[reference.object_id] = (offset, 0)
+ return reference
+
+ delimiter = br"[][()<>{}/%]"
+ delimiter_or_ws = br"[][()<>{}/%\000\011\012\014\015\040]"
+ whitespace = br"[\000\011\012\014\015\040]"
+ whitespace_or_hex = br"[\000\011\012\014\015\0400-9a-fA-F]"
+ whitespace_optional = whitespace + b"*"
+ whitespace_mandatory = whitespace + b"+"
+ whitespace_optional_no_nl = br"[\000\011\014\015\040]*" # no "\012" aka "\n"
+ newline_only = br"[\r\n]+"
+ newline = whitespace_optional_no_nl + newline_only + whitespace_optional_no_nl
+ re_trailer_end = re.compile(
+ whitespace_mandatory
+ + br"trailer"
+ + whitespace_optional
+ + br"\<\<(.*\>\>)"
+ + newline
+ + br"startxref"
+ + newline
+ + br"([0-9]+)"
+ + newline
+ + br"%%EOF"
+ + whitespace_optional
+ + br"$",
+ re.DOTALL,
+ )
+ re_trailer_prev = re.compile(
+ whitespace_optional
+ + br"trailer"
+ + whitespace_optional
+ + br"\<\<(.*?\>\>)"
+ + newline
+ + br"startxref"
+ + newline
+ + br"([0-9]+)"
+ + newline
+ + br"%%EOF"
+ + whitespace_optional,
+ re.DOTALL,
+ )
+
+ def read_trailer(self):
+ search_start_offset = len(self.buf) - 16384
+ if search_start_offset < self.start_offset:
+ search_start_offset = self.start_offset
+ m = self.re_trailer_end.search(self.buf, search_start_offset)
+ check_format_condition(m, "trailer end not found")
+ # make sure we found the LAST trailer
+ last_match = m
+ while m:
+ last_match = m
+ m = self.re_trailer_end.search(self.buf, m.start() + 16)
+ if not m:
+ m = last_match
+ trailer_data = m.group(1)
+ self.last_xref_section_offset = int(m.group(2))
+ self.trailer_dict = self.interpret_trailer(trailer_data)
+ self.xref_table = XrefTable()
+ self.read_xref_table(xref_section_offset=self.last_xref_section_offset)
+ if b"Prev" in self.trailer_dict:
+ self.read_prev_trailer(self.trailer_dict[b"Prev"])
+
+ def read_prev_trailer(self, xref_section_offset):
+ trailer_offset = self.read_xref_table(xref_section_offset=xref_section_offset)
+ m = self.re_trailer_prev.search(
+ self.buf[trailer_offset : trailer_offset + 16384]
+ )
+ check_format_condition(m, "previous trailer not found")
+ trailer_data = m.group(1)
+ check_format_condition(
+ int(m.group(2)) == xref_section_offset,
+ "xref section offset in previous trailer doesn't match what was expected",
+ )
+ trailer_dict = self.interpret_trailer(trailer_data)
+ if b"Prev" in trailer_dict:
+ self.read_prev_trailer(trailer_dict[b"Prev"])
+
+ re_whitespace_optional = re.compile(whitespace_optional)
+ re_name = re.compile(
+ whitespace_optional
+ + br"/([!-$&'*-.0-;=?-Z\\^-z|~]+)(?="
+ + delimiter_or_ws
+ + br")"
+ )
+ re_dict_start = re.compile(whitespace_optional + br"\<\<")
+ re_dict_end = re.compile(whitespace_optional + br"\>\>" + whitespace_optional)
+
+ @classmethod
+ def interpret_trailer(cls, trailer_data):
+ trailer = {}
+ offset = 0
+ while True:
+ m = cls.re_name.match(trailer_data, offset)
+ if not m:
+ m = cls.re_dict_end.match(trailer_data, offset)
+ check_format_condition(
+ m and m.end() == len(trailer_data),
+ "name not found in trailer, remaining data: "
+ + repr(trailer_data[offset:]),
+ )
+ break
+ key = cls.interpret_name(m.group(1))
+ value, offset = cls.get_value(trailer_data, m.end())
+ trailer[key] = value
+ check_format_condition(
+ b"Size" in trailer and isinstance(trailer[b"Size"], int),
+ "/Size not in trailer or not an integer",
+ )
+ check_format_condition(
+ b"Root" in trailer and isinstance(trailer[b"Root"], IndirectReference),
+ "/Root not in trailer or not an indirect reference",
+ )
+ return trailer
+
+ re_hashes_in_name = re.compile(br"([^#]*)(#([0-9a-fA-F]{2}))?")
+
+ @classmethod
+ def interpret_name(cls, raw, as_text=False):
+ name = b""
+ for m in cls.re_hashes_in_name.finditer(raw):
+ if m.group(3):
+ name += m.group(1) + bytearray.fromhex(m.group(3).decode("us-ascii"))
+ else:
+ name += m.group(1)
+ if as_text:
+ return name.decode("utf-8")
+ else:
+ return bytes(name)
+
+ re_null = re.compile(whitespace_optional + br"null(?=" + delimiter_or_ws + br")")
+ re_true = re.compile(whitespace_optional + br"true(?=" + delimiter_or_ws + br")")
+ re_false = re.compile(whitespace_optional + br"false(?=" + delimiter_or_ws + br")")
+ re_int = re.compile(
+ whitespace_optional + br"([-+]?[0-9]+)(?=" + delimiter_or_ws + br")"
+ )
+ re_real = re.compile(
+ whitespace_optional
+ + br"([-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+))(?="
+ + delimiter_or_ws
+ + br")"
+ )
+ re_array_start = re.compile(whitespace_optional + br"\[")
+ re_array_end = re.compile(whitespace_optional + br"]")
+ re_string_hex = re.compile(
+ whitespace_optional + br"\<(" + whitespace_or_hex + br"*)\>"
+ )
+ re_string_lit = re.compile(whitespace_optional + br"\(")
+ re_indirect_reference = re.compile(
+ whitespace_optional
+ + br"([-+]?[0-9]+)"
+ + whitespace_mandatory
+ + br"([-+]?[0-9]+)"
+ + whitespace_mandatory
+ + br"R(?="
+ + delimiter_or_ws
+ + br")"
+ )
+ re_indirect_def_start = re.compile(
+ whitespace_optional
+ + br"([-+]?[0-9]+)"
+ + whitespace_mandatory
+ + br"([-+]?[0-9]+)"
+ + whitespace_mandatory
+ + br"obj(?="
+ + delimiter_or_ws
+ + br")"
+ )
+ re_indirect_def_end = re.compile(
+ whitespace_optional + br"endobj(?=" + delimiter_or_ws + br")"
+ )
+ re_comment = re.compile(
+ br"(" + whitespace_optional + br"%[^\r\n]*" + newline + br")*"
+ )
+ re_stream_start = re.compile(whitespace_optional + br"stream\r?\n")
+ re_stream_end = re.compile(
+ whitespace_optional + br"endstream(?=" + delimiter_or_ws + br")"
+ )
+
+ @classmethod
+ def get_value(cls, data, offset, expect_indirect=None, max_nesting=-1):
+ if max_nesting == 0:
+ return None, None
+ m = cls.re_comment.match(data, offset)
+ if m:
+ offset = m.end()
+ m = cls.re_indirect_def_start.match(data, offset)
+ if m:
+ check_format_condition(
+ int(m.group(1)) > 0,
+ "indirect object definition: object ID must be greater than 0",
+ )
+ check_format_condition(
+ int(m.group(2)) >= 0,
+ "indirect object definition: generation must be non-negative",
+ )
+ check_format_condition(
+ expect_indirect is None
+ or expect_indirect
+ == IndirectReference(int(m.group(1)), int(m.group(2))),
+ "indirect object definition different than expected",
+ )
+ object, offset = cls.get_value(data, m.end(), max_nesting=max_nesting - 1)
+ if offset is None:
+ return object, None
+ m = cls.re_indirect_def_end.match(data, offset)
+ check_format_condition(m, "indirect object definition end not found")
+ return object, m.end()
+ check_format_condition(
+ not expect_indirect, "indirect object definition not found"
+ )
+ m = cls.re_indirect_reference.match(data, offset)
+ if m:
+ check_format_condition(
+ int(m.group(1)) > 0,
+ "indirect object reference: object ID must be greater than 0",
+ )
+ check_format_condition(
+ int(m.group(2)) >= 0,
+ "indirect object reference: generation must be non-negative",
+ )
+ return IndirectReference(int(m.group(1)), int(m.group(2))), m.end()
+ m = cls.re_dict_start.match(data, offset)
+ if m:
+ offset = m.end()
+ result = {}
+ m = cls.re_dict_end.match(data, offset)
+ while not m:
+ key, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1)
+ if offset is None:
+ return result, None
+ value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1)
+ result[key] = value
+ if offset is None:
+ return result, None
+ m = cls.re_dict_end.match(data, offset)
+ offset = m.end()
+ m = cls.re_stream_start.match(data, offset)
+ if m:
+ try:
+ stream_len = int(result[b"Length"])
+ except (TypeError, KeyError, ValueError) as e:
+ raise PdfFormatError(
+ "bad or missing Length in stream dict (%r)"
+ % result.get(b"Length", None)
+ ) from e
+ stream_data = data[m.end() : m.end() + stream_len]
+ m = cls.re_stream_end.match(data, m.end() + stream_len)
+ check_format_condition(m, "stream end not found")
+ offset = m.end()
+ result = PdfStream(PdfDict(result), stream_data)
+ else:
+ result = PdfDict(result)
+ return result, offset
+ m = cls.re_array_start.match(data, offset)
+ if m:
+ offset = m.end()
+ result = []
+ m = cls.re_array_end.match(data, offset)
+ while not m:
+ value, offset = cls.get_value(data, offset, max_nesting=max_nesting - 1)
+ result.append(value)
+ if offset is None:
+ return result, None
+ m = cls.re_array_end.match(data, offset)
+ return result, m.end()
+ m = cls.re_null.match(data, offset)
+ if m:
+ return None, m.end()
+ m = cls.re_true.match(data, offset)
+ if m:
+ return True, m.end()
+ m = cls.re_false.match(data, offset)
+ if m:
+ return False, m.end()
+ m = cls.re_name.match(data, offset)
+ if m:
+ return PdfName(cls.interpret_name(m.group(1))), m.end()
+ m = cls.re_int.match(data, offset)
+ if m:
+ return int(m.group(1)), m.end()
+ m = cls.re_real.match(data, offset)
+ if m:
+ # XXX Decimal instead of float???
+ return float(m.group(1)), m.end()
+ m = cls.re_string_hex.match(data, offset)
+ if m:
+ # filter out whitespace
+ hex_string = bytearray(
+ [b for b in m.group(1) if b in b"0123456789abcdefABCDEF"]
+ )
+ if len(hex_string) % 2 == 1:
+ # append a 0 if the length is not even - yes, at the end
+ hex_string.append(ord(b"0"))
+ return bytearray.fromhex(hex_string.decode("us-ascii")), m.end()
+ m = cls.re_string_lit.match(data, offset)
+ if m:
+ return cls.get_literal_string(data, m.end())
+ # return None, offset # fallback (only for debugging)
+ raise PdfFormatError("unrecognized object: " + repr(data[offset : offset + 32]))
+
+ re_lit_str_token = re.compile(
+ br"(\\[nrtbf()\\])|(\\[0-9]{1,3})|(\\(\r\n|\r|\n))|(\r\n|\r|\n)|(\()|(\))"
+ )
+ escaped_chars = {
+ b"n": b"\n",
+ b"r": b"\r",
+ b"t": b"\t",
+ b"b": b"\b",
+ b"f": b"\f",
+ b"(": b"(",
+ b")": b")",
+ b"\\": b"\\",
+ ord(b"n"): b"\n",
+ ord(b"r"): b"\r",
+ ord(b"t"): b"\t",
+ ord(b"b"): b"\b",
+ ord(b"f"): b"\f",
+ ord(b"("): b"(",
+ ord(b")"): b")",
+ ord(b"\\"): b"\\",
+ }
+
+ @classmethod
+ def get_literal_string(cls, data, offset):
+ nesting_depth = 0
+ result = bytearray()
+ for m in cls.re_lit_str_token.finditer(data, offset):
+ result.extend(data[offset : m.start()])
+ if m.group(1):
+ result.extend(cls.escaped_chars[m.group(1)[1]])
+ elif m.group(2):
+ result.append(int(m.group(2)[1:], 8))
+ elif m.group(3):
+ pass
+ elif m.group(5):
+ result.extend(b"\n")
+ elif m.group(6):
+ result.extend(b"(")
+ nesting_depth += 1
+ elif m.group(7):
+ if nesting_depth == 0:
+ return bytes(result), m.end()
+ result.extend(b")")
+ nesting_depth -= 1
+ offset = m.end()
+ raise PdfFormatError("unfinished literal string")
+
+ re_xref_section_start = re.compile(whitespace_optional + br"xref" + newline)
+ re_xref_subsection_start = re.compile(
+ whitespace_optional
+ + br"([0-9]+)"
+ + whitespace_mandatory
+ + br"([0-9]+)"
+ + whitespace_optional
+ + newline_only
+ )
+ re_xref_entry = re.compile(br"([0-9]{10}) ([0-9]{5}) ([fn])( \r| \n|\r\n)")
+
+ def read_xref_table(self, xref_section_offset):
+ subsection_found = False
+ m = self.re_xref_section_start.match(
+ self.buf, xref_section_offset + self.start_offset
+ )
+ check_format_condition(m, "xref section start not found")
+ offset = m.end()
+ while True:
+ m = self.re_xref_subsection_start.match(self.buf, offset)
+ if not m:
+ check_format_condition(
+ subsection_found, "xref subsection start not found"
+ )
+ break
+ subsection_found = True
+ offset = m.end()
+ first_object = int(m.group(1))
+ num_objects = int(m.group(2))
+ for i in range(first_object, first_object + num_objects):
+ m = self.re_xref_entry.match(self.buf, offset)
+ check_format_condition(m, "xref entry not found")
+ offset = m.end()
+ is_free = m.group(3) == b"f"
+ generation = int(m.group(2))
+ if not is_free:
+ new_entry = (int(m.group(1)), generation)
+ check_format_condition(
+ i not in self.xref_table or self.xref_table[i] == new_entry,
+ "xref entry duplicated (and not identical)",
+ )
+ self.xref_table[i] = new_entry
+ return offset
+
+ def read_indirect(self, ref, max_nesting=-1):
+ offset, generation = self.xref_table[ref[0]]
+ check_format_condition(
+ generation == ref[1],
+ f"expected to find generation {ref[1]} for object ID {ref[0]} in xref "
+ f"table, instead found generation {generation} at offset {offset}",
+ )
+ value = self.get_value(
+ self.buf,
+ offset + self.start_offset,
+ expect_indirect=IndirectReference(*ref),
+ max_nesting=max_nesting,
+ )[0]
+ self.cached_objects[ref] = value
+ return value
+
+ def linearize_page_tree(self, node=None):
+ if node is None:
+ node = self.page_tree_root
+ check_format_condition(
+ node[b"Type"] == b"Pages", "/Type of page tree node is not /Pages"
+ )
+ pages = []
+ for kid in node[b"Kids"]:
+ kid_object = self.read_indirect(kid)
+ if kid_object[b"Type"] == b"Page":
+ pages.append(kid)
+ else:
+ pages.extend(self.linearize_page_tree(node=kid_object))
+ return pages
diff --git a/venv/Lib/site-packages/PIL/PixarImagePlugin.py b/venv/Lib/site-packages/PIL/PixarImagePlugin.py
new file mode 100644
index 0000000..c4860b6
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PixarImagePlugin.py
@@ -0,0 +1,70 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PIXAR raster support for PIL
+#
+# history:
+# 97-01-29 fl Created
+#
+# notes:
+# This is incomplete; it is based on a few samples created with
+# Photoshop 2.5 and 3.0, and a summary description provided by
+# Greg Coats . Hopefully, "L" and
+# "RGBA" support will be added in future versions.
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from . import Image, ImageFile
+from ._binary import i16le as i16
+
+#
+# helpers
+
+
+def _accept(prefix):
+ return prefix[:4] == b"\200\350\000\000"
+
+
+##
+# Image plugin for PIXAR raster images.
+
+
+class PixarImageFile(ImageFile.ImageFile):
+
+ format = "PIXAR"
+ format_description = "PIXAR raster image"
+
+ def _open(self):
+
+ # assuming a 4-byte magic label
+ s = self.fp.read(4)
+ if not _accept(s):
+ raise SyntaxError("not a PIXAR file")
+
+ # read rest of header
+ s = s + self.fp.read(508)
+
+ self._size = i16(s, 418), i16(s, 416)
+
+ # get channel/depth descriptions
+ mode = i16(s, 424), i16(s, 426)
+
+ if mode == (14, 2):
+ self.mode = "RGB"
+ # FIXME: to be continued...
+
+ # create tile descriptor (assuming "dumped")
+ self.tile = [("raw", (0, 0) + self.size, 1024, (self.mode, 0, 1))]
+
+
+#
+# --------------------------------------------------------------------
+
+Image.register_open(PixarImageFile.format, PixarImageFile, _accept)
+
+Image.register_extension(PixarImageFile.format, ".pxr")
diff --git a/venv/Lib/site-packages/PIL/PngImagePlugin.py b/venv/Lib/site-packages/PIL/PngImagePlugin.py
new file mode 100644
index 0000000..2d4ac76
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PngImagePlugin.py
@@ -0,0 +1,1395 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PNG support code
+#
+# See "PNG (Portable Network Graphics) Specification, version 1.0;
+# W3C Recommendation", 1996-10-01, Thomas Boutell (ed.).
+#
+# history:
+# 1996-05-06 fl Created (couldn't resist it)
+# 1996-12-14 fl Upgraded, added read and verify support (0.2)
+# 1996-12-15 fl Separate PNG stream parser
+# 1996-12-29 fl Added write support, added getchunks
+# 1996-12-30 fl Eliminated circular references in decoder (0.3)
+# 1998-07-12 fl Read/write 16-bit images as mode I (0.4)
+# 2001-02-08 fl Added transparency support (from Zircon) (0.5)
+# 2001-04-16 fl Don't close data source in "open" method (0.6)
+# 2004-02-24 fl Don't even pretend to support interlaced files (0.7)
+# 2004-08-31 fl Do basic sanity check on chunk identifiers (0.8)
+# 2004-09-20 fl Added PngInfo chunk container
+# 2004-12-18 fl Added DPI read support (based on code by Niki Spahiev)
+# 2008-08-13 fl Added tRNS support for RGB images
+# 2009-03-06 fl Support for preserving ICC profiles (by Florian Hoech)
+# 2009-03-08 fl Added zTXT support (from Lowell Alleman)
+# 2009-03-29 fl Read interlaced PNG files (from Conrado Porto Lopes Gouvua)
+#
+# Copyright (c) 1997-2009 by Secret Labs AB
+# Copyright (c) 1996 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import itertools
+import logging
+import re
+import struct
+import warnings
+import zlib
+
+from . import Image, ImageChops, ImageFile, ImagePalette, ImageSequence
+from ._binary import i16be as i16
+from ._binary import i32be as i32
+from ._binary import o8
+from ._binary import o16be as o16
+from ._binary import o32be as o32
+
+logger = logging.getLogger(__name__)
+
+is_cid = re.compile(br"\w\w\w\w").match
+
+
+_MAGIC = b"\211PNG\r\n\032\n"
+
+
+_MODES = {
+ # supported bits/color combinations, and corresponding modes/rawmodes
+ # Greyscale
+ (1, 0): ("1", "1"),
+ (2, 0): ("L", "L;2"),
+ (4, 0): ("L", "L;4"),
+ (8, 0): ("L", "L"),
+ (16, 0): ("I", "I;16B"),
+ # Truecolour
+ (8, 2): ("RGB", "RGB"),
+ (16, 2): ("RGB", "RGB;16B"),
+ # Indexed-colour
+ (1, 3): ("P", "P;1"),
+ (2, 3): ("P", "P;2"),
+ (4, 3): ("P", "P;4"),
+ (8, 3): ("P", "P"),
+ # Greyscale with alpha
+ (8, 4): ("LA", "LA"),
+ (16, 4): ("RGBA", "LA;16B"), # LA;16B->LA not yet available
+ # Truecolour with alpha
+ (8, 6): ("RGBA", "RGBA"),
+ (16, 6): ("RGBA", "RGBA;16B"),
+}
+
+
+_simple_palette = re.compile(b"^\xff*\x00\xff*$")
+
+MAX_TEXT_CHUNK = ImageFile.SAFEBLOCK
+"""
+Maximum decompressed size for a iTXt or zTXt chunk.
+Eliminates decompression bombs where compressed chunks can expand 1000x.
+See :ref:`Text in PNG File Format`.
+"""
+MAX_TEXT_MEMORY = 64 * MAX_TEXT_CHUNK
+"""
+Set the maximum total text chunk size.
+See :ref:`Text in PNG File Format`.
+"""
+
+
+# APNG frame disposal modes
+APNG_DISPOSE_OP_NONE = 0
+"""
+No disposal is done on this frame before rendering the next frame.
+See :ref:`Saving APNG sequences`.
+"""
+APNG_DISPOSE_OP_BACKGROUND = 1
+"""
+This frame’s modified region is cleared to fully transparent black before rendering
+the next frame.
+See :ref:`Saving APNG sequences`.
+"""
+APNG_DISPOSE_OP_PREVIOUS = 2
+"""
+This frame’s modified region is reverted to the previous frame’s contents before
+rendering the next frame.
+See :ref:`Saving APNG sequences`.
+"""
+
+# APNG frame blend modes
+APNG_BLEND_OP_SOURCE = 0
+"""
+All color components of this frame, including alpha, overwrite the previous output
+image contents.
+See :ref:`Saving APNG sequences`.
+"""
+APNG_BLEND_OP_OVER = 1
+"""
+This frame should be alpha composited with the previous output image contents.
+See :ref:`Saving APNG sequences`.
+"""
+
+
+def _safe_zlib_decompress(s):
+ dobj = zlib.decompressobj()
+ plaintext = dobj.decompress(s, MAX_TEXT_CHUNK)
+ if dobj.unconsumed_tail:
+ raise ValueError("Decompressed Data Too Large")
+ return plaintext
+
+
+def _crc32(data, seed=0):
+ return zlib.crc32(data, seed) & 0xFFFFFFFF
+
+
+# --------------------------------------------------------------------
+# Support classes. Suitable for PNG and related formats like MNG etc.
+
+
+class ChunkStream:
+ def __init__(self, fp):
+
+ self.fp = fp
+ self.queue = []
+
+ def read(self):
+ """Fetch a new chunk. Returns header information."""
+ cid = None
+
+ if self.queue:
+ cid, pos, length = self.queue.pop()
+ self.fp.seek(pos)
+ else:
+ s = self.fp.read(8)
+ cid = s[4:]
+ pos = self.fp.tell()
+ length = i32(s)
+
+ if not is_cid(cid):
+ if not ImageFile.LOAD_TRUNCATED_IMAGES:
+ raise SyntaxError(f"broken PNG file (chunk {repr(cid)})")
+
+ return cid, pos, length
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def close(self):
+ self.queue = self.crc = self.fp = None
+
+ def push(self, cid, pos, length):
+
+ self.queue.append((cid, pos, length))
+
+ def call(self, cid, pos, length):
+ """Call the appropriate chunk handler"""
+
+ logger.debug("STREAM %r %s %s", cid, pos, length)
+ return getattr(self, "chunk_" + cid.decode("ascii"))(pos, length)
+
+ def crc(self, cid, data):
+ """Read and verify checksum"""
+
+ # Skip CRC checks for ancillary chunks if allowed to load truncated
+ # images
+ # 5th byte of first char is 1 [specs, section 5.4]
+ if ImageFile.LOAD_TRUNCATED_IMAGES and (cid[0] >> 5 & 1):
+ self.crc_skip(cid, data)
+ return
+
+ try:
+ crc1 = _crc32(data, _crc32(cid))
+ crc2 = i32(self.fp.read(4))
+ if crc1 != crc2:
+ raise SyntaxError(
+ f"broken PNG file (bad header checksum in {repr(cid)})"
+ )
+ except struct.error as e:
+ raise SyntaxError(
+ f"broken PNG file (incomplete checksum in {repr(cid)})"
+ ) from e
+
+ def crc_skip(self, cid, data):
+ """Read checksum. Used if the C module is not present"""
+
+ self.fp.read(4)
+
+ def verify(self, endchunk=b"IEND"):
+
+ # Simple approach; just calculate checksum for all remaining
+ # blocks. Must be called directly after open.
+
+ cids = []
+
+ while True:
+ try:
+ cid, pos, length = self.read()
+ except struct.error as e:
+ raise OSError("truncated PNG file") from e
+
+ if cid == endchunk:
+ break
+ self.crc(cid, ImageFile._safe_read(self.fp, length))
+ cids.append(cid)
+
+ return cids
+
+
+class iTXt(str):
+ """
+ Subclass of string to allow iTXt chunks to look like strings while
+ keeping their extra information
+
+ """
+
+ @staticmethod
+ def __new__(cls, text, lang=None, tkey=None):
+ """
+ :param cls: the class to use when creating the instance
+ :param text: value for this key
+ :param lang: language code
+ :param tkey: UTF-8 version of the key name
+ """
+
+ self = str.__new__(cls, text)
+ self.lang = lang
+ self.tkey = tkey
+ return self
+
+
+class PngInfo:
+ """
+ PNG chunk container (for use with save(pnginfo=))
+
+ """
+
+ def __init__(self):
+ self.chunks = []
+
+ def add(self, cid, data, after_idat=False):
+ """Appends an arbitrary chunk. Use with caution.
+
+ :param cid: a byte string, 4 bytes long.
+ :param data: a byte string of the encoded data
+ :param after_idat: for use with private chunks. Whether the chunk
+ should be written after IDAT
+
+ """
+
+ chunk = [cid, data]
+ if after_idat:
+ chunk.append(True)
+ self.chunks.append(tuple(chunk))
+
+ def add_itxt(self, key, value, lang="", tkey="", zip=False):
+ """Appends an iTXt chunk.
+
+ :param key: latin-1 encodable text key name
+ :param value: value for this key
+ :param lang: language code
+ :param tkey: UTF-8 version of the key name
+ :param zip: compression flag
+
+ """
+
+ if not isinstance(key, bytes):
+ key = key.encode("latin-1", "strict")
+ if not isinstance(value, bytes):
+ value = value.encode("utf-8", "strict")
+ if not isinstance(lang, bytes):
+ lang = lang.encode("utf-8", "strict")
+ if not isinstance(tkey, bytes):
+ tkey = tkey.encode("utf-8", "strict")
+
+ if zip:
+ self.add(
+ b"iTXt",
+ key + b"\0\x01\0" + lang + b"\0" + tkey + b"\0" + zlib.compress(value),
+ )
+ else:
+ self.add(b"iTXt", key + b"\0\0\0" + lang + b"\0" + tkey + b"\0" + value)
+
+ def add_text(self, key, value, zip=False):
+ """Appends a text chunk.
+
+ :param key: latin-1 encodable text key name
+ :param value: value for this key, text or an
+ :py:class:`PIL.PngImagePlugin.iTXt` instance
+ :param zip: compression flag
+
+ """
+ if isinstance(value, iTXt):
+ return self.add_itxt(key, value, value.lang, value.tkey, zip=zip)
+
+ # The tEXt chunk stores latin-1 text
+ if not isinstance(value, bytes):
+ try:
+ value = value.encode("latin-1", "strict")
+ except UnicodeError:
+ return self.add_itxt(key, value, zip=zip)
+
+ if not isinstance(key, bytes):
+ key = key.encode("latin-1", "strict")
+
+ if zip:
+ self.add(b"zTXt", key + b"\0\0" + zlib.compress(value))
+ else:
+ self.add(b"tEXt", key + b"\0" + value)
+
+
+# --------------------------------------------------------------------
+# PNG image stream (IHDR/IEND)
+
+
+class PngStream(ChunkStream):
+ def __init__(self, fp):
+ super().__init__(fp)
+
+ # local copies of Image attributes
+ self.im_info = {}
+ self.im_text = {}
+ self.im_size = (0, 0)
+ self.im_mode = None
+ self.im_tile = None
+ self.im_palette = None
+ self.im_custom_mimetype = None
+ self.im_n_frames = None
+ self._seq_num = None
+ self.rewind_state = None
+
+ self.text_memory = 0
+
+ def check_text_memory(self, chunklen):
+ self.text_memory += chunklen
+ if self.text_memory > MAX_TEXT_MEMORY:
+ raise ValueError(
+ "Too much memory used in text chunks: "
+ f"{self.text_memory}>MAX_TEXT_MEMORY"
+ )
+
+ def save_rewind(self):
+ self.rewind_state = {
+ "info": self.im_info.copy(),
+ "tile": self.im_tile,
+ "seq_num": self._seq_num,
+ }
+
+ def rewind(self):
+ self.im_info = self.rewind_state["info"]
+ self.im_tile = self.rewind_state["tile"]
+ self._seq_num = self.rewind_state["seq_num"]
+
+ def chunk_iCCP(self, pos, length):
+
+ # ICC profile
+ s = ImageFile._safe_read(self.fp, length)
+ # according to PNG spec, the iCCP chunk contains:
+ # Profile name 1-79 bytes (character string)
+ # Null separator 1 byte (null character)
+ # Compression method 1 byte (0)
+ # Compressed profile n bytes (zlib with deflate compression)
+ i = s.find(b"\0")
+ logger.debug("iCCP profile name %r", s[:i])
+ logger.debug("Compression method %s", s[i])
+ comp_method = s[i]
+ if comp_method != 0:
+ raise SyntaxError(f"Unknown compression method {comp_method} in iCCP chunk")
+ try:
+ icc_profile = _safe_zlib_decompress(s[i + 2 :])
+ except ValueError:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ icc_profile = None
+ else:
+ raise
+ except zlib.error:
+ icc_profile = None # FIXME
+ self.im_info["icc_profile"] = icc_profile
+ return s
+
+ def chunk_IHDR(self, pos, length):
+
+ # image header
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_size = i32(s, 0), i32(s, 4)
+ try:
+ self.im_mode, self.im_rawmode = _MODES[(s[8], s[9])]
+ except Exception:
+ pass
+ if s[12]:
+ self.im_info["interlace"] = 1
+ if s[11]:
+ raise SyntaxError("unknown filter category")
+ return s
+
+ def chunk_IDAT(self, pos, length):
+
+ # image data
+ if "bbox" in self.im_info:
+ tile = [("zip", self.im_info["bbox"], pos, self.im_rawmode)]
+ else:
+ if self.im_n_frames is not None:
+ self.im_info["default_image"] = True
+ tile = [("zip", (0, 0) + self.im_size, pos, self.im_rawmode)]
+ self.im_tile = tile
+ self.im_idat = length
+ raise EOFError
+
+ def chunk_IEND(self, pos, length):
+
+ # end of PNG image
+ raise EOFError
+
+ def chunk_PLTE(self, pos, length):
+
+ # palette
+ s = ImageFile._safe_read(self.fp, length)
+ if self.im_mode == "P":
+ self.im_palette = "RGB", s
+ return s
+
+ def chunk_tRNS(self, pos, length):
+
+ # transparency
+ s = ImageFile._safe_read(self.fp, length)
+ if self.im_mode == "P":
+ if _simple_palette.match(s):
+ # tRNS contains only one full-transparent entry,
+ # other entries are full opaque
+ i = s.find(b"\0")
+ if i >= 0:
+ self.im_info["transparency"] = i
+ else:
+ # otherwise, we have a byte string with one alpha value
+ # for each palette entry
+ self.im_info["transparency"] = s
+ elif self.im_mode in ("1", "L", "I"):
+ self.im_info["transparency"] = i16(s)
+ elif self.im_mode == "RGB":
+ self.im_info["transparency"] = i16(s), i16(s, 2), i16(s, 4)
+ return s
+
+ def chunk_gAMA(self, pos, length):
+ # gamma setting
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_info["gamma"] = i32(s) / 100000.0
+ return s
+
+ def chunk_cHRM(self, pos, length):
+ # chromaticity, 8 unsigned ints, actual value is scaled by 100,000
+ # WP x,y, Red x,y, Green x,y Blue x,y
+
+ s = ImageFile._safe_read(self.fp, length)
+ raw_vals = struct.unpack(">%dI" % (len(s) // 4), s)
+ self.im_info["chromaticity"] = tuple(elt / 100000.0 for elt in raw_vals)
+ return s
+
+ def chunk_sRGB(self, pos, length):
+ # srgb rendering intent, 1 byte
+ # 0 perceptual
+ # 1 relative colorimetric
+ # 2 saturation
+ # 3 absolute colorimetric
+
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_info["srgb"] = s[0]
+ return s
+
+ def chunk_pHYs(self, pos, length):
+
+ # pixels per unit
+ s = ImageFile._safe_read(self.fp, length)
+ px, py = i32(s, 0), i32(s, 4)
+ unit = s[8]
+ if unit == 1: # meter
+ dpi = int(px * 0.0254 + 0.5), int(py * 0.0254 + 0.5)
+ self.im_info["dpi"] = dpi
+ elif unit == 0:
+ self.im_info["aspect"] = px, py
+ return s
+
+ def chunk_tEXt(self, pos, length):
+
+ # text
+ s = ImageFile._safe_read(self.fp, length)
+ try:
+ k, v = s.split(b"\0", 1)
+ except ValueError:
+ # fallback for broken tEXt tags
+ k = s
+ v = b""
+ if k:
+ k = k.decode("latin-1", "strict")
+ v_str = v.decode("latin-1", "replace")
+
+ self.im_info[k] = v if k == "exif" else v_str
+ self.im_text[k] = v_str
+ self.check_text_memory(len(v_str))
+
+ return s
+
+ def chunk_zTXt(self, pos, length):
+
+ # compressed text
+ s = ImageFile._safe_read(self.fp, length)
+ try:
+ k, v = s.split(b"\0", 1)
+ except ValueError:
+ k = s
+ v = b""
+ if v:
+ comp_method = v[0]
+ else:
+ comp_method = 0
+ if comp_method != 0:
+ raise SyntaxError(f"Unknown compression method {comp_method} in zTXt chunk")
+ try:
+ v = _safe_zlib_decompress(v[1:])
+ except ValueError:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ v = b""
+ else:
+ raise
+ except zlib.error:
+ v = b""
+
+ if k:
+ k = k.decode("latin-1", "strict")
+ v = v.decode("latin-1", "replace")
+
+ self.im_info[k] = self.im_text[k] = v
+ self.check_text_memory(len(v))
+
+ return s
+
+ def chunk_iTXt(self, pos, length):
+
+ # international text
+ r = s = ImageFile._safe_read(self.fp, length)
+ try:
+ k, r = r.split(b"\0", 1)
+ except ValueError:
+ return s
+ if len(r) < 2:
+ return s
+ cf, cm, r = r[0], r[1], r[2:]
+ try:
+ lang, tk, v = r.split(b"\0", 2)
+ except ValueError:
+ return s
+ if cf != 0:
+ if cm == 0:
+ try:
+ v = _safe_zlib_decompress(v)
+ except ValueError:
+ if ImageFile.LOAD_TRUNCATED_IMAGES:
+ return s
+ else:
+ raise
+ except zlib.error:
+ return s
+ else:
+ return s
+ try:
+ k = k.decode("latin-1", "strict")
+ lang = lang.decode("utf-8", "strict")
+ tk = tk.decode("utf-8", "strict")
+ v = v.decode("utf-8", "strict")
+ except UnicodeError:
+ return s
+
+ self.im_info[k] = self.im_text[k] = iTXt(v, lang, tk)
+ self.check_text_memory(len(v))
+
+ return s
+
+ def chunk_eXIf(self, pos, length):
+ s = ImageFile._safe_read(self.fp, length)
+ self.im_info["exif"] = b"Exif\x00\x00" + s
+ return s
+
+ # APNG chunks
+ def chunk_acTL(self, pos, length):
+ s = ImageFile._safe_read(self.fp, length)
+ if self.im_n_frames is not None:
+ self.im_n_frames = None
+ warnings.warn("Invalid APNG, will use default PNG image if possible")
+ return s
+ n_frames = i32(s)
+ if n_frames == 0 or n_frames > 0x80000000:
+ warnings.warn("Invalid APNG, will use default PNG image if possible")
+ return s
+ self.im_n_frames = n_frames
+ self.im_info["loop"] = i32(s, 4)
+ self.im_custom_mimetype = "image/apng"
+ return s
+
+ def chunk_fcTL(self, pos, length):
+ s = ImageFile._safe_read(self.fp, length)
+ seq = i32(s)
+ if (self._seq_num is None and seq != 0) or (
+ self._seq_num is not None and self._seq_num != seq - 1
+ ):
+ raise SyntaxError("APNG contains frame sequence errors")
+ self._seq_num = seq
+ width, height = i32(s, 4), i32(s, 8)
+ px, py = i32(s, 12), i32(s, 16)
+ im_w, im_h = self.im_size
+ if px + width > im_w or py + height > im_h:
+ raise SyntaxError("APNG contains invalid frames")
+ self.im_info["bbox"] = (px, py, px + width, py + height)
+ delay_num, delay_den = i16(s, 20), i16(s, 22)
+ if delay_den == 0:
+ delay_den = 100
+ self.im_info["duration"] = float(delay_num) / float(delay_den) * 1000
+ self.im_info["disposal"] = s[24]
+ self.im_info["blend"] = s[25]
+ return s
+
+ def chunk_fdAT(self, pos, length):
+ s = ImageFile._safe_read(self.fp, 4)
+ seq = i32(s)
+ if self._seq_num != seq - 1:
+ raise SyntaxError("APNG contains frame sequence errors")
+ self._seq_num = seq
+ return self.chunk_IDAT(pos + 4, length - 4)
+
+
+# --------------------------------------------------------------------
+# PNG reader
+
+
+def _accept(prefix):
+ return prefix[:8] == _MAGIC
+
+
+##
+# Image plugin for PNG images.
+
+
+class PngImageFile(ImageFile.ImageFile):
+
+ format = "PNG"
+ format_description = "Portable network graphics"
+
+ def _open(self):
+
+ if not _accept(self.fp.read(8)):
+ raise SyntaxError("not a PNG file")
+ self.__fp = self.fp
+ self.__frame = 0
+
+ #
+ # Parse headers up to the first IDAT or fDAT chunk
+
+ self.private_chunks = []
+ self.png = PngStream(self.fp)
+
+ while True:
+
+ #
+ # get next chunk
+
+ cid, pos, length = self.png.read()
+
+ try:
+ s = self.png.call(cid, pos, length)
+ except EOFError:
+ break
+ except AttributeError:
+ logger.debug("%r %s %s (unknown)", cid, pos, length)
+ s = ImageFile._safe_read(self.fp, length)
+ if cid[1:2].islower():
+ self.private_chunks.append((cid, s))
+
+ self.png.crc(cid, s)
+
+ #
+ # Copy relevant attributes from the PngStream. An alternative
+ # would be to let the PngStream class modify these attributes
+ # directly, but that introduces circular references which are
+ # difficult to break if things go wrong in the decoder...
+ # (believe me, I've tried ;-)
+
+ self.mode = self.png.im_mode
+ self._size = self.png.im_size
+ self.info = self.png.im_info
+ self._text = None
+ self.tile = self.png.im_tile
+ self.custom_mimetype = self.png.im_custom_mimetype
+ self.n_frames = self.png.im_n_frames or 1
+ self.default_image = self.info.get("default_image", False)
+
+ if self.png.im_palette:
+ rawmode, data = self.png.im_palette
+ self.palette = ImagePalette.raw(rawmode, data)
+
+ if cid == b"fdAT":
+ self.__prepare_idat = length - 4
+ else:
+ self.__prepare_idat = length # used by load_prepare()
+
+ if self.png.im_n_frames is not None:
+ self._close_exclusive_fp_after_loading = False
+ self.png.save_rewind()
+ self.__rewind_idat = self.__prepare_idat
+ self.__rewind = self.__fp.tell()
+ if self.default_image:
+ # IDAT chunk contains default image and not first animation frame
+ self.n_frames += 1
+ self._seek(0)
+ self.is_animated = self.n_frames > 1
+
+ @property
+ def text(self):
+ # experimental
+ if self._text is None:
+ # iTxt, tEXt and zTXt chunks may appear at the end of the file
+ # So load the file to ensure that they are read
+ if self.is_animated:
+ frame = self.__frame
+ # for APNG, seek to the final frame before loading
+ self.seek(self.n_frames - 1)
+ self.load()
+ if self.is_animated:
+ self.seek(frame)
+ return self._text
+
+ def verify(self):
+ """Verify PNG file"""
+
+ if self.fp is None:
+ raise RuntimeError("verify must be called directly after open")
+
+ # back up to beginning of IDAT block
+ self.fp.seek(self.tile[0][2] - 8)
+
+ self.png.verify()
+ self.png.close()
+
+ if self._exclusive_fp:
+ self.fp.close()
+ self.fp = None
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+ if frame < self.__frame:
+ self._seek(0, True)
+
+ last_frame = self.__frame
+ for f in range(self.__frame + 1, frame + 1):
+ try:
+ self._seek(f)
+ except EOFError as e:
+ self.seek(last_frame)
+ raise EOFError("no more images in APNG file") from e
+
+ def _seek(self, frame, rewind=False):
+ if frame == 0:
+ if rewind:
+ self.__fp.seek(self.__rewind)
+ self.png.rewind()
+ self.__prepare_idat = self.__rewind_idat
+ self.im = None
+ if self.pyaccess:
+ self.pyaccess = None
+ self.info = self.png.im_info
+ self.tile = self.png.im_tile
+ self.fp = self.__fp
+ self._prev_im = None
+ self.dispose = None
+ self.default_image = self.info.get("default_image", False)
+ self.dispose_op = self.info.get("disposal")
+ self.blend_op = self.info.get("blend")
+ self.dispose_extent = self.info.get("bbox")
+ self.__frame = 0
+ else:
+ if frame != self.__frame + 1:
+ raise ValueError(f"cannot seek to frame {frame}")
+
+ # ensure previous frame was loaded
+ self.load()
+
+ if self.dispose:
+ self.im.paste(self.dispose, self.dispose_extent)
+ self._prev_im = self.im.copy()
+
+ self.fp = self.__fp
+
+ # advance to the next frame
+ if self.__prepare_idat:
+ ImageFile._safe_read(self.fp, self.__prepare_idat)
+ self.__prepare_idat = 0
+ frame_start = False
+ while True:
+ self.fp.read(4) # CRC
+
+ try:
+ cid, pos, length = self.png.read()
+ except (struct.error, SyntaxError):
+ break
+
+ if cid == b"IEND":
+ raise EOFError("No more images in APNG file")
+ if cid == b"fcTL":
+ if frame_start:
+ # there must be at least one fdAT chunk between fcTL chunks
+ raise SyntaxError("APNG missing frame data")
+ frame_start = True
+
+ try:
+ self.png.call(cid, pos, length)
+ except UnicodeDecodeError:
+ break
+ except EOFError:
+ if cid == b"fdAT":
+ length -= 4
+ if frame_start:
+ self.__prepare_idat = length
+ break
+ ImageFile._safe_read(self.fp, length)
+ except AttributeError:
+ logger.debug("%r %s %s (unknown)", cid, pos, length)
+ ImageFile._safe_read(self.fp, length)
+
+ self.__frame = frame
+ self.tile = self.png.im_tile
+ self.dispose_op = self.info.get("disposal")
+ self.blend_op = self.info.get("blend")
+ self.dispose_extent = self.info.get("bbox")
+
+ if not self.tile:
+ raise EOFError
+
+ # setup frame disposal (actual disposal done when needed in the next _seek())
+ if self._prev_im is None and self.dispose_op == APNG_DISPOSE_OP_PREVIOUS:
+ self.dispose_op = APNG_DISPOSE_OP_BACKGROUND
+
+ if self.dispose_op == APNG_DISPOSE_OP_PREVIOUS:
+ self.dispose = self._prev_im.copy()
+ self.dispose = self._crop(self.dispose, self.dispose_extent)
+ elif self.dispose_op == APNG_DISPOSE_OP_BACKGROUND:
+ self.dispose = Image.core.fill(self.mode, self.size)
+ self.dispose = self._crop(self.dispose, self.dispose_extent)
+ else:
+ self.dispose = None
+
+ def tell(self):
+ return self.__frame
+
+ def load_prepare(self):
+ """internal: prepare to read PNG file"""
+
+ if self.info.get("interlace"):
+ self.decoderconfig = self.decoderconfig + (1,)
+
+ self.__idat = self.__prepare_idat # used by load_read()
+ ImageFile.ImageFile.load_prepare(self)
+
+ def load_read(self, read_bytes):
+ """internal: read more image data"""
+
+ while self.__idat == 0:
+ # end of chunk, skip forward to next one
+
+ self.fp.read(4) # CRC
+
+ cid, pos, length = self.png.read()
+
+ if cid not in [b"IDAT", b"DDAT", b"fdAT"]:
+ self.png.push(cid, pos, length)
+ return b""
+
+ if cid == b"fdAT":
+ try:
+ self.png.call(cid, pos, length)
+ except EOFError:
+ pass
+ self.__idat = length - 4 # sequence_num has already been read
+ else:
+ self.__idat = length # empty chunks are allowed
+
+ # read more data from this chunk
+ if read_bytes <= 0:
+ read_bytes = self.__idat
+ else:
+ read_bytes = min(read_bytes, self.__idat)
+
+ self.__idat = self.__idat - read_bytes
+
+ return self.fp.read(read_bytes)
+
+ def load_end(self):
+ """internal: finished reading image data"""
+ while True:
+ self.fp.read(4) # CRC
+
+ try:
+ cid, pos, length = self.png.read()
+ except (struct.error, SyntaxError):
+ break
+
+ if cid == b"IEND":
+ break
+ elif cid == b"fcTL" and self.is_animated:
+ # start of the next frame, stop reading
+ self.__prepare_idat = 0
+ self.png.push(cid, pos, length)
+ break
+
+ try:
+ self.png.call(cid, pos, length)
+ except UnicodeDecodeError:
+ break
+ except EOFError:
+ if cid == b"fdAT":
+ length -= 4
+ ImageFile._safe_read(self.fp, length)
+ except AttributeError:
+ logger.debug("%r %s %s (unknown)", cid, pos, length)
+ s = ImageFile._safe_read(self.fp, length)
+ if cid[1:2].islower():
+ self.private_chunks.append((cid, s, True))
+ self._text = self.png.im_text
+ if not self.is_animated:
+ self.png.close()
+ self.png = None
+ else:
+ if self._prev_im and self.blend_op == APNG_BLEND_OP_OVER:
+ updated = self._crop(self.im, self.dispose_extent)
+ self._prev_im.paste(
+ updated, self.dispose_extent, updated.convert("RGBA")
+ )
+ self.im = self._prev_im
+ if self.pyaccess:
+ self.pyaccess = None
+
+ def _getexif(self):
+ if "exif" not in self.info:
+ self.load()
+ if "exif" not in self.info and "Raw profile type exif" not in self.info:
+ return None
+ return dict(self.getexif())
+
+ def getexif(self):
+ if "exif" not in self.info:
+ self.load()
+
+ return super().getexif()
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+# --------------------------------------------------------------------
+# PNG writer
+
+_OUTMODES = {
+ # supported PIL modes, and corresponding rawmodes/bits/color combinations
+ "1": ("1", b"\x01\x00"),
+ "L;1": ("L;1", b"\x01\x00"),
+ "L;2": ("L;2", b"\x02\x00"),
+ "L;4": ("L;4", b"\x04\x00"),
+ "L": ("L", b"\x08\x00"),
+ "LA": ("LA", b"\x08\x04"),
+ "I": ("I;16B", b"\x10\x00"),
+ "I;16": ("I;16B", b"\x10\x00"),
+ "P;1": ("P;1", b"\x01\x03"),
+ "P;2": ("P;2", b"\x02\x03"),
+ "P;4": ("P;4", b"\x04\x03"),
+ "P": ("P", b"\x08\x03"),
+ "RGB": ("RGB", b"\x08\x02"),
+ "RGBA": ("RGBA", b"\x08\x06"),
+}
+
+
+def putchunk(fp, cid, *data):
+ """Write a PNG chunk (including CRC field)"""
+
+ data = b"".join(data)
+
+ fp.write(o32(len(data)) + cid)
+ fp.write(data)
+ crc = _crc32(data, _crc32(cid))
+ fp.write(o32(crc))
+
+
+class _idat:
+ # wrap output from the encoder in IDAT chunks
+
+ def __init__(self, fp, chunk):
+ self.fp = fp
+ self.chunk = chunk
+
+ def write(self, data):
+ self.chunk(self.fp, b"IDAT", data)
+
+
+class _fdat:
+ # wrap encoder output in fdAT chunks
+
+ def __init__(self, fp, chunk, seq_num):
+ self.fp = fp
+ self.chunk = chunk
+ self.seq_num = seq_num
+
+ def write(self, data):
+ self.chunk(self.fp, b"fdAT", o32(self.seq_num), data)
+ self.seq_num += 1
+
+
+def _write_multiple_frames(im, fp, chunk, rawmode):
+ default_image = im.encoderinfo.get("default_image", im.info.get("default_image"))
+ duration = im.encoderinfo.get("duration", im.info.get("duration", 0))
+ loop = im.encoderinfo.get("loop", im.info.get("loop", 0))
+ disposal = im.encoderinfo.get("disposal", im.info.get("disposal"))
+ blend = im.encoderinfo.get("blend", im.info.get("blend"))
+
+ if default_image:
+ chain = itertools.chain(im.encoderinfo.get("append_images", []))
+ else:
+ chain = itertools.chain([im], im.encoderinfo.get("append_images", []))
+
+ im_frames = []
+ frame_count = 0
+ for im_seq in chain:
+ for im_frame in ImageSequence.Iterator(im_seq):
+ im_frame = im_frame.copy()
+ if im_frame.mode != im.mode:
+ if im.mode == "P":
+ im_frame = im_frame.convert(im.mode, palette=im.palette)
+ else:
+ im_frame = im_frame.convert(im.mode)
+ encoderinfo = im.encoderinfo.copy()
+ if isinstance(duration, (list, tuple)):
+ encoderinfo["duration"] = duration[frame_count]
+ if isinstance(disposal, (list, tuple)):
+ encoderinfo["disposal"] = disposal[frame_count]
+ if isinstance(blend, (list, tuple)):
+ encoderinfo["blend"] = blend[frame_count]
+ frame_count += 1
+
+ if im_frames:
+ previous = im_frames[-1]
+ prev_disposal = previous["encoderinfo"].get("disposal")
+ prev_blend = previous["encoderinfo"].get("blend")
+ if prev_disposal == APNG_DISPOSE_OP_PREVIOUS and len(im_frames) < 2:
+ prev_disposal = APNG_DISPOSE_OP_BACKGROUND
+
+ if prev_disposal == APNG_DISPOSE_OP_BACKGROUND:
+ base_im = previous["im"]
+ dispose = Image.core.fill("RGBA", im.size, (0, 0, 0, 0))
+ bbox = previous["bbox"]
+ if bbox:
+ dispose = dispose.crop(bbox)
+ else:
+ bbox = (0, 0) + im.size
+ base_im.paste(dispose, bbox)
+ elif prev_disposal == APNG_DISPOSE_OP_PREVIOUS:
+ base_im = im_frames[-2]["im"]
+ else:
+ base_im = previous["im"]
+ delta = ImageChops.subtract_modulo(
+ im_frame.convert("RGB"), base_im.convert("RGB")
+ )
+ bbox = delta.getbbox()
+ if (
+ not bbox
+ and prev_disposal == encoderinfo.get("disposal")
+ and prev_blend == encoderinfo.get("blend")
+ ):
+ duration = encoderinfo.get("duration", 0)
+ if duration:
+ if "duration" in previous["encoderinfo"]:
+ previous["encoderinfo"]["duration"] += duration
+ else:
+ previous["encoderinfo"]["duration"] = duration
+ continue
+ else:
+ bbox = None
+ im_frames.append({"im": im_frame, "bbox": bbox, "encoderinfo": encoderinfo})
+
+ # animation control
+ chunk(
+ fp,
+ b"acTL",
+ o32(len(im_frames)), # 0: num_frames
+ o32(loop), # 4: num_plays
+ )
+
+ # default image IDAT (if it exists)
+ if default_image:
+ ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
+
+ seq_num = 0
+ for frame, frame_data in enumerate(im_frames):
+ im_frame = frame_data["im"]
+ if not frame_data["bbox"]:
+ bbox = (0, 0) + im_frame.size
+ else:
+ bbox = frame_data["bbox"]
+ im_frame = im_frame.crop(bbox)
+ size = im_frame.size
+ duration = int(round(frame_data["encoderinfo"].get("duration", 0)))
+ disposal = frame_data["encoderinfo"].get("disposal", APNG_DISPOSE_OP_NONE)
+ blend = frame_data["encoderinfo"].get("blend", APNG_BLEND_OP_SOURCE)
+ # frame control
+ chunk(
+ fp,
+ b"fcTL",
+ o32(seq_num), # sequence_number
+ o32(size[0]), # width
+ o32(size[1]), # height
+ o32(bbox[0]), # x_offset
+ o32(bbox[1]), # y_offset
+ o16(duration), # delay_numerator
+ o16(1000), # delay_denominator
+ o8(disposal), # dispose_op
+ o8(blend), # blend_op
+ )
+ seq_num += 1
+ # frame data
+ if frame == 0 and not default_image:
+ # first frame must be in IDAT chunks for backwards compatibility
+ ImageFile._save(
+ im_frame,
+ _idat(fp, chunk),
+ [("zip", (0, 0) + im_frame.size, 0, rawmode)],
+ )
+ else:
+ fdat_chunks = _fdat(fp, chunk, seq_num)
+ ImageFile._save(
+ im_frame,
+ fdat_chunks,
+ [("zip", (0, 0) + im_frame.size, 0, rawmode)],
+ )
+ seq_num = fdat_chunks.seq_num
+
+
+def _save_all(im, fp, filename):
+ _save(im, fp, filename, save_all=True)
+
+
+def _save(im, fp, filename, chunk=putchunk, save_all=False):
+ # save an image to disk (called by the save method)
+
+ mode = im.mode
+
+ if mode == "P":
+
+ #
+ # attempt to minimize storage requirements for palette images
+ if "bits" in im.encoderinfo:
+ # number of bits specified by user
+ colors = 1 << im.encoderinfo["bits"]
+ else:
+ # check palette contents
+ if im.palette:
+ colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 2)
+ else:
+ colors = 256
+
+ if colors <= 2:
+ bits = 1
+ elif colors <= 4:
+ bits = 2
+ elif colors <= 16:
+ bits = 4
+ else:
+ bits = 8
+ if bits != 8:
+ mode = f"{mode};{bits}"
+
+ # encoder options
+ im.encoderconfig = (
+ im.encoderinfo.get("optimize", False),
+ im.encoderinfo.get("compress_level", -1),
+ im.encoderinfo.get("compress_type", -1),
+ im.encoderinfo.get("dictionary", b""),
+ )
+
+ # get the corresponding PNG mode
+ try:
+ rawmode, mode = _OUTMODES[mode]
+ except KeyError as e:
+ raise OSError(f"cannot write mode {mode} as PNG") from e
+
+ #
+ # write minimal PNG file
+
+ fp.write(_MAGIC)
+
+ chunk(
+ fp,
+ b"IHDR",
+ o32(im.size[0]), # 0: size
+ o32(im.size[1]),
+ mode, # 8: depth/type
+ b"\0", # 10: compression
+ b"\0", # 11: filter category
+ b"\0", # 12: interlace flag
+ )
+
+ chunks = [b"cHRM", b"gAMA", b"sBIT", b"sRGB", b"tIME"]
+
+ icc = im.encoderinfo.get("icc_profile", im.info.get("icc_profile"))
+ if icc:
+ # ICC profile
+ # according to PNG spec, the iCCP chunk contains:
+ # Profile name 1-79 bytes (character string)
+ # Null separator 1 byte (null character)
+ # Compression method 1 byte (0)
+ # Compressed profile n bytes (zlib with deflate compression)
+ name = b"ICC Profile"
+ data = name + b"\0\0" + zlib.compress(icc)
+ chunk(fp, b"iCCP", data)
+
+ # You must either have sRGB or iCCP.
+ # Disallow sRGB chunks when an iCCP-chunk has been emitted.
+ chunks.remove(b"sRGB")
+
+ info = im.encoderinfo.get("pnginfo")
+ if info:
+ chunks_multiple_allowed = [b"sPLT", b"iTXt", b"tEXt", b"zTXt"]
+ for info_chunk in info.chunks:
+ cid, data = info_chunk[:2]
+ if cid in chunks:
+ chunks.remove(cid)
+ chunk(fp, cid, data)
+ elif cid in chunks_multiple_allowed:
+ chunk(fp, cid, data)
+ elif cid[1:2].islower():
+ # Private chunk
+ after_idat = info_chunk[2:3]
+ if not after_idat:
+ chunk(fp, cid, data)
+
+ if im.mode == "P":
+ palette_byte_number = (2 ** bits) * 3
+ palette_bytes = im.im.getpalette("RGB")[:palette_byte_number]
+ while len(palette_bytes) < palette_byte_number:
+ palette_bytes += b"\0"
+ chunk(fp, b"PLTE", palette_bytes)
+
+ transparency = im.encoderinfo.get("transparency", im.info.get("transparency", None))
+
+ if transparency or transparency == 0:
+ if im.mode == "P":
+ # limit to actual palette size
+ alpha_bytes = 2 ** bits
+ if isinstance(transparency, bytes):
+ chunk(fp, b"tRNS", transparency[:alpha_bytes])
+ else:
+ transparency = max(0, min(255, transparency))
+ alpha = b"\xFF" * transparency + b"\0"
+ chunk(fp, b"tRNS", alpha[:alpha_bytes])
+ elif im.mode in ("1", "L", "I"):
+ transparency = max(0, min(65535, transparency))
+ chunk(fp, b"tRNS", o16(transparency))
+ elif im.mode == "RGB":
+ red, green, blue = transparency
+ chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
+ else:
+ if "transparency" in im.encoderinfo:
+ # don't bother with transparency if it's an RGBA
+ # and it's in the info dict. It's probably just stale.
+ raise OSError("cannot use transparency for this mode")
+ else:
+ if im.mode == "P" and im.im.getpalettemode() == "RGBA":
+ alpha = im.im.getpalette("RGBA", "A")
+ alpha_bytes = 2 ** bits
+ chunk(fp, b"tRNS", alpha[:alpha_bytes])
+
+ dpi = im.encoderinfo.get("dpi")
+ if dpi:
+ chunk(
+ fp,
+ b"pHYs",
+ o32(int(dpi[0] / 0.0254 + 0.5)),
+ o32(int(dpi[1] / 0.0254 + 0.5)),
+ b"\x01",
+ )
+
+ if info:
+ chunks = [b"bKGD", b"hIST"]
+ for info_chunk in info.chunks:
+ cid, data = info_chunk[:2]
+ if cid in chunks:
+ chunks.remove(cid)
+ chunk(fp, cid, data)
+
+ exif = im.encoderinfo.get("exif", im.info.get("exif"))
+ if exif:
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes(8)
+ if exif.startswith(b"Exif\x00\x00"):
+ exif = exif[6:]
+ chunk(fp, b"eXIf", exif)
+
+ if save_all:
+ _write_multiple_frames(im, fp, chunk, rawmode)
+ else:
+ ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])
+
+ if info:
+ for info_chunk in info.chunks:
+ cid, data = info_chunk[:2]
+ if cid[1:2].islower():
+ # Private chunk
+ after_idat = info_chunk[2:3]
+ if after_idat:
+ chunk(fp, cid, data)
+
+ chunk(fp, b"IEND", b"")
+
+ if hasattr(fp, "flush"):
+ fp.flush()
+
+
+# --------------------------------------------------------------------
+# PNG chunk converter
+
+
+def getchunks(im, **params):
+ """Return a list of PNG chunks representing this image."""
+
+ class collector:
+ data = []
+
+ def write(self, data):
+ pass
+
+ def append(self, chunk):
+ self.data.append(chunk)
+
+ def append(fp, cid, *data):
+ data = b"".join(data)
+ crc = o32(_crc32(data, _crc32(cid)))
+ fp.append((cid, data, crc))
+
+ fp = collector()
+
+ try:
+ im.encoderinfo = params
+ _save(im, fp, None, append)
+ finally:
+ del im.encoderinfo
+
+ return fp.data
+
+
+# --------------------------------------------------------------------
+# Registry
+
+Image.register_open(PngImageFile.format, PngImageFile, _accept)
+Image.register_save(PngImageFile.format, _save)
+Image.register_save_all(PngImageFile.format, _save_all)
+
+Image.register_extensions(PngImageFile.format, [".png", ".apng"])
+
+Image.register_mime(PngImageFile.format, "image/png")
diff --git a/venv/Lib/site-packages/PIL/PpmImagePlugin.py b/venv/Lib/site-packages/PIL/PpmImagePlugin.py
new file mode 100644
index 0000000..abf4d65
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PpmImagePlugin.py
@@ -0,0 +1,164 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# PPM support for PIL
+#
+# History:
+# 96-03-24 fl Created
+# 98-03-06 fl Write RGBA images (as RGB, that is)
+#
+# Copyright (c) Secret Labs AB 1997-98.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile
+
+#
+# --------------------------------------------------------------------
+
+b_whitespace = b"\x20\x09\x0a\x0b\x0c\x0d"
+
+MODES = {
+ # standard
+ b"P4": "1",
+ b"P5": "L",
+ b"P6": "RGB",
+ # extensions
+ b"P0CMYK": "CMYK",
+ # PIL extensions (for test purposes only)
+ b"PyP": "P",
+ b"PyRGBA": "RGBA",
+ b"PyCMYK": "CMYK",
+}
+
+
+def _accept(prefix):
+ return prefix[0:1] == b"P" and prefix[1] in b"0456y"
+
+
+##
+# Image plugin for PBM, PGM, and PPM images.
+
+
+class PpmImageFile(ImageFile.ImageFile):
+
+ format = "PPM"
+ format_description = "Pbmplus image"
+
+ def _token(self, s=b""):
+ while True: # read until next whitespace
+ c = self.fp.read(1)
+ if not c or c in b_whitespace:
+ break
+ if c > b"\x79":
+ raise ValueError("Expected ASCII value, found binary")
+ s = s + c
+ if len(s) > 9:
+ raise ValueError("Expected int, got > 9 digits")
+ return s
+
+ def _open(self):
+
+ # check magic
+ s = self.fp.read(1)
+ if s != b"P":
+ raise SyntaxError("not a PPM file")
+ magic_number = self._token(s)
+ mode = MODES[magic_number]
+
+ self.custom_mimetype = {
+ b"P4": "image/x-portable-bitmap",
+ b"P5": "image/x-portable-graymap",
+ b"P6": "image/x-portable-pixmap",
+ }.get(magic_number)
+
+ if mode == "1":
+ self.mode = "1"
+ rawmode = "1;I"
+ else:
+ self.mode = rawmode = mode
+
+ for ix in range(3):
+ while True:
+ while True:
+ s = self.fp.read(1)
+ if s not in b_whitespace:
+ break
+ if s == b"":
+ raise ValueError("File does not extend beyond magic number")
+ if s != b"#":
+ break
+ s = self.fp.readline()
+ s = int(self._token(s))
+ if ix == 0:
+ xsize = s
+ elif ix == 1:
+ ysize = s
+ if mode == "1":
+ break
+ elif ix == 2:
+ # maxgrey
+ if s > 255:
+ if not mode == "L":
+ raise ValueError(f"Too many colors for band: {s}")
+ if s < 2 ** 16:
+ self.mode = "I"
+ rawmode = "I;16B"
+ else:
+ self.mode = "I"
+ rawmode = "I;32B"
+
+ self._size = xsize, ysize
+ self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), (rawmode, 0, 1))]
+
+
+#
+# --------------------------------------------------------------------
+
+
+def _save(im, fp, filename):
+ if im.mode == "1":
+ rawmode, head = "1;I", b"P4"
+ elif im.mode == "L":
+ rawmode, head = "L", b"P5"
+ elif im.mode == "I":
+ if im.getextrema()[1] < 2 ** 16:
+ rawmode, head = "I;16B", b"P5"
+ else:
+ rawmode, head = "I;32B", b"P5"
+ elif im.mode == "RGB":
+ rawmode, head = "RGB", b"P6"
+ elif im.mode == "RGBA":
+ rawmode, head = "RGB", b"P6"
+ else:
+ raise OSError(f"cannot write mode {im.mode} as PPM")
+ fp.write(head + ("\n%d %d\n" % im.size).encode("ascii"))
+ if head == b"P6":
+ fp.write(b"255\n")
+ if head == b"P5":
+ if rawmode == "L":
+ fp.write(b"255\n")
+ elif rawmode == "I;16B":
+ fp.write(b"65535\n")
+ elif rawmode == "I;32B":
+ fp.write(b"2147483648\n")
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
+
+ # ALTERNATIVE: save via builtin debug function
+ # im._dump(filename)
+
+
+#
+# --------------------------------------------------------------------
+
+
+Image.register_open(PpmImageFile.format, PpmImageFile, _accept)
+Image.register_save(PpmImageFile.format, _save)
+
+Image.register_extensions(PpmImageFile.format, [".pbm", ".pgm", ".ppm", ".pnm"])
+
+Image.register_mime(PpmImageFile.format, "image/x-portable-anymap")
diff --git a/venv/Lib/site-packages/PIL/PsdImagePlugin.py b/venv/Lib/site-packages/PIL/PsdImagePlugin.py
new file mode 100644
index 0000000..d3799ed
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PsdImagePlugin.py
@@ -0,0 +1,313 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# Adobe PSD 2.5/3.0 file handling
+#
+# History:
+# 1995-09-01 fl Created
+# 1997-01-03 fl Read most PSD images
+# 1997-01-18 fl Fixed P and CMYK support
+# 2001-10-21 fl Added seek/tell support (for layers)
+#
+# Copyright (c) 1997-2001 by Secret Labs AB.
+# Copyright (c) 1995-2001 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i8
+from ._binary import i16be as i16
+from ._binary import i32be as i32
+
+MODES = {
+ # (photoshop mode, bits) -> (pil mode, required channels)
+ (0, 1): ("1", 1),
+ (0, 8): ("L", 1),
+ (1, 8): ("L", 1),
+ (2, 8): ("P", 1),
+ (3, 8): ("RGB", 3),
+ (4, 8): ("CMYK", 4),
+ (7, 8): ("L", 1), # FIXME: multilayer
+ (8, 8): ("L", 1), # duotone
+ (9, 8): ("LAB", 3),
+}
+
+
+# --------------------------------------------------------------------.
+# read PSD images
+
+
+def _accept(prefix):
+ return prefix[:4] == b"8BPS"
+
+
+##
+# Image plugin for Photoshop images.
+
+
+class PsdImageFile(ImageFile.ImageFile):
+
+ format = "PSD"
+ format_description = "Adobe Photoshop"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+
+ read = self.fp.read
+
+ #
+ # header
+
+ s = read(26)
+ if not _accept(s) or i16(s, 4) != 1:
+ raise SyntaxError("not a PSD file")
+
+ psd_bits = i16(s, 22)
+ psd_channels = i16(s, 12)
+ psd_mode = i16(s, 24)
+
+ mode, channels = MODES[(psd_mode, psd_bits)]
+
+ if channels > psd_channels:
+ raise OSError("not enough channels")
+
+ self.mode = mode
+ self._size = i32(s, 18), i32(s, 14)
+
+ #
+ # color mode data
+
+ size = i32(read(4))
+ if size:
+ data = read(size)
+ if mode == "P" and size == 768:
+ self.palette = ImagePalette.raw("RGB;L", data)
+
+ #
+ # image resources
+
+ self.resources = []
+
+ size = i32(read(4))
+ if size:
+ # load resources
+ end = self.fp.tell() + size
+ while self.fp.tell() < end:
+ read(4) # signature
+ id = i16(read(2))
+ name = read(i8(read(1)))
+ if not (len(name) & 1):
+ read(1) # padding
+ data = read(i32(read(4)))
+ if len(data) & 1:
+ read(1) # padding
+ self.resources.append((id, name, data))
+ if id == 1039: # ICC profile
+ self.info["icc_profile"] = data
+
+ #
+ # layer and mask information
+
+ self.layers = []
+
+ size = i32(read(4))
+ if size:
+ end = self.fp.tell() + size
+ size = i32(read(4))
+ if size:
+ self.layers = _layerinfo(self.fp)
+ self.fp.seek(end)
+ self.n_frames = len(self.layers)
+ self.is_animated = self.n_frames > 1
+
+ #
+ # image descriptor
+
+ self.tile = _maketile(self.fp, mode, (0, 0) + self.size, channels)
+
+ # keep the file open
+ self.__fp = self.fp
+ self.frame = 1
+ self._min_frame = 1
+
+ def seek(self, layer):
+ if not self._seek_check(layer):
+ return
+
+ # seek to given layer (1..max)
+ try:
+ name, mode, bbox, tile = self.layers[layer - 1]
+ self.mode = mode
+ self.tile = tile
+ self.frame = layer
+ self.fp = self.__fp
+ return name, bbox
+ except IndexError as e:
+ raise EOFError("no such layer") from e
+
+ def tell(self):
+ # return layer number (0=image, 1..max=layers)
+ return self.frame
+
+ def load_prepare(self):
+ # create image memory if necessary
+ if not self.im or self.im.mode != self.mode or self.im.size != self.size:
+ self.im = Image.core.fill(self.mode, self.size, 0)
+ # create palette (optional)
+ if self.mode == "P":
+ Image.Image.load(self)
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+def _layerinfo(file):
+ # read layerinfo block
+ layers = []
+ read = file.read
+ for i in range(abs(i16(read(2)))):
+
+ # bounding box
+ y0 = i32(read(4))
+ x0 = i32(read(4))
+ y1 = i32(read(4))
+ x1 = i32(read(4))
+
+ # image info
+ info = []
+ mode = []
+ types = list(range(i16(read(2))))
+ if len(types) > 4:
+ continue
+
+ for i in types:
+ type = i16(read(2))
+
+ if type == 65535:
+ m = "A"
+ else:
+ m = "RGBA"[type]
+
+ mode.append(m)
+ size = i32(read(4))
+ info.append((m, size))
+
+ # figure out the image mode
+ mode.sort()
+ if mode == ["R"]:
+ mode = "L"
+ elif mode == ["B", "G", "R"]:
+ mode = "RGB"
+ elif mode == ["A", "B", "G", "R"]:
+ mode = "RGBA"
+ else:
+ mode = None # unknown
+
+ # skip over blend flags and extra information
+ read(12) # filler
+ name = ""
+ size = i32(read(4)) # length of the extra data field
+ combined = 0
+ if size:
+ data_end = file.tell() + size
+
+ length = i32(read(4))
+ if length:
+ file.seek(length - 16, io.SEEK_CUR)
+ combined += length + 4
+
+ length = i32(read(4))
+ if length:
+ file.seek(length, io.SEEK_CUR)
+ combined += length + 4
+
+ length = i8(read(1))
+ if length:
+ # Don't know the proper encoding,
+ # Latin-1 should be a good guess
+ name = read(length).decode("latin-1", "replace")
+ combined += length + 1
+
+ file.seek(data_end)
+ layers.append((name, mode, (x0, y0, x1, y1)))
+
+ # get tiles
+ i = 0
+ for name, mode, bbox in layers:
+ tile = []
+ for m in mode:
+ t = _maketile(file, m, bbox, 1)
+ if t:
+ tile.extend(t)
+ layers[i] = name, mode, bbox, tile
+ i += 1
+
+ return layers
+
+
+def _maketile(file, mode, bbox, channels):
+
+ tile = None
+ read = file.read
+
+ compression = i16(read(2))
+
+ xsize = bbox[2] - bbox[0]
+ ysize = bbox[3] - bbox[1]
+
+ offset = file.tell()
+
+ if compression == 0:
+ #
+ # raw compression
+ tile = []
+ for channel in range(channels):
+ layer = mode[channel]
+ if mode == "CMYK":
+ layer += ";I"
+ tile.append(("raw", bbox, offset, layer))
+ offset = offset + xsize * ysize
+
+ elif compression == 1:
+ #
+ # packbits compression
+ i = 0
+ tile = []
+ bytecount = read(channels * ysize * 2)
+ offset = file.tell()
+ for channel in range(channels):
+ layer = mode[channel]
+ if mode == "CMYK":
+ layer += ";I"
+ tile.append(("packbits", bbox, offset, layer))
+ for y in range(ysize):
+ offset = offset + i16(bytecount, i)
+ i += 2
+
+ file.seek(offset)
+
+ if offset & 1:
+ read(1) # padding
+
+ return tile
+
+
+# --------------------------------------------------------------------
+# registry
+
+
+Image.register_open(PsdImageFile.format, PsdImageFile, _accept)
+
+Image.register_extension(PsdImageFile.format, ".psd")
+
+Image.register_mime(PsdImageFile.format, "image/vnd.adobe.photoshop")
diff --git a/venv/Lib/site-packages/PIL/PyAccess.py b/venv/Lib/site-packages/PIL/PyAccess.py
new file mode 100644
index 0000000..494f5f9
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/PyAccess.py
@@ -0,0 +1,352 @@
+#
+# The Python Imaging Library
+# Pillow fork
+#
+# Python implementation of the PixelAccess Object
+#
+# Copyright (c) 1997-2009 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1995-2009 by Fredrik Lundh.
+# Copyright (c) 2013 Eric Soroos
+#
+# See the README file for information on usage and redistribution
+#
+
+# Notes:
+#
+# * Implements the pixel access object following Access.
+# * Does not implement the line functions, as they don't appear to be used
+# * Taking only the tuple form, which is used from python.
+# * Fill.c uses the integer form, but it's still going to use the old
+# Access.c implementation.
+#
+
+import logging
+import sys
+
+try:
+ from cffi import FFI
+
+ defs = """
+ struct Pixel_RGBA {
+ unsigned char r,g,b,a;
+ };
+ struct Pixel_I16 {
+ unsigned char l,r;
+ };
+ """
+ ffi = FFI()
+ ffi.cdef(defs)
+except ImportError as ex:
+ # Allow error import for doc purposes, but error out when accessing
+ # anything in core.
+ from ._util import deferred_error
+
+ FFI = ffi = deferred_error(ex)
+
+logger = logging.getLogger(__name__)
+
+
+class PyAccess:
+ def __init__(self, img, readonly=False):
+ vals = dict(img.im.unsafe_ptrs)
+ self.readonly = readonly
+ self.image8 = ffi.cast("unsigned char **", vals["image8"])
+ self.image32 = ffi.cast("int **", vals["image32"])
+ self.image = ffi.cast("unsigned char **", vals["image"])
+ self.xsize, self.ysize = img.im.size
+
+ # Keep pointer to im object to prevent dereferencing.
+ self._im = img.im
+ if self._im.mode == "P":
+ self._palette = img.palette
+
+ # Debugging is polluting test traces, only useful here
+ # when hacking on PyAccess
+ # logger.debug("%s", vals)
+ self._post_init()
+
+ def _post_init(self):
+ pass
+
+ def __setitem__(self, xy, color):
+ """
+ Modifies the pixel at x,y. The color is given as a single
+ numerical value for single band images, and a tuple for
+ multi-band images
+
+ :param xy: The pixel coordinate, given as (x, y). See
+ :ref:`coordinate-system`.
+ :param color: The pixel value.
+ """
+ if self.readonly:
+ raise ValueError("Attempt to putpixel a read only image")
+ (x, y) = xy
+ if x < 0:
+ x = self.xsize + x
+ if y < 0:
+ y = self.ysize + y
+ (x, y) = self.check_xy((x, y))
+
+ if (
+ self._im.mode == "P"
+ and isinstance(color, (list, tuple))
+ and len(color) in [3, 4]
+ ):
+ # RGB or RGBA value for a P image
+ color = self._palette.getcolor(color)
+
+ return self.set_pixel(x, y, color)
+
+ def __getitem__(self, xy):
+ """
+ Returns the pixel at x,y. The pixel is returned as a single
+ value for single band images or a tuple for multiple band
+ images
+
+ :param xy: The pixel coordinate, given as (x, y). See
+ :ref:`coordinate-system`.
+ :returns: a pixel value for single band images, a tuple of
+ pixel values for multiband images.
+ """
+ (x, y) = xy
+ if x < 0:
+ x = self.xsize + x
+ if y < 0:
+ y = self.ysize + y
+ (x, y) = self.check_xy((x, y))
+ return self.get_pixel(x, y)
+
+ putpixel = __setitem__
+ getpixel = __getitem__
+
+ def check_xy(self, xy):
+ (x, y) = xy
+ if not (0 <= x < self.xsize and 0 <= y < self.ysize):
+ raise ValueError("pixel location out of range")
+ return xy
+
+
+class _PyAccess32_2(PyAccess):
+ """ PA, LA, stored in first and last bytes of a 32 bit word """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return (pixel.r, pixel.a)
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ # tuple
+ pixel.r = min(color[0], 255)
+ pixel.a = min(color[1], 255)
+
+
+class _PyAccess32_3(PyAccess):
+ """ RGB and friends, stored in the first three bytes of a 32 bit word """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return (pixel.r, pixel.g, pixel.b)
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ # tuple
+ pixel.r = min(color[0], 255)
+ pixel.g = min(color[1], 255)
+ pixel.b = min(color[2], 255)
+ pixel.a = 255
+
+
+class _PyAccess32_4(PyAccess):
+ """ RGBA etc, all 4 bytes of a 32 bit word """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_RGBA **", self.image32)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return (pixel.r, pixel.g, pixel.b, pixel.a)
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ # tuple
+ pixel.r = min(color[0], 255)
+ pixel.g = min(color[1], 255)
+ pixel.b = min(color[2], 255)
+ pixel.a = min(color[3], 255)
+
+
+class _PyAccess8(PyAccess):
+ """ 1, L, P, 8 bit images stored as uint8 """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = self.image8
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ try:
+ # integer
+ self.pixels[y][x] = min(color, 255)
+ except TypeError:
+ # tuple
+ self.pixels[y][x] = min(color[0], 255)
+
+
+class _PyAccessI16_N(PyAccess):
+ """ I;16 access, native bitendian without conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("unsigned short **", self.image)
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ try:
+ # integer
+ self.pixels[y][x] = min(color, 65535)
+ except TypeError:
+ # tuple
+ self.pixels[y][x] = min(color[0], 65535)
+
+
+class _PyAccessI16_L(PyAccess):
+ """ I;16L access, with conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_I16 **", self.image)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return pixel.l + pixel.r * 256
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ try:
+ color = min(color, 65535)
+ except TypeError:
+ color = min(color[0], 65535)
+
+ pixel.l = color & 0xFF # noqa: E741
+ pixel.r = color >> 8
+
+
+class _PyAccessI16_B(PyAccess):
+ """ I;16B access, with conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("struct Pixel_I16 **", self.image)
+
+ def get_pixel(self, x, y):
+ pixel = self.pixels[y][x]
+ return pixel.l * 256 + pixel.r
+
+ def set_pixel(self, x, y, color):
+ pixel = self.pixels[y][x]
+ try:
+ color = min(color, 65535)
+ except Exception:
+ color = min(color[0], 65535)
+
+ pixel.l = color >> 8 # noqa: E741
+ pixel.r = color & 0xFF
+
+
+class _PyAccessI32_N(PyAccess):
+ """ Signed Int32 access, native endian """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = self.image32
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ self.pixels[y][x] = color
+
+
+class _PyAccessI32_Swap(PyAccess):
+ """ I;32L/B access, with byteswapping conversion """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = self.image32
+
+ def reverse(self, i):
+ orig = ffi.new("int *", i)
+ chars = ffi.cast("unsigned char *", orig)
+ chars[0], chars[1], chars[2], chars[3] = chars[3], chars[2], chars[1], chars[0]
+ return ffi.cast("int *", chars)[0]
+
+ def get_pixel(self, x, y):
+ return self.reverse(self.pixels[y][x])
+
+ def set_pixel(self, x, y, color):
+ self.pixels[y][x] = self.reverse(color)
+
+
+class _PyAccessF(PyAccess):
+ """ 32 bit float access """
+
+ def _post_init(self, *args, **kwargs):
+ self.pixels = ffi.cast("float **", self.image32)
+
+ def get_pixel(self, x, y):
+ return self.pixels[y][x]
+
+ def set_pixel(self, x, y, color):
+ try:
+ # not a tuple
+ self.pixels[y][x] = color
+ except TypeError:
+ # tuple
+ self.pixels[y][x] = color[0]
+
+
+mode_map = {
+ "1": _PyAccess8,
+ "L": _PyAccess8,
+ "P": _PyAccess8,
+ "LA": _PyAccess32_2,
+ "La": _PyAccess32_2,
+ "PA": _PyAccess32_2,
+ "RGB": _PyAccess32_3,
+ "LAB": _PyAccess32_3,
+ "HSV": _PyAccess32_3,
+ "YCbCr": _PyAccess32_3,
+ "RGBA": _PyAccess32_4,
+ "RGBa": _PyAccess32_4,
+ "RGBX": _PyAccess32_4,
+ "CMYK": _PyAccess32_4,
+ "F": _PyAccessF,
+ "I": _PyAccessI32_N,
+}
+
+if sys.byteorder == "little":
+ mode_map["I;16"] = _PyAccessI16_N
+ mode_map["I;16L"] = _PyAccessI16_N
+ mode_map["I;16B"] = _PyAccessI16_B
+
+ mode_map["I;32L"] = _PyAccessI32_N
+ mode_map["I;32B"] = _PyAccessI32_Swap
+else:
+ mode_map["I;16"] = _PyAccessI16_L
+ mode_map["I;16L"] = _PyAccessI16_L
+ mode_map["I;16B"] = _PyAccessI16_N
+
+ mode_map["I;32L"] = _PyAccessI32_Swap
+ mode_map["I;32B"] = _PyAccessI32_N
+
+
+def new(img, readonly=False):
+ access_type = mode_map.get(img.mode, None)
+ if not access_type:
+ logger.debug("PyAccess Not Implemented: %s", img.mode)
+ return None
+ return access_type(img, readonly)
diff --git a/venv/Lib/site-packages/PIL/SgiImagePlugin.py b/venv/Lib/site-packages/PIL/SgiImagePlugin.py
new file mode 100644
index 0000000..d0f7c99
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/SgiImagePlugin.py
@@ -0,0 +1,229 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# SGI image file handling
+#
+# See "The SGI Image File Format (Draft version 0.97)", Paul Haeberli.
+#
+#
+#
+# History:
+# 2017-22-07 mb Add RLE decompression
+# 2016-16-10 mb Add save method without compression
+# 1995-09-10 fl Created
+#
+# Copyright (c) 2016 by Mickael Bonfill.
+# Copyright (c) 2008 by Karsten Hiddemann.
+# Copyright (c) 1997 by Secret Labs AB.
+# Copyright (c) 1995 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import os
+import struct
+
+from . import Image, ImageFile
+from ._binary import i16be as i16
+from ._binary import o8
+
+
+def _accept(prefix):
+ return len(prefix) >= 2 and i16(prefix) == 474
+
+
+MODES = {
+ (1, 1, 1): "L",
+ (1, 2, 1): "L",
+ (2, 1, 1): "L;16B",
+ (2, 2, 1): "L;16B",
+ (1, 3, 3): "RGB",
+ (2, 3, 3): "RGB;16B",
+ (1, 3, 4): "RGBA",
+ (2, 3, 4): "RGBA;16B",
+}
+
+
+##
+# Image plugin for SGI images.
+class SgiImageFile(ImageFile.ImageFile):
+
+ format = "SGI"
+ format_description = "SGI Image File Format"
+
+ def _open(self):
+
+ # HEAD
+ headlen = 512
+ s = self.fp.read(headlen)
+
+ if not _accept(s):
+ raise ValueError("Not an SGI image file")
+
+ # compression : verbatim or RLE
+ compression = s[2]
+
+ # bpc : 1 or 2 bytes (8bits or 16bits)
+ bpc = s[3]
+
+ # dimension : 1, 2 or 3 (depending on xsize, ysize and zsize)
+ dimension = i16(s, 4)
+
+ # xsize : width
+ xsize = i16(s, 6)
+
+ # ysize : height
+ ysize = i16(s, 8)
+
+ # zsize : channels count
+ zsize = i16(s, 10)
+
+ # layout
+ layout = bpc, dimension, zsize
+
+ # determine mode from bits/zsize
+ rawmode = ""
+ try:
+ rawmode = MODES[layout]
+ except KeyError:
+ pass
+
+ if rawmode == "":
+ raise ValueError("Unsupported SGI image mode")
+
+ self._size = xsize, ysize
+ self.mode = rawmode.split(";")[0]
+ if self.mode == "RGB":
+ self.custom_mimetype = "image/rgb"
+
+ # orientation -1 : scanlines begins at the bottom-left corner
+ orientation = -1
+
+ # decoder info
+ if compression == 0:
+ pagesize = xsize * ysize * bpc
+ if bpc == 2:
+ self.tile = [
+ ("SGI16", (0, 0) + self.size, headlen, (self.mode, 0, orientation))
+ ]
+ else:
+ self.tile = []
+ offset = headlen
+ for layer in self.mode:
+ self.tile.append(
+ ("raw", (0, 0) + self.size, offset, (layer, 0, orientation))
+ )
+ offset += pagesize
+ elif compression == 1:
+ self.tile = [
+ ("sgi_rle", (0, 0) + self.size, headlen, (rawmode, orientation, bpc))
+ ]
+
+
+def _save(im, fp, filename):
+ if im.mode != "RGB" and im.mode != "RGBA" and im.mode != "L":
+ raise ValueError("Unsupported SGI image mode")
+
+ # Get the keyword arguments
+ info = im.encoderinfo
+
+ # Byte-per-pixel precision, 1 = 8bits per pixel
+ bpc = info.get("bpc", 1)
+
+ if bpc not in (1, 2):
+ raise ValueError("Unsupported number of bytes per pixel")
+
+ # Flip the image, since the origin of SGI file is the bottom-left corner
+ orientation = -1
+ # Define the file as SGI File Format
+ magicNumber = 474
+ # Run-Length Encoding Compression - Unsupported at this time
+ rle = 0
+
+ # Number of dimensions (x,y,z)
+ dim = 3
+ # X Dimension = width / Y Dimension = height
+ x, y = im.size
+ if im.mode == "L" and y == 1:
+ dim = 1
+ elif im.mode == "L":
+ dim = 2
+ # Z Dimension: Number of channels
+ z = len(im.mode)
+
+ if dim == 1 or dim == 2:
+ z = 1
+
+ # assert we've got the right number of bands.
+ if len(im.getbands()) != z:
+ raise ValueError(
+ f"incorrect number of bands in SGI write: {z} vs {len(im.getbands())}"
+ )
+
+ # Minimum Byte value
+ pinmin = 0
+ # Maximum Byte value (255 = 8bits per pixel)
+ pinmax = 255
+ # Image name (79 characters max, truncated below in write)
+ imgName = os.path.splitext(os.path.basename(filename))[0]
+ imgName = imgName.encode("ascii", "ignore")
+ # Standard representation of pixel in the file
+ colormap = 0
+ fp.write(struct.pack(">h", magicNumber))
+ fp.write(o8(rle))
+ fp.write(o8(bpc))
+ fp.write(struct.pack(">H", dim))
+ fp.write(struct.pack(">H", x))
+ fp.write(struct.pack(">H", y))
+ fp.write(struct.pack(">H", z))
+ fp.write(struct.pack(">l", pinmin))
+ fp.write(struct.pack(">l", pinmax))
+ fp.write(struct.pack("4s", b"")) # dummy
+ fp.write(struct.pack("79s", imgName)) # truncates to 79 chars
+ fp.write(struct.pack("s", b"")) # force null byte after imgname
+ fp.write(struct.pack(">l", colormap))
+ fp.write(struct.pack("404s", b"")) # dummy
+
+ rawmode = "L"
+ if bpc == 2:
+ rawmode = "L;16B"
+
+ for channel in im.split():
+ fp.write(channel.tobytes("raw", rawmode, 0, orientation))
+
+ fp.close()
+
+
+class SGI16Decoder(ImageFile.PyDecoder):
+ _pulls_fd = True
+
+ def decode(self, buffer):
+ rawmode, stride, orientation = self.args
+ pagesize = self.state.xsize * self.state.ysize
+ zsize = len(self.mode)
+ self.fd.seek(512)
+
+ for band in range(zsize):
+ channel = Image.new("L", (self.state.xsize, self.state.ysize))
+ channel.frombytes(
+ self.fd.read(2 * pagesize), "raw", "L;16B", stride, orientation
+ )
+ self.im.putband(channel.im, band)
+
+ return -1, 0
+
+
+#
+# registry
+
+
+Image.register_decoder("SGI16", SGI16Decoder)
+Image.register_open(SgiImageFile.format, SgiImageFile, _accept)
+Image.register_save(SgiImageFile.format, _save)
+Image.register_mime(SgiImageFile.format, "image/sgi")
+
+Image.register_extensions(SgiImageFile.format, [".bw", ".rgb", ".rgba", ".sgi"])
+
+# End of file
diff --git a/venv/Lib/site-packages/PIL/SpiderImagePlugin.py b/venv/Lib/site-packages/PIL/SpiderImagePlugin.py
new file mode 100644
index 0000000..819f2ed
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/SpiderImagePlugin.py
@@ -0,0 +1,324 @@
+#
+# The Python Imaging Library.
+#
+# SPIDER image file handling
+#
+# History:
+# 2004-08-02 Created BB
+# 2006-03-02 added save method
+# 2006-03-13 added support for stack images
+#
+# Copyright (c) 2004 by Health Research Inc. (HRI) RENSSELAER, NY 12144.
+# Copyright (c) 2004 by William Baxter.
+# Copyright (c) 2004 by Secret Labs AB.
+# Copyright (c) 2004 by Fredrik Lundh.
+#
+
+##
+# Image plugin for the Spider image format. This format is is used
+# by the SPIDER software, in processing image data from electron
+# microscopy and tomography.
+##
+
+#
+# SpiderImagePlugin.py
+#
+# The Spider image format is used by SPIDER software, in processing
+# image data from electron microscopy and tomography.
+#
+# Spider home page:
+# https://spider.wadsworth.org/spider_doc/spider/docs/spider.html
+#
+# Details about the Spider image format:
+# https://spider.wadsworth.org/spider_doc/spider/docs/image_doc.html
+#
+import os
+import struct
+import sys
+
+from PIL import Image, ImageFile
+
+
+def isInt(f):
+ try:
+ i = int(f)
+ if f - i == 0:
+ return 1
+ else:
+ return 0
+ except (ValueError, OverflowError):
+ return 0
+
+
+iforms = [1, 3, -11, -12, -21, -22]
+
+
+# There is no magic number to identify Spider files, so just check a
+# series of header locations to see if they have reasonable values.
+# Returns no. of bytes in the header, if it is a valid Spider header,
+# otherwise returns 0
+
+
+def isSpiderHeader(t):
+ h = (99,) + t # add 1 value so can use spider header index start=1
+ # header values 1,2,5,12,13,22,23 should be integers
+ for i in [1, 2, 5, 12, 13, 22, 23]:
+ if not isInt(h[i]):
+ return 0
+ # check iform
+ iform = int(h[5])
+ if iform not in iforms:
+ return 0
+ # check other header values
+ labrec = int(h[13]) # no. records in file header
+ labbyt = int(h[22]) # total no. of bytes in header
+ lenbyt = int(h[23]) # record length in bytes
+ if labbyt != (labrec * lenbyt):
+ return 0
+ # looks like a valid header
+ return labbyt
+
+
+def isSpiderImage(filename):
+ with open(filename, "rb") as fp:
+ f = fp.read(92) # read 23 * 4 bytes
+ t = struct.unpack(">23f", f) # try big-endian first
+ hdrlen = isSpiderHeader(t)
+ if hdrlen == 0:
+ t = struct.unpack("<23f", f) # little-endian
+ hdrlen = isSpiderHeader(t)
+ return hdrlen
+
+
+class SpiderImageFile(ImageFile.ImageFile):
+
+ format = "SPIDER"
+ format_description = "Spider 2D image"
+ _close_exclusive_fp_after_loading = False
+
+ def _open(self):
+ # check header
+ n = 27 * 4 # read 27 float values
+ f = self.fp.read(n)
+
+ try:
+ self.bigendian = 1
+ t = struct.unpack(">27f", f) # try big-endian first
+ hdrlen = isSpiderHeader(t)
+ if hdrlen == 0:
+ self.bigendian = 0
+ t = struct.unpack("<27f", f) # little-endian
+ hdrlen = isSpiderHeader(t)
+ if hdrlen == 0:
+ raise SyntaxError("not a valid Spider file")
+ except struct.error as e:
+ raise SyntaxError("not a valid Spider file") from e
+
+ h = (99,) + t # add 1 value : spider header index starts at 1
+ iform = int(h[5])
+ if iform != 1:
+ raise SyntaxError("not a Spider 2D image")
+
+ self._size = int(h[12]), int(h[2]) # size in pixels (width, height)
+ self.istack = int(h[24])
+ self.imgnumber = int(h[27])
+
+ if self.istack == 0 and self.imgnumber == 0:
+ # stk=0, img=0: a regular 2D image
+ offset = hdrlen
+ self._nimages = 1
+ elif self.istack > 0 and self.imgnumber == 0:
+ # stk>0, img=0: Opening the stack for the first time
+ self.imgbytes = int(h[12]) * int(h[2]) * 4
+ self.hdrlen = hdrlen
+ self._nimages = int(h[26])
+ # Point to the first image in the stack
+ offset = hdrlen * 2
+ self.imgnumber = 1
+ elif self.istack == 0 and self.imgnumber > 0:
+ # stk=0, img>0: an image within the stack
+ offset = hdrlen + self.stkoffset
+ self.istack = 2 # So Image knows it's still a stack
+ else:
+ raise SyntaxError("inconsistent stack header values")
+
+ if self.bigendian:
+ self.rawmode = "F;32BF"
+ else:
+ self.rawmode = "F;32F"
+ self.mode = "F"
+
+ self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
+ self.__fp = self.fp # FIXME: hack
+
+ @property
+ def n_frames(self):
+ return self._nimages
+
+ @property
+ def is_animated(self):
+ return self._nimages > 1
+
+ # 1st image index is zero (although SPIDER imgnumber starts at 1)
+ def tell(self):
+ if self.imgnumber < 1:
+ return 0
+ else:
+ return self.imgnumber - 1
+
+ def seek(self, frame):
+ if self.istack == 0:
+ raise EOFError("attempt to seek in a non-stack file")
+ if not self._seek_check(frame):
+ return
+ self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes)
+ self.fp = self.__fp
+ self.fp.seek(self.stkoffset)
+ self._open()
+
+ # returns a byte image after rescaling to 0..255
+ def convert2byte(self, depth=255):
+ (minimum, maximum) = self.getextrema()
+ m = 1
+ if maximum != minimum:
+ m = depth / (maximum - minimum)
+ b = -m * minimum
+ return self.point(lambda i, m=m, b=b: i * m + b).convert("L")
+
+ # returns a ImageTk.PhotoImage object, after rescaling to 0..255
+ def tkPhotoImage(self):
+ from PIL import ImageTk
+
+ return ImageTk.PhotoImage(self.convert2byte(), palette=256)
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+# --------------------------------------------------------------------
+# Image series
+
+# given a list of filenames, return a list of images
+def loadImageSeries(filelist=None):
+ """create a list of :py:class:`~PIL.Image.Image` objects for use in a montage"""
+ if filelist is None or len(filelist) < 1:
+ return
+
+ imglist = []
+ for img in filelist:
+ if not os.path.exists(img):
+ print(f"unable to find {img}")
+ continue
+ try:
+ with Image.open(img) as im:
+ im = im.convert2byte()
+ except Exception:
+ if not isSpiderImage(img):
+ print(img + " is not a Spider image file")
+ continue
+ im.info["filename"] = img
+ imglist.append(im)
+ return imglist
+
+
+# --------------------------------------------------------------------
+# For saving images in Spider format
+
+
+def makeSpiderHeader(im):
+ nsam, nrow = im.size
+ lenbyt = nsam * 4 # There are labrec records in the header
+ labrec = int(1024 / lenbyt)
+ if 1024 % lenbyt != 0:
+ labrec += 1
+ labbyt = labrec * lenbyt
+ hdr = []
+ nvalues = int(labbyt / 4)
+ for i in range(nvalues):
+ hdr.append(0.0)
+
+ if len(hdr) < 23:
+ return []
+
+ # NB these are Fortran indices
+ hdr[1] = 1.0 # nslice (=1 for an image)
+ hdr[2] = float(nrow) # number of rows per slice
+ hdr[5] = 1.0 # iform for 2D image
+ hdr[12] = float(nsam) # number of pixels per line
+ hdr[13] = float(labrec) # number of records in file header
+ hdr[22] = float(labbyt) # total number of bytes in header
+ hdr[23] = float(lenbyt) # record length in bytes
+
+ # adjust for Fortran indexing
+ hdr = hdr[1:]
+ hdr.append(0.0)
+ # pack binary data into a string
+ hdrstr = []
+ for v in hdr:
+ hdrstr.append(struct.pack("f", v))
+ return hdrstr
+
+
+def _save(im, fp, filename):
+ if im.mode[0] != "F":
+ im = im.convert("F")
+
+ hdr = makeSpiderHeader(im)
+ if len(hdr) < 256:
+ raise OSError("Error creating Spider header")
+
+ # write the SPIDER header
+ fp.writelines(hdr)
+
+ rawmode = "F;32NF" # 32-bit native floating point
+ ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
+
+
+def _save_spider(im, fp, filename):
+ # get the filename extension and register it with Image
+ ext = os.path.splitext(filename)[1]
+ Image.register_extension(SpiderImageFile.format, ext)
+ _save(im, fp, filename)
+
+
+# --------------------------------------------------------------------
+
+
+Image.register_open(SpiderImageFile.format, SpiderImageFile)
+Image.register_save(SpiderImageFile.format, _save_spider)
+
+if __name__ == "__main__":
+
+ if len(sys.argv) < 2:
+ print("Syntax: python SpiderImagePlugin.py [infile] [outfile]")
+ sys.exit()
+
+ filename = sys.argv[1]
+ if not isSpiderImage(filename):
+ print("input image must be in Spider format")
+ sys.exit()
+
+ with Image.open(filename) as im:
+ print("image: " + str(im))
+ print("format: " + str(im.format))
+ print("size: " + str(im.size))
+ print("mode: " + str(im.mode))
+ print("max, min: ", end=" ")
+ print(im.getextrema())
+
+ if len(sys.argv) > 2:
+ outfile = sys.argv[2]
+
+ # perform some image operation
+ im = im.transpose(Image.FLIP_LEFT_RIGHT)
+ print(
+ f"saving a flipped version of {os.path.basename(filename)} "
+ f"as {outfile} "
+ )
+ im.save(outfile, SpiderImageFile.format)
diff --git a/venv/Lib/site-packages/PIL/SunImagePlugin.py b/venv/Lib/site-packages/PIL/SunImagePlugin.py
new file mode 100644
index 0000000..c03759a
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/SunImagePlugin.py
@@ -0,0 +1,136 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Sun image file handling
+#
+# History:
+# 1995-09-10 fl Created
+# 1996-05-28 fl Fixed 32-bit alignment
+# 1998-12-29 fl Import ImagePalette module
+# 2001-12-18 fl Fixed palette loading (from Jean-Claude Rimbault)
+#
+# Copyright (c) 1997-2001 by Secret Labs AB
+# Copyright (c) 1995-1996 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i32be as i32
+
+
+def _accept(prefix):
+ return len(prefix) >= 4 and i32(prefix) == 0x59A66A95
+
+
+##
+# Image plugin for Sun raster files.
+
+
+class SunImageFile(ImageFile.ImageFile):
+
+ format = "SUN"
+ format_description = "Sun Raster File"
+
+ def _open(self):
+
+ # The Sun Raster file header is 32 bytes in length
+ # and has the following format:
+
+ # typedef struct _SunRaster
+ # {
+ # DWORD MagicNumber; /* Magic (identification) number */
+ # DWORD Width; /* Width of image in pixels */
+ # DWORD Height; /* Height of image in pixels */
+ # DWORD Depth; /* Number of bits per pixel */
+ # DWORD Length; /* Size of image data in bytes */
+ # DWORD Type; /* Type of raster file */
+ # DWORD ColorMapType; /* Type of color map */
+ # DWORD ColorMapLength; /* Size of the color map in bytes */
+ # } SUNRASTER;
+
+ # HEAD
+ s = self.fp.read(32)
+ if not _accept(s):
+ raise SyntaxError("not an SUN raster file")
+
+ offset = 32
+
+ self._size = i32(s, 4), i32(s, 8)
+
+ depth = i32(s, 12)
+ # data_length = i32(s, 16) # unreliable, ignore.
+ file_type = i32(s, 20)
+ palette_type = i32(s, 24) # 0: None, 1: RGB, 2: Raw/arbitrary
+ palette_length = i32(s, 28)
+
+ if depth == 1:
+ self.mode, rawmode = "1", "1;I"
+ elif depth == 4:
+ self.mode, rawmode = "L", "L;4"
+ elif depth == 8:
+ self.mode = rawmode = "L"
+ elif depth == 24:
+ if file_type == 3:
+ self.mode, rawmode = "RGB", "RGB"
+ else:
+ self.mode, rawmode = "RGB", "BGR"
+ elif depth == 32:
+ if file_type == 3:
+ self.mode, rawmode = "RGB", "RGBX"
+ else:
+ self.mode, rawmode = "RGB", "BGRX"
+ else:
+ raise SyntaxError("Unsupported Mode/Bit Depth")
+
+ if palette_length:
+ if palette_length > 1024:
+ raise SyntaxError("Unsupported Color Palette Length")
+
+ if palette_type != 1:
+ raise SyntaxError("Unsupported Palette Type")
+
+ offset = offset + palette_length
+ self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length))
+ if self.mode == "L":
+ self.mode = "P"
+ rawmode = rawmode.replace("L", "P")
+
+ # 16 bit boundaries on stride
+ stride = ((self.size[0] * depth + 15) // 16) * 2
+
+ # file type: Type is the version (or flavor) of the bitmap
+ # file. The following values are typically found in the Type
+ # field:
+ # 0000h Old
+ # 0001h Standard
+ # 0002h Byte-encoded
+ # 0003h RGB format
+ # 0004h TIFF format
+ # 0005h IFF format
+ # FFFFh Experimental
+
+ # Old and standard are the same, except for the length tag.
+ # byte-encoded is run-length-encoded
+ # RGB looks similar to standard, but RGB byte order
+ # TIFF and IFF mean that they were converted from T/IFF
+ # Experimental means that it's something else.
+ # (https://www.fileformat.info/format/sunraster/egff.htm)
+
+ if file_type in (0, 1, 3, 4, 5):
+ self.tile = [("raw", (0, 0) + self.size, offset, (rawmode, stride))]
+ elif file_type == 2:
+ self.tile = [("sun_rle", (0, 0) + self.size, offset, rawmode)]
+ else:
+ raise SyntaxError("Unsupported Sun Raster file type")
+
+
+#
+# registry
+
+
+Image.register_open(SunImageFile.format, SunImageFile, _accept)
+
+Image.register_extension(SunImageFile.format, ".ras")
diff --git a/venv/Lib/site-packages/PIL/TarIO.py b/venv/Lib/site-packages/PIL/TarIO.py
new file mode 100644
index 0000000..d108362
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/TarIO.py
@@ -0,0 +1,65 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# read files from within a tar file
+#
+# History:
+# 95-06-18 fl Created
+# 96-05-28 fl Open files in binary mode
+#
+# Copyright (c) Secret Labs AB 1997.
+# Copyright (c) Fredrik Lundh 1995-96.
+#
+# See the README file for information on usage and redistribution.
+#
+
+import io
+
+from . import ContainerIO
+
+
+class TarIO(ContainerIO.ContainerIO):
+ """A file object that provides read access to a given member of a TAR file."""
+
+ def __init__(self, tarfile, file):
+ """
+ Create file object.
+
+ :param tarfile: Name of TAR file.
+ :param file: Name of member file.
+ """
+ self.fh = open(tarfile, "rb")
+
+ while True:
+
+ s = self.fh.read(512)
+ if len(s) != 512:
+ raise OSError("unexpected end of tar file")
+
+ name = s[:100].decode("utf-8")
+ i = name.find("\0")
+ if i == 0:
+ raise OSError("cannot find subfile")
+ if i > 0:
+ name = name[:i]
+
+ size = int(s[124:135], 8)
+
+ if file == name:
+ break
+
+ self.fh.seek((size + 511) & (~511), io.SEEK_CUR)
+
+ # Open region
+ super().__init__(self.fh, self.fh.tell(), size)
+
+ # Context manager support
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *args):
+ self.close()
+
+ def close(self):
+ self.fh.close()
diff --git a/venv/Lib/site-packages/PIL/TgaImagePlugin.py b/venv/Lib/site-packages/PIL/TgaImagePlugin.py
new file mode 100644
index 0000000..2b936d6
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/TgaImagePlugin.py
@@ -0,0 +1,248 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# TGA file handling
+#
+# History:
+# 95-09-01 fl created (reads 24-bit files only)
+# 97-01-04 fl support more TGA versions, including compressed images
+# 98-07-04 fl fixed orientation and alpha layer bugs
+# 98-09-11 fl fixed orientation for runlength decoder
+#
+# Copyright (c) Secret Labs AB 1997-98.
+# Copyright (c) Fredrik Lundh 1995-97.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import warnings
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import i16le as i16
+from ._binary import o8
+from ._binary import o16le as o16
+
+#
+# --------------------------------------------------------------------
+# Read RGA file
+
+
+MODES = {
+ # map imagetype/depth to rawmode
+ (1, 8): "P",
+ (3, 1): "1",
+ (3, 8): "L",
+ (3, 16): "LA",
+ (2, 16): "BGR;5",
+ (2, 24): "BGR",
+ (2, 32): "BGRA",
+}
+
+
+##
+# Image plugin for Targa files.
+
+
+class TgaImageFile(ImageFile.ImageFile):
+
+ format = "TGA"
+ format_description = "Targa"
+
+ def _open(self):
+
+ # process header
+ s = self.fp.read(18)
+
+ id_len = s[0]
+
+ colormaptype = s[1]
+ imagetype = s[2]
+
+ depth = s[16]
+
+ flags = s[17]
+
+ self._size = i16(s, 12), i16(s, 14)
+
+ # validate header fields
+ if (
+ colormaptype not in (0, 1)
+ or self.size[0] <= 0
+ or self.size[1] <= 0
+ or depth not in (1, 8, 16, 24, 32)
+ ):
+ raise SyntaxError("not a TGA file")
+
+ # image mode
+ if imagetype in (3, 11):
+ self.mode = "L"
+ if depth == 1:
+ self.mode = "1" # ???
+ elif depth == 16:
+ self.mode = "LA"
+ elif imagetype in (1, 9):
+ self.mode = "P"
+ elif imagetype in (2, 10):
+ self.mode = "RGB"
+ if depth == 32:
+ self.mode = "RGBA"
+ else:
+ raise SyntaxError("unknown TGA mode")
+
+ # orientation
+ orientation = flags & 0x30
+ if orientation == 0x20:
+ orientation = 1
+ elif not orientation:
+ orientation = -1
+ else:
+ raise SyntaxError("unknown TGA orientation")
+
+ self.info["orientation"] = orientation
+
+ if imagetype & 8:
+ self.info["compression"] = "tga_rle"
+
+ if id_len:
+ self.info["id_section"] = self.fp.read(id_len)
+
+ if colormaptype:
+ # read palette
+ start, size, mapdepth = i16(s, 3), i16(s, 5), i16(s, 7)
+ if mapdepth == 16:
+ self.palette = ImagePalette.raw(
+ "BGR;16", b"\0" * 2 * start + self.fp.read(2 * size)
+ )
+ elif mapdepth == 24:
+ self.palette = ImagePalette.raw(
+ "BGR", b"\0" * 3 * start + self.fp.read(3 * size)
+ )
+ elif mapdepth == 32:
+ self.palette = ImagePalette.raw(
+ "BGRA", b"\0" * 4 * start + self.fp.read(4 * size)
+ )
+
+ # setup tile descriptor
+ try:
+ rawmode = MODES[(imagetype & 7, depth)]
+ if imagetype & 8:
+ # compressed
+ self.tile = [
+ (
+ "tga_rle",
+ (0, 0) + self.size,
+ self.fp.tell(),
+ (rawmode, orientation, depth),
+ )
+ ]
+ else:
+ self.tile = [
+ (
+ "raw",
+ (0, 0) + self.size,
+ self.fp.tell(),
+ (rawmode, 0, orientation),
+ )
+ ]
+ except KeyError:
+ pass # cannot decode
+
+
+#
+# --------------------------------------------------------------------
+# Write TGA file
+
+
+SAVE = {
+ "1": ("1", 1, 0, 3),
+ "L": ("L", 8, 0, 3),
+ "LA": ("LA", 16, 0, 3),
+ "P": ("P", 8, 1, 1),
+ "RGB": ("BGR", 24, 0, 2),
+ "RGBA": ("BGRA", 32, 0, 2),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ rawmode, bits, colormaptype, imagetype = SAVE[im.mode]
+ except KeyError as e:
+ raise OSError(f"cannot write mode {im.mode} as TGA") from e
+
+ if "rle" in im.encoderinfo:
+ rle = im.encoderinfo["rle"]
+ else:
+ compression = im.encoderinfo.get("compression", im.info.get("compression"))
+ rle = compression == "tga_rle"
+ if rle:
+ imagetype += 8
+
+ id_section = im.encoderinfo.get("id_section", im.info.get("id_section", ""))
+ id_len = len(id_section)
+ if id_len > 255:
+ id_len = 255
+ id_section = id_section[:255]
+ warnings.warn("id_section has been trimmed to 255 characters")
+
+ if colormaptype:
+ colormapfirst, colormaplength, colormapentry = 0, 256, 24
+ else:
+ colormapfirst, colormaplength, colormapentry = 0, 0, 0
+
+ if im.mode in ("LA", "RGBA"):
+ flags = 8
+ else:
+ flags = 0
+
+ orientation = im.encoderinfo.get("orientation", im.info.get("orientation", -1))
+ if orientation > 0:
+ flags = flags | 0x20
+
+ fp.write(
+ o8(id_len)
+ + o8(colormaptype)
+ + o8(imagetype)
+ + o16(colormapfirst)
+ + o16(colormaplength)
+ + o8(colormapentry)
+ + o16(0)
+ + o16(0)
+ + o16(im.size[0])
+ + o16(im.size[1])
+ + o8(bits)
+ + o8(flags)
+ )
+
+ if id_section:
+ fp.write(id_section)
+
+ if colormaptype:
+ fp.write(im.im.getpalette("RGB", "BGR"))
+
+ if rle:
+ ImageFile._save(
+ im, fp, [("tga_rle", (0, 0) + im.size, 0, (rawmode, orientation))]
+ )
+ else:
+ ImageFile._save(
+ im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))]
+ )
+
+ # write targa version 2 footer
+ fp.write(b"\000" * 8 + b"TRUEVISION-XFILE." + b"\000")
+
+
+#
+# --------------------------------------------------------------------
+# Registry
+
+
+Image.register_open(TgaImageFile.format, TgaImageFile)
+Image.register_save(TgaImageFile.format, _save)
+
+Image.register_extensions(TgaImageFile.format, [".tga", ".icb", ".vda", ".vst"])
+
+Image.register_mime(TgaImageFile.format, "image/x-tga")
diff --git a/venv/Lib/site-packages/PIL/TiffImagePlugin.py b/venv/Lib/site-packages/PIL/TiffImagePlugin.py
new file mode 100644
index 0000000..0b70ce3
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/TiffImagePlugin.py
@@ -0,0 +1,1924 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# TIFF file handling
+#
+# TIFF is a flexible, if somewhat aged, image file format originally
+# defined by Aldus. Although TIFF supports a wide variety of pixel
+# layouts and compression methods, the name doesn't really stand for
+# "thousands of incompatible file formats," it just feels that way.
+#
+# To read TIFF data from a stream, the stream must be seekable. For
+# progressive decoding, make sure to use TIFF files where the tag
+# directory is placed first in the file.
+#
+# History:
+# 1995-09-01 fl Created
+# 1996-05-04 fl Handle JPEGTABLES tag
+# 1996-05-18 fl Fixed COLORMAP support
+# 1997-01-05 fl Fixed PREDICTOR support
+# 1997-08-27 fl Added support for rational tags (from Perry Stoll)
+# 1998-01-10 fl Fixed seek/tell (from Jan Blom)
+# 1998-07-15 fl Use private names for internal variables
+# 1999-06-13 fl Rewritten for PIL 1.0 (1.0)
+# 2000-10-11 fl Additional fixes for Python 2.0 (1.1)
+# 2001-04-17 fl Fixed rewind support (seek to frame 0) (1.2)
+# 2001-05-12 fl Added write support for more tags (from Greg Couch) (1.3)
+# 2001-12-18 fl Added workaround for broken Matrox library
+# 2002-01-18 fl Don't mess up if photometric tag is missing (D. Alan Stewart)
+# 2003-05-19 fl Check FILLORDER tag
+# 2003-09-26 fl Added RGBa support
+# 2004-02-24 fl Added DPI support; fixed rational write support
+# 2005-02-07 fl Added workaround for broken Corel Draw 10 files
+# 2006-01-09 fl Added support for float/double tags (from Russell Nelson)
+#
+# Copyright (c) 1997-2006 by Secret Labs AB. All rights reserved.
+# Copyright (c) 1995-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+import io
+import itertools
+import logging
+import os
+import struct
+import warnings
+from collections.abc import MutableMapping
+from fractions import Fraction
+from numbers import Number, Rational
+
+from . import Image, ImageFile, ImagePalette, TiffTags
+from ._binary import o8
+from .TiffTags import TYPES
+
+logger = logging.getLogger(__name__)
+
+# Set these to true to force use of libtiff for reading or writing.
+READ_LIBTIFF = False
+WRITE_LIBTIFF = False
+IFD_LEGACY_API = True
+
+II = b"II" # little-endian (Intel style)
+MM = b"MM" # big-endian (Motorola style)
+
+#
+# --------------------------------------------------------------------
+# Read TIFF files
+
+# a few tag names, just to make the code below a bit more readable
+IMAGEWIDTH = 256
+IMAGELENGTH = 257
+BITSPERSAMPLE = 258
+COMPRESSION = 259
+PHOTOMETRIC_INTERPRETATION = 262
+FILLORDER = 266
+IMAGEDESCRIPTION = 270
+STRIPOFFSETS = 273
+SAMPLESPERPIXEL = 277
+ROWSPERSTRIP = 278
+STRIPBYTECOUNTS = 279
+X_RESOLUTION = 282
+Y_RESOLUTION = 283
+PLANAR_CONFIGURATION = 284
+RESOLUTION_UNIT = 296
+TRANSFERFUNCTION = 301
+SOFTWARE = 305
+DATE_TIME = 306
+ARTIST = 315
+PREDICTOR = 317
+COLORMAP = 320
+TILEOFFSETS = 324
+SUBIFD = 330
+EXTRASAMPLES = 338
+SAMPLEFORMAT = 339
+JPEGTABLES = 347
+REFERENCEBLACKWHITE = 532
+COPYRIGHT = 33432
+IPTC_NAA_CHUNK = 33723 # newsphoto properties
+PHOTOSHOP_CHUNK = 34377 # photoshop properties
+ICCPROFILE = 34675
+EXIFIFD = 34665
+XMP = 700
+JPEGQUALITY = 65537 # pseudo-tag by libtiff
+
+# https://github.com/imagej/ImageJA/blob/master/src/main/java/ij/io/TiffDecoder.java
+IMAGEJ_META_DATA_BYTE_COUNTS = 50838
+IMAGEJ_META_DATA = 50839
+
+COMPRESSION_INFO = {
+ # Compression => pil compression name
+ 1: "raw",
+ 2: "tiff_ccitt",
+ 3: "group3",
+ 4: "group4",
+ 5: "tiff_lzw",
+ 6: "tiff_jpeg", # obsolete
+ 7: "jpeg",
+ 8: "tiff_adobe_deflate",
+ 32771: "tiff_raw_16", # 16-bit padding
+ 32773: "packbits",
+ 32809: "tiff_thunderscan",
+ 32946: "tiff_deflate",
+ 34676: "tiff_sgilog",
+ 34677: "tiff_sgilog24",
+ 34925: "lzma",
+ 50000: "zstd",
+ 50001: "webp",
+}
+
+COMPRESSION_INFO_REV = {v: k for k, v in COMPRESSION_INFO.items()}
+
+OPEN_INFO = {
+ # (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
+ # ExtraSamples) => mode, rawmode
+ (II, 0, (1,), 1, (1,), ()): ("1", "1;I"),
+ (MM, 0, (1,), 1, (1,), ()): ("1", "1;I"),
+ (II, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
+ (MM, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
+ (II, 1, (1,), 1, (1,), ()): ("1", "1"),
+ (MM, 1, (1,), 1, (1,), ()): ("1", "1"),
+ (II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
+ (MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
+ (II, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
+ (MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
+ (II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
+ (MM, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
+ (II, 1, (1,), 1, (2,), ()): ("L", "L;2"),
+ (MM, 1, (1,), 1, (2,), ()): ("L", "L;2"),
+ (II, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
+ (MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
+ (II, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
+ (MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
+ (II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
+ (MM, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
+ (II, 1, (1,), 1, (4,), ()): ("L", "L;4"),
+ (MM, 1, (1,), 1, (4,), ()): ("L", "L;4"),
+ (II, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
+ (MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
+ (II, 0, (1,), 1, (8,), ()): ("L", "L;I"),
+ (MM, 0, (1,), 1, (8,), ()): ("L", "L;I"),
+ (II, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
+ (MM, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
+ (II, 1, (1,), 1, (8,), ()): ("L", "L"),
+ (MM, 1, (1,), 1, (8,), ()): ("L", "L"),
+ (II, 1, (1,), 2, (8,), ()): ("L", "L;R"),
+ (MM, 1, (1,), 2, (8,), ()): ("L", "L;R"),
+ (II, 1, (1,), 1, (12,), ()): ("I;16", "I;12"),
+ (II, 1, (1,), 1, (16,), ()): ("I;16", "I;16"),
+ (MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"),
+ (II, 1, (2,), 1, (16,), ()): ("I", "I;16S"),
+ (MM, 1, (2,), 1, (16,), ()): ("I", "I;16BS"),
+ (II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
+ (MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
+ (II, 1, (1,), 1, (32,), ()): ("I", "I;32N"),
+ (II, 1, (2,), 1, (32,), ()): ("I", "I;32S"),
+ (MM, 1, (2,), 1, (32,), ()): ("I", "I;32BS"),
+ (II, 1, (3,), 1, (32,), ()): ("F", "F;32F"),
+ (MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"),
+ (II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
+ (MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
+ (II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
+ (MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
+ (II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
+ (MM, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
+ (MM, 2, (1,), 1, (8, 8, 8, 8), ()): ("RGBA", "RGBA"), # missing ExtraSamples
+ (II, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (0,)): ("RGBX", "RGBX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGBX", "RGBXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGBX", "RGBXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGBX", "RGBXXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGBX", "RGBXXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (1,)): ("RGBA", "RGBa"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (1, 0)): ("RGBA", "RGBaX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (1, 0, 0)): ("RGBA", "RGBaXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8), (2, 0)): ("RGBA", "RGBAX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"),
+ (MM, 2, (1,), 1, (8, 8, 8, 8, 8, 8), (2, 0, 0)): ("RGBA", "RGBAXX"),
+ (II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
+ (MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
+ (II, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16), ()): ("RGB", "RGB;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), ()): ("RGBA", "RGBA;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), (0,)): ("RGBX", "RGBX;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), (1,)): ("RGBA", "RGBa;16B"),
+ (II, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16L"),
+ (MM, 2, (1,), 1, (16, 16, 16, 16), (2,)): ("RGBA", "RGBA;16B"),
+ (II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
+ (MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
+ (II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
+ (MM, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
+ (II, 3, (1,), 1, (2,), ()): ("P", "P;2"),
+ (MM, 3, (1,), 1, (2,), ()): ("P", "P;2"),
+ (II, 3, (1,), 2, (2,), ()): ("P", "P;2R"),
+ (MM, 3, (1,), 2, (2,), ()): ("P", "P;2R"),
+ (II, 3, (1,), 1, (4,), ()): ("P", "P;4"),
+ (MM, 3, (1,), 1, (4,), ()): ("P", "P;4"),
+ (II, 3, (1,), 2, (4,), ()): ("P", "P;4R"),
+ (MM, 3, (1,), 2, (4,), ()): ("P", "P;4R"),
+ (II, 3, (1,), 1, (8,), ()): ("P", "P"),
+ (MM, 3, (1,), 1, (8,), ()): ("P", "P"),
+ (II, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
+ (MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
+ (II, 3, (1,), 2, (8,), ()): ("P", "P;R"),
+ (MM, 3, (1,), 2, (8,), ()): ("P", "P;R"),
+ (II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
+ (MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
+ (II, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"),
+ (MM, 5, (1,), 1, (8, 8, 8, 8, 8), (0,)): ("CMYK", "CMYKX"),
+ (II, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
+ (MM, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
+ (II, 5, (1,), 1, (16, 16, 16, 16), ()): ("CMYK", "CMYK;16L"),
+ # JPEG compressed images handled by LibTiff and auto-converted to RGBX
+ # Minimal Baseline TIFF requires YCbCr images to have 3 SamplesPerPixel
+ (II, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"),
+ (MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGBX"),
+ (II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
+ (MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
+}
+
+PREFIXES = [
+ b"MM\x00\x2A", # Valid TIFF header with big-endian byte order
+ b"II\x2A\x00", # Valid TIFF header with little-endian byte order
+ b"MM\x2A\x00", # Invalid TIFF header, assume big-endian
+ b"II\x00\x2A", # Invalid TIFF header, assume little-endian
+]
+
+
+def _accept(prefix):
+ return prefix[:4] in PREFIXES
+
+
+def _limit_rational(val, max_val):
+ inv = abs(val) > 1
+ n_d = IFDRational(1 / val if inv else val).limit_rational(max_val)
+ return n_d[::-1] if inv else n_d
+
+
+def _limit_signed_rational(val, max_val, min_val):
+ frac = Fraction(val)
+ n_d = frac.numerator, frac.denominator
+
+ if min(n_d) < min_val:
+ n_d = _limit_rational(val, abs(min_val))
+
+ if max(n_d) > max_val:
+ val = Fraction(*n_d)
+ n_d = _limit_rational(val, max_val)
+
+ return n_d
+
+
+##
+# Wrapper for TIFF IFDs.
+
+_load_dispatch = {}
+_write_dispatch = {}
+
+
+class IFDRational(Rational):
+ """Implements a rational class where 0/0 is a legal value to match
+ the in the wild use of exif rationals.
+
+ e.g., DigitalZoomRatio - 0.00/0.00 indicates that no digital zoom was used
+ """
+
+ """ If the denominator is 0, store this as a float('nan'), otherwise store
+ as a fractions.Fraction(). Delegate as appropriate
+
+ """
+
+ __slots__ = ("_numerator", "_denominator", "_val")
+
+ def __init__(self, value, denominator=1):
+ """
+ :param value: either an integer numerator, a
+ float/rational/other number, or an IFDRational
+ :param denominator: Optional integer denominator
+ """
+ if isinstance(value, IFDRational):
+ self._numerator = value.numerator
+ self._denominator = value.denominator
+ self._val = value._val
+ return
+
+ if isinstance(value, Fraction):
+ self._numerator = value.numerator
+ self._denominator = value.denominator
+ else:
+ self._numerator = value
+ self._denominator = denominator
+
+ if denominator == 0:
+ self._val = float("nan")
+ elif denominator == 1:
+ self._val = Fraction(value)
+ else:
+ self._val = Fraction(value, denominator)
+
+ @property
+ def numerator(a):
+ return a._numerator
+
+ @property
+ def denominator(a):
+ return a._denominator
+
+ def limit_rational(self, max_denominator):
+ """
+
+ :param max_denominator: Integer, the maximum denominator value
+ :returns: Tuple of (numerator, denominator)
+ """
+
+ if self.denominator == 0:
+ return (self.numerator, self.denominator)
+
+ f = self._val.limit_denominator(max_denominator)
+ return (f.numerator, f.denominator)
+
+ def __repr__(self):
+ return str(float(self._val))
+
+ def __hash__(self):
+ return self._val.__hash__()
+
+ def __eq__(self, other):
+ if isinstance(other, IFDRational):
+ other = other._val
+ return self._val == other
+
+ def _delegate(op):
+ def delegate(self, *args):
+ return getattr(self._val, op)(*args)
+
+ return delegate
+
+ """ a = ['add','radd', 'sub', 'rsub', 'mul', 'rmul',
+ 'truediv', 'rtruediv', 'floordiv', 'rfloordiv',
+ 'mod','rmod', 'pow','rpow', 'pos', 'neg',
+ 'abs', 'trunc', 'lt', 'gt', 'le', 'ge', 'bool',
+ 'ceil', 'floor', 'round']
+ print("\n".join("__%s__ = _delegate('__%s__')" % (s,s) for s in a))
+ """
+
+ __add__ = _delegate("__add__")
+ __radd__ = _delegate("__radd__")
+ __sub__ = _delegate("__sub__")
+ __rsub__ = _delegate("__rsub__")
+ __mul__ = _delegate("__mul__")
+ __rmul__ = _delegate("__rmul__")
+ __truediv__ = _delegate("__truediv__")
+ __rtruediv__ = _delegate("__rtruediv__")
+ __floordiv__ = _delegate("__floordiv__")
+ __rfloordiv__ = _delegate("__rfloordiv__")
+ __mod__ = _delegate("__mod__")
+ __rmod__ = _delegate("__rmod__")
+ __pow__ = _delegate("__pow__")
+ __rpow__ = _delegate("__rpow__")
+ __pos__ = _delegate("__pos__")
+ __neg__ = _delegate("__neg__")
+ __abs__ = _delegate("__abs__")
+ __trunc__ = _delegate("__trunc__")
+ __lt__ = _delegate("__lt__")
+ __gt__ = _delegate("__gt__")
+ __le__ = _delegate("__le__")
+ __ge__ = _delegate("__ge__")
+ __bool__ = _delegate("__bool__")
+ __ceil__ = _delegate("__ceil__")
+ __floor__ = _delegate("__floor__")
+ __round__ = _delegate("__round__")
+
+
+class ImageFileDirectory_v2(MutableMapping):
+ """This class represents a TIFF tag directory. To speed things up, we
+ don't decode tags unless they're asked for.
+
+ Exposes a dictionary interface of the tags in the directory::
+
+ ifd = ImageFileDirectory_v2()
+ ifd[key] = 'Some Data'
+ ifd.tagtype[key] = TiffTags.ASCII
+ print(ifd[key])
+ 'Some Data'
+
+ Individual values are returned as the strings or numbers, sequences are
+ returned as tuples of the values.
+
+ The tiff metadata type of each item is stored in a dictionary of
+ tag types in
+ :attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v2.tagtype`. The types
+ are read from a tiff file, guessed from the type added, or added
+ manually.
+
+ Data Structures:
+
+ * self.tagtype = {}
+
+ * Key: numerical tiff tag number
+ * Value: integer corresponding to the data type from
+ ~PIL.TiffTags.TYPES`
+
+ .. versionadded:: 3.0.0
+ """
+
+ """
+ Documentation:
+
+ 'internal' data structures:
+ * self._tags_v2 = {} Key: numerical tiff tag number
+ Value: decoded data, as tuple for multiple values
+ * self._tagdata = {} Key: numerical tiff tag number
+ Value: undecoded byte string from file
+ * self._tags_v1 = {} Key: numerical tiff tag number
+ Value: decoded data in the v1 format
+
+ Tags will be found in the private attributes self._tagdata, and in
+ self._tags_v2 once decoded.
+
+ Self.legacy_api is a value for internal use, and shouldn't be
+ changed from outside code. In cooperation with the
+ ImageFileDirectory_v1 class, if legacy_api is true, then decoded
+ tags will be populated into both _tags_v1 and _tags_v2. _Tags_v2
+ will be used if this IFD is used in the TIFF save routine. Tags
+ should be read from tags_v1 if legacy_api == true.
+
+ """
+
+ def __init__(self, ifh=b"II\052\0\0\0\0\0", prefix=None):
+ """Initialize an ImageFileDirectory.
+
+ To construct an ImageFileDirectory from a real file, pass the 8-byte
+ magic header to the constructor. To only set the endianness, pass it
+ as the 'prefix' keyword argument.
+
+ :param ifh: One of the accepted magic headers (cf. PREFIXES); also sets
+ endianness.
+ :param prefix: Override the endianness of the file.
+ """
+ if ifh[:4] not in PREFIXES:
+ raise SyntaxError(f"not a TIFF file (header {repr(ifh)} not valid)")
+ self._prefix = prefix if prefix is not None else ifh[:2]
+ if self._prefix == MM:
+ self._endian = ">"
+ elif self._prefix == II:
+ self._endian = "<"
+ else:
+ raise SyntaxError("not a TIFF IFD")
+ self.tagtype = {}
+ """ Dictionary of tag types """
+ self.reset()
+ (self.next,) = self._unpack("L", ifh[4:])
+ self._legacy_api = False
+
+ prefix = property(lambda self: self._prefix)
+ offset = property(lambda self: self._offset)
+ legacy_api = property(lambda self: self._legacy_api)
+
+ @legacy_api.setter
+ def legacy_api(self, value):
+ raise Exception("Not allowing setting of legacy api")
+
+ def reset(self):
+ self._tags_v1 = {} # will remain empty if legacy_api is false
+ self._tags_v2 = {} # main tag storage
+ self._tagdata = {}
+ self.tagtype = {} # added 2008-06-05 by Florian Hoech
+ self._next = None
+ self._offset = None
+
+ def __str__(self):
+ return str(dict(self))
+
+ def named(self):
+ """
+ :returns: dict of name|key: value
+
+ Returns the complete tag dictionary, with named tags where possible.
+ """
+ return {TiffTags.lookup(code).name: value for code, value in self.items()}
+
+ def __len__(self):
+ return len(set(self._tagdata) | set(self._tags_v2))
+
+ def __getitem__(self, tag):
+ if tag not in self._tags_v2: # unpack on the fly
+ data = self._tagdata[tag]
+ typ = self.tagtype[tag]
+ size, handler = self._load_dispatch[typ]
+ self[tag] = handler(self, data, self.legacy_api) # check type
+ val = self._tags_v2[tag]
+ if self.legacy_api and not isinstance(val, (tuple, bytes)):
+ val = (val,)
+ return val
+
+ def __contains__(self, tag):
+ return tag in self._tags_v2 or tag in self._tagdata
+
+ def __setitem__(self, tag, value):
+ self._setitem(tag, value, self.legacy_api)
+
+ def _setitem(self, tag, value, legacy_api):
+ basetypes = (Number, bytes, str)
+
+ info = TiffTags.lookup(tag)
+ values = [value] if isinstance(value, basetypes) else value
+
+ if tag not in self.tagtype:
+ if info.type:
+ self.tagtype[tag] = info.type
+ else:
+ self.tagtype[tag] = TiffTags.UNDEFINED
+ if all(isinstance(v, IFDRational) for v in values):
+ self.tagtype[tag] = (
+ TiffTags.RATIONAL
+ if all(v >= 0 for v in values)
+ else TiffTags.SIGNED_RATIONAL
+ )
+ elif all(isinstance(v, int) for v in values):
+ if all(0 <= v < 2 ** 16 for v in values):
+ self.tagtype[tag] = TiffTags.SHORT
+ elif all(-(2 ** 15) < v < 2 ** 15 for v in values):
+ self.tagtype[tag] = TiffTags.SIGNED_SHORT
+ else:
+ self.tagtype[tag] = (
+ TiffTags.LONG
+ if all(v >= 0 for v in values)
+ else TiffTags.SIGNED_LONG
+ )
+ elif all(isinstance(v, float) for v in values):
+ self.tagtype[tag] = TiffTags.DOUBLE
+ elif all(isinstance(v, str) for v in values):
+ self.tagtype[tag] = TiffTags.ASCII
+ elif all(isinstance(v, bytes) for v in values):
+ self.tagtype[tag] = TiffTags.BYTE
+
+ if self.tagtype[tag] == TiffTags.UNDEFINED:
+ values = [
+ value.encode("ascii", "replace") if isinstance(value, str) else value
+ ]
+ elif self.tagtype[tag] == TiffTags.RATIONAL:
+ values = [float(v) if isinstance(v, int) else v for v in values]
+
+ is_ifd = self.tagtype[tag] == TiffTags.LONG and isinstance(values, dict)
+ if not is_ifd:
+ values = tuple(info.cvt_enum(value) for value in values)
+
+ dest = self._tags_v1 if legacy_api else self._tags_v2
+
+ # Three branches:
+ # Spec'd length == 1, Actual length 1, store as element
+ # Spec'd length == 1, Actual > 1, Warn and truncate. Formerly barfed.
+ # No Spec, Actual length 1, Formerly (<4.2) returned a 1 element tuple.
+ # Don't mess with the legacy api, since it's frozen.
+ if not is_ifd and (
+ (info.length == 1)
+ or self.tagtype[tag] == TiffTags.BYTE
+ or (info.length is None and len(values) == 1 and not legacy_api)
+ ):
+ # Don't mess with the legacy api, since it's frozen.
+ if legacy_api and self.tagtype[tag] in [
+ TiffTags.RATIONAL,
+ TiffTags.SIGNED_RATIONAL,
+ ]: # rationals
+ values = (values,)
+ try:
+ (dest[tag],) = values
+ except ValueError:
+ # We've got a builtin tag with 1 expected entry
+ warnings.warn(
+ f"Metadata Warning, tag {tag} had too many entries: "
+ f"{len(values)}, expected 1"
+ )
+ dest[tag] = values[0]
+
+ else:
+ # Spec'd length > 1 or undefined
+ # Unspec'd, and length > 1
+ dest[tag] = values
+
+ def __delitem__(self, tag):
+ self._tags_v2.pop(tag, None)
+ self._tags_v1.pop(tag, None)
+ self._tagdata.pop(tag, None)
+
+ def __iter__(self):
+ return iter(set(self._tagdata) | set(self._tags_v2))
+
+ def _unpack(self, fmt, data):
+ return struct.unpack(self._endian + fmt, data)
+
+ def _pack(self, fmt, *values):
+ return struct.pack(self._endian + fmt, *values)
+
+ def _register_loader(idx, size):
+ def decorator(func):
+ from .TiffTags import TYPES
+
+ if func.__name__.startswith("load_"):
+ TYPES[idx] = func.__name__[5:].replace("_", " ")
+ _load_dispatch[idx] = size, func # noqa: F821
+ return func
+
+ return decorator
+
+ def _register_writer(idx):
+ def decorator(func):
+ _write_dispatch[idx] = func # noqa: F821
+ return func
+
+ return decorator
+
+ def _register_basic(idx_fmt_name):
+ from .TiffTags import TYPES
+
+ idx, fmt, name = idx_fmt_name
+ TYPES[idx] = name
+ size = struct.calcsize("=" + fmt)
+ _load_dispatch[idx] = ( # noqa: F821
+ size,
+ lambda self, data, legacy_api=True: (
+ self._unpack("{}{}".format(len(data) // size, fmt), data)
+ ),
+ )
+ _write_dispatch[idx] = lambda self, *values: ( # noqa: F821
+ b"".join(self._pack(fmt, value) for value in values)
+ )
+
+ list(
+ map(
+ _register_basic,
+ [
+ (TiffTags.SHORT, "H", "short"),
+ (TiffTags.LONG, "L", "long"),
+ (TiffTags.SIGNED_BYTE, "b", "signed byte"),
+ (TiffTags.SIGNED_SHORT, "h", "signed short"),
+ (TiffTags.SIGNED_LONG, "l", "signed long"),
+ (TiffTags.FLOAT, "f", "float"),
+ (TiffTags.DOUBLE, "d", "double"),
+ (TiffTags.IFD, "L", "long"),
+ ],
+ )
+ )
+
+ @_register_loader(1, 1) # Basic type, except for the legacy API.
+ def load_byte(self, data, legacy_api=True):
+ return data
+
+ @_register_writer(1) # Basic type, except for the legacy API.
+ def write_byte(self, data):
+ return data
+
+ @_register_loader(2, 1)
+ def load_string(self, data, legacy_api=True):
+ if data.endswith(b"\0"):
+ data = data[:-1]
+ return data.decode("latin-1", "replace")
+
+ @_register_writer(2)
+ def write_string(self, value):
+ # remerge of https://github.com/python-pillow/Pillow/pull/1416
+ return b"" + value.encode("ascii", "replace") + b"\0"
+
+ @_register_loader(5, 8)
+ def load_rational(self, data, legacy_api=True):
+ vals = self._unpack("{}L".format(len(data) // 4), data)
+
+ def combine(a, b):
+ return (a, b) if legacy_api else IFDRational(a, b)
+
+ return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
+
+ @_register_writer(5)
+ def write_rational(self, *values):
+ return b"".join(
+ self._pack("2L", *_limit_rational(frac, 2 ** 32 - 1)) for frac in values
+ )
+
+ @_register_loader(7, 1)
+ def load_undefined(self, data, legacy_api=True):
+ return data
+
+ @_register_writer(7)
+ def write_undefined(self, value):
+ return value
+
+ @_register_loader(10, 8)
+ def load_signed_rational(self, data, legacy_api=True):
+ vals = self._unpack("{}l".format(len(data) // 4), data)
+
+ def combine(a, b):
+ return (a, b) if legacy_api else IFDRational(a, b)
+
+ return tuple(combine(num, denom) for num, denom in zip(vals[::2], vals[1::2]))
+
+ @_register_writer(10)
+ def write_signed_rational(self, *values):
+ return b"".join(
+ self._pack("2l", *_limit_signed_rational(frac, 2 ** 31 - 1, -(2 ** 31)))
+ for frac in values
+ )
+
+ def _ensure_read(self, fp, size):
+ ret = fp.read(size)
+ if len(ret) != size:
+ raise OSError(
+ "Corrupt EXIF data. "
+ f"Expecting to read {size} bytes but only got {len(ret)}. "
+ )
+ return ret
+
+ def load(self, fp):
+
+ self.reset()
+ self._offset = fp.tell()
+
+ try:
+ for i in range(self._unpack("H", self._ensure_read(fp, 2))[0]):
+ tag, typ, count, data = self._unpack("HHL4s", self._ensure_read(fp, 12))
+
+ tagname = TiffTags.lookup(tag).name
+ typname = TYPES.get(typ, "unknown")
+ msg = f"tag: {tagname} ({tag}) - type: {typname} ({typ})"
+
+ try:
+ unit_size, handler = self._load_dispatch[typ]
+ except KeyError:
+ logger.debug(msg + f" - unsupported type {typ}")
+ continue # ignore unsupported type
+ size = count * unit_size
+ if size > 4:
+ here = fp.tell()
+ (offset,) = self._unpack("L", data)
+ msg += f" Tag Location: {here} - Data Location: {offset}"
+ fp.seek(offset)
+ data = ImageFile._safe_read(fp, size)
+ fp.seek(here)
+ else:
+ data = data[:size]
+
+ if len(data) != size:
+ warnings.warn(
+ "Possibly corrupt EXIF data. "
+ f"Expecting to read {size} bytes but only got {len(data)}."
+ f" Skipping tag {tag}"
+ )
+ logger.debug(msg)
+ continue
+
+ if not data:
+ logger.debug(msg)
+ continue
+
+ self._tagdata[tag] = data
+ self.tagtype[tag] = typ
+
+ msg += " - value: " + (
+ "" % size if size > 32 else repr(data)
+ )
+ logger.debug(msg)
+
+ (self.next,) = self._unpack("L", self._ensure_read(fp, 4))
+ except OSError as msg:
+ warnings.warn(str(msg))
+ return
+
+ def tobytes(self, offset=0):
+ # FIXME What about tagdata?
+ result = self._pack("H", len(self._tags_v2))
+
+ entries = []
+ offset = offset + len(result) + len(self._tags_v2) * 12 + 4
+ stripoffsets = None
+
+ # pass 1: convert tags to binary format
+ # always write tags in ascending order
+ for tag, value in sorted(self._tags_v2.items()):
+ if tag == STRIPOFFSETS:
+ stripoffsets = len(entries)
+ typ = self.tagtype.get(tag)
+ logger.debug(f"Tag {tag}, Type: {typ}, Value: {repr(value)}")
+ is_ifd = typ == TiffTags.LONG and isinstance(value, dict)
+ if is_ifd:
+ if self._endian == "<":
+ ifh = b"II\x2A\x00\x08\x00\x00\x00"
+ else:
+ ifh = b"MM\x00\x2A\x00\x00\x00\x08"
+ ifd = ImageFileDirectory_v2(ifh)
+ for ifd_tag, ifd_value in self._tags_v2[tag].items():
+ ifd[ifd_tag] = ifd_value
+ data = ifd.tobytes(offset)
+ else:
+ values = value if isinstance(value, tuple) else (value,)
+ data = self._write_dispatch[typ](self, *values)
+
+ tagname = TiffTags.lookup(tag).name
+ typname = "ifd" if is_ifd else TYPES.get(typ, "unknown")
+ msg = f"save: {tagname} ({tag}) - type: {typname} ({typ})"
+ msg += " - value: " + (
+ "" % len(data) if len(data) >= 16 else str(values)
+ )
+ logger.debug(msg)
+
+ # count is sum of lengths for string and arbitrary data
+ if is_ifd:
+ count = 1
+ elif typ in [TiffTags.BYTE, TiffTags.ASCII, TiffTags.UNDEFINED]:
+ count = len(data)
+ else:
+ count = len(values)
+ # figure out if data fits into the entry
+ if len(data) <= 4:
+ entries.append((tag, typ, count, data.ljust(4, b"\0"), b""))
+ else:
+ entries.append((tag, typ, count, self._pack("L", offset), data))
+ offset += (len(data) + 1) // 2 * 2 # pad to word
+
+ # update strip offset data to point beyond auxiliary data
+ if stripoffsets is not None:
+ tag, typ, count, value, data = entries[stripoffsets]
+ if data:
+ raise NotImplementedError("multistrip support not yet implemented")
+ value = self._pack("L", self._unpack("L", value)[0] + offset)
+ entries[stripoffsets] = tag, typ, count, value, data
+
+ # pass 2: write entries to file
+ for tag, typ, count, value, data in entries:
+ logger.debug(f"{tag} {typ} {count} {repr(value)} {repr(data)}")
+ result += self._pack("HHL4s", tag, typ, count, value)
+
+ # -- overwrite here for multi-page --
+ result += b"\0\0\0\0" # end of entries
+
+ # pass 3: write auxiliary data to file
+ for tag, typ, count, value, data in entries:
+ result += data
+ if len(data) & 1:
+ result += b"\0"
+
+ return result
+
+ def save(self, fp):
+
+ if fp.tell() == 0: # skip TIFF header on subsequent pages
+ # tiff header -- PIL always starts the first IFD at offset 8
+ fp.write(self._prefix + self._pack("HL", 42, 8))
+
+ offset = fp.tell()
+ result = self.tobytes(offset)
+ fp.write(result)
+ return offset + len(result)
+
+
+ImageFileDirectory_v2._load_dispatch = _load_dispatch
+ImageFileDirectory_v2._write_dispatch = _write_dispatch
+for idx, name in TYPES.items():
+ name = name.replace(" ", "_")
+ setattr(ImageFileDirectory_v2, "load_" + name, _load_dispatch[idx][1])
+ setattr(ImageFileDirectory_v2, "write_" + name, _write_dispatch[idx])
+del _load_dispatch, _write_dispatch, idx, name
+
+
+# Legacy ImageFileDirectory support.
+class ImageFileDirectory_v1(ImageFileDirectory_v2):
+ """This class represents the **legacy** interface to a TIFF tag directory.
+
+ Exposes a dictionary interface of the tags in the directory::
+
+ ifd = ImageFileDirectory_v1()
+ ifd[key] = 'Some Data'
+ ifd.tagtype[key] = TiffTags.ASCII
+ print(ifd[key])
+ ('Some Data',)
+
+ Also contains a dictionary of tag types as read from the tiff image file,
+ :attr:`~PIL.TiffImagePlugin.ImageFileDirectory_v1.tagtype`.
+
+ Values are returned as a tuple.
+
+ .. deprecated:: 3.0.0
+ """
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self._legacy_api = True
+
+ tags = property(lambda self: self._tags_v1)
+ tagdata = property(lambda self: self._tagdata)
+
+ # defined in ImageFileDirectory_v2
+ tagtype: dict
+ """Dictionary of tag types"""
+
+ @classmethod
+ def from_v2(cls, original):
+ """Returns an
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
+ instance with the same data as is contained in the original
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
+ instance.
+
+ :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
+
+ """
+
+ ifd = cls(prefix=original.prefix)
+ ifd._tagdata = original._tagdata
+ ifd.tagtype = original.tagtype
+ ifd.next = original.next # an indicator for multipage tiffs
+ return ifd
+
+ def to_v2(self):
+ """Returns an
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
+ instance with the same data as is contained in the original
+ :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v1`
+ instance.
+
+ :returns: :py:class:`~PIL.TiffImagePlugin.ImageFileDirectory_v2`
+
+ """
+
+ ifd = ImageFileDirectory_v2(prefix=self.prefix)
+ ifd._tagdata = dict(self._tagdata)
+ ifd.tagtype = dict(self.tagtype)
+ ifd._tags_v2 = dict(self._tags_v2)
+ return ifd
+
+ def __contains__(self, tag):
+ return tag in self._tags_v1 or tag in self._tagdata
+
+ def __len__(self):
+ return len(set(self._tagdata) | set(self._tags_v1))
+
+ def __iter__(self):
+ return iter(set(self._tagdata) | set(self._tags_v1))
+
+ def __setitem__(self, tag, value):
+ for legacy_api in (False, True):
+ self._setitem(tag, value, legacy_api)
+
+ def __getitem__(self, tag):
+ if tag not in self._tags_v1: # unpack on the fly
+ data = self._tagdata[tag]
+ typ = self.tagtype[tag]
+ size, handler = self._load_dispatch[typ]
+ for legacy in (False, True):
+ self._setitem(tag, handler(self, data, legacy), legacy)
+ val = self._tags_v1[tag]
+ if not isinstance(val, (tuple, bytes)):
+ val = (val,)
+ return val
+
+
+# undone -- switch this pointer when IFD_LEGACY_API == False
+ImageFileDirectory = ImageFileDirectory_v1
+
+
+##
+# Image plugin for TIFF files.
+
+
+class TiffImageFile(ImageFile.ImageFile):
+
+ format = "TIFF"
+ format_description = "Adobe TIFF"
+ _close_exclusive_fp_after_loading = False
+
+ def __init__(self, fp=None, filename=None):
+ self.tag_v2 = None
+ """ Image file directory (tag dictionary) """
+
+ self.tag = None
+ """ Legacy tag entries """
+
+ super().__init__(fp, filename)
+
+ def _open(self):
+ """Open the first image in a TIFF file"""
+
+ # Header
+ ifh = self.fp.read(8)
+
+ self.tag_v2 = ImageFileDirectory_v2(ifh)
+
+ # legacy IFD entries will be filled in later
+ self.ifd = None
+
+ # setup frame pointers
+ self.__first = self.__next = self.tag_v2.next
+ self.__frame = -1
+ self.__fp = self.fp
+ self._frame_pos = []
+ self._n_frames = None
+
+ logger.debug("*** TiffImageFile._open ***")
+ logger.debug(f"- __first: {self.__first}")
+ logger.debug(f"- ifh: {repr(ifh)}") # Use repr to avoid str(bytes)
+
+ # and load the first frame
+ self._seek(0)
+
+ @property
+ def n_frames(self):
+ if self._n_frames is None:
+ current = self.tell()
+ self._seek(len(self._frame_pos))
+ while self._n_frames is None:
+ self._seek(self.tell() + 1)
+ self.seek(current)
+ return self._n_frames
+
+ def seek(self, frame):
+ """Select a given frame as current image"""
+ if not self._seek_check(frame):
+ return
+ self._seek(frame)
+ # Create a new core image object on second and
+ # subsequent frames in the image. Image may be
+ # different size/mode.
+ Image._decompression_bomb_check(self.size)
+ self.im = Image.core.new(self.mode, self.size)
+
+ def _seek(self, frame):
+ self.fp = self.__fp
+ while len(self._frame_pos) <= frame:
+ if not self.__next:
+ raise EOFError("no more images in TIFF file")
+ logger.debug(
+ f"Seeking to frame {frame}, on frame {self.__frame}, "
+ f"__next {self.__next}, location: {self.fp.tell()}"
+ )
+ # reset buffered io handle in case fp
+ # was passed to libtiff, invalidating the buffer
+ self.fp.tell()
+ self.fp.seek(self.__next)
+ self._frame_pos.append(self.__next)
+ logger.debug("Loading tags, location: %s" % self.fp.tell())
+ self.tag_v2.load(self.fp)
+ self.__next = self.tag_v2.next
+ if self.__next == 0:
+ self._n_frames = frame + 1
+ if len(self._frame_pos) == 1:
+ self.is_animated = self.__next != 0
+ self.__frame += 1
+ self.fp.seek(self._frame_pos[frame])
+ self.tag_v2.load(self.fp)
+ # fill the legacy tag/ifd entries
+ self.tag = self.ifd = ImageFileDirectory_v1.from_v2(self.tag_v2)
+ self.__frame = frame
+ self._setup()
+
+ def tell(self):
+ """Return the current frame number"""
+ return self.__frame
+
+ def load(self):
+ if self.tile and self.use_load_libtiff:
+ return self._load_libtiff()
+ return super().load()
+
+ def load_end(self):
+ if self._tile_orientation:
+ method = {
+ 2: Image.FLIP_LEFT_RIGHT,
+ 3: Image.ROTATE_180,
+ 4: Image.FLIP_TOP_BOTTOM,
+ 5: Image.TRANSPOSE,
+ 6: Image.ROTATE_270,
+ 7: Image.TRANSVERSE,
+ 8: Image.ROTATE_90,
+ }.get(self._tile_orientation)
+ if method is not None:
+ self.im = self.im.transpose(method)
+ self._size = self.im.size
+
+ # allow closing if we're on the first frame, there's no next
+ # This is the ImageFile.load path only, libtiff specific below.
+ if not self.is_animated:
+ self._close_exclusive_fp_after_loading = True
+
+ def _load_libtiff(self):
+ """Overload method triggered when we detect a compressed tiff
+ Calls out to libtiff"""
+
+ Image.Image.load(self)
+
+ self.load_prepare()
+
+ if not len(self.tile) == 1:
+ raise OSError("Not exactly one tile")
+
+ # (self._compression, (extents tuple),
+ # 0, (rawmode, self._compression, fp))
+ extents = self.tile[0][1]
+ args = list(self.tile[0][3])
+
+ # To be nice on memory footprint, if there's a
+ # file descriptor, use that instead of reading
+ # into a string in python.
+ # libtiff closes the file descriptor, so pass in a dup.
+ try:
+ fp = hasattr(self.fp, "fileno") and os.dup(self.fp.fileno())
+ # flush the file descriptor, prevents error on pypy 2.4+
+ # should also eliminate the need for fp.tell
+ # in _seek
+ if hasattr(self.fp, "flush"):
+ self.fp.flush()
+ except OSError:
+ # io.BytesIO have a fileno, but returns an OSError if
+ # it doesn't use a file descriptor.
+ fp = False
+
+ if fp:
+ args[2] = fp
+
+ decoder = Image._getdecoder(
+ self.mode, "libtiff", tuple(args), self.decoderconfig
+ )
+ try:
+ decoder.setimage(self.im, extents)
+ except ValueError as e:
+ raise OSError("Couldn't set the image") from e
+
+ close_self_fp = self._exclusive_fp and not self.is_animated
+ if hasattr(self.fp, "getvalue"):
+ # We've got a stringio like thing passed in. Yay for all in memory.
+ # The decoder needs the entire file in one shot, so there's not
+ # a lot we can do here other than give it the entire file.
+ # unless we could do something like get the address of the
+ # underlying string for stringio.
+ #
+ # Rearranging for supporting byteio items, since they have a fileno
+ # that returns an OSError if there's no underlying fp. Easier to
+ # deal with here by reordering.
+ logger.debug("have getvalue. just sending in a string from getvalue")
+ n, err = decoder.decode(self.fp.getvalue())
+ elif fp:
+ # we've got a actual file on disk, pass in the fp.
+ logger.debug("have fileno, calling fileno version of the decoder.")
+ if not close_self_fp:
+ self.fp.seek(0)
+ # 4 bytes, otherwise the trace might error out
+ n, err = decoder.decode(b"fpfp")
+ else:
+ # we have something else.
+ logger.debug("don't have fileno or getvalue. just reading")
+ self.fp.seek(0)
+ # UNDONE -- so much for that buffer size thing.
+ n, err = decoder.decode(self.fp.read())
+
+ self.tile = []
+ self.readonly = 0
+
+ self.load_end()
+
+ # libtiff closed the fp in a, we need to close self.fp, if possible
+ if close_self_fp:
+ self.fp.close()
+ self.fp = None # might be shared
+
+ if err < 0:
+ raise OSError(err)
+
+ return Image.Image.load(self)
+
+ def _setup(self):
+ """Setup this image object based on current tags"""
+
+ if 0xBC01 in self.tag_v2:
+ raise OSError("Windows Media Photo files not yet supported")
+
+ # extract relevant tags
+ self._compression = COMPRESSION_INFO[self.tag_v2.get(COMPRESSION, 1)]
+ self._planar_configuration = self.tag_v2.get(PLANAR_CONFIGURATION, 1)
+
+ # photometric is a required tag, but not everyone is reading
+ # the specification
+ photo = self.tag_v2.get(PHOTOMETRIC_INTERPRETATION, 0)
+
+ # old style jpeg compression images most certainly are YCbCr
+ if self._compression == "tiff_jpeg":
+ photo = 6
+
+ fillorder = self.tag_v2.get(FILLORDER, 1)
+
+ logger.debug("*** Summary ***")
+ logger.debug(f"- compression: {self._compression}")
+ logger.debug(f"- photometric_interpretation: {photo}")
+ logger.debug(f"- planar_configuration: {self._planar_configuration}")
+ logger.debug(f"- fill_order: {fillorder}")
+ logger.debug(f"- YCbCr subsampling: {self.tag.get(530)}")
+
+ # size
+ xsize = int(self.tag_v2.get(IMAGEWIDTH))
+ ysize = int(self.tag_v2.get(IMAGELENGTH))
+ self._size = xsize, ysize
+
+ logger.debug(f"- size: {self.size}")
+
+ sampleFormat = self.tag_v2.get(SAMPLEFORMAT, (1,))
+ if len(sampleFormat) > 1 and max(sampleFormat) == min(sampleFormat) == 1:
+ # SAMPLEFORMAT is properly per band, so an RGB image will
+ # be (1,1,1). But, we don't support per band pixel types,
+ # and anything more than one band is a uint8. So, just
+ # take the first element. Revisit this if adding support
+ # for more exotic images.
+ sampleFormat = (1,)
+
+ bps_tuple = self.tag_v2.get(BITSPERSAMPLE, (1,))
+ extra_tuple = self.tag_v2.get(EXTRASAMPLES, ())
+ if photo in (2, 6, 8): # RGB, YCbCr, LAB
+ bps_count = 3
+ elif photo == 5: # CMYK
+ bps_count = 4
+ else:
+ bps_count = 1
+ bps_count += len(extra_tuple)
+ # Some files have only one value in bps_tuple,
+ # while should have more. Fix it
+ if bps_count > len(bps_tuple) and len(bps_tuple) == 1:
+ bps_tuple = bps_tuple * bps_count
+
+ # mode: check photometric interpretation and bits per pixel
+ key = (
+ self.tag_v2.prefix,
+ photo,
+ sampleFormat,
+ fillorder,
+ bps_tuple,
+ extra_tuple,
+ )
+ logger.debug(f"format key: {key}")
+ try:
+ self.mode, rawmode = OPEN_INFO[key]
+ except KeyError as e:
+ logger.debug("- unsupported format")
+ raise SyntaxError("unknown pixel mode") from e
+
+ logger.debug(f"- raw mode: {rawmode}")
+ logger.debug(f"- pil mode: {self.mode}")
+
+ self.info["compression"] = self._compression
+
+ xres = self.tag_v2.get(X_RESOLUTION, 1)
+ yres = self.tag_v2.get(Y_RESOLUTION, 1)
+
+ if xres and yres:
+ resunit = self.tag_v2.get(RESOLUTION_UNIT)
+ if resunit == 2: # dots per inch
+ self.info["dpi"] = int(xres + 0.5), int(yres + 0.5)
+ elif resunit == 3: # dots per centimeter. convert to dpi
+ self.info["dpi"] = int(xres * 2.54 + 0.5), int(yres * 2.54 + 0.5)
+ elif resunit is None: # used to default to 1, but now 2)
+ self.info["dpi"] = int(xres + 0.5), int(yres + 0.5)
+ # For backward compatibility,
+ # we also preserve the old behavior
+ self.info["resolution"] = xres, yres
+ else: # No absolute unit of measurement
+ self.info["resolution"] = xres, yres
+
+ # build tile descriptors
+ x = y = layer = 0
+ self.tile = []
+ self.use_load_libtiff = READ_LIBTIFF or self._compression != "raw"
+ if self.use_load_libtiff:
+ # Decoder expects entire file as one tile.
+ # There's a buffer size limit in load (64k)
+ # so large g4 images will fail if we use that
+ # function.
+ #
+ # Setup the one tile for the whole image, then
+ # use the _load_libtiff function.
+
+ # libtiff handles the fillmode for us, so 1;IR should
+ # actually be 1;I. Including the R double reverses the
+ # bits, so stripes of the image are reversed. See
+ # https://github.com/python-pillow/Pillow/issues/279
+ if fillorder == 2:
+ # Replace fillorder with fillorder=1
+ key = key[:3] + (1,) + key[4:]
+ logger.debug(f"format key: {key}")
+ # this should always work, since all the
+ # fillorder==2 modes have a corresponding
+ # fillorder=1 mode
+ self.mode, rawmode = OPEN_INFO[key]
+ # libtiff always returns the bytes in native order.
+ # we're expecting image byte order. So, if the rawmode
+ # contains I;16, we need to convert from native to image
+ # byte order.
+ if rawmode == "I;16":
+ rawmode = "I;16N"
+ if ";16B" in rawmode:
+ rawmode = rawmode.replace(";16B", ";16N")
+ if ";16L" in rawmode:
+ rawmode = rawmode.replace(";16L", ";16N")
+
+ # Offset in the tile tuple is 0, we go from 0,0 to
+ # w,h, and we only do this once -- eds
+ a = (rawmode, self._compression, False, self.tag_v2.offset)
+ self.tile.append(("libtiff", (0, 0, xsize, ysize), 0, a))
+
+ elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
+ # striped image
+ if STRIPOFFSETS in self.tag_v2:
+ offsets = self.tag_v2[STRIPOFFSETS]
+ h = self.tag_v2.get(ROWSPERSTRIP, ysize)
+ w = self.size[0]
+ else:
+ # tiled image
+ offsets = self.tag_v2[TILEOFFSETS]
+ w = self.tag_v2.get(322)
+ h = self.tag_v2.get(323)
+
+ for offset in offsets:
+ if x + w > xsize:
+ stride = w * sum(bps_tuple) / 8 # bytes per line
+ else:
+ stride = 0
+
+ tile_rawmode = rawmode
+ if self._planar_configuration == 2:
+ # each band on it's own layer
+ tile_rawmode = rawmode[layer]
+ # adjust stride width accordingly
+ stride /= bps_count
+
+ a = (tile_rawmode, int(stride), 1)
+ self.tile.append(
+ (
+ self._compression,
+ (x, y, min(x + w, xsize), min(y + h, ysize)),
+ offset,
+ a,
+ )
+ )
+ x = x + w
+ if x >= self.size[0]:
+ x, y = 0, y + h
+ if y >= self.size[1]:
+ x = y = 0
+ layer += 1
+ else:
+ logger.debug("- unsupported data organization")
+ raise SyntaxError("unknown data organization")
+
+ # Fix up info.
+ if ICCPROFILE in self.tag_v2:
+ self.info["icc_profile"] = self.tag_v2[ICCPROFILE]
+
+ # fixup palette descriptor
+
+ if self.mode in ["P", "PA"]:
+ palette = [o8(b // 256) for b in self.tag_v2[COLORMAP]]
+ self.palette = ImagePalette.raw("RGB;L", b"".join(palette))
+
+ self._tile_orientation = self.tag_v2.get(0x0112)
+
+ def _close__fp(self):
+ try:
+ if self.__fp != self.fp:
+ self.__fp.close()
+ except AttributeError:
+ pass
+ finally:
+ self.__fp = None
+
+
+#
+# --------------------------------------------------------------------
+# Write TIFF files
+
+# little endian is default except for image modes with
+# explicit big endian byte-order
+
+SAVE_INFO = {
+ # mode => rawmode, byteorder, photometrics,
+ # sampleformat, bitspersample, extra
+ "1": ("1", II, 1, 1, (1,), None),
+ "L": ("L", II, 1, 1, (8,), None),
+ "LA": ("LA", II, 1, 1, (8, 8), 2),
+ "P": ("P", II, 3, 1, (8,), None),
+ "PA": ("PA", II, 3, 1, (8, 8), 2),
+ "I": ("I;32S", II, 1, 2, (32,), None),
+ "I;16": ("I;16", II, 1, 1, (16,), None),
+ "I;16S": ("I;16S", II, 1, 2, (16,), None),
+ "F": ("F;32F", II, 1, 3, (32,), None),
+ "RGB": ("RGB", II, 2, 1, (8, 8, 8), None),
+ "RGBX": ("RGBX", II, 2, 1, (8, 8, 8, 8), 0),
+ "RGBA": ("RGBA", II, 2, 1, (8, 8, 8, 8), 2),
+ "CMYK": ("CMYK", II, 5, 1, (8, 8, 8, 8), None),
+ "YCbCr": ("YCbCr", II, 6, 1, (8, 8, 8), None),
+ "LAB": ("LAB", II, 8, 1, (8, 8, 8), None),
+ "I;32BS": ("I;32BS", MM, 1, 2, (32,), None),
+ "I;16B": ("I;16B", MM, 1, 1, (16,), None),
+ "I;16BS": ("I;16BS", MM, 1, 2, (16,), None),
+ "F;32BF": ("F;32BF", MM, 1, 3, (32,), None),
+}
+
+
+def _save(im, fp, filename):
+
+ try:
+ rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
+ except KeyError as e:
+ raise OSError(f"cannot write mode {im.mode} as TIFF") from e
+
+ ifd = ImageFileDirectory_v2(prefix=prefix)
+
+ compression = im.encoderinfo.get("compression", im.info.get("compression"))
+ if compression is None:
+ compression = "raw"
+ elif compression == "tiff_jpeg":
+ # OJPEG is obsolete, so use new-style JPEG compression instead
+ compression = "jpeg"
+
+ libtiff = WRITE_LIBTIFF or compression != "raw"
+
+ # required for color libtiff images
+ ifd[PLANAR_CONFIGURATION] = getattr(im, "_planar_configuration", 1)
+
+ ifd[IMAGEWIDTH] = im.size[0]
+ ifd[IMAGELENGTH] = im.size[1]
+
+ # write any arbitrary tags passed in as an ImageFileDirectory
+ info = im.encoderinfo.get("tiffinfo", {})
+ logger.debug("Tiffinfo Keys: %s" % list(info))
+ if isinstance(info, ImageFileDirectory_v1):
+ info = info.to_v2()
+ for key in info:
+ ifd[key] = info.get(key)
+ try:
+ ifd.tagtype[key] = info.tagtype[key]
+ except Exception:
+ pass # might not be an IFD. Might not have populated type
+
+ # additions written by Greg Couch, gregc@cgl.ucsf.edu
+ # inspired by image-sig posting from Kevin Cazabon, kcazabon@home.com
+ if hasattr(im, "tag_v2"):
+ # preserve tags from original TIFF image file
+ for key in (
+ RESOLUTION_UNIT,
+ X_RESOLUTION,
+ Y_RESOLUTION,
+ IPTC_NAA_CHUNK,
+ PHOTOSHOP_CHUNK,
+ XMP,
+ ):
+ if key in im.tag_v2:
+ ifd[key] = im.tag_v2[key]
+ ifd.tagtype[key] = im.tag_v2.tagtype[key]
+
+ # preserve ICC profile (should also work when saving other formats
+ # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
+ if "icc_profile" in im.info:
+ ifd[ICCPROFILE] = im.info["icc_profile"]
+
+ for key, name in [
+ (IMAGEDESCRIPTION, "description"),
+ (X_RESOLUTION, "resolution"),
+ (Y_RESOLUTION, "resolution"),
+ (X_RESOLUTION, "x_resolution"),
+ (Y_RESOLUTION, "y_resolution"),
+ (RESOLUTION_UNIT, "resolution_unit"),
+ (SOFTWARE, "software"),
+ (DATE_TIME, "date_time"),
+ (ARTIST, "artist"),
+ (COPYRIGHT, "copyright"),
+ ]:
+ if name in im.encoderinfo:
+ ifd[key] = im.encoderinfo[name]
+
+ dpi = im.encoderinfo.get("dpi")
+ if dpi:
+ ifd[RESOLUTION_UNIT] = 2
+ ifd[X_RESOLUTION] = int(dpi[0] + 0.5)
+ ifd[Y_RESOLUTION] = int(dpi[1] + 0.5)
+
+ if bits != (1,):
+ ifd[BITSPERSAMPLE] = bits
+ if len(bits) != 1:
+ ifd[SAMPLESPERPIXEL] = len(bits)
+ if extra is not None:
+ ifd[EXTRASAMPLES] = extra
+ if format != 1:
+ ifd[SAMPLEFORMAT] = format
+
+ ifd[PHOTOMETRIC_INTERPRETATION] = photo
+
+ if im.mode in ["P", "PA"]:
+ lut = im.im.getpalette("RGB", "RGB;L")
+ ifd[COLORMAP] = tuple(v * 256 for v in lut)
+ # data orientation
+ stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
+ ifd[ROWSPERSTRIP] = im.size[1]
+ strip_byte_counts = stride * im.size[1]
+ if strip_byte_counts >= 2 ** 16:
+ ifd.tagtype[STRIPBYTECOUNTS] = TiffTags.LONG
+ ifd[STRIPBYTECOUNTS] = strip_byte_counts
+ ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
+ # no compression by default:
+ ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)
+
+ if libtiff:
+ if "quality" in im.encoderinfo:
+ quality = im.encoderinfo["quality"]
+ if not isinstance(quality, int) or quality < 0 or quality > 100:
+ raise ValueError("Invalid quality setting")
+ if compression != "jpeg":
+ raise ValueError(
+ "quality setting only supported for 'jpeg' compression"
+ )
+ ifd[JPEGQUALITY] = quality
+
+ logger.debug("Saving using libtiff encoder")
+ logger.debug("Items: %s" % sorted(ifd.items()))
+ _fp = 0
+ if hasattr(fp, "fileno"):
+ try:
+ fp.seek(0)
+ _fp = os.dup(fp.fileno())
+ except io.UnsupportedOperation:
+ pass
+
+ # optional types for non core tags
+ types = {}
+ # SAMPLEFORMAT is determined by the image format and should not be copied
+ # from legacy_ifd.
+ # STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
+ # based on the data in the strip.
+ # The other tags expect arrays with a certain length (fixed or depending on
+ # BITSPERSAMPLE, etc), passing arrays with a different length will result in
+ # segfaults. Block these tags until we add extra validation.
+ # SUBIFD may also cause a segfault.
+ blocklist = [
+ REFERENCEBLACKWHITE,
+ SAMPLEFORMAT,
+ STRIPBYTECOUNTS,
+ STRIPOFFSETS,
+ TRANSFERFUNCTION,
+ SUBIFD,
+ ]
+
+ atts = {}
+ # bits per sample is a single short in the tiff directory, not a list.
+ atts[BITSPERSAMPLE] = bits[0]
+ # Merge the ones that we have with (optional) more bits from
+ # the original file, e.g x,y resolution so that we can
+ # save(load('')) == original file.
+ legacy_ifd = {}
+ if hasattr(im, "tag"):
+ legacy_ifd = im.tag.to_v2()
+ for tag, value in itertools.chain(
+ ifd.items(), getattr(im, "tag_v2", {}).items(), legacy_ifd.items()
+ ):
+ # Libtiff can only process certain core items without adding
+ # them to the custom dictionary.
+ # Custom items are supported for int, float, unicode, string and byte
+ # values. Other types and tuples require a tagtype.
+ if tag not in TiffTags.LIBTIFF_CORE:
+ if not Image.core.libtiff_support_custom_tags:
+ continue
+
+ if tag in ifd.tagtype:
+ types[tag] = ifd.tagtype[tag]
+ elif not (isinstance(value, (int, float, str, bytes))):
+ continue
+ else:
+ type = TiffTags.lookup(tag).type
+ if type:
+ types[tag] = type
+ if tag not in atts and tag not in blocklist:
+ if isinstance(value, str):
+ atts[tag] = value.encode("ascii", "replace") + b"\0"
+ elif isinstance(value, IFDRational):
+ atts[tag] = float(value)
+ else:
+ atts[tag] = value
+
+ logger.debug("Converted items: %s" % sorted(atts.items()))
+
+ # libtiff always expects the bytes in native order.
+ # we're storing image byte order. So, if the rawmode
+ # contains I;16, we need to convert from native to image
+ # byte order.
+ if im.mode in ("I;16B", "I;16"):
+ rawmode = "I;16N"
+
+ # Pass tags as sorted list so that the tags are set in a fixed order.
+ # This is required by libtiff for some tags. For example, the JPEGQUALITY
+ # pseudo tag requires that the COMPRESS tag was already set.
+ tags = list(atts.items())
+ tags.sort()
+ a = (rawmode, compression, _fp, filename, tags, types)
+ e = Image._getencoder(im.mode, "libtiff", a, im.encoderconfig)
+ e.setimage(im.im, (0, 0) + im.size)
+ while True:
+ # undone, change to self.decodermaxblock:
+ l, s, d = e.encode(16 * 1024)
+ if not _fp:
+ fp.write(d)
+ if s:
+ break
+ if s < 0:
+ raise OSError(f"encoder error {s} when writing image file")
+
+ else:
+ offset = ifd.save(fp)
+
+ ImageFile._save(
+ im, fp, [("raw", (0, 0) + im.size, offset, (rawmode, stride, 1))]
+ )
+
+ # -- helper for multi-page save --
+ if "_debug_multipage" in im.encoderinfo:
+ # just to access o32 and o16 (using correct byte order)
+ im._debug_multipage = ifd
+
+
+class AppendingTiffWriter:
+ fieldSizes = [
+ 0, # None
+ 1, # byte
+ 1, # ascii
+ 2, # short
+ 4, # long
+ 8, # rational
+ 1, # sbyte
+ 1, # undefined
+ 2, # sshort
+ 4, # slong
+ 8, # srational
+ 4, # float
+ 8, # double
+ ]
+
+ # StripOffsets = 273
+ # FreeOffsets = 288
+ # TileOffsets = 324
+ # JPEGQTables = 519
+ # JPEGDCTables = 520
+ # JPEGACTables = 521
+ Tags = {273, 288, 324, 519, 520, 521}
+
+ def __init__(self, fn, new=False):
+ if hasattr(fn, "read"):
+ self.f = fn
+ self.close_fp = False
+ else:
+ self.name = fn
+ self.close_fp = True
+ try:
+ self.f = open(fn, "w+b" if new else "r+b")
+ except OSError:
+ self.f = open(fn, "w+b")
+ self.beginning = self.f.tell()
+ self.setup()
+
+ def setup(self):
+ # Reset everything.
+ self.f.seek(self.beginning, os.SEEK_SET)
+
+ self.whereToWriteNewIFDOffset = None
+ self.offsetOfNewPage = 0
+
+ self.IIMM = IIMM = self.f.read(4)
+ if not IIMM:
+ # empty file - first page
+ self.isFirst = True
+ return
+
+ self.isFirst = False
+ if IIMM == b"II\x2a\x00":
+ self.setEndian("<")
+ elif IIMM == b"MM\x00\x2a":
+ self.setEndian(">")
+ else:
+ raise RuntimeError("Invalid TIFF file header")
+
+ self.skipIFDs()
+ self.goToEnd()
+
+ def finalize(self):
+ if self.isFirst:
+ return
+
+ # fix offsets
+ self.f.seek(self.offsetOfNewPage)
+
+ IIMM = self.f.read(4)
+ if not IIMM:
+ # raise RuntimeError("nothing written into new page")
+ # Make it easy to finish a frame without committing to a new one.
+ return
+
+ if IIMM != self.IIMM:
+ raise RuntimeError("IIMM of new page doesn't match IIMM of first page")
+
+ IFDoffset = self.readLong()
+ IFDoffset += self.offsetOfNewPage
+ self.f.seek(self.whereToWriteNewIFDOffset)
+ self.writeLong(IFDoffset)
+ self.f.seek(IFDoffset)
+ self.fixIFD()
+
+ def newFrame(self):
+ # Call this to finish a frame.
+ self.finalize()
+ self.setup()
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if self.close_fp:
+ self.close()
+ return False
+
+ def tell(self):
+ return self.f.tell() - self.offsetOfNewPage
+
+ def seek(self, offset, whence=io.SEEK_SET):
+ if whence == os.SEEK_SET:
+ offset += self.offsetOfNewPage
+
+ self.f.seek(offset, whence)
+ return self.tell()
+
+ def goToEnd(self):
+ self.f.seek(0, os.SEEK_END)
+ pos = self.f.tell()
+
+ # pad to 16 byte boundary
+ padBytes = 16 - pos % 16
+ if 0 < padBytes < 16:
+ self.f.write(bytes(padBytes))
+ self.offsetOfNewPage = self.f.tell()
+
+ def setEndian(self, endian):
+ self.endian = endian
+ self.longFmt = self.endian + "L"
+ self.shortFmt = self.endian + "H"
+ self.tagFormat = self.endian + "HHL"
+
+ def skipIFDs(self):
+ while True:
+ IFDoffset = self.readLong()
+ if IFDoffset == 0:
+ self.whereToWriteNewIFDOffset = self.f.tell() - 4
+ break
+
+ self.f.seek(IFDoffset)
+ numTags = self.readShort()
+ self.f.seek(numTags * 12, os.SEEK_CUR)
+
+ def write(self, data):
+ return self.f.write(data)
+
+ def readShort(self):
+ (value,) = struct.unpack(self.shortFmt, self.f.read(2))
+ return value
+
+ def readLong(self):
+ (value,) = struct.unpack(self.longFmt, self.f.read(4))
+ return value
+
+ def rewriteLastShortToLong(self, value):
+ self.f.seek(-2, os.SEEK_CUR)
+ bytesWritten = self.f.write(struct.pack(self.longFmt, value))
+ if bytesWritten is not None and bytesWritten != 4:
+ raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 4")
+
+ def rewriteLastShort(self, value):
+ self.f.seek(-2, os.SEEK_CUR)
+ bytesWritten = self.f.write(struct.pack(self.shortFmt, value))
+ if bytesWritten is not None and bytesWritten != 2:
+ raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 2")
+
+ def rewriteLastLong(self, value):
+ self.f.seek(-4, os.SEEK_CUR)
+ bytesWritten = self.f.write(struct.pack(self.longFmt, value))
+ if bytesWritten is not None and bytesWritten != 4:
+ raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 4")
+
+ def writeShort(self, value):
+ bytesWritten = self.f.write(struct.pack(self.shortFmt, value))
+ if bytesWritten is not None and bytesWritten != 2:
+ raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 2")
+
+ def writeLong(self, value):
+ bytesWritten = self.f.write(struct.pack(self.longFmt, value))
+ if bytesWritten is not None and bytesWritten != 4:
+ raise RuntimeError(f"wrote only {bytesWritten} bytes but wanted 4")
+
+ def close(self):
+ self.finalize()
+ self.f.close()
+
+ def fixIFD(self):
+ numTags = self.readShort()
+
+ for i in range(numTags):
+ tag, fieldType, count = struct.unpack(self.tagFormat, self.f.read(8))
+
+ fieldSize = self.fieldSizes[fieldType]
+ totalSize = fieldSize * count
+ isLocal = totalSize <= 4
+ if not isLocal:
+ offset = self.readLong()
+ offset += self.offsetOfNewPage
+ self.rewriteLastLong(offset)
+
+ if tag in self.Tags:
+ curPos = self.f.tell()
+
+ if isLocal:
+ self.fixOffsets(
+ count, isShort=(fieldSize == 2), isLong=(fieldSize == 4)
+ )
+ self.f.seek(curPos + 4)
+ else:
+ self.f.seek(offset)
+ self.fixOffsets(
+ count, isShort=(fieldSize == 2), isLong=(fieldSize == 4)
+ )
+ self.f.seek(curPos)
+
+ offset = curPos = None
+
+ elif isLocal:
+ # skip the locally stored value that is not an offset
+ self.f.seek(4, os.SEEK_CUR)
+
+ def fixOffsets(self, count, isShort=False, isLong=False):
+ if not isShort and not isLong:
+ raise RuntimeError("offset is neither short nor long")
+
+ for i in range(count):
+ offset = self.readShort() if isShort else self.readLong()
+ offset += self.offsetOfNewPage
+ if isShort and offset >= 65536:
+ # offset is now too large - we must convert shorts to longs
+ if count != 1:
+ raise RuntimeError("not implemented") # XXX TODO
+
+ # simple case - the offset is just one and therefore it is
+ # local (not referenced with another offset)
+ self.rewriteLastShortToLong(offset)
+ self.f.seek(-10, os.SEEK_CUR)
+ self.writeShort(TiffTags.LONG) # rewrite the type to LONG
+ self.f.seek(8, os.SEEK_CUR)
+ elif isShort:
+ self.rewriteLastShort(offset)
+ else:
+ self.rewriteLastLong(offset)
+
+
+def _save_all(im, fp, filename):
+ encoderinfo = im.encoderinfo.copy()
+ encoderconfig = im.encoderconfig
+ append_images = list(encoderinfo.get("append_images", []))
+ if not hasattr(im, "n_frames") and not append_images:
+ return _save(im, fp, filename)
+
+ cur_idx = im.tell()
+ try:
+ with AppendingTiffWriter(fp) as tf:
+ for ims in [im] + append_images:
+ ims.encoderinfo = encoderinfo
+ ims.encoderconfig = encoderconfig
+ if not hasattr(ims, "n_frames"):
+ nfr = 1
+ else:
+ nfr = ims.n_frames
+
+ for idx in range(nfr):
+ ims.seek(idx)
+ ims.load()
+ _save(ims, tf, filename)
+ tf.newFrame()
+ finally:
+ im.seek(cur_idx)
+
+
+#
+# --------------------------------------------------------------------
+# Register
+
+Image.register_open(TiffImageFile.format, TiffImageFile, _accept)
+Image.register_save(TiffImageFile.format, _save)
+Image.register_save_all(TiffImageFile.format, _save_all)
+
+Image.register_extensions(TiffImageFile.format, [".tif", ".tiff"])
+
+Image.register_mime(TiffImageFile.format, "image/tiff")
diff --git a/venv/Lib/site-packages/PIL/TiffTags.py b/venv/Lib/site-packages/PIL/TiffTags.py
new file mode 100644
index 0000000..796ff34
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/TiffTags.py
@@ -0,0 +1,499 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# TIFF tags
+#
+# This module provides clear-text names for various well-known
+# TIFF tags. the TIFF codec works just fine without it.
+#
+# Copyright (c) Secret Labs AB 1999.
+#
+# See the README file for information on usage and redistribution.
+#
+
+##
+# This module provides constants and clear-text names for various
+# well-known TIFF tags.
+##
+
+from collections import namedtuple
+
+
+class TagInfo(namedtuple("_TagInfo", "value name type length enum")):
+ __slots__ = []
+
+ def __new__(cls, value=None, name="unknown", type=None, length=None, enum=None):
+ return super().__new__(cls, value, name, type, length, enum or {})
+
+ def cvt_enum(self, value):
+ # Using get will call hash(value), which can be expensive
+ # for some types (e.g. Fraction). Since self.enum is rarely
+ # used, it's usually better to test it first.
+ return self.enum.get(value, value) if self.enum else value
+
+
+def lookup(tag):
+ """
+ :param tag: Integer tag number
+ :returns: Taginfo namedtuple, From the TAGS_V2 info if possible,
+ otherwise just populating the value and name from TAGS.
+ If the tag is not recognized, "unknown" is returned for the name
+
+ """
+
+ return TAGS_V2.get(tag, TagInfo(tag, TAGS.get(tag, "unknown")))
+
+
+##
+# Map tag numbers to tag info.
+#
+# id: (Name, Type, Length, enum_values)
+#
+# The length here differs from the length in the tiff spec. For
+# numbers, the tiff spec is for the number of fields returned. We
+# agree here. For string-like types, the tiff spec uses the length of
+# field in bytes. In Pillow, we are using the number of expected
+# fields, in general 1 for string-like types.
+
+
+BYTE = 1
+ASCII = 2
+SHORT = 3
+LONG = 4
+RATIONAL = 5
+SIGNED_BYTE = 6
+UNDEFINED = 7
+SIGNED_SHORT = 8
+SIGNED_LONG = 9
+SIGNED_RATIONAL = 10
+FLOAT = 11
+DOUBLE = 12
+IFD = 13
+
+TAGS_V2 = {
+ 254: ("NewSubfileType", LONG, 1),
+ 255: ("SubfileType", SHORT, 1),
+ 256: ("ImageWidth", LONG, 1),
+ 257: ("ImageLength", LONG, 1),
+ 258: ("BitsPerSample", SHORT, 0),
+ 259: (
+ "Compression",
+ SHORT,
+ 1,
+ {
+ "Uncompressed": 1,
+ "CCITT 1d": 2,
+ "Group 3 Fax": 3,
+ "Group 4 Fax": 4,
+ "LZW": 5,
+ "JPEG": 6,
+ "PackBits": 32773,
+ },
+ ),
+ 262: (
+ "PhotometricInterpretation",
+ SHORT,
+ 1,
+ {
+ "WhiteIsZero": 0,
+ "BlackIsZero": 1,
+ "RGB": 2,
+ "RGB Palette": 3,
+ "Transparency Mask": 4,
+ "CMYK": 5,
+ "YCbCr": 6,
+ "CieLAB": 8,
+ "CFA": 32803, # TIFF/EP, Adobe DNG
+ "LinearRaw": 32892, # Adobe DNG
+ },
+ ),
+ 263: ("Threshholding", SHORT, 1),
+ 264: ("CellWidth", SHORT, 1),
+ 265: ("CellLength", SHORT, 1),
+ 266: ("FillOrder", SHORT, 1),
+ 269: ("DocumentName", ASCII, 1),
+ 270: ("ImageDescription", ASCII, 1),
+ 271: ("Make", ASCII, 1),
+ 272: ("Model", ASCII, 1),
+ 273: ("StripOffsets", LONG, 0),
+ 274: ("Orientation", SHORT, 1),
+ 277: ("SamplesPerPixel", SHORT, 1),
+ 278: ("RowsPerStrip", LONG, 1),
+ 279: ("StripByteCounts", LONG, 0),
+ 280: ("MinSampleValue", SHORT, 0),
+ 281: ("MaxSampleValue", SHORT, 0),
+ 282: ("XResolution", RATIONAL, 1),
+ 283: ("YResolution", RATIONAL, 1),
+ 284: ("PlanarConfiguration", SHORT, 1, {"Contiguous": 1, "Separate": 2}),
+ 285: ("PageName", ASCII, 1),
+ 286: ("XPosition", RATIONAL, 1),
+ 287: ("YPosition", RATIONAL, 1),
+ 288: ("FreeOffsets", LONG, 1),
+ 289: ("FreeByteCounts", LONG, 1),
+ 290: ("GrayResponseUnit", SHORT, 1),
+ 291: ("GrayResponseCurve", SHORT, 0),
+ 292: ("T4Options", LONG, 1),
+ 293: ("T6Options", LONG, 1),
+ 296: ("ResolutionUnit", SHORT, 1, {"none": 1, "inch": 2, "cm": 3}),
+ 297: ("PageNumber", SHORT, 2),
+ 301: ("TransferFunction", SHORT, 0),
+ 305: ("Software", ASCII, 1),
+ 306: ("DateTime", ASCII, 1),
+ 315: ("Artist", ASCII, 1),
+ 316: ("HostComputer", ASCII, 1),
+ 317: ("Predictor", SHORT, 1, {"none": 1, "Horizontal Differencing": 2}),
+ 318: ("WhitePoint", RATIONAL, 2),
+ 319: ("PrimaryChromaticities", RATIONAL, 6),
+ 320: ("ColorMap", SHORT, 0),
+ 321: ("HalftoneHints", SHORT, 2),
+ 322: ("TileWidth", LONG, 1),
+ 323: ("TileLength", LONG, 1),
+ 324: ("TileOffsets", LONG, 0),
+ 325: ("TileByteCounts", LONG, 0),
+ 332: ("InkSet", SHORT, 1),
+ 333: ("InkNames", ASCII, 1),
+ 334: ("NumberOfInks", SHORT, 1),
+ 336: ("DotRange", SHORT, 0),
+ 337: ("TargetPrinter", ASCII, 1),
+ 338: ("ExtraSamples", SHORT, 0),
+ 339: ("SampleFormat", SHORT, 0),
+ 340: ("SMinSampleValue", DOUBLE, 0),
+ 341: ("SMaxSampleValue", DOUBLE, 0),
+ 342: ("TransferRange", SHORT, 6),
+ 347: ("JPEGTables", UNDEFINED, 1),
+ # obsolete JPEG tags
+ 512: ("JPEGProc", SHORT, 1),
+ 513: ("JPEGInterchangeFormat", LONG, 1),
+ 514: ("JPEGInterchangeFormatLength", LONG, 1),
+ 515: ("JPEGRestartInterval", SHORT, 1),
+ 517: ("JPEGLosslessPredictors", SHORT, 0),
+ 518: ("JPEGPointTransforms", SHORT, 0),
+ 519: ("JPEGQTables", LONG, 0),
+ 520: ("JPEGDCTables", LONG, 0),
+ 521: ("JPEGACTables", LONG, 0),
+ 529: ("YCbCrCoefficients", RATIONAL, 3),
+ 530: ("YCbCrSubSampling", SHORT, 2),
+ 531: ("YCbCrPositioning", SHORT, 1),
+ 532: ("ReferenceBlackWhite", RATIONAL, 6),
+ 700: ("XMP", BYTE, 0),
+ 33432: ("Copyright", ASCII, 1),
+ 33723: ("IptcNaaInfo", UNDEFINED, 0),
+ 34377: ("PhotoshopInfo", BYTE, 0),
+ # FIXME add more tags here
+ 34665: ("ExifIFD", LONG, 1),
+ 34675: ("ICCProfile", UNDEFINED, 1),
+ 34853: ("GPSInfoIFD", LONG, 1),
+ # MPInfo
+ 45056: ("MPFVersion", UNDEFINED, 1),
+ 45057: ("NumberOfImages", LONG, 1),
+ 45058: ("MPEntry", UNDEFINED, 1),
+ 45059: ("ImageUIDList", UNDEFINED, 0), # UNDONE, check
+ 45060: ("TotalFrames", LONG, 1),
+ 45313: ("MPIndividualNum", LONG, 1),
+ 45569: ("PanOrientation", LONG, 1),
+ 45570: ("PanOverlap_H", RATIONAL, 1),
+ 45571: ("PanOverlap_V", RATIONAL, 1),
+ 45572: ("BaseViewpointNum", LONG, 1),
+ 45573: ("ConvergenceAngle", SIGNED_RATIONAL, 1),
+ 45574: ("BaselineLength", RATIONAL, 1),
+ 45575: ("VerticalDivergence", SIGNED_RATIONAL, 1),
+ 45576: ("AxisDistance_X", SIGNED_RATIONAL, 1),
+ 45577: ("AxisDistance_Y", SIGNED_RATIONAL, 1),
+ 45578: ("AxisDistance_Z", SIGNED_RATIONAL, 1),
+ 45579: ("YawAngle", SIGNED_RATIONAL, 1),
+ 45580: ("PitchAngle", SIGNED_RATIONAL, 1),
+ 45581: ("RollAngle", SIGNED_RATIONAL, 1),
+ 50741: ("MakerNoteSafety", SHORT, 1, {"Unsafe": 0, "Safe": 1}),
+ 50780: ("BestQualityScale", RATIONAL, 1),
+ 50838: ("ImageJMetaDataByteCounts", LONG, 0), # Can be more than one
+ 50839: ("ImageJMetaData", UNDEFINED, 1), # see Issue #2006
+}
+
+# Legacy Tags structure
+# these tags aren't included above, but were in the previous versions
+TAGS = {
+ 347: "JPEGTables",
+ 700: "XMP",
+ # Additional Exif Info
+ 32932: "Wang Annotation",
+ 33434: "ExposureTime",
+ 33437: "FNumber",
+ 33445: "MD FileTag",
+ 33446: "MD ScalePixel",
+ 33447: "MD ColorTable",
+ 33448: "MD LabName",
+ 33449: "MD SampleInfo",
+ 33450: "MD PrepDate",
+ 33451: "MD PrepTime",
+ 33452: "MD FileUnits",
+ 33550: "ModelPixelScaleTag",
+ 33723: "IptcNaaInfo",
+ 33918: "INGR Packet Data Tag",
+ 33919: "INGR Flag Registers",
+ 33920: "IrasB Transformation Matrix",
+ 33922: "ModelTiepointTag",
+ 34264: "ModelTransformationTag",
+ 34377: "PhotoshopInfo",
+ 34735: "GeoKeyDirectoryTag",
+ 34736: "GeoDoubleParamsTag",
+ 34737: "GeoAsciiParamsTag",
+ 34850: "ExposureProgram",
+ 34852: "SpectralSensitivity",
+ 34855: "ISOSpeedRatings",
+ 34856: "OECF",
+ 34864: "SensitivityType",
+ 34865: "StandardOutputSensitivity",
+ 34866: "RecommendedExposureIndex",
+ 34867: "ISOSpeed",
+ 34868: "ISOSpeedLatitudeyyy",
+ 34869: "ISOSpeedLatitudezzz",
+ 34908: "HylaFAX FaxRecvParams",
+ 34909: "HylaFAX FaxSubAddress",
+ 34910: "HylaFAX FaxRecvTime",
+ 36864: "ExifVersion",
+ 36867: "DateTimeOriginal",
+ 36868: "DateTImeDigitized",
+ 37121: "ComponentsConfiguration",
+ 37122: "CompressedBitsPerPixel",
+ 37724: "ImageSourceData",
+ 37377: "ShutterSpeedValue",
+ 37378: "ApertureValue",
+ 37379: "BrightnessValue",
+ 37380: "ExposureBiasValue",
+ 37381: "MaxApertureValue",
+ 37382: "SubjectDistance",
+ 37383: "MeteringMode",
+ 37384: "LightSource",
+ 37385: "Flash",
+ 37386: "FocalLength",
+ 37396: "SubjectArea",
+ 37500: "MakerNote",
+ 37510: "UserComment",
+ 37520: "SubSec",
+ 37521: "SubSecTimeOriginal",
+ 37522: "SubsecTimeDigitized",
+ 40960: "FlashPixVersion",
+ 40961: "ColorSpace",
+ 40962: "PixelXDimension",
+ 40963: "PixelYDimension",
+ 40964: "RelatedSoundFile",
+ 40965: "InteroperabilityIFD",
+ 41483: "FlashEnergy",
+ 41484: "SpatialFrequencyResponse",
+ 41486: "FocalPlaneXResolution",
+ 41487: "FocalPlaneYResolution",
+ 41488: "FocalPlaneResolutionUnit",
+ 41492: "SubjectLocation",
+ 41493: "ExposureIndex",
+ 41495: "SensingMethod",
+ 41728: "FileSource",
+ 41729: "SceneType",
+ 41730: "CFAPattern",
+ 41985: "CustomRendered",
+ 41986: "ExposureMode",
+ 41987: "WhiteBalance",
+ 41988: "DigitalZoomRatio",
+ 41989: "FocalLengthIn35mmFilm",
+ 41990: "SceneCaptureType",
+ 41991: "GainControl",
+ 41992: "Contrast",
+ 41993: "Saturation",
+ 41994: "Sharpness",
+ 41995: "DeviceSettingDescription",
+ 41996: "SubjectDistanceRange",
+ 42016: "ImageUniqueID",
+ 42032: "CameraOwnerName",
+ 42033: "BodySerialNumber",
+ 42034: "LensSpecification",
+ 42035: "LensMake",
+ 42036: "LensModel",
+ 42037: "LensSerialNumber",
+ 42112: "GDAL_METADATA",
+ 42113: "GDAL_NODATA",
+ 42240: "Gamma",
+ 50215: "Oce Scanjob Description",
+ 50216: "Oce Application Selector",
+ 50217: "Oce Identification Number",
+ 50218: "Oce ImageLogic Characteristics",
+ # Adobe DNG
+ 50706: "DNGVersion",
+ 50707: "DNGBackwardVersion",
+ 50708: "UniqueCameraModel",
+ 50709: "LocalizedCameraModel",
+ 50710: "CFAPlaneColor",
+ 50711: "CFALayout",
+ 50712: "LinearizationTable",
+ 50713: "BlackLevelRepeatDim",
+ 50714: "BlackLevel",
+ 50715: "BlackLevelDeltaH",
+ 50716: "BlackLevelDeltaV",
+ 50717: "WhiteLevel",
+ 50718: "DefaultScale",
+ 50719: "DefaultCropOrigin",
+ 50720: "DefaultCropSize",
+ 50721: "ColorMatrix1",
+ 50722: "ColorMatrix2",
+ 50723: "CameraCalibration1",
+ 50724: "CameraCalibration2",
+ 50725: "ReductionMatrix1",
+ 50726: "ReductionMatrix2",
+ 50727: "AnalogBalance",
+ 50728: "AsShotNeutral",
+ 50729: "AsShotWhiteXY",
+ 50730: "BaselineExposure",
+ 50731: "BaselineNoise",
+ 50732: "BaselineSharpness",
+ 50733: "BayerGreenSplit",
+ 50734: "LinearResponseLimit",
+ 50735: "CameraSerialNumber",
+ 50736: "LensInfo",
+ 50737: "ChromaBlurRadius",
+ 50738: "AntiAliasStrength",
+ 50740: "DNGPrivateData",
+ 50778: "CalibrationIlluminant1",
+ 50779: "CalibrationIlluminant2",
+ 50784: "Alias Layer Metadata",
+}
+
+
+def _populate():
+ for k, v in TAGS_V2.items():
+ # Populate legacy structure.
+ TAGS[k] = v[0]
+ if len(v) == 4:
+ for sk, sv in v[3].items():
+ TAGS[(k, sv)] = sk
+
+ TAGS_V2[k] = TagInfo(k, *v)
+
+
+_populate()
+##
+# Map type numbers to type names -- defined in ImageFileDirectory.
+
+TYPES = {}
+
+# was:
+# TYPES = {
+# 1: "byte",
+# 2: "ascii",
+# 3: "short",
+# 4: "long",
+# 5: "rational",
+# 6: "signed byte",
+# 7: "undefined",
+# 8: "signed short",
+# 9: "signed long",
+# 10: "signed rational",
+# 11: "float",
+# 12: "double",
+# }
+
+#
+# These tags are handled by default in libtiff, without
+# adding to the custom dictionary. From tif_dir.c, searching for
+# case TIFFTAG in the _TIFFVSetField function:
+# Line: item.
+# 148: case TIFFTAG_SUBFILETYPE:
+# 151: case TIFFTAG_IMAGEWIDTH:
+# 154: case TIFFTAG_IMAGELENGTH:
+# 157: case TIFFTAG_BITSPERSAMPLE:
+# 181: case TIFFTAG_COMPRESSION:
+# 202: case TIFFTAG_PHOTOMETRIC:
+# 205: case TIFFTAG_THRESHHOLDING:
+# 208: case TIFFTAG_FILLORDER:
+# 214: case TIFFTAG_ORIENTATION:
+# 221: case TIFFTAG_SAMPLESPERPIXEL:
+# 228: case TIFFTAG_ROWSPERSTRIP:
+# 238: case TIFFTAG_MINSAMPLEVALUE:
+# 241: case TIFFTAG_MAXSAMPLEVALUE:
+# 244: case TIFFTAG_SMINSAMPLEVALUE:
+# 247: case TIFFTAG_SMAXSAMPLEVALUE:
+# 250: case TIFFTAG_XRESOLUTION:
+# 256: case TIFFTAG_YRESOLUTION:
+# 262: case TIFFTAG_PLANARCONFIG:
+# 268: case TIFFTAG_XPOSITION:
+# 271: case TIFFTAG_YPOSITION:
+# 274: case TIFFTAG_RESOLUTIONUNIT:
+# 280: case TIFFTAG_PAGENUMBER:
+# 284: case TIFFTAG_HALFTONEHINTS:
+# 288: case TIFFTAG_COLORMAP:
+# 294: case TIFFTAG_EXTRASAMPLES:
+# 298: case TIFFTAG_MATTEING:
+# 305: case TIFFTAG_TILEWIDTH:
+# 316: case TIFFTAG_TILELENGTH:
+# 327: case TIFFTAG_TILEDEPTH:
+# 333: case TIFFTAG_DATATYPE:
+# 344: case TIFFTAG_SAMPLEFORMAT:
+# 361: case TIFFTAG_IMAGEDEPTH:
+# 364: case TIFFTAG_SUBIFD:
+# 376: case TIFFTAG_YCBCRPOSITIONING:
+# 379: case TIFFTAG_YCBCRSUBSAMPLING:
+# 383: case TIFFTAG_TRANSFERFUNCTION:
+# 389: case TIFFTAG_REFERENCEBLACKWHITE:
+# 393: case TIFFTAG_INKNAMES:
+
+# Following pseudo-tags are also handled by default in libtiff:
+# TIFFTAG_JPEGQUALITY 65537
+
+# some of these are not in our TAGS_V2 dict and were included from tiff.h
+
+# This list also exists in encode.c
+LIBTIFF_CORE = {
+ 255,
+ 256,
+ 257,
+ 258,
+ 259,
+ 262,
+ 263,
+ 266,
+ 274,
+ 277,
+ 278,
+ 280,
+ 281,
+ 340,
+ 341,
+ 282,
+ 283,
+ 284,
+ 286,
+ 287,
+ 296,
+ 297,
+ 321,
+ 320,
+ 338,
+ 32995,
+ 322,
+ 323,
+ 32998,
+ 32996,
+ 339,
+ 32997,
+ 330,
+ 531,
+ 530,
+ 301,
+ 532,
+ 333,
+ # as above
+ 269, # this has been in our tests forever, and works
+ 65537,
+}
+
+LIBTIFF_CORE.remove(301) # Array of short, crashes
+LIBTIFF_CORE.remove(532) # Array of long, crashes
+
+LIBTIFF_CORE.remove(255) # We don't have support for subfiletypes
+LIBTIFF_CORE.remove(322) # We don't have support for writing tiled images with libtiff
+LIBTIFF_CORE.remove(323) # Tiled images
+LIBTIFF_CORE.remove(333) # Ink Names either
+
+# Note to advanced users: There may be combinations of these
+# parameters and values that when added properly, will work and
+# produce valid tiff images that may work in your application.
+# It is safe to add and remove tags from this set from Pillow's point
+# of view so long as you test against libtiff.
diff --git a/venv/Lib/site-packages/PIL/WalImageFile.py b/venv/Lib/site-packages/PIL/WalImageFile.py
new file mode 100644
index 0000000..b578d69
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/WalImageFile.py
@@ -0,0 +1,126 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# WAL file handling
+#
+# History:
+# 2003-04-23 fl created
+#
+# Copyright (c) 2003 by Fredrik Lundh.
+#
+# See the README file for information on usage and redistribution.
+#
+
+"""
+This reader is based on the specification available from:
+https://www.flipcode.com/archives/Quake_2_BSP_File_Format.shtml
+and has been tested with a few sample files found using google.
+
+.. note::
+ This format cannot be automatically recognized, so the reader
+ is not registered for use with :py:func:`PIL.Image.open()`.
+ To open a WAL file, use the :py:func:`PIL.WalImageFile.open()` function instead.
+"""
+
+import builtins
+
+from . import Image
+from ._binary import i32le as i32
+
+
+def open(filename):
+ """
+ Load texture from a Quake2 WAL texture file.
+
+ By default, a Quake2 standard palette is attached to the texture.
+ To override the palette, use the :py:func:`PIL.Image.Image.putpalette()` method.
+
+ :param filename: WAL file name, or an opened file handle.
+ :returns: An image instance.
+ """
+ # FIXME: modify to return a WalImageFile instance instead of
+ # plain Image object ?
+
+ def imopen(fp):
+ # read header fields
+ header = fp.read(32 + 24 + 32 + 12)
+ size = i32(header, 32), i32(header, 36)
+ offset = i32(header, 40)
+
+ # load pixel data
+ fp.seek(offset)
+
+ Image._decompression_bomb_check(size)
+ im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
+ im.putpalette(quake2palette)
+
+ im.format = "WAL"
+ im.format_description = "Quake2 Texture"
+
+ # strings are null-terminated
+ im.info["name"] = header[:32].split(b"\0", 1)[0]
+ next_name = header[56 : 56 + 32].split(b"\0", 1)[0]
+ if next_name:
+ im.info["next_name"] = next_name
+
+ return im
+
+ if hasattr(filename, "read"):
+ return imopen(filename)
+ else:
+ with builtins.open(filename, "rb") as fp:
+ return imopen(fp)
+
+
+quake2palette = (
+ # default palette taken from piffo 0.93 by Hans Häggström
+ b"\x01\x01\x01\x0b\x0b\x0b\x12\x12\x12\x17\x17\x17\x1b\x1b\x1b\x1e"
+ b"\x1e\x1e\x22\x22\x22\x26\x26\x26\x29\x29\x29\x2c\x2c\x2c\x2f\x2f"
+ b"\x2f\x32\x32\x32\x35\x35\x35\x37\x37\x37\x3a\x3a\x3a\x3c\x3c\x3c"
+ b"\x24\x1e\x13\x22\x1c\x12\x20\x1b\x12\x1f\x1a\x10\x1d\x19\x10\x1b"
+ b"\x17\x0f\x1a\x16\x0f\x18\x14\x0d\x17\x13\x0d\x16\x12\x0d\x14\x10"
+ b"\x0b\x13\x0f\x0b\x10\x0d\x0a\x0f\x0b\x0a\x0d\x0b\x07\x0b\x0a\x07"
+ b"\x23\x23\x26\x22\x22\x25\x22\x20\x23\x21\x1f\x22\x20\x1e\x20\x1f"
+ b"\x1d\x1e\x1d\x1b\x1c\x1b\x1a\x1a\x1a\x19\x19\x18\x17\x17\x17\x16"
+ b"\x16\x14\x14\x14\x13\x13\x13\x10\x10\x10\x0f\x0f\x0f\x0d\x0d\x0d"
+ b"\x2d\x28\x20\x29\x24\x1c\x27\x22\x1a\x25\x1f\x17\x38\x2e\x1e\x31"
+ b"\x29\x1a\x2c\x25\x17\x26\x20\x14\x3c\x30\x14\x37\x2c\x13\x33\x28"
+ b"\x12\x2d\x24\x10\x28\x1f\x0f\x22\x1a\x0b\x1b\x14\x0a\x13\x0f\x07"
+ b"\x31\x1a\x16\x30\x17\x13\x2e\x16\x10\x2c\x14\x0d\x2a\x12\x0b\x27"
+ b"\x0f\x0a\x25\x0f\x07\x21\x0d\x01\x1e\x0b\x01\x1c\x0b\x01\x1a\x0b"
+ b"\x01\x18\x0a\x01\x16\x0a\x01\x13\x0a\x01\x10\x07\x01\x0d\x07\x01"
+ b"\x29\x23\x1e\x27\x21\x1c\x26\x20\x1b\x25\x1f\x1a\x23\x1d\x19\x21"
+ b"\x1c\x18\x20\x1b\x17\x1e\x19\x16\x1c\x18\x14\x1b\x17\x13\x19\x14"
+ b"\x10\x17\x13\x0f\x14\x10\x0d\x12\x0f\x0b\x0f\x0b\x0a\x0b\x0a\x07"
+ b"\x26\x1a\x0f\x23\x19\x0f\x20\x17\x0f\x1c\x16\x0f\x19\x13\x0d\x14"
+ b"\x10\x0b\x10\x0d\x0a\x0b\x0a\x07\x33\x22\x1f\x35\x29\x26\x37\x2f"
+ b"\x2d\x39\x35\x34\x37\x39\x3a\x33\x37\x39\x30\x34\x36\x2b\x31\x34"
+ b"\x27\x2e\x31\x22\x2b\x2f\x1d\x28\x2c\x17\x25\x2a\x0f\x20\x26\x0d"
+ b"\x1e\x25\x0b\x1c\x22\x0a\x1b\x20\x07\x19\x1e\x07\x17\x1b\x07\x14"
+ b"\x18\x01\x12\x16\x01\x0f\x12\x01\x0b\x0d\x01\x07\x0a\x01\x01\x01"
+ b"\x2c\x21\x21\x2a\x1f\x1f\x29\x1d\x1d\x27\x1c\x1c\x26\x1a\x1a\x24"
+ b"\x18\x18\x22\x17\x17\x21\x16\x16\x1e\x13\x13\x1b\x12\x12\x18\x10"
+ b"\x10\x16\x0d\x0d\x12\x0b\x0b\x0d\x0a\x0a\x0a\x07\x07\x01\x01\x01"
+ b"\x2e\x30\x29\x2d\x2e\x27\x2b\x2c\x26\x2a\x2a\x24\x28\x29\x23\x27"
+ b"\x27\x21\x26\x26\x1f\x24\x24\x1d\x22\x22\x1c\x1f\x1f\x1a\x1c\x1c"
+ b"\x18\x19\x19\x16\x17\x17\x13\x13\x13\x10\x0f\x0f\x0d\x0b\x0b\x0a"
+ b"\x30\x1e\x1b\x2d\x1c\x19\x2c\x1a\x17\x2a\x19\x14\x28\x17\x13\x26"
+ b"\x16\x10\x24\x13\x0f\x21\x12\x0d\x1f\x10\x0b\x1c\x0f\x0a\x19\x0d"
+ b"\x0a\x16\x0b\x07\x12\x0a\x07\x0f\x07\x01\x0a\x01\x01\x01\x01\x01"
+ b"\x28\x29\x38\x26\x27\x36\x25\x26\x34\x24\x24\x31\x22\x22\x2f\x20"
+ b"\x21\x2d\x1e\x1f\x2a\x1d\x1d\x27\x1b\x1b\x25\x19\x19\x21\x17\x17"
+ b"\x1e\x14\x14\x1b\x13\x12\x17\x10\x0f\x13\x0d\x0b\x0f\x0a\x07\x07"
+ b"\x2f\x32\x29\x2d\x30\x26\x2b\x2e\x24\x29\x2c\x21\x27\x2a\x1e\x25"
+ b"\x28\x1c\x23\x26\x1a\x21\x25\x18\x1e\x22\x14\x1b\x1f\x10\x19\x1c"
+ b"\x0d\x17\x1a\x0a\x13\x17\x07\x10\x13\x01\x0d\x0f\x01\x0a\x0b\x01"
+ b"\x01\x3f\x01\x13\x3c\x0b\x1b\x39\x10\x20\x35\x14\x23\x31\x17\x23"
+ b"\x2d\x18\x23\x29\x18\x3f\x3f\x3f\x3f\x3f\x39\x3f\x3f\x31\x3f\x3f"
+ b"\x2a\x3f\x3f\x20\x3f\x3f\x14\x3f\x3c\x12\x3f\x39\x0f\x3f\x35\x0b"
+ b"\x3f\x32\x07\x3f\x2d\x01\x3d\x2a\x01\x3b\x26\x01\x39\x21\x01\x37"
+ b"\x1d\x01\x34\x1a\x01\x32\x16\x01\x2f\x12\x01\x2d\x0f\x01\x2a\x0b"
+ b"\x01\x27\x07\x01\x23\x01\x01\x1d\x01\x01\x17\x01\x01\x10\x01\x01"
+ b"\x3d\x01\x01\x19\x19\x3f\x3f\x01\x01\x01\x01\x3f\x16\x16\x13\x10"
+ b"\x10\x0f\x0d\x0d\x0b\x3c\x2e\x2a\x36\x27\x20\x30\x21\x18\x29\x1b"
+ b"\x10\x3c\x39\x37\x37\x32\x2f\x31\x2c\x28\x2b\x26\x21\x30\x22\x20"
+)
diff --git a/venv/Lib/site-packages/PIL/WebPImagePlugin.py b/venv/Lib/site-packages/PIL/WebPImagePlugin.py
new file mode 100644
index 0000000..2e9746f
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/WebPImagePlugin.py
@@ -0,0 +1,351 @@
+from io import BytesIO
+
+from . import Image, ImageFile
+
+try:
+ from . import _webp
+
+ SUPPORTED = True
+except ImportError:
+ SUPPORTED = False
+
+
+_VALID_WEBP_MODES = {"RGBX": True, "RGBA": True, "RGB": True}
+
+_VALID_WEBP_LEGACY_MODES = {"RGB": True, "RGBA": True}
+
+_VP8_MODES_BY_IDENTIFIER = {
+ b"VP8 ": "RGB",
+ b"VP8X": "RGBA",
+ b"VP8L": "RGBA", # lossless
+}
+
+
+def _accept(prefix):
+ is_riff_file_format = prefix[:4] == b"RIFF"
+ is_webp_file = prefix[8:12] == b"WEBP"
+ is_valid_vp8_mode = prefix[12:16] in _VP8_MODES_BY_IDENTIFIER
+
+ if is_riff_file_format and is_webp_file and is_valid_vp8_mode:
+ if not SUPPORTED:
+ return (
+ "image file could not be identified because WEBP support not installed"
+ )
+ return True
+
+
+class WebPImageFile(ImageFile.ImageFile):
+
+ format = "WEBP"
+ format_description = "WebP image"
+ __loaded = 0
+ __logical_frame = 0
+
+ def _open(self):
+ if not _webp.HAVE_WEBPANIM:
+ # Legacy mode
+ data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode(
+ self.fp.read()
+ )
+ if icc_profile:
+ self.info["icc_profile"] = icc_profile
+ if exif:
+ self.info["exif"] = exif
+ self._size = width, height
+ self.fp = BytesIO(data)
+ self.tile = [("raw", (0, 0) + self.size, 0, self.mode)]
+ self.n_frames = 1
+ self.is_animated = False
+ return
+
+ # Use the newer AnimDecoder API to parse the (possibly) animated file,
+ # and access muxed chunks like ICC/EXIF/XMP.
+ self._decoder = _webp.WebPAnimDecoder(self.fp.read())
+
+ # Get info from decoder
+ width, height, loop_count, bgcolor, frame_count, mode = self._decoder.get_info()
+ self._size = width, height
+ self.info["loop"] = loop_count
+ bg_a, bg_r, bg_g, bg_b = (
+ (bgcolor >> 24) & 0xFF,
+ (bgcolor >> 16) & 0xFF,
+ (bgcolor >> 8) & 0xFF,
+ bgcolor & 0xFF,
+ )
+ self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
+ self.n_frames = frame_count
+ self.is_animated = self.n_frames > 1
+ self.mode = "RGB" if mode == "RGBX" else mode
+ self.rawmode = mode
+ self.tile = []
+
+ # Attempt to read ICC / EXIF / XMP chunks from file
+ icc_profile = self._decoder.get_chunk("ICCP")
+ exif = self._decoder.get_chunk("EXIF")
+ xmp = self._decoder.get_chunk("XMP ")
+ if icc_profile:
+ self.info["icc_profile"] = icc_profile
+ if exif:
+ self.info["exif"] = exif
+ if xmp:
+ self.info["xmp"] = xmp
+
+ # Initialize seek state
+ self._reset(reset=False)
+
+ def _getexif(self):
+ if "exif" not in self.info:
+ return None
+ return dict(self.getexif())
+
+ def seek(self, frame):
+ if not self._seek_check(frame):
+ return
+
+ # Set logical frame to requested position
+ self.__logical_frame = frame
+
+ def _reset(self, reset=True):
+ if reset:
+ self._decoder.reset()
+ self.__physical_frame = 0
+ self.__loaded = -1
+ self.__timestamp = 0
+
+ def _get_next(self):
+ # Get next frame
+ ret = self._decoder.get_next()
+ self.__physical_frame += 1
+
+ # Check if an error occurred
+ if ret is None:
+ self._reset() # Reset just to be safe
+ self.seek(0)
+ raise EOFError("failed to decode next frame in WebP file")
+
+ # Compute duration
+ data, timestamp = ret
+ duration = timestamp - self.__timestamp
+ self.__timestamp = timestamp
+
+ # libwebp gives frame end, adjust to start of frame
+ timestamp -= duration
+ return data, timestamp, duration
+
+ def _seek(self, frame):
+ if self.__physical_frame == frame:
+ return # Nothing to do
+ if frame < self.__physical_frame:
+ self._reset() # Rewind to beginning
+ while self.__physical_frame < frame:
+ self._get_next() # Advance to the requested frame
+
+ def load(self):
+ if _webp.HAVE_WEBPANIM:
+ if self.__loaded != self.__logical_frame:
+ self._seek(self.__logical_frame)
+
+ # We need to load the image data for this frame
+ data, timestamp, duration = self._get_next()
+ self.info["timestamp"] = timestamp
+ self.info["duration"] = duration
+ self.__loaded = self.__logical_frame
+
+ # Set tile
+ if self.fp and self._exclusive_fp:
+ self.fp.close()
+ self.fp = BytesIO(data)
+ self.tile = [("raw", (0, 0) + self.size, 0, self.rawmode)]
+
+ return super().load()
+
+ def tell(self):
+ if not _webp.HAVE_WEBPANIM:
+ return super().tell()
+
+ return self.__logical_frame
+
+
+def _save_all(im, fp, filename):
+ encoderinfo = im.encoderinfo.copy()
+ append_images = list(encoderinfo.get("append_images", []))
+
+ # If total frame count is 1, then save using the legacy API, which
+ # will preserve non-alpha modes
+ total = 0
+ for ims in [im] + append_images:
+ total += getattr(ims, "n_frames", 1)
+ if total == 1:
+ _save(im, fp, filename)
+ return
+
+ background = (0, 0, 0, 0)
+ if "background" in encoderinfo:
+ background = encoderinfo["background"]
+ elif "background" in im.info:
+ background = im.info["background"]
+ if isinstance(background, int):
+ # GifImagePlugin stores a global color table index in
+ # info["background"]. So it must be converted to an RGBA value
+ palette = im.getpalette()
+ if palette:
+ r, g, b = palette[background * 3 : (background + 1) * 3]
+ background = (r, g, b, 0)
+
+ duration = im.encoderinfo.get("duration", 0)
+ loop = im.encoderinfo.get("loop", 0)
+ minimize_size = im.encoderinfo.get("minimize_size", False)
+ kmin = im.encoderinfo.get("kmin", None)
+ kmax = im.encoderinfo.get("kmax", None)
+ allow_mixed = im.encoderinfo.get("allow_mixed", False)
+ verbose = False
+ lossless = im.encoderinfo.get("lossless", False)
+ quality = im.encoderinfo.get("quality", 80)
+ method = im.encoderinfo.get("method", 0)
+ icc_profile = im.encoderinfo.get("icc_profile", "")
+ exif = im.encoderinfo.get("exif", "")
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes()
+ xmp = im.encoderinfo.get("xmp", "")
+ if allow_mixed:
+ lossless = False
+
+ # Sensible keyframe defaults are from gif2webp.c script
+ if kmin is None:
+ kmin = 9 if lossless else 3
+ if kmax is None:
+ kmax = 17 if lossless else 5
+
+ # Validate background color
+ if (
+ not isinstance(background, (list, tuple))
+ or len(background) != 4
+ or not all(v >= 0 and v < 256 for v in background)
+ ):
+ raise OSError(
+ "Background color is not an RGBA tuple clamped to (0-255): %s"
+ % str(background)
+ )
+
+ # Convert to packed uint
+ bg_r, bg_g, bg_b, bg_a = background
+ background = (bg_a << 24) | (bg_r << 16) | (bg_g << 8) | (bg_b << 0)
+
+ # Setup the WebP animation encoder
+ enc = _webp.WebPAnimEncoder(
+ im.size[0],
+ im.size[1],
+ background,
+ loop,
+ minimize_size,
+ kmin,
+ kmax,
+ allow_mixed,
+ verbose,
+ )
+
+ # Add each frame
+ frame_idx = 0
+ timestamp = 0
+ cur_idx = im.tell()
+ try:
+ for ims in [im] + append_images:
+ # Get # of frames in this image
+ nfr = getattr(ims, "n_frames", 1)
+
+ for idx in range(nfr):
+ ims.seek(idx)
+ ims.load()
+
+ # Make sure image mode is supported
+ frame = ims
+ rawmode = ims.mode
+ if ims.mode not in _VALID_WEBP_MODES:
+ alpha = (
+ "A" in ims.mode
+ or "a" in ims.mode
+ or (ims.mode == "P" and "A" in ims.im.getpalettemode())
+ )
+ rawmode = "RGBA" if alpha else "RGB"
+ frame = ims.convert(rawmode)
+
+ if rawmode == "RGB":
+ # For faster conversion, use RGBX
+ rawmode = "RGBX"
+
+ # Append the frame to the animation encoder
+ enc.add(
+ frame.tobytes("raw", rawmode),
+ timestamp,
+ frame.size[0],
+ frame.size[1],
+ rawmode,
+ lossless,
+ quality,
+ method,
+ )
+
+ # Update timestamp and frame index
+ if isinstance(duration, (list, tuple)):
+ timestamp += duration[frame_idx]
+ else:
+ timestamp += duration
+ frame_idx += 1
+
+ finally:
+ im.seek(cur_idx)
+
+ # Force encoder to flush frames
+ enc.add(None, timestamp, 0, 0, "", lossless, quality, 0)
+
+ # Get the final output from the encoder
+ data = enc.assemble(icc_profile, exif, xmp)
+ if data is None:
+ raise OSError("cannot write file as WebP (encoder returned None)")
+
+ fp.write(data)
+
+
+def _save(im, fp, filename):
+ lossless = im.encoderinfo.get("lossless", False)
+ quality = im.encoderinfo.get("quality", 80)
+ icc_profile = im.encoderinfo.get("icc_profile", "")
+ exif = im.encoderinfo.get("exif", "")
+ if isinstance(exif, Image.Exif):
+ exif = exif.tobytes()
+ xmp = im.encoderinfo.get("xmp", "")
+ method = im.encoderinfo.get("method", 0)
+
+ if im.mode not in _VALID_WEBP_LEGACY_MODES:
+ alpha = (
+ "A" in im.mode
+ or "a" in im.mode
+ or (im.mode == "P" and "A" in im.im.getpalettemode())
+ )
+ im = im.convert("RGBA" if alpha else "RGB")
+
+ data = _webp.WebPEncode(
+ im.tobytes(),
+ im.size[0],
+ im.size[1],
+ lossless,
+ float(quality),
+ im.mode,
+ icc_profile,
+ method,
+ exif,
+ xmp,
+ )
+ if data is None:
+ raise OSError("cannot write file as WebP (encoder returned None)")
+
+ fp.write(data)
+
+
+Image.register_open(WebPImageFile.format, WebPImageFile, _accept)
+if SUPPORTED:
+ Image.register_save(WebPImageFile.format, _save)
+ if _webp.HAVE_WEBPANIM:
+ Image.register_save_all(WebPImageFile.format, _save_all)
+ Image.register_extension(WebPImageFile.format, ".webp")
+ Image.register_mime(WebPImageFile.format, "image/webp")
diff --git a/venv/Lib/site-packages/PIL/WmfImagePlugin.py b/venv/Lib/site-packages/PIL/WmfImagePlugin.py
new file mode 100644
index 0000000..87847a1
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/WmfImagePlugin.py
@@ -0,0 +1,178 @@
+#
+# The Python Imaging Library
+# $Id$
+#
+# WMF stub codec
+#
+# history:
+# 1996-12-14 fl Created
+# 2004-02-22 fl Turned into a stub driver
+# 2004-02-23 fl Added EMF support
+#
+# Copyright (c) Secret Labs AB 1997-2004. All rights reserved.
+# Copyright (c) Fredrik Lundh 1996.
+#
+# See the README file for information on usage and redistribution.
+#
+# WMF/EMF reference documentation:
+# https://winprotocoldoc.blob.core.windows.net/productionwindowsarchives/MS-WMF/[MS-WMF].pdf
+# http://wvware.sourceforge.net/caolan/index.html
+# http://wvware.sourceforge.net/caolan/ora-wmf.html
+
+from . import Image, ImageFile
+from ._binary import i16le as word
+from ._binary import i32le as dword
+from ._binary import si16le as short
+from ._binary import si32le as _long
+
+_handler = None
+
+
+def register_handler(handler):
+ """
+ Install application-specific WMF image handler.
+
+ :param handler: Handler object.
+ """
+ global _handler
+ _handler = handler
+
+
+if hasattr(Image.core, "drawwmf"):
+ # install default handler (windows only)
+
+ class WmfHandler:
+ def open(self, im):
+ im.mode = "RGB"
+ self.bbox = im.info["wmf_bbox"]
+
+ def load(self, im):
+ im.fp.seek(0) # rewind
+ return Image.frombytes(
+ "RGB",
+ im.size,
+ Image.core.drawwmf(im.fp.read(), im.size, self.bbox),
+ "raw",
+ "BGR",
+ (im.size[0] * 3 + 3) & -4,
+ -1,
+ )
+
+ register_handler(WmfHandler())
+
+#
+# --------------------------------------------------------------------
+# Read WMF file
+
+
+def _accept(prefix):
+ return (
+ prefix[:6] == b"\xd7\xcd\xc6\x9a\x00\x00" or prefix[:4] == b"\x01\x00\x00\x00"
+ )
+
+
+##
+# Image plugin for Windows metafiles.
+
+
+class WmfStubImageFile(ImageFile.StubImageFile):
+
+ format = "WMF"
+ format_description = "Windows Metafile"
+
+ def _open(self):
+ self._inch = None
+
+ # check placable header
+ s = self.fp.read(80)
+
+ if s[:6] == b"\xd7\xcd\xc6\x9a\x00\x00":
+
+ # placeable windows metafile
+
+ # get units per inch
+ self._inch = word(s, 14)
+
+ # get bounding box
+ x0 = short(s, 6)
+ y0 = short(s, 8)
+ x1 = short(s, 10)
+ y1 = short(s, 12)
+
+ # normalize size to 72 dots per inch
+ self.info["dpi"] = 72
+ size = (
+ (x1 - x0) * self.info["dpi"] // self._inch,
+ (y1 - y0) * self.info["dpi"] // self._inch,
+ )
+
+ self.info["wmf_bbox"] = x0, y0, x1, y1
+
+ # sanity check (standard metafile header)
+ if s[22:26] != b"\x01\x00\t\x00":
+ raise SyntaxError("Unsupported WMF file format")
+
+ elif dword(s) == 1 and s[40:44] == b" EMF":
+ # enhanced metafile
+
+ # get bounding box
+ x0 = _long(s, 8)
+ y0 = _long(s, 12)
+ x1 = _long(s, 16)
+ y1 = _long(s, 20)
+
+ # get frame (in 0.01 millimeter units)
+ frame = _long(s, 24), _long(s, 28), _long(s, 32), _long(s, 36)
+
+ size = x1 - x0, y1 - y0
+
+ # calculate dots per inch from bbox and frame
+ xdpi = int(2540.0 * (x1 - y0) / (frame[2] - frame[0]) + 0.5)
+ ydpi = int(2540.0 * (y1 - y0) / (frame[3] - frame[1]) + 0.5)
+
+ self.info["wmf_bbox"] = x0, y0, x1, y1
+
+ if xdpi == ydpi:
+ self.info["dpi"] = xdpi
+ else:
+ self.info["dpi"] = xdpi, ydpi
+
+ else:
+ raise SyntaxError("Unsupported file format")
+
+ self.mode = "RGB"
+ self._size = size
+
+ loader = self._load()
+ if loader:
+ loader.open(self)
+
+ def _load(self):
+ return _handler
+
+ def load(self, dpi=None):
+ if dpi is not None and self._inch is not None:
+ self.info["dpi"] = int(dpi + 0.5)
+ x0, y0, x1, y1 = self.info["wmf_bbox"]
+ self._size = (
+ (x1 - x0) * self.info["dpi"] // self._inch,
+ (y1 - y0) * self.info["dpi"] // self._inch,
+ )
+ super().load()
+
+
+def _save(im, fp, filename):
+ if _handler is None or not hasattr(_handler, "save"):
+ raise OSError("WMF save handler not installed")
+ _handler.save(im, fp, filename)
+
+
+#
+# --------------------------------------------------------------------
+# Registry stuff
+
+
+Image.register_open(WmfStubImageFile.format, WmfStubImageFile, _accept)
+Image.register_save(WmfStubImageFile.format, _save)
+
+Image.register_extensions(WmfStubImageFile.format, [".wmf", ".emf"])
diff --git a/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py b/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py
new file mode 100644
index 0000000..4efedb7
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/XVThumbImagePlugin.py
@@ -0,0 +1,78 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# XV Thumbnail file handler by Charles E. "Gene" Cash
+# (gcash@magicnet.net)
+#
+# see xvcolor.c and xvbrowse.c in the sources to John Bradley's XV,
+# available from ftp://ftp.cis.upenn.edu/pub/xv/
+#
+# history:
+# 98-08-15 cec created (b/w only)
+# 98-12-09 cec added color palette
+# 98-12-28 fl added to PIL (with only a few very minor modifications)
+#
+# To do:
+# FIXME: make save work (this requires quantization support)
+#
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import o8
+
+_MAGIC = b"P7 332"
+
+# standard color palette for thumbnails (RGB332)
+PALETTE = b""
+for r in range(8):
+ for g in range(8):
+ for b in range(4):
+ PALETTE = PALETTE + (
+ o8((r * 255) // 7) + o8((g * 255) // 7) + o8((b * 255) // 3)
+ )
+
+
+def _accept(prefix):
+ return prefix[:6] == _MAGIC
+
+
+##
+# Image plugin for XV thumbnail images.
+
+
+class XVThumbImageFile(ImageFile.ImageFile):
+
+ format = "XVThumb"
+ format_description = "XV thumbnail image"
+
+ def _open(self):
+
+ # check magic
+ if not _accept(self.fp.read(6)):
+ raise SyntaxError("not an XV thumbnail file")
+
+ # Skip to beginning of next line
+ self.fp.readline()
+
+ # skip info comments
+ while True:
+ s = self.fp.readline()
+ if not s:
+ raise SyntaxError("Unexpected EOF reading XV thumbnail file")
+ if s[0] != 35: # ie. when not a comment: '#'
+ break
+
+ # parse header line (already read)
+ s = s.strip().split()
+
+ self.mode = "P"
+ self._size = int(s[0]), int(s[1])
+
+ self.palette = ImagePalette.raw("RGB", PALETTE)
+
+ self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), (self.mode, 0, 1))]
+
+
+# --------------------------------------------------------------------
+
+Image.register_open(XVThumbImageFile.format, XVThumbImageFile, _accept)
diff --git a/venv/Lib/site-packages/PIL/XbmImagePlugin.py b/venv/Lib/site-packages/PIL/XbmImagePlugin.py
new file mode 100644
index 0000000..644cfb3
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/XbmImagePlugin.py
@@ -0,0 +1,94 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# XBM File handling
+#
+# History:
+# 1995-09-08 fl Created
+# 1996-11-01 fl Added save support
+# 1997-07-07 fl Made header parser more tolerant
+# 1997-07-22 fl Fixed yet another parser bug
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.4)
+# 2001-05-13 fl Added hotspot handling (based on code from Bernhard Herzog)
+# 2004-02-24 fl Allow some whitespace before first #define
+#
+# Copyright (c) 1997-2004 by Secret Labs AB
+# Copyright (c) 1996-1997 by Fredrik Lundh
+#
+# See the README file for information on usage and redistribution.
+#
+
+import re
+
+from . import Image, ImageFile
+
+# XBM header
+xbm_head = re.compile(
+ br"\s*#define[ \t]+.*_width[ \t]+(?P[0-9]+)[\r\n]+"
+ b"#define[ \t]+.*_height[ \t]+(?P[0-9]+)[\r\n]+"
+ b"(?P"
+ b"#define[ \t]+[^_]*_x_hot[ \t]+(?P[0-9]+)[\r\n]+"
+ b"#define[ \t]+[^_]*_y_hot[ \t]+(?P[0-9]+)[\r\n]+"
+ b")?"
+ b"[\\000-\\377]*_bits\\[\\]"
+)
+
+
+def _accept(prefix):
+ return prefix.lstrip()[:7] == b"#define"
+
+
+##
+# Image plugin for X11 bitmaps.
+
+
+class XbmImageFile(ImageFile.ImageFile):
+
+ format = "XBM"
+ format_description = "X11 Bitmap"
+
+ def _open(self):
+
+ m = xbm_head.match(self.fp.read(512))
+
+ if m:
+
+ xsize = int(m.group("width"))
+ ysize = int(m.group("height"))
+
+ if m.group("hotspot"):
+ self.info["hotspot"] = (int(m.group("xhot")), int(m.group("yhot")))
+
+ self.mode = "1"
+ self._size = xsize, ysize
+
+ self.tile = [("xbm", (0, 0) + self.size, m.end(), None)]
+
+
+def _save(im, fp, filename):
+
+ if im.mode != "1":
+ raise OSError(f"cannot write mode {im.mode} as XBM")
+
+ fp.write(f"#define im_width {im.size[0]}\n".encode("ascii"))
+ fp.write(f"#define im_height {im.size[1]}\n".encode("ascii"))
+
+ hotspot = im.encoderinfo.get("hotspot")
+ if hotspot:
+ fp.write(f"#define im_x_hot {hotspot[0]}\n".encode("ascii"))
+ fp.write(f"#define im_y_hot {hotspot[1]}\n".encode("ascii"))
+
+ fp.write(b"static char im_bits[] = {\n")
+
+ ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)])
+
+ fp.write(b"};\n")
+
+
+Image.register_open(XbmImageFile.format, XbmImageFile, _accept)
+Image.register_save(XbmImageFile.format, _save)
+
+Image.register_extension(XbmImageFile.format, ".xbm")
+
+Image.register_mime(XbmImageFile.format, "image/xbm")
diff --git a/venv/Lib/site-packages/PIL/XpmImagePlugin.py b/venv/Lib/site-packages/PIL/XpmImagePlugin.py
new file mode 100644
index 0000000..ebd65ba
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/XpmImagePlugin.py
@@ -0,0 +1,130 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# XPM File handling
+#
+# History:
+# 1996-12-29 fl Created
+# 2001-02-17 fl Use 're' instead of 'regex' (Python 2.1) (0.7)
+#
+# Copyright (c) Secret Labs AB 1997-2001.
+# Copyright (c) Fredrik Lundh 1996-2001.
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+import re
+
+from . import Image, ImageFile, ImagePalette
+from ._binary import o8
+
+# XPM header
+xpm_head = re.compile(b'"([0-9]*) ([0-9]*) ([0-9]*) ([0-9]*)')
+
+
+def _accept(prefix):
+ return prefix[:9] == b"/* XPM */"
+
+
+##
+# Image plugin for X11 pixel maps.
+
+
+class XpmImageFile(ImageFile.ImageFile):
+
+ format = "XPM"
+ format_description = "X11 Pixel Map"
+
+ def _open(self):
+
+ if not _accept(self.fp.read(9)):
+ raise SyntaxError("not an XPM file")
+
+ # skip forward to next string
+ while True:
+ s = self.fp.readline()
+ if not s:
+ raise SyntaxError("broken XPM file")
+ m = xpm_head.match(s)
+ if m:
+ break
+
+ self._size = int(m.group(1)), int(m.group(2))
+
+ pal = int(m.group(3))
+ bpp = int(m.group(4))
+
+ if pal > 256 or bpp != 1:
+ raise ValueError("cannot read this XPM file")
+
+ #
+ # load palette description
+
+ palette = [b"\0\0\0"] * 256
+
+ for i in range(pal):
+
+ s = self.fp.readline()
+ if s[-2:] == b"\r\n":
+ s = s[:-2]
+ elif s[-1:] in b"\r\n":
+ s = s[:-1]
+
+ c = s[1]
+ s = s[2:-2].split()
+
+ for i in range(0, len(s), 2):
+
+ if s[i] == b"c":
+
+ # process colour key
+ rgb = s[i + 1]
+ if rgb == b"None":
+ self.info["transparency"] = c
+ elif rgb[0:1] == b"#":
+ # FIXME: handle colour names (see ImagePalette.py)
+ rgb = int(rgb[1:], 16)
+ palette[c] = (
+ o8((rgb >> 16) & 255) + o8((rgb >> 8) & 255) + o8(rgb & 255)
+ )
+ else:
+ # unknown colour
+ raise ValueError("cannot read this XPM file")
+ break
+
+ else:
+
+ # missing colour key
+ raise ValueError("cannot read this XPM file")
+
+ self.mode = "P"
+ self.palette = ImagePalette.raw("RGB", b"".join(palette))
+
+ self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))]
+
+ def load_read(self, bytes):
+
+ #
+ # load all image data in one chunk
+
+ xsize, ysize = self.size
+
+ s = [None] * ysize
+
+ for i in range(ysize):
+ s[i] = self.fp.readline()[1 : xsize + 1].ljust(xsize)
+
+ return b"".join(s)
+
+
+#
+# Registry
+
+
+Image.register_open(XpmImageFile.format, XpmImageFile, _accept)
+
+Image.register_extension(XpmImageFile.format, ".xpm")
+
+Image.register_mime(XpmImageFile.format, "image/xpm")
diff --git a/venv/Lib/site-packages/PIL/__init__.py b/venv/Lib/site-packages/PIL/__init__.py
new file mode 100644
index 0000000..890ae44
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/__init__.py
@@ -0,0 +1,139 @@
+"""Pillow (Fork of the Python Imaging Library)
+
+Pillow is the friendly PIL fork by Alex Clark and Contributors.
+ https://github.com/python-pillow/Pillow/
+
+Pillow is forked from PIL 1.1.7.
+
+PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
+Copyright (c) 1999 by Secret Labs AB.
+
+Use PIL.__version__ for this Pillow version.
+
+;-)
+"""
+
+import sys
+import warnings
+
+from . import _version
+
+# VERSION was removed in Pillow 6.0.0.
+__version__ = _version.__version__
+
+
+# PILLOW_VERSION is deprecated and will be removed in a future release.
+# Use __version__ instead.
+def _raise_version_warning():
+ warnings.warn(
+ "PILLOW_VERSION is deprecated and will be removed in Pillow 9 (2022-01-02). "
+ "Use __version__ instead.",
+ DeprecationWarning,
+ stacklevel=3,
+ )
+
+
+if sys.version_info >= (3, 7):
+
+ def __getattr__(name):
+ if name == "PILLOW_VERSION":
+ _raise_version_warning()
+ return __version__
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
+
+
+else:
+
+ class _Deprecated_Version(str):
+ def __str__(self):
+ _raise_version_warning()
+ return super().__str__()
+
+ def __getitem__(self, key):
+ _raise_version_warning()
+ return super().__getitem__(key)
+
+ def __eq__(self, other):
+ _raise_version_warning()
+ return super().__eq__(other)
+
+ def __ne__(self, other):
+ _raise_version_warning()
+ return super().__ne__(other)
+
+ def __gt__(self, other):
+ _raise_version_warning()
+ return super().__gt__(other)
+
+ def __lt__(self, other):
+ _raise_version_warning()
+ return super().__lt__(other)
+
+ def __ge__(self, other):
+ _raise_version_warning()
+ return super().__gt__(other)
+
+ def __le__(self, other):
+ _raise_version_warning()
+ return super().__lt__(other)
+
+ PILLOW_VERSION = _Deprecated_Version(__version__)
+
+del _version
+
+
+_plugins = [
+ "BlpImagePlugin",
+ "BmpImagePlugin",
+ "BufrStubImagePlugin",
+ "CurImagePlugin",
+ "DcxImagePlugin",
+ "DdsImagePlugin",
+ "EpsImagePlugin",
+ "FitsStubImagePlugin",
+ "FliImagePlugin",
+ "FpxImagePlugin",
+ "FtexImagePlugin",
+ "GbrImagePlugin",
+ "GifImagePlugin",
+ "GribStubImagePlugin",
+ "Hdf5StubImagePlugin",
+ "IcnsImagePlugin",
+ "IcoImagePlugin",
+ "ImImagePlugin",
+ "ImtImagePlugin",
+ "IptcImagePlugin",
+ "JpegImagePlugin",
+ "Jpeg2KImagePlugin",
+ "McIdasImagePlugin",
+ "MicImagePlugin",
+ "MpegImagePlugin",
+ "MpoImagePlugin",
+ "MspImagePlugin",
+ "PalmImagePlugin",
+ "PcdImagePlugin",
+ "PcxImagePlugin",
+ "PdfImagePlugin",
+ "PixarImagePlugin",
+ "PngImagePlugin",
+ "PpmImagePlugin",
+ "PsdImagePlugin",
+ "SgiImagePlugin",
+ "SpiderImagePlugin",
+ "SunImagePlugin",
+ "TgaImagePlugin",
+ "TiffImagePlugin",
+ "WebPImagePlugin",
+ "WmfImagePlugin",
+ "XbmImagePlugin",
+ "XpmImagePlugin",
+ "XVThumbImagePlugin",
+]
+
+
+class UnidentifiedImageError(OSError):
+ """
+ Raised in :py:meth:`PIL.Image.open` if an image cannot be opened and identified.
+ """
+
+ pass
diff --git a/venv/Lib/site-packages/PIL/__main__.py b/venv/Lib/site-packages/PIL/__main__.py
new file mode 100644
index 0000000..a05323f
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/__main__.py
@@ -0,0 +1,3 @@
+from .features import pilinfo
+
+pilinfo()
diff --git a/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-39.pyc
new file mode 100644
index 0000000..7301d22
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/BdfFontFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..441060b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/BlpImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..d8c9070
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/BmpImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..fe7b6c3
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/BufrStubImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-39.pyc
new file mode 100644
index 0000000..d50cc3b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ContainerIO.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..bb02e0f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/CurImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..a7706a6
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/DcxImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..b592d51
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/DdsImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..6f6040c
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/EpsImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-39.pyc
new file mode 100644
index 0000000..c5f6b26
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ExifTags.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/FitsStubImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/FitsStubImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..28deacd
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/FitsStubImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..421d178
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/FliImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-39.pyc
new file mode 100644
index 0000000..44c00b4
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/FontFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..787a9da
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/FpxImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..23b254a
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/FtexImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..bf5e971
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/GbrImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-39.pyc
new file mode 100644
index 0000000..864c57f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/GdImageFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..681f903
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/GifImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-39.pyc
new file mode 100644
index 0000000..353c4bb
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/GimpGradientFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-39.pyc
new file mode 100644
index 0000000..95133d7
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/GimpPaletteFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..6a0dd25
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/GribStubImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..9f10354
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/Hdf5StubImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..9b36ee5
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/IcnsImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..044dabc
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/IcoImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..2879cc3
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-39.pyc
new file mode 100644
index 0000000..7e5e5e7
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/Image.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-39.pyc
new file mode 100644
index 0000000..a906d61
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageChops.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-39.pyc
new file mode 100644
index 0000000..c93350a
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageCms.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-39.pyc
new file mode 100644
index 0000000..008a4ec
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageColor.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-39.pyc
new file mode 100644
index 0000000..8b9fd0f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-39.pyc
new file mode 100644
index 0000000..b184a57
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageDraw2.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-39.pyc
new file mode 100644
index 0000000..da35a9e
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageEnhance.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-39.pyc
new file mode 100644
index 0000000..7a1a065
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-39.pyc
new file mode 100644
index 0000000..d038366
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageFilter.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-39.pyc
new file mode 100644
index 0000000..5fda042
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageFont.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-39.pyc
new file mode 100644
index 0000000..1a5a4d7
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageGrab.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-39.pyc
new file mode 100644
index 0000000..4f1835f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageMath.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-39.pyc
new file mode 100644
index 0000000..0917656
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageMode.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-39.pyc
new file mode 100644
index 0000000..c089ae6
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageMorph.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-39.pyc
new file mode 100644
index 0000000..3288831
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageOps.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-39.pyc
new file mode 100644
index 0000000..62f74ce
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImagePalette.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-39.pyc
new file mode 100644
index 0000000..00ecacf
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImagePath.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-39.pyc
new file mode 100644
index 0000000..11540d5
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageQt.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-39.pyc
new file mode 100644
index 0000000..52bc8fc
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageSequence.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-39.pyc
new file mode 100644
index 0000000..78f6e2d
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageShow.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-39.pyc
new file mode 100644
index 0000000..d52618e
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageStat.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-39.pyc
new file mode 100644
index 0000000..9a4106e
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageTk.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-39.pyc
new file mode 100644
index 0000000..1ec1765
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageTransform.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-39.pyc
new file mode 100644
index 0000000..aa28949
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImageWin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..1728703
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/ImtImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..706a39f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/IptcImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..c01d18e
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/Jpeg2KImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..30e4138
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/JpegImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-39.pyc
new file mode 100644
index 0000000..aad786b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/JpegPresets.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..b8c8360
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/McIdasImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..d77fbb7
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/MicImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..6c14d3a
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/MpegImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..46f2ce0
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/MpoImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..615a22e
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/MspImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-39.pyc
new file mode 100644
index 0000000..839e0fa
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PSDraw.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-39.pyc
new file mode 100644
index 0000000..f0417eb
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PaletteFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..a16564b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PalmImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..e1a419d
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PcdImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-39.pyc
new file mode 100644
index 0000000..1992766
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PcfFontFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..0987700
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PcxImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..cf95778
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PdfImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-39.pyc
new file mode 100644
index 0000000..5e54b17
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PdfParser.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..b6a15ed
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PixarImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..302c809
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PngImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..aa161e0
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PpmImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..c29fb66
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PsdImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/PyAccess.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/PyAccess.cpython-39.pyc
new file mode 100644
index 0000000..43c5773
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/PyAccess.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..23fe7ab
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/SgiImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..9d458be
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/SpiderImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..13d3602
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/SunImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-39.pyc
new file mode 100644
index 0000000..2373e9b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/TarIO.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..22f6c62
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/TgaImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..ae647f9
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/TiffImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-39.pyc
new file mode 100644
index 0000000..9cfb6d9
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/TiffTags.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-39.pyc
new file mode 100644
index 0000000..f95fdae
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/WalImageFile.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..1df03a5
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/WebPImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..87de731
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/WmfImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..2f0110f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/XVThumbImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..268090b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/XbmImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-39.pyc
new file mode 100644
index 0000000..d93df69
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/XpmImagePlugin.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..4067a8f
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/__init__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-39.pyc
new file mode 100644
index 0000000..ce6ee5b
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/__main__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-39.pyc
new file mode 100644
index 0000000..b86fd3a
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/_binary.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-39.pyc
new file mode 100644
index 0000000..1c36b91
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/_tkinter_finder.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-39.pyc
new file mode 100644
index 0000000..7725789
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/_util.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-39.pyc
new file mode 100644
index 0000000..e855336
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/_version.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/__pycache__/features.cpython-39.pyc b/venv/Lib/site-packages/PIL/__pycache__/features.cpython-39.pyc
new file mode 100644
index 0000000..af3e0ce
Binary files /dev/null and b/venv/Lib/site-packages/PIL/__pycache__/features.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/PIL/_binary.py b/venv/Lib/site-packages/PIL/_binary.py
new file mode 100644
index 0000000..5564f45
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/_binary.py
@@ -0,0 +1,92 @@
+#
+# The Python Imaging Library.
+# $Id$
+#
+# Binary input/output support routines.
+#
+# Copyright (c) 1997-2003 by Secret Labs AB
+# Copyright (c) 1995-2003 by Fredrik Lundh
+# Copyright (c) 2012 by Brian Crowell
+#
+# See the README file for information on usage and redistribution.
+#
+
+
+"""Binary input/output support routines."""
+
+
+from struct import pack, unpack_from
+
+
+def i8(c):
+ return c if c.__class__ is int else c[0]
+
+
+def o8(i):
+ return bytes((i & 255,))
+
+
+# Input, le = little endian, be = big endian
+def i16le(c, o=0):
+ """
+ Converts a 2-bytes (16 bits) string to an unsigned integer.
+
+ :param c: string containing bytes to convert
+ :param o: offset of bytes to convert in string
+ """
+ return unpack_from("H", c, o)[0]
+
+
+def i32be(c, o=0):
+ return unpack_from(">I", c, o)[0]
+
+
+# Output, le = little endian, be = big endian
+def o16le(i):
+ return pack("H", i)
+
+
+def o32be(i):
+ return pack(">I", i)
diff --git a/venv/Lib/site-packages/PIL/_imaging.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imaging.cp39-win_amd64.pyd
new file mode 100644
index 0000000..903a844
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_imaging.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/_imagingcms.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingcms.cp39-win_amd64.pyd
new file mode 100644
index 0000000..cda52f6
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_imagingcms.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/_imagingft.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingft.cp39-win_amd64.pyd
new file mode 100644
index 0000000..cd5c7a4
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_imagingft.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/_imagingmath.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingmath.cp39-win_amd64.pyd
new file mode 100644
index 0000000..a565465
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_imagingmath.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/_imagingmorph.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingmorph.cp39-win_amd64.pyd
new file mode 100644
index 0000000..b0e4b02
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_imagingmorph.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/_imagingtk.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_imagingtk.cp39-win_amd64.pyd
new file mode 100644
index 0000000..fcec3e1
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_imagingtk.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/_tkinter_finder.py b/venv/Lib/site-packages/PIL/_tkinter_finder.py
new file mode 100644
index 0000000..7018a1b
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/_tkinter_finder.py
@@ -0,0 +1,9 @@
+""" Find compiled module linking to Tcl / Tk libraries
+"""
+import sys
+from tkinter import _tkinter as tk
+
+if hasattr(sys, "pypy_find_executable"):
+ TKINTER_LIB = tk.tklib_cffi.__file__
+else:
+ TKINTER_LIB = tk.__file__
diff --git a/venv/Lib/site-packages/PIL/_util.py b/venv/Lib/site-packages/PIL/_util.py
new file mode 100644
index 0000000..0c5d389
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/_util.py
@@ -0,0 +1,19 @@
+import os
+from pathlib import Path
+
+
+def isPath(f):
+ return isinstance(f, (bytes, str, Path))
+
+
+# Checks if an object is a string, and that it points to a directory.
+def isDirectory(f):
+ return isPath(f) and os.path.isdir(f)
+
+
+class deferred_error:
+ def __init__(self, ex):
+ self.ex = ex
+
+ def __getattr__(self, elt):
+ raise self.ex
diff --git a/venv/Lib/site-packages/PIL/_version.py b/venv/Lib/site-packages/PIL/_version.py
new file mode 100644
index 0000000..888d315
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/_version.py
@@ -0,0 +1,2 @@
+# Master version for Pillow
+__version__ = "8.1.2"
diff --git a/venv/Lib/site-packages/PIL/_webp.cp39-win_amd64.pyd b/venv/Lib/site-packages/PIL/_webp.cp39-win_amd64.pyd
new file mode 100644
index 0000000..2d49b47
Binary files /dev/null and b/venv/Lib/site-packages/PIL/_webp.cp39-win_amd64.pyd differ
diff --git a/venv/Lib/site-packages/PIL/features.py b/venv/Lib/site-packages/PIL/features.py
new file mode 100644
index 0000000..da0ca55
--- /dev/null
+++ b/venv/Lib/site-packages/PIL/features.py
@@ -0,0 +1,313 @@
+import collections
+import os
+import sys
+import warnings
+
+import PIL
+
+from . import Image
+
+modules = {
+ "pil": ("PIL._imaging", "PILLOW_VERSION"),
+ "tkinter": ("PIL._tkinter_finder", None),
+ "freetype2": ("PIL._imagingft", "freetype2_version"),
+ "littlecms2": ("PIL._imagingcms", "littlecms_version"),
+ "webp": ("PIL._webp", "webpdecoder_version"),
+}
+
+
+def check_module(feature):
+ """
+ Checks if a module is available.
+
+ :param feature: The module to check for.
+ :returns: ``True`` if available, ``False`` otherwise.
+ :raises ValueError: If the module is not defined in this version of Pillow.
+ """
+ if not (feature in modules):
+ raise ValueError(f"Unknown module {feature}")
+
+ module, ver = modules[feature]
+
+ try:
+ __import__(module)
+ return True
+ except ImportError:
+ return False
+
+
+def version_module(feature):
+ """
+ :param feature: The module to check for.
+ :returns:
+ The loaded version number as a string, or ``None`` if unknown or not available.
+ :raises ValueError: If the module is not defined in this version of Pillow.
+ """
+ if not check_module(feature):
+ return None
+
+ module, ver = modules[feature]
+
+ if ver is None:
+ return None
+
+ return getattr(__import__(module, fromlist=[ver]), ver)
+
+
+def get_supported_modules():
+ """
+ :returns: A list of all supported modules.
+ """
+ return [f for f in modules if check_module(f)]
+
+
+codecs = {
+ "jpg": ("jpeg", "jpeglib"),
+ "jpg_2000": ("jpeg2k", "jp2klib"),
+ "zlib": ("zip", "zlib"),
+ "libtiff": ("libtiff", "libtiff"),
+}
+
+
+def check_codec(feature):
+ """
+ Checks if a codec is available.
+
+ :param feature: The codec to check for.
+ :returns: ``True`` if available, ``False`` otherwise.
+ :raises ValueError: If the codec is not defined in this version of Pillow.
+ """
+ if feature not in codecs:
+ raise ValueError(f"Unknown codec {feature}")
+
+ codec, lib = codecs[feature]
+
+ return codec + "_encoder" in dir(Image.core)
+
+
+def version_codec(feature):
+ """
+ :param feature: The codec to check for.
+ :returns:
+ The version number as a string, or ``None`` if not available.
+ Checked at compile time for ``jpg``, run-time otherwise.
+ :raises ValueError: If the codec is not defined in this version of Pillow.
+ """
+ if not check_codec(feature):
+ return None
+
+ codec, lib = codecs[feature]
+
+ version = getattr(Image.core, lib + "_version")
+
+ if feature == "libtiff":
+ return version.split("\n")[0].split("Version ")[1]
+
+ return version
+
+
+def get_supported_codecs():
+ """
+ :returns: A list of all supported codecs.
+ """
+ return [f for f in codecs if check_codec(f)]
+
+
+features = {
+ "webp_anim": ("PIL._webp", "HAVE_WEBPANIM", None),
+ "webp_mux": ("PIL._webp", "HAVE_WEBPMUX", None),
+ "transp_webp": ("PIL._webp", "HAVE_TRANSPARENCY", None),
+ "raqm": ("PIL._imagingft", "HAVE_RAQM", "raqm_version"),
+ "libjpeg_turbo": ("PIL._imaging", "HAVE_LIBJPEGTURBO", "libjpeg_turbo_version"),
+ "libimagequant": ("PIL._imaging", "HAVE_LIBIMAGEQUANT", "imagequant_version"),
+ "xcb": ("PIL._imaging", "HAVE_XCB", None),
+}
+
+
+def check_feature(feature):
+ """
+ Checks if a feature is available.
+
+ :param feature: The feature to check for.
+ :returns: ``True`` if available, ``False`` if unavailable, ``None`` if unknown.
+ :raises ValueError: If the feature is not defined in this version of Pillow.
+ """
+ if feature not in features:
+ raise ValueError(f"Unknown feature {feature}")
+
+ module, flag, ver = features[feature]
+
+ try:
+ imported_module = __import__(module, fromlist=["PIL"])
+ return getattr(imported_module, flag)
+ except ImportError:
+ return None
+
+
+def version_feature(feature):
+ """
+ :param feature: The feature to check for.
+ :returns: The version number as a string, or ``None`` if not available.
+ :raises ValueError: If the feature is not defined in this version of Pillow.
+ """
+ if not check_feature(feature):
+ return None
+
+ module, flag, ver = features[feature]
+
+ if ver is None:
+ return None
+
+ return getattr(__import__(module, fromlist=[ver]), ver)
+
+
+def get_supported_features():
+ """
+ :returns: A list of all supported features.
+ """
+ return [f for f in features if check_feature(f)]
+
+
+def check(feature):
+ """
+ :param feature: A module, codec, or feature name.
+ :returns:
+ ``True`` if the module, codec, or feature is available,
+ ``False`` or ``None`` otherwise.
+ """
+
+ if feature in modules:
+ return check_module(feature)
+ if feature in codecs:
+ return check_codec(feature)
+ if feature in features:
+ return check_feature(feature)
+ warnings.warn(f"Unknown feature '{feature}'.", stacklevel=2)
+ return False
+
+
+def version(feature):
+ """
+ :param feature:
+ The module, codec, or feature to check for.
+ :returns:
+ The version number as a string, or ``None`` if unknown or not available.
+ """
+ if feature in modules:
+ return version_module(feature)
+ if feature in codecs:
+ return version_codec(feature)
+ if feature in features:
+ return version_feature(feature)
+ return None
+
+
+def get_supported():
+ """
+ :returns: A list of all supported modules, features, and codecs.
+ """
+
+ ret = get_supported_modules()
+ ret.extend(get_supported_features())
+ ret.extend(get_supported_codecs())
+ return ret
+
+
+def pilinfo(out=None, supported_formats=True):
+ """
+ Prints information about this installation of Pillow.
+ This function can be called with ``python -m PIL``.
+
+ :param out:
+ The output stream to print to. Defaults to ``sys.stdout`` if ``None``.
+ :param supported_formats:
+ If ``True``, a list of all supported image file formats will be printed.
+ """
+
+ if out is None:
+ out = sys.stdout
+
+ Image.init()
+
+ print("-" * 68, file=out)
+ print(f"Pillow {PIL.__version__}", file=out)
+ py_version = sys.version.splitlines()
+ print(f"Python {py_version[0].strip()}", file=out)
+ for py_version in py_version[1:]:
+ print(f" {py_version.strip()}", file=out)
+ print("-" * 68, file=out)
+ print(
+ f"Python modules loaded from {os.path.dirname(Image.__file__)}",
+ file=out,
+ )
+ print(
+ f"Binary modules loaded from {os.path.dirname(Image.core.__file__)}",
+ file=out,
+ )
+ print("-" * 68, file=out)
+
+ for name, feature in [
+ ("pil", "PIL CORE"),
+ ("tkinter", "TKINTER"),
+ ("freetype2", "FREETYPE2"),
+ ("littlecms2", "LITTLECMS2"),
+ ("webp", "WEBP"),
+ ("transp_webp", "WEBP Transparency"),
+ ("webp_mux", "WEBPMUX"),
+ ("webp_anim", "WEBP Animation"),
+ ("jpg", "JPEG"),
+ ("jpg_2000", "OPENJPEG (JPEG2000)"),
+ ("zlib", "ZLIB (PNG/ZIP)"),
+ ("libtiff", "LIBTIFF"),
+ ("raqm", "RAQM (Bidirectional Text)"),
+ ("libimagequant", "LIBIMAGEQUANT (Quantization method)"),
+ ("xcb", "XCB (X protocol)"),
+ ]:
+ if check(name):
+ if name == "jpg" and check_feature("libjpeg_turbo"):
+ v = "libjpeg-turbo " + version_feature("libjpeg_turbo")
+ else:
+ v = version(name)
+ if v is not None:
+ version_static = name in ("pil", "jpg")
+ if name == "littlecms2":
+ # this check is also in src/_imagingcms.c:setup_module()
+ version_static = tuple(int(x) for x in v.split(".")) < (2, 7)
+ t = "compiled for" if version_static else "loaded"
+ print("---", feature, "support ok,", t, v, file=out)
+ else:
+ print("---", feature, "support ok", file=out)
+ else:
+ print("***", feature, "support not installed", file=out)
+ print("-" * 68, file=out)
+
+ if supported_formats:
+ extensions = collections.defaultdict(list)
+ for ext, i in Image.EXTENSION.items():
+ extensions[i].append(ext)
+
+ for i in sorted(Image.ID):
+ line = f"{i}"
+ if i in Image.MIME:
+ line = f"{line} {Image.MIME[i]}"
+ print(line, file=out)
+
+ if i in extensions:
+ print(
+ "Extensions: {}".format(", ".join(sorted(extensions[i]))), file=out
+ )
+
+ features = []
+ if i in Image.OPEN:
+ features.append("open")
+ if i in Image.SAVE:
+ features.append("save")
+ if i in Image.SAVE_ALL:
+ features.append("save_all")
+ if i in Image.DECODERS:
+ features.append("decode")
+ if i in Image.ENCODERS:
+ features.append("encode")
+
+ print("Features: {}".format(", ".join(features)), file=out)
+ print("-" * 68, file=out)
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/INSTALLER b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/LICENSE b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/LICENSE
new file mode 100644
index 0000000..1197291
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/LICENSE
@@ -0,0 +1,30 @@
+The Python Imaging Library (PIL) is
+
+ Copyright © 1997-2011 by Secret Labs AB
+ Copyright © 1995-2011 by Fredrik Lundh
+
+Pillow is the friendly PIL fork. It is
+
+ Copyright © 2010-2021 by Alex Clark and contributors
+
+Like PIL, Pillow is licensed under the open source HPND License:
+
+By obtaining, using, and/or copying this software and/or its associated
+documentation, you agree that you have read, understood, and will comply
+with the following terms and conditions:
+
+Permission to use, copy, modify, and distribute this software and its
+associated documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appears in all copies, and that
+both that copyright notice and this permission notice appear in supporting
+documentation, and that the name of Secret Labs AB or the author not be
+used in advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
+SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR ANY SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/METADATA b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/METADATA
new file mode 100644
index 0000000..b62f028
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/METADATA
@@ -0,0 +1,137 @@
+Metadata-Version: 2.1
+Name: Pillow
+Version: 8.1.2
+Summary: Python Imaging Library (Fork)
+Home-page: https://python-pillow.org
+Author: Alex Clark (PIL Fork Author)
+Author-email: aclark@python-pillow.org
+License: HPND
+Project-URL: Documentation, https://pillow.readthedocs.io
+Project-URL: Source, https://github.com/python-pillow/Pillow
+Project-URL: Funding, https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=pypi
+Project-URL: Release notes, https://pillow.readthedocs.io/en/stable/releasenotes/index.html
+Project-URL: Changelog, https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst
+Keywords: Imaging
+Platform: UNKNOWN
+Classifier: Development Status :: 6 - Mature
+Classifier: License :: OSI Approved :: Historical Permission Notice and Disclaimer (HPND)
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Topic :: Multimedia :: Graphics
+Classifier: Topic :: Multimedia :: Graphics :: Capture :: Digital Camera
+Classifier: Topic :: Multimedia :: Graphics :: Capture :: Screen Capture
+Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
+Classifier: Topic :: Multimedia :: Graphics :: Viewers
+Requires-Python: >=3.6
+Description-Content-Type: text/markdown
+
+
+
+
+
+# Pillow
+
+## Python Imaging Library (Fork)
+
+Pillow is the friendly PIL fork by [Alex Clark and
+Contributors](https://github.com/python-pillow/Pillow/graphs/contributors).
+PIL is the Python Imaging Library by Fredrik Lundh and Contributors.
+As of 2019, Pillow development is
+[supported by Tidelift](https://tidelift.com/subscription/pkg/pypi-pillow?utm_source=pypi-pillow&utm_medium=readme&utm_campaign=enterprise).
+
+
+
+ docs
+
+
+
+
+
+ tests
+
+
+
+
+
+
+
+
+
+
+
+ package
+
+
+
+
+
+
+
+
+ social
+
+
+
+
+
+
+
+## Overview
+
+The Python Imaging Library adds image processing capabilities to your Python interpreter.
+
+This library provides extensive file format support, an efficient internal representation, and fairly powerful image processing capabilities.
+
+The core image library is designed for fast access to data stored in a few basic pixel formats. It should provide a solid foundation for a general image processing tool.
+
+## More Information
+
+- [Documentation](https://pillow.readthedocs.io/)
+ - [Installation](https://pillow.readthedocs.io/en/latest/installation.html)
+ - [Handbook](https://pillow.readthedocs.io/en/latest/handbook/index.html)
+- [Contribute](https://github.com/python-pillow/Pillow/blob/master/.github/CONTRIBUTING.md)
+ - [Issues](https://github.com/python-pillow/Pillow/issues)
+ - [Pull requests](https://github.com/python-pillow/Pillow/pulls)
+- [Release notes](https://pillow.readthedocs.io/en/stable/releasenotes/index.html)
+- [Changelog](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst)
+ - [Pre-fork](https://github.com/python-pillow/Pillow/blob/master/CHANGES.rst#pre-fork)
+
+## Report a Vulnerability
+
+To report a security vulnerability, please follow the procedure described in the [Tidelift security policy](https://tidelift.com/docs/security).
+
+
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/RECORD b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/RECORD
new file mode 100644
index 0000000..7c450da
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/RECORD
@@ -0,0 +1,198 @@
+PIL/BdfFontFile.py,sha256=hRnSgFZOIiTgWfJIaRHRQpU4TKVok2E31KJY6sbZPwc,2817
+PIL/BlpImagePlugin.py,sha256=9hOQPSrh9b2lX_B_iVMLzg5ydCQsxrNH9ODtZzgR9xQ,14390
+PIL/BmpImagePlugin.py,sha256=JNcxnXmnv4s_TuFKOqqrjsVHC6cyVSN2BiA2fTiY7Rg,14164
+PIL/BufrStubImagePlugin.py,sha256=Zq60GwcqQJTmZJrA9EQq94QvYpNqwYvQzHojh4U7SDw,1520
+PIL/ContainerIO.py,sha256=1U15zUXjWO8uWK-MyCp66Eh7djQEU-oUeCDoBqewNkA,2883
+PIL/CurImagePlugin.py,sha256=er_bI3V1Ezly0QfFJq0fZMlGwrD5izDutwF1FrOwiMA,1679
+PIL/DcxImagePlugin.py,sha256=bfESLTji9GerqI4oYsy5oTFyRMlr2mjSsXzpY9IuLsk,2145
+PIL/DdsImagePlugin.py,sha256=DxDAfsdOvcjyLvMwbcZWLbYBxNv2sxNUOZ5dlOPOPhQ,6009
+PIL/EpsImagePlugin.py,sha256=12udC0cavBCfJ0hfv3nDrn8HHxNIAzQ9nVbGQmRsCaM,12096
+PIL/ExifTags.py,sha256=fx7S0CnztT9ptHT2HGuMYteI99CMVrD73IHeRI5OFjU,9009
+PIL/FitsStubImagePlugin.py,sha256=8Zq2D9ReJE-stBppxB_ELX3wxcS0_BDGg6Xce7sWpaU,1624
+PIL/FliImagePlugin.py,sha256=pGeC1JI6d5xdYWRhsKz0_3yeFzGII_jYbQhJYNo6n7Y,4260
+PIL/FontFile.py,sha256=LkQcbwUu1C4fokMnbg-ao9ksp2RX-saaPRie-z2rpH4,2765
+PIL/FpxImagePlugin.py,sha256=nKGioxa5C0q9X9qva3t_htRV_3jXQcFkclVxTEaSusk,6658
+PIL/FtexImagePlugin.py,sha256=d5xy9hZ6vzmzfTS7eUM_LaB8NHgV6izj1VKTBHOfFEQ,3309
+PIL/GbrImagePlugin.py,sha256=u9kOIdBxYMRrXfXfIwGcz0uyvvxNRCwO3U1xcfa51T4,2794
+PIL/GdImageFile.py,sha256=JFWSUssG1z1r884GQtBbZ3T7uhPF4cDXSuW3ctgf3TU,2465
+PIL/GifImagePlugin.py,sha256=c0OnvrO4R74seBRjSDgWyfomkGf29RrhAO9Ljd7A-7o,28917
+PIL/GimpGradientFile.py,sha256=G0ClRmjRHIJoU0nmG-P-tgehLHZip5i0rY4-5pjJ7bc,3353
+PIL/GimpPaletteFile.py,sha256=_wWvNmB40AfQ1M5sTxoYYXOMApWQji7rrubqZhfd1dU,1274
+PIL/GribStubImagePlugin.py,sha256=sSBrTisTcunuC0WcSQ4_55nV6uFvLCQ0JLSd62dgURw,1515
+PIL/Hdf5StubImagePlugin.py,sha256=zjtFPZIcVkWXvYRPnHow6XA9kElEi772w7PFSuEqmq4,1517
+PIL/IcnsImagePlugin.py,sha256=Zef5EX1IlPq_LHdig-TEF_njD5KeXpTnvdiSTYaqi50,11782
+PIL/IcoImagePlugin.py,sha256=umIc2ud-FGl0ITHBfltfIY7dQMOkBsO6irhnTYP6QBA,10340
+PIL/ImImagePlugin.py,sha256=RFFyRlFJTVuti-TZ9yWsqP7vJJydgX1MC6mjYwwdw-0,10729
+PIL/Image.py,sha256=WyxivptE6qQtik2pLO1201eQ3CGJojxFFoVNZU00KYE,116624
+PIL/ImageChops.py,sha256=HOGSnuU4EcCbdeUzEGPm54zewppHWWe12XLyOLLPgCw,7297
+PIL/ImageCms.py,sha256=NZs-joebSCHg2J0fKXASLNgiXl7FRfWmUn-IW7AkonQ,37087
+PIL/ImageColor.py,sha256=zUDJ9l_gRzB2Xb5JX5lfDhOdsL8l7hmLte7YEmVHI3s,8638
+PIL/ImageDraw.py,sha256=lVcv9yoadOXjcV9PaaYrMpBiP9_j2Y-GBayaPd-YZJQ,30660
+PIL/ImageDraw2.py,sha256=oBhpBTZhx3bd4D0s8E2kDjBzgThRkDU_TE_987l501k,5019
+PIL/ImageEnhance.py,sha256=CJnCouiBmxN2fE0xW7m_uMdBqcm-Fp0S3ruHhkygal4,3190
+PIL/ImageFile.py,sha256=Oe8P0zXRFcACneJqwkNSLrnZnnyIBzpE1nxIjmMcJvo,21246
+PIL/ImageFilter.py,sha256=3zaG3rvTfdox6zKcXq3sbHHwEfl7E1jJd5_KTirH2hw,15827
+PIL/ImageFont.py,sha256=zYN6axJ_u7Jt62bH0o3SaEO6Cxwk79PMUn5FlWY0S7s,45202
+PIL/ImageGrab.py,sha256=2o1aA0_vP-KeRJsJtIxYhi61yCK4k_Khh6NHQD7HO2Q,3625
+PIL/ImageMath.py,sha256=iQPtbXgdhcCchGTXbDop7AiI_Fe-fNmq8m1YHsHMBgc,7048
+PIL/ImageMode.py,sha256=gI88wDgAc4y-m46vTA4zPmipG12wpYLNXPRHyPZBZaY,1638
+PIL/ImageMorph.py,sha256=TM0-barsZdbHEyQ_wB2SrdZvJBkRnWnUbDzGVzDECL4,7854
+PIL/ImageOps.py,sha256=8n-F_HEVRt2l7SENEoiSHpWKn6EehLT0tYfZKKCGB7I,18462
+PIL/ImagePalette.py,sha256=ZjkQry8gfuET-QmG8P18UcZlttKUQjZUgQ3EKh3E6Js,6350
+PIL/ImagePath.py,sha256=lVmH1-lCd0SyrFoqyhlstAFW2iJuC14fPcW8iewvxCQ,336
+PIL/ImageQt.py,sha256=xAXlhkwENjox8CcQYKEq9CJjNk8bzpIH8C_XsLBSDzM,5994
+PIL/ImageSequence.py,sha256=3djA7vDH6wafTGbt4e_lPlVhy2TaKfdSrA1XQ4n-Uoc,1850
+PIL/ImageShow.py,sha256=Df6u8oiv8O4VBmOyfqj53AJAN3kiWsOb97xJaevj8XM,6295
+PIL/ImageStat.py,sha256=PieQi44mRHE6jod7NqujwGr6WCntuZuNGmC2z9PaoDY,3901
+PIL/ImageTk.py,sha256=rLPqAnLH61y2XRHgRPUdesYLQqnDQ__LeRK66KL_fPQ,9324
+PIL/ImageTransform.py,sha256=V2l6tsjmymMIF7HQBMI21UPn4mlicarrm4NF3Kazvio,2843
+PIL/ImageWin.py,sha256=1MQBJS7tVrQzI9jN0nmeNeFpIaq8fXra9kQocHkiFxM,7191
+PIL/ImtImagePlugin.py,sha256=cn60lqUVnK2oh_sPqPBORr_rZ4zuF_6FU0V96IAh8Ww,2203
+PIL/IptcImagePlugin.py,sha256=-RZBUUodHcF5wLKanW1MxJj7cbLOpx5LvXqm0vDM22U,5714
+PIL/Jpeg2KImagePlugin.py,sha256=3NAbqBmvSU_fHUIGspXFsVQV7uYMydN2Rj8jP2bGdiA,8722
+PIL/JpegImagePlugin.py,sha256=cpE4tQ3IqdtP3__RjZDLOEygwoFnska6MgbL8o6NXuI,27740
+PIL/JpegPresets.py,sha256=6gYstS6ZLaE0ENw7qcz1vlNtF2HMGSKx5Sm-KfKKCJ0,12709
+PIL/McIdasImagePlugin.py,sha256=LrP5nA7l8IQG3WhlMI0Xs8fGXY_uf6IDmzNCERl3tGw,1754
+PIL/MicImagePlugin.py,sha256=t8iqakHjOilWVEOrjTISN2-ctxkTYSZgzmtxf4ufrfg,2606
+PIL/MpegImagePlugin.py,sha256=n16Zgdy8Hcfke16lQwZWs53PZq4BA_OxPCMPDkW62nw,1803
+PIL/MpoImagePlugin.py,sha256=lbBbUp-o6xVnfaX3sQYpd7RN4-5-KHcbwi0Km2vN0eg,4244
+PIL/MspImagePlugin.py,sha256=Rjs-Vw2v1RtdP0V3RS6cf_1edF9FIpn9fYApatwLXXM,5524
+PIL/PSDraw.py,sha256=caJ_uayWqTlk0EhPSKTUOevVooEfTV1ny3jw2PtteoI,6670
+PIL/PaletteFile.py,sha256=s3KtsDuY5S04MKDyiXK3iIbiOGzV9PvCDUpOQHI7yqc,1106
+PIL/PalmImagePlugin.py,sha256=lTVwwSPFrQ-IPFGU8_gRCMZ1Lb73cuVhQ-nkx1Q0oqc,9108
+PIL/PcdImagePlugin.py,sha256=cnBm_xKcpLGT6hZ8QKai9Up0gZERMxZwhDXl1hQtBm0,1476
+PIL/PcfFontFile.py,sha256=njhgblsjSVcITVz1DpWdEligmJgPMh5nTk_zDDWWTik,6348
+PIL/PcxImagePlugin.py,sha256=KVYbCKGGp2DcsYwZSv3YYo3GrcxNTQAniZKlzKvHowg,5682
+PIL/PdfImagePlugin.py,sha256=H2zXDGd_he0MO411T_yREpn9IoA2nifXzaRn3WBGYqk,7665
+PIL/PdfParser.py,sha256=Cb4zRBgnG4_1kmkimjfxvGpUOvOk8aPVLdfa-7mQ2v0,34479
+PIL/PixarImagePlugin.py,sha256=5MMcrrShVr511QKevK1ziKyJn0WllokWQxBhs8NWttY,1631
+PIL/PngImagePlugin.py,sha256=S7cPWcRuk98HDquNoBFIKEBJQ_5jmgaSgRIdWL-LIQs,43885
+PIL/PpmImagePlugin.py,sha256=UNwCp3h7psEK8i0p3P93VVXUBz9_8tUVzUWsITux6HQ,4447
+PIL/PsdImagePlugin.py,sha256=OSfBzyxW2_DclFj6k7ElqERo9oFIBrJ5KH6vRhcDjw4,7725
+PIL/PyAccess.py,sha256=U_N4WB6yg_qpWKo1X7avE98p6Ve3bqqnWOGX6DeyE4U,9592
+PIL/SgiImagePlugin.py,sha256=fdY5GOfjLgGVV5nvZ9gGomYboQ0-uPqyosDAU5M9eeU,6064
+PIL/SpiderImagePlugin.py,sha256=1m1xCZ2S7i2w4f-Tz2FSNkqUzqqZzYaZetKXevmsx6Y,9534
+PIL/SunImagePlugin.py,sha256=bnjnVFRjvApCH1QC1F9HeynoCe5AZk3wa1tOhPvHzKU,4282
+PIL/TarIO.py,sha256=E_pjAxk9wHezXUuR_99liySBXfJoL2wjzdNDf0g1hTo,1440
+PIL/TgaImagePlugin.py,sha256=UmGHaYcHHz3V1T87ZfFNR5TvP1QnQ1QG_EfuJPLmDpw,6277
+PIL/TiffImagePlugin.py,sha256=2RhRdr-ZeaZibTSW5jg-bWTgznQDhoQRwPtvpx4LWIg,68529
+PIL/TiffTags.py,sha256=ZAu3cTEiWLV5QkVFSzpY8LDdXv_RPhQoSa4XS8PYVmE,14560
+PIL/WalImageFile.py,sha256=Mfwtpwi-CgRKGORZbdc35uVG0XdelIEIafmtzh0aTKw,5531
+PIL/WebPImagePlugin.py,sha256=RKHtxgrWjuxN1fQF8AX0ckl3cEJkltOiKJrHYh--gk4,10795
+PIL/WmfImagePlugin.py,sha256=Ht5JppC4GZiYz8GNaww4IXEXTJkSQK7h-A2tt4AEvSI,4672
+PIL/XVThumbImagePlugin.py,sha256=zmZ8Z4B8Kr6NOdUqSipW9_X5mKiLBLs-wxvPRRg1l0M,1940
+PIL/XbmImagePlugin.py,sha256=oIEt_uqwKKU6lLS_IVFwEjotwE1FI4_IHUnx_6Ul_gk,2430
+PIL/XpmImagePlugin.py,sha256=1EBt-g678p0A0NXOkxq7sGM8dymneDMHHQmwJzAbrlw,3062
+PIL/__init__.py,sha256=NnlpBykSA7dIeA6k7aHKD2ikvrCKhpieYVv7UieVoyk,3260
+PIL/__main__.py,sha256=axR7PO-HtXp-o0rBhKIxs0wark0rBfaDIhAIWqtWUo4,41
+PIL/__pycache__/BdfFontFile.cpython-39.pyc,,
+PIL/__pycache__/BlpImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/BmpImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/BufrStubImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/ContainerIO.cpython-39.pyc,,
+PIL/__pycache__/CurImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/DcxImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/DdsImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/EpsImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/ExifTags.cpython-39.pyc,,
+PIL/__pycache__/FitsStubImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/FliImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/FontFile.cpython-39.pyc,,
+PIL/__pycache__/FpxImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/FtexImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/GbrImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/GdImageFile.cpython-39.pyc,,
+PIL/__pycache__/GifImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/GimpGradientFile.cpython-39.pyc,,
+PIL/__pycache__/GimpPaletteFile.cpython-39.pyc,,
+PIL/__pycache__/GribStubImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/Hdf5StubImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/IcnsImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/IcoImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/ImImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/Image.cpython-39.pyc,,
+PIL/__pycache__/ImageChops.cpython-39.pyc,,
+PIL/__pycache__/ImageCms.cpython-39.pyc,,
+PIL/__pycache__/ImageColor.cpython-39.pyc,,
+PIL/__pycache__/ImageDraw.cpython-39.pyc,,
+PIL/__pycache__/ImageDraw2.cpython-39.pyc,,
+PIL/__pycache__/ImageEnhance.cpython-39.pyc,,
+PIL/__pycache__/ImageFile.cpython-39.pyc,,
+PIL/__pycache__/ImageFilter.cpython-39.pyc,,
+PIL/__pycache__/ImageFont.cpython-39.pyc,,
+PIL/__pycache__/ImageGrab.cpython-39.pyc,,
+PIL/__pycache__/ImageMath.cpython-39.pyc,,
+PIL/__pycache__/ImageMode.cpython-39.pyc,,
+PIL/__pycache__/ImageMorph.cpython-39.pyc,,
+PIL/__pycache__/ImageOps.cpython-39.pyc,,
+PIL/__pycache__/ImagePalette.cpython-39.pyc,,
+PIL/__pycache__/ImagePath.cpython-39.pyc,,
+PIL/__pycache__/ImageQt.cpython-39.pyc,,
+PIL/__pycache__/ImageSequence.cpython-39.pyc,,
+PIL/__pycache__/ImageShow.cpython-39.pyc,,
+PIL/__pycache__/ImageStat.cpython-39.pyc,,
+PIL/__pycache__/ImageTk.cpython-39.pyc,,
+PIL/__pycache__/ImageTransform.cpython-39.pyc,,
+PIL/__pycache__/ImageWin.cpython-39.pyc,,
+PIL/__pycache__/ImtImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/IptcImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/Jpeg2KImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/JpegImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/JpegPresets.cpython-39.pyc,,
+PIL/__pycache__/McIdasImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/MicImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/MpegImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/MpoImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/MspImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PSDraw.cpython-39.pyc,,
+PIL/__pycache__/PaletteFile.cpython-39.pyc,,
+PIL/__pycache__/PalmImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PcdImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PcfFontFile.cpython-39.pyc,,
+PIL/__pycache__/PcxImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PdfImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PdfParser.cpython-39.pyc,,
+PIL/__pycache__/PixarImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PngImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PpmImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PsdImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/PyAccess.cpython-39.pyc,,
+PIL/__pycache__/SgiImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/SpiderImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/SunImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/TarIO.cpython-39.pyc,,
+PIL/__pycache__/TgaImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/TiffImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/TiffTags.cpython-39.pyc,,
+PIL/__pycache__/WalImageFile.cpython-39.pyc,,
+PIL/__pycache__/WebPImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/WmfImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/XVThumbImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/XbmImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/XpmImagePlugin.cpython-39.pyc,,
+PIL/__pycache__/__init__.cpython-39.pyc,,
+PIL/__pycache__/__main__.cpython-39.pyc,,
+PIL/__pycache__/_binary.cpython-39.pyc,,
+PIL/__pycache__/_tkinter_finder.cpython-39.pyc,,
+PIL/__pycache__/_util.cpython-39.pyc,,
+PIL/__pycache__/_version.cpython-39.pyc,,
+PIL/__pycache__/features.cpython-39.pyc,,
+PIL/_binary.py,sha256=M_yObPVR_1rxnS5craSJsSbFJMykMYqJ0vNHeUpAmj4,1793
+PIL/_imaging.cp39-win_amd64.pyd,sha256=U-DsTtH4YpGMEFMAKat_Q-VFNO7HmRub_8z8vtDMndY,2673664
+PIL/_imagingcms.cp39-win_amd64.pyd,sha256=PMNzR1OzsXH_17diS3TMLr3NDXy4Urskhu50_lFaTcI,247808
+PIL/_imagingft.cp39-win_amd64.pyd,sha256=dsk-dpoB6Vjp_OMkD-Ky7pZv8yBOpAMzvB2TER73QFI,736256
+PIL/_imagingmath.cp39-win_amd64.pyd,sha256=XR54b7XMyJE0fV4gl0OdkUJwTMGcWSc2csdr_t0vxLg,24576
+PIL/_imagingmorph.cp39-win_amd64.pyd,sha256=jC1VarRx26Uo-2DU-_bNgfByk6i34ZkOZJBZwbY8vcE,13312
+PIL/_imagingtk.cp39-win_amd64.pyd,sha256=KWNEuJhQKniNQQKaWyvnYGVlvJF65CUdMuBpDFcMRqE,15360
+PIL/_tkinter_finder.py,sha256=pWHz4HAUfRlF12YrGMXIZM1evllpRHq2kRAxD43hFmk,224
+PIL/_util.py,sha256=pbjX5KY1W2oZyYVC4TE9ai2PfrJZrAsO5hAnz_JMees,359
+PIL/_version.py,sha256=nipLPSncfZKlWDDuqECMIojv_6gPyytRZAiAhbdZwe4,50
+PIL/_webp.cp39-win_amd64.pyd,sha256=RMoUWC7ffX1JIGkHvS5HurM7QhMyVVdTzkZpSiBaITQ,550400
+PIL/features.py,sha256=sM5E4oDEBqAZ3kHxVRTG7drsuJth_GPRxIUbCDqGHAk,9008
+Pillow-8.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Pillow-8.1.2.dist-info/LICENSE,sha256=W7EdlrOTppjfcAGAaamGJIAh8oY0TEN6E_KZw9rx39Q,1444
+Pillow-8.1.2.dist-info/METADATA,sha256=UVOKy10Ljoj2kd8ziDYE0MmlMsW2mgPdyROsPbLDij0,7064
+Pillow-8.1.2.dist-info/RECORD,,
+Pillow-8.1.2.dist-info/WHEEL,sha256=jr7ubY0Lkz_yXH9FfFe9PTtLhGOsf62dZkNvTYrJINE,100
+Pillow-8.1.2.dist-info/top_level.txt,sha256=riZqrk-hyZqh5f1Z0Zwii3dKfxEsByhu9cU9IODF-NY,4
+Pillow-8.1.2.dist-info/zip-safe,sha256=frcCV1k9oG9oKj3dpUqdJg1PxRT2RSN_XKdLCPjaYaY,2
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/WHEEL b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/WHEEL
new file mode 100644
index 0000000..d1267fc
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.36.2)
+Root-Is-Purelib: false
+Tag: cp39-cp39-win_amd64
+
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/top_level.txt b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/top_level.txt
new file mode 100644
index 0000000..b338169
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/top_level.txt
@@ -0,0 +1 @@
+PIL
diff --git a/venv/Lib/site-packages/Pillow-8.1.2.dist-info/zip-safe b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/zip-safe
new file mode 100644
index 0000000..d3f5a12
--- /dev/null
+++ b/venv/Lib/site-packages/Pillow-8.1.2.dist-info/zip-safe
@@ -0,0 +1 @@
+
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/INSTALLER b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/LICENSE b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/LICENSE
new file mode 100644
index 0000000..5d58a45
--- /dev/null
+++ b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Vaibhav Singh
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/METADATA b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/METADATA
new file mode 100644
index 0000000..ed050bf
--- /dev/null
+++ b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/METADATA
@@ -0,0 +1,160 @@
+Metadata-Version: 2.1
+Name: Random-Word
+Version: 1.0.7
+Summary: This is a simple python package to generate random english words
+Home-page: https://github.com/vaibhavsingh97/random-word
+Author: Vaibhav Singh
+Author-email: hi@vaibhavsingh97.com
+License: MIT
+Keywords: package random words word of the day random word generator
+Platform: UNKNOWN
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.1
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.2
+Classifier: Programming Language :: Python :: 3.3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Description-Content-Type: text/markdown
+Requires-Dist: requests
+Requires-Dist: nose
+
+# random-word
+
+[](https://travis-ci.org/vaibhavsingh97/random-word)
+[](https://badge.fury.io/py/Random-Word)
+[](https://pypi.org/project/random-word/)
+[](https://pypi.org/project/random-word/)
+[](https://www.codacy.com/app/vaibhavsingh97/random-word?utm_source=github.com&utm_medium=referral&utm_content=vaibhavsingh97/random-word&utm_campaign=Badge_Grade)
+[](http://pepy.tech/project/random-word)
+[](https://vaibhavsingh97.mit-license.org/)
+
+This is a simple python package to generate random english words.
+If you need help after reading the below, please find me at [@vaibhavsingh97](https://twitter.com/vaibhavsingh97) on Twitter.
+
+If you love the package, please :star2: the repo.
+
+## Installation
+
+You should be able to install using `easy_install` or `pip` in the usual ways:
+
+```sh
+$ easy_install random-word
+$ pip install random-word
+```
+
+Or just clone this repository and run:
+
+```sh
+$ python3 setup.py install
+```
+
+Or place the `random-word` folder that you downloaded somewhere where it can be accessed by your scripts.
+
+## Basic Usage
+
+```python
+from random_word import RandomWords
+r = RandomWords()
+
+# Return a single random word
+r.get_random_word()
+# Return list of Random words
+r.get_random_words()
+# Return Word of the day
+r.word_of_the_day()
+```
+
+## Advance Usage
+
+1. To generate single random word we can use these optional parameters
+
+ - `hasDictionaryDef (string)` - Only return words with dictionary definitions (optional)
+ - `includePartOfSpeech (string)` - CSV part-of-speech values to include (optional)
+ - `excludePartOfSpeech (string)` - CSV part-of-speech values to exclude (optional)
+ - `minCorpusCount (integer)` - Minimum corpus frequency for terms (optional)
+ - `maxCorpusCount (integer)` - Maximum corpus frequency for terms (optional)
+ - `minDictionaryCount (integer)` - Minimum dictionary count (optional)
+ - `maxDictionaryCount (integer)` - Maximum dictionary count (optional)
+ - `minLength (integer)` - Minimum word length (optional)
+ - `maxLength (integer)` - Maximum word length (optional)
+
+ ```python
+ r.get_random_word(hasDictionaryDef="true", includePartOfSpeech="noun,verb", minCorpusCount=1, maxCorpusCount=10, minDictionaryCount=1, maxDictionaryCount=10, minLength=5, maxLength=10)
+
+ # Output: pediophobia
+ ```
+
+2. To generate list of random word we can use these optional parameters
+
+ - `hasDictionaryDef (string)` - Only return words with dictionary definitions (optional)
+ - `includePartOfSpeech (string)` - CSV part-of-speech values to include (optional)
+ - `excludePartOfSpeech (string)` - CSV part-of-speech values to exclude (optional)
+ - `minCorpusCount (integer)` - Minimum corpus frequency for terms (optional)
+ - `maxCorpusCount (integer)` - Maximum corpus frequency for terms (optional)
+ - `minDictionaryCount (integer)` - Minimum dictionary count (optional)
+ - `maxDictionaryCount (integer)` - Maximum dictionary count (optional)
+ - `minLength (integer)` - Minimum word length (optional)
+ - `maxLength (integer)` - Maximum word length (optional)
+ - `sortBy (string)` - Attribute to sort by `alpha` or `count` (optional)
+ - `sortOrder (string)` - Sort direction by `asc` or `desc` (optional)
+ - `limit (integer)` - Maximum number of results to return (optional)
+
+ ```python
+ r.get_random_words(hasDictionaryDef="true", includePartOfSpeech="noun,verb", minCorpusCount=1, maxCorpusCount=10, minDictionaryCount=1, maxDictionaryCount=10, minLength=5, maxLength=10, sortBy="alpha", sortOrder="asc", limit=15)
+
+ # Output: ['ambivert', 'calcspar', 'deaness', 'entrete', 'gades', 'monkeydom', 'outclimbed', 'outdared', 'pistoleers', 'redbugs', 'snake-line', 'subrules', 'subtrends', 'torenia', 'unhides']
+ ```
+
+3. To get word of the day we can use these optional parameters
+
+ - `date (string)` - Fetches by date in yyyy-MM-dd (optional)
+
+ ```python
+ r.word_of_the_day(date="2018-01-01")
+
+ # Output: {"word": "qualtagh", "definations": [{"text": "The first person one encounters, either after leaving one\'s home or (sometimes) outside one\'s home, especially on New Year\'s Day.", "source": "wiktionary", "partOfSpeech": "noun"}, {"text": "A Christmas or New Year\'s ceremony, in the Isle of Man; one who takes part in the ceremony. See the first extract.", "source": "century", "partOfSpeech": "noun"}]}
+ ```
+
+## Development
+
+Assuming that you have [`Python`](https://www.python.org/) and [`pipenv`](https://docs.pipenv.org) installed, set up your environment and install the required dependencies like this instead of the `pip install random-word` defined above:
+
+```sh
+$ git clone https://github.com/vaibhavsingh97/random-word.git
+$ cd random-word
+$ pipenv install
+...
+$ pipenv shell
+```
+
+Add API Key in `random_word` directory defining API Key in `config.py`. If you don't have an API key than request your API key [here](https://developer.wordnik.com)
+
+```sh
+API_KEY = ""
+```
+
+After that, install your package locally
+
+```sh
+$ pip install -e .
+```
+
+## Issues
+
+You can report the bugs at the [issue tracker](https://github.com/vaibhavsingh97/random-word/issues)
+
+## License
+
+Built with ♥ by Vaibhav Singh([@vaibhavsingh97](https://github.com/vaibhavsingh97)) under [MIT License](https://vaibhavsingh97.mit-license.org/)
+
+You can find a copy of the License at
+
+
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/RECORD b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/RECORD
new file mode 100644
index 0000000..9a2637a
--- /dev/null
+++ b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/RECORD
@@ -0,0 +1,22 @@
+Random_Word-1.0.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Random_Word-1.0.7.dist-info/LICENSE,sha256=huRUHwv7Uz5ms3PPM4cMuKIm7MnSUQh71WSQnGyE1kM,1070
+Random_Word-1.0.7.dist-info/METADATA,sha256=uKR4xHS277Caf46ql9L_K2rVL53jNk8gH_p_4gOVrTk,6999
+Random_Word-1.0.7.dist-info/RECORD,,
+Random_Word-1.0.7.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+Random_Word-1.0.7.dist-info/WHEEL,sha256=EVRjI69F5qVjm_YgqcTXPnTAv3BfSUr0WVAHuSP3Xoo,92
+Random_Word-1.0.7.dist-info/top_level.txt,sha256=euInd3lC3tB8s9vSkm9ArZbZCJo7RWFWOSnLpv8DFN0,12
+random_word/__init__.py,sha256=VdguCb8BwI_hPf66o10RedpHcQGKnHobB35IiSq6AbE,138
+random_word/__pycache__/__init__.cpython-39.pyc,,
+random_word/__pycache__/random_word.cpython-39.pyc,,
+random_word/config.yml,sha256=Da01Mu7AmWaQiYizmQZUh0LxP04JjXrJzS_OfNEE7as,178
+random_word/random_word.py,sha256=pzW-WG8Ey4Jstig8_qx1q22yPuaosugVQmVr0RPFr64,7573
+random_word/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+random_word/tests/__pycache__/__init__.cpython-39.pyc,,
+random_word/tests/__pycache__/test_word.cpython-39.pyc,,
+random_word/tests/test_word.py,sha256=C8SnnvV2FBgyQr2e6XNJSpcd30YOVsw9Nc2FZp1mftU,435
+random_word/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+random_word/utils/__pycache__/__init__.cpython-39.pyc,,
+random_word/utils/__pycache__/retry_generator.cpython-39.pyc,,
+random_word/utils/__pycache__/utils.cpython-39.pyc,,
+random_word/utils/retry_generator.py,sha256=mCS3ivSlQ7K3urJs314_6264FbVvTo8cOaLthl7sd38,700
+random_word/utils/utils.py,sha256=IK80NdgbgmlT0d_QC6v6_xQLqYaZR0Umu-W3WegCHYw,872
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/REQUESTED b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/WHEEL b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/WHEEL
new file mode 100644
index 0000000..83ff02e
--- /dev/null
+++ b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.35.1)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/top_level.txt b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/top_level.txt
new file mode 100644
index 0000000..a7dfd9c
--- /dev/null
+++ b/venv/Lib/site-packages/Random_Word-1.0.7.dist-info/top_level.txt
@@ -0,0 +1 @@
+random_word
diff --git a/venv/Lib/site-packages/_distutils_hack/__init__.py b/venv/Lib/site-packages/_distutils_hack/__init__.py
new file mode 100644
index 0000000..c31edfe
--- /dev/null
+++ b/venv/Lib/site-packages/_distutils_hack/__init__.py
@@ -0,0 +1,123 @@
+import sys
+import os
+import re
+import importlib
+import warnings
+
+
+is_pypy = '__pypy__' in sys.builtin_module_names
+
+
+def warn_distutils_present():
+ if 'distutils' not in sys.modules:
+ return
+ if is_pypy and sys.version_info < (3, 7):
+ # PyPy for 3.6 unconditionally imports distutils, so bypass the warning
+ # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
+ return
+ warnings.warn(
+ "Distutils was imported before Setuptools, but importing Setuptools "
+ "also replaces the `distutils` module in `sys.modules`. This may lead "
+ "to undesirable behaviors or errors. To avoid these issues, avoid "
+ "using distutils directly, ensure that setuptools is installed in the "
+ "traditional way (e.g. not an editable install), and/or make sure "
+ "that setuptools is always imported before distutils.")
+
+
+def clear_distutils():
+ if 'distutils' not in sys.modules:
+ return
+ warnings.warn("Setuptools is replacing distutils.")
+ mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
+ for name in mods:
+ del sys.modules[name]
+
+
+def enabled():
+ """
+ Allow selection of distutils by environment variable.
+ """
+ which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
+ return which == 'local'
+
+
+def ensure_local_distutils():
+ clear_distutils()
+ distutils = importlib.import_module('setuptools._distutils')
+ distutils.__name__ = 'distutils'
+ sys.modules['distutils'] = distutils
+
+ # sanity check that submodules load as expected
+ core = importlib.import_module('distutils.core')
+ assert '_distutils' in core.__file__, core.__file__
+
+
+def do_override():
+ """
+ Ensure that the local copy of distutils is preferred over stdlib.
+
+ See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
+ for more motivation.
+ """
+ if enabled():
+ warn_distutils_present()
+ ensure_local_distutils()
+
+
+class DistutilsMetaFinder:
+ def find_spec(self, fullname, path, target=None):
+ if path is not None:
+ return
+
+ method_name = 'spec_for_{fullname}'.format(**locals())
+ method = getattr(self, method_name, lambda: None)
+ return method()
+
+ def spec_for_distutils(self):
+ import importlib.abc
+ import importlib.util
+
+ class DistutilsLoader(importlib.abc.Loader):
+
+ def create_module(self, spec):
+ return importlib.import_module('setuptools._distutils')
+
+ def exec_module(self, module):
+ pass
+
+ return importlib.util.spec_from_loader('distutils', DistutilsLoader())
+
+ def spec_for_pip(self):
+ """
+ Ensure stdlib distutils when running under pip.
+ See pypa/pip#8761 for rationale.
+ """
+ if self.pip_imported_during_build():
+ return
+ clear_distutils()
+ self.spec_for_distutils = lambda: None
+
+ @staticmethod
+ def pip_imported_during_build():
+ """
+ Detect if pip is being imported in a build script. Ref #2355.
+ """
+ import traceback
+ return any(
+ frame.f_globals['__file__'].endswith('setup.py')
+ for frame, line in traceback.walk_stack(None)
+ )
+
+
+DISTUTILS_FINDER = DistutilsMetaFinder()
+
+
+def add_shim():
+ sys.meta_path.insert(0, DISTUTILS_FINDER)
+
+
+def remove_shim():
+ try:
+ sys.meta_path.remove(DISTUTILS_FINDER)
+ except ValueError:
+ pass
diff --git a/venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..b00bf4f
Binary files /dev/null and b/venv/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-39.pyc b/venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-39.pyc
new file mode 100644
index 0000000..efdc7e0
Binary files /dev/null and b/venv/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/_distutils_hack/override.py b/venv/Lib/site-packages/_distutils_hack/override.py
new file mode 100644
index 0000000..2cc433a
--- /dev/null
+++ b/venv/Lib/site-packages/_distutils_hack/override.py
@@ -0,0 +1 @@
+__import__('_distutils_hack').do_override()
diff --git a/venv/Lib/site-packages/distutils-precedence.pth b/venv/Lib/site-packages/distutils-precedence.pth
new file mode 100644
index 0000000..6de4198
--- /dev/null
+++ b/venv/Lib/site-packages/distutils-precedence.pth
@@ -0,0 +1 @@
+import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'stdlib') == 'local'; enabled and __import__('_distutils_hack').add_shim();
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/INSTALLER b/venv/Lib/site-packages/numpy-1.20.1.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/LICENSE.txt b/venv/Lib/site-packages/numpy-1.20.1.dist-info/LICENSE.txt
new file mode 100644
index 0000000..04738ae
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/LICENSE.txt
@@ -0,0 +1,938 @@
+
+----
+
+This binary distribution of NumPy also bundles the following software:
+
+
+Name: OpenBLAS
+Files: extra-dll\libopenb*.dll
+Description: bundled as a dynamically linked library
+Availability: https://github.com/xianyi/OpenBLAS/
+License: 3-clause BSD
+ Copyright (c) 2011-2014, The OpenBLAS Project
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. Neither the name of the OpenBLAS project nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Name: LAPACK
+Files: extra-dll\libopenb*.dll
+Description: bundled in OpenBLAS
+Availability: https://github.com/xianyi/OpenBLAS/
+License 3-clause BSD
+ Copyright (c) 1992-2013 The University of Tennessee and The University
+ of Tennessee Research Foundation. All rights
+ reserved.
+ Copyright (c) 2000-2013 The University of California Berkeley. All
+ rights reserved.
+ Copyright (c) 2006-2013 The University of Colorado Denver. All rights
+ reserved.
+
+ $COPYRIGHT$
+
+ Additional copyrights may follow
+
+ $HEADER$
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer listed
+ in this license in the documentation and/or other materials
+ provided with the distribution.
+
+ - Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ The copyright holders provide no reassurances that the source code
+ provided does not infringe any patent, copyright, or any other
+ intellectual property rights of third parties. The copyright holders
+ disclaim any liability to any recipient for claims brought against
+ recipient by any third party for infringement of that parties
+ intellectual property rights.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Name: GCC runtime library
+Files: extra-dll\*.dll
+Description: statically linked, in DLL files compiled with gfortran only
+Availability: https://gcc.gnu.org/viewcvs/gcc/
+License: GPLv3 + runtime exception
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
+
+ Libgfortran is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgfortran is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ .
+
+
+Name: Microsoft Visual C++ Runtime Files
+Files: extra-dll\msvcp140.dll
+License: MSVC
+ https://www.visualstudio.com/license-terms/distributable-code-microsoft-visual-studio-2015-rc-microsoft-visual-studio-2015-sdk-rc-includes-utilities-buildserver-files/#visual-c-runtime
+
+ Subject to the License Terms for the software, you may copy and
+ distribute with your program any of the files within the followng
+ folder and its subfolders except as noted below. You may not modify
+ these files.
+
+ C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist
+
+ You may not distribute the contents of the following folders:
+
+ C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\debug_nonredist
+ C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\onecore\debug_nonredist
+
+ Subject to the License Terms for the software, you may copy and
+ distribute the following files with your program in your program’s
+ application local folder or by deploying them into the Global
+ Assembly Cache (GAC):
+
+ VC\atlmfc\lib\mfcmifc80.dll
+ VC\atlmfc\lib\amd64\mfcmifc80.dll
+
+
+Name: Microsoft Visual C++ Runtime Files
+Files: extra-dll\msvc*90.dll, extra-dll\Microsoft.VC90.CRT.manifest
+License: MSVC
+ For your convenience, we have provided the following folders for
+ use when redistributing VC++ runtime files. Subject to the license
+ terms for the software, you may redistribute the folder
+ (unmodified) in the application local folder as a sub-folder with
+ no change to the folder name. You may also redistribute all the
+ files (*.dll and *.manifest) within a folder, listed below the
+ folder for your convenience, as an entire set.
+
+ \VC\redist\x86\Microsoft.VC90.ATL\
+ atl90.dll
+ Microsoft.VC90.ATL.manifest
+ \VC\redist\ia64\Microsoft.VC90.ATL\
+ atl90.dll
+ Microsoft.VC90.ATL.manifest
+ \VC\redist\amd64\Microsoft.VC90.ATL\
+ atl90.dll
+ Microsoft.VC90.ATL.manifest
+ \VC\redist\x86\Microsoft.VC90.CRT\
+ msvcm90.dll
+ msvcp90.dll
+ msvcr90.dll
+ Microsoft.VC90.CRT.manifest
+ \VC\redist\ia64\Microsoft.VC90.CRT\
+ msvcm90.dll
+ msvcp90.dll
+ msvcr90.dll
+ Microsoft.VC90.CRT.manifest
+
+----
+
+Full text of license texts referred to above follows (that they are
+listed below does not necessarily imply the conditions apply to the
+present binary release):
+
+----
+
+GCC RUNTIME LIBRARY EXCEPTION
+
+Version 3.1, 31 March 2009
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+This GCC Runtime Library Exception ("Exception") is an additional
+permission under section 7 of the GNU General Public License, version
+3 ("GPLv3"). It applies to a given file (the "Runtime Library") that
+bears a notice placed by the copyright holder of the file stating that
+the file is governed by GPLv3 along with this Exception.
+
+When you use GCC to compile a program, GCC may combine portions of
+certain GCC header files and runtime libraries with the compiled
+program. The purpose of this Exception is to allow compilation of
+non-GPL (including proprietary) programs to use, in this way, the
+header files and runtime libraries covered by this Exception.
+
+0. Definitions.
+
+A file is an "Independent Module" if it either requires the Runtime
+Library for execution after a Compilation Process, or makes use of an
+interface provided by the Runtime Library, but is not otherwise based
+on the Runtime Library.
+
+"GCC" means a version of the GNU Compiler Collection, with or without
+modifications, governed by version 3 (or a specified later version) of
+the GNU General Public License (GPL) with the option of using any
+subsequent versions published by the FSF.
+
+"GPL-compatible Software" is software whose conditions of propagation,
+modification and use would permit combination with GCC in accord with
+the license of GCC.
+
+"Target Code" refers to output from any compiler for a real or virtual
+target processor architecture, in executable form or suitable for
+input to an assembler, loader, linker and/or execution
+phase. Notwithstanding that, Target Code does not include data in any
+format that is used as a compiler intermediate representation, or used
+for producing a compiler intermediate representation.
+
+The "Compilation Process" transforms code entirely represented in
+non-intermediate languages designed for human-written code, and/or in
+Java Virtual Machine byte code, into Target Code. Thus, for example,
+use of source code generators and preprocessors need not be considered
+part of the Compilation Process, since the Compilation Process can be
+understood as starting with the output of the generators or
+preprocessors.
+
+A Compilation Process is "Eligible" if it is done using GCC, alone or
+with other GPL-compatible software, or if it is done without using any
+work based on GCC. For example, using non-GPL-compatible Software to
+optimize any GCC intermediate representations would not qualify as an
+Eligible Compilation Process.
+
+1. Grant of Additional Permission.
+
+You have permission to propagate a work of Target Code formed by
+combining the Runtime Library with Independent Modules, even if such
+propagation would otherwise violate the terms of GPLv3, provided that
+all Target Code was generated by Eligible Compilation Processes. You
+may then convey such a combination under terms of your choice,
+consistent with the licensing of the Independent Modules.
+
+2. No Weakening of GCC Copyleft.
+
+The availability of this Exception does not imply any general
+presumption that third-party software is unaffected by the copyleft
+requirements of the license of GCC.
+
+----
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+ .
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/LICENSES_bundled.txt b/venv/Lib/site-packages/numpy-1.20.1.dist-info/LICENSES_bundled.txt
new file mode 100644
index 0000000..55185fa
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/LICENSES_bundled.txt
@@ -0,0 +1,17 @@
+The NumPy repository and source distributions bundle several libraries that are
+compatibly licensed. We list these here.
+
+Name: lapack-lite
+Files: numpy/linalg/lapack_lite/*
+License: BSD-3-Clause
+ For details, see numpy/linalg/lapack_lite/LICENSE.txt
+
+Name: tempita
+Files: tools/npy_tempita/*
+License: MIT
+ For details, see tools/npy_tempita/license.txt
+
+Name: dragon4
+Files: numpy/core/src/multiarray/dragon4.c
+License: MIT
+ For license text, see numpy/core/src/multiarray/dragon4.c
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/METADATA b/venv/Lib/site-packages/numpy-1.20.1.dist-info/METADATA
new file mode 100644
index 0000000..1e10354
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/METADATA
@@ -0,0 +1,56 @@
+Metadata-Version: 2.1
+Name: numpy
+Version: 1.20.1
+Summary: NumPy is the fundamental package for array computing with Python.
+Home-page: https://www.numpy.org
+Author: Travis E. Oliphant et al.
+Maintainer: NumPy Developers
+Maintainer-email: numpy-discussion@python.org
+License: BSD
+Download-URL: https://pypi.python.org/pypi/numpy
+Project-URL: Bug Tracker, https://github.com/numpy/numpy/issues
+Project-URL: Documentation, https://numpy.org/doc/1.20
+Project-URL: Source Code, https://github.com/numpy/numpy
+Platform: Windows
+Platform: Linux
+Platform: Solaris
+Platform: Mac OS-X
+Platform: Unix
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Science/Research
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Programming Language :: C
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Topic :: Software Development
+Classifier: Topic :: Scientific/Engineering
+Classifier: Typing :: Typed
+Classifier: Operating System :: Microsoft :: Windows
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Unix
+Classifier: Operating System :: MacOS
+Requires-Python: >=3.7
+
+It provides:
+
+- a powerful N-dimensional array object
+- sophisticated (broadcasting) functions
+- tools for integrating C/C++ and Fortran code
+- useful linear algebra, Fourier transform, and random number capabilities
+- and much more
+
+Besides its obvious scientific uses, NumPy can also be used as an efficient
+multi-dimensional container of generic data. Arbitrary data-types can be
+defined. This allows NumPy to seamlessly and speedily integrate with a wide
+variety of databases.
+
+All NumPy wheels distributed on PyPI are BSD licensed.
+
+
+
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/RECORD b/venv/Lib/site-packages/numpy-1.20.1.dist-info/RECORD
new file mode 100644
index 0000000..11c2849
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/RECORD
@@ -0,0 +1,1063 @@
+../../Scripts/f2py.exe,sha256=qI3n2gLXnKQOVTk83nEDtx1saIc6bEj9ehi5xoIMOtw,106363
+numpy-1.20.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+numpy-1.20.1.dist-info/LICENSE.txt,sha256=VDW_78UWZhzN_Z729vbkkr7MzLGzi7lj3OKbwZkxrP0,47238
+numpy-1.20.1.dist-info/LICENSES_bundled.txt,sha256=LIMgxkCENPlSsRND8mqjqWqU-7nkH-bRMqz8H8d0M24,505
+numpy-1.20.1.dist-info/METADATA,sha256=U2LukRlUJcO3S3tEhl-awqMqgsL5kwDRqHH8wEH7U_c,2043
+numpy-1.20.1.dist-info/RECORD,,
+numpy-1.20.1.dist-info/WHEEL,sha256=jr7ubY0Lkz_yXH9FfFe9PTtLhGOsf62dZkNvTYrJINE,100
+numpy-1.20.1.dist-info/entry_points.txt,sha256=cOAXaHCx7qU-bvE9TStTTZW46RN-s-i6Mz9smnWkL3g,49
+numpy-1.20.1.dist-info/top_level.txt,sha256=4J9lbBMLnAiyxatxh8iRKV5Entd_6-oqbO7pzJjMsPw,6
+numpy/.libs/libopenblas.JPIJNSWNNAN3CE6LLI5FWSPHUT2VXMTH.gfortran-win_amd64.dll,sha256=JVUPyvs9v39s8ULJWSe8uTdMwNUQ_MD3BMT-iHiUKaU,34413408
+numpy/LICENSE.txt,sha256=VDW_78UWZhzN_Z729vbkkr7MzLGzi7lj3OKbwZkxrP0,47238
+numpy/__config__.py,sha256=IHRa3rupkgR7i9orKgDOiGPeOriQOaDHFF5q7kCETEc,3016
+numpy/__init__.cython-30.pxd,sha256=kg17mANuYQtmc1DmNYwOYCyWcPidN_TCcP0KU6oe4No,37385
+numpy/__init__.pxd,sha256=u2NusfQDgMzoxakO9ePcl81ioWdFfMPa0i6p1xXxU3I,35718
+numpy/__init__.py,sha256=5c-ypjhSjsBLzPlh6eL4BWvuY3b8R6dqMt9JkIaghw4,15676
+numpy/__init__.pyi,sha256=RvyJeclwt2bhmxxt47xZZN7dVRnFnza-R9ektnnrj8M,62623
+numpy/__pycache__/__config__.cpython-39.pyc,,
+numpy/__pycache__/__init__.cpython-39.pyc,,
+numpy/__pycache__/_distributor_init.cpython-39.pyc,,
+numpy/__pycache__/_globals.cpython-39.pyc,,
+numpy/__pycache__/_pytesttester.cpython-39.pyc,,
+numpy/__pycache__/conftest.cpython-39.pyc,,
+numpy/__pycache__/ctypeslib.cpython-39.pyc,,
+numpy/__pycache__/dual.cpython-39.pyc,,
+numpy/__pycache__/matlib.cpython-39.pyc,,
+numpy/__pycache__/setup.cpython-39.pyc,,
+numpy/__pycache__/version.cpython-39.pyc,,
+numpy/_distributor_init.py,sha256=JOqSUAVCNcvuXYwzfs41kJFHvhLdrqRfp3ZYk5U71Pc,1247
+numpy/_globals.py,sha256=Hn6HQltNo4q5i1uia9p4o0l4H8RCAa9y9DG9rEF5J_M,2384
+numpy/_pytesttester.py,sha256=l1KszmXKpS0O-_nGwVPbM71bt3LiZj6J_OUzH464uhU,6954
+numpy/char.pyi,sha256=1q4RiJ6LG9U8E0wic6eMz-X41aeZ0uqBgQf6Atx6Bxg,771
+numpy/compat/__init__.py,sha256=kryOGy6TD3f9oEXy1sZZOxEMc50A7GtON1yf0nMPzr8,450
+numpy/compat/__pycache__/__init__.cpython-39.pyc,,
+numpy/compat/__pycache__/_inspect.cpython-39.pyc,,
+numpy/compat/__pycache__/py3k.cpython-39.pyc,,
+numpy/compat/__pycache__/setup.cpython-39.pyc,,
+numpy/compat/_inspect.py,sha256=4PWDVD-iE3lZGrBCWdiLMn2oSytssuFszubUkC0oruA,7638
+numpy/compat/py3k.py,sha256=rNPRSpbICl4N5Er9N8Du7IgNY2mKgw8jrH__5-pxfRM,3527
+numpy/compat/setup.py,sha256=PmRas58NGR72H-7OsQj6kElSUeQHjN75qVh5jlQIJmc,345
+numpy/compat/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/compat/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/compat/tests/__pycache__/test_compat.cpython-39.pyc,,
+numpy/compat/tests/test_compat.py,sha256=6i0bPM1Nqw0n3wtMphMU7ul7fkQNwcuH2Xxc9vpnQy8,495
+numpy/conftest.py,sha256=yzmbZ_hizvOf-RT3PLYIYrvhNpj7L2CLBMoPiHMCNQ4,4150
+numpy/core/__init__.py,sha256=D3i0c-7P6m6hvSRyJRXM_u2fp4U35HEKo6YlMkgGceI,5470
+numpy/core/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/core/__pycache__/__init__.cpython-39.pyc,,
+numpy/core/__pycache__/_add_newdocs.cpython-39.pyc,,
+numpy/core/__pycache__/_add_newdocs_scalars.cpython-39.pyc,,
+numpy/core/__pycache__/_asarray.cpython-39.pyc,,
+numpy/core/__pycache__/_dtype.cpython-39.pyc,,
+numpy/core/__pycache__/_dtype_ctypes.cpython-39.pyc,,
+numpy/core/__pycache__/_exceptions.cpython-39.pyc,,
+numpy/core/__pycache__/_internal.cpython-39.pyc,,
+numpy/core/__pycache__/_methods.cpython-39.pyc,,
+numpy/core/__pycache__/_string_helpers.cpython-39.pyc,,
+numpy/core/__pycache__/_type_aliases.cpython-39.pyc,,
+numpy/core/__pycache__/_ufunc_config.cpython-39.pyc,,
+numpy/core/__pycache__/arrayprint.cpython-39.pyc,,
+numpy/core/__pycache__/cversions.cpython-39.pyc,,
+numpy/core/__pycache__/defchararray.cpython-39.pyc,,
+numpy/core/__pycache__/einsumfunc.cpython-39.pyc,,
+numpy/core/__pycache__/fromnumeric.cpython-39.pyc,,
+numpy/core/__pycache__/function_base.cpython-39.pyc,,
+numpy/core/__pycache__/generate_numpy_api.cpython-39.pyc,,
+numpy/core/__pycache__/getlimits.cpython-39.pyc,,
+numpy/core/__pycache__/machar.cpython-39.pyc,,
+numpy/core/__pycache__/memmap.cpython-39.pyc,,
+numpy/core/__pycache__/multiarray.cpython-39.pyc,,
+numpy/core/__pycache__/numeric.cpython-39.pyc,,
+numpy/core/__pycache__/numerictypes.cpython-39.pyc,,
+numpy/core/__pycache__/overrides.cpython-39.pyc,,
+numpy/core/__pycache__/records.cpython-39.pyc,,
+numpy/core/__pycache__/setup.cpython-39.pyc,,
+numpy/core/__pycache__/setup_common.cpython-39.pyc,,
+numpy/core/__pycache__/shape_base.cpython-39.pyc,,
+numpy/core/__pycache__/umath.cpython-39.pyc,,
+numpy/core/__pycache__/umath_tests.cpython-39.pyc,,
+numpy/core/_add_newdocs.py,sha256=khECrR7Rf1cvVcocZXeuIBf-1nylFJKpX8OpQUij2WQ,190584
+numpy/core/_add_newdocs_scalars.py,sha256=Z_1yGo28WECk5w0rN7e7n0GSrh7gsgSRrp02bRUwH_g,8818
+numpy/core/_asarray.py,sha256=APygHZC-8_LtPS4e1DH8uy_AoXW3D4drHKIN5OIBa-U,12595
+numpy/core/_asarray.pyi,sha256=dyUZzE1AIyyuEWY6KYYXlVbzyX-bdFDNUlZiEh4gxeE,1849
+numpy/core/_dtype.py,sha256=rrmrfzsthRMpG42judFTK7s6FJLfuYhMp5NY3F4lAaU,10185
+numpy/core/_dtype_ctypes.py,sha256=O8tYBqU1QzCG1CXviBe6jrgHYnyIPqpci9GEy9lXO08,3790
+numpy/core/_exceptions.py,sha256=AKdiXex1lQsv-tdKzhBbW-m5anJJFXpsWisjz8S3tAY,6342
+numpy/core/_internal.py,sha256=pmRIldMwdXHB4Pe23_utM0mEw0G9TrEUYX4ngBt16xg,27048
+numpy/core/_internal.pyi,sha256=fi4i96SaeVYEbpT5H2EY_A4n7TssO3NRU3qI4oa6PDo,543
+numpy/core/_methods.py,sha256=Z2atswmr5O-tqEIn4VHy_bmG_3RXNzFUkgUwG7RVCG0,11059
+numpy/core/_multiarray_tests.cp39-win_amd64.pyd,sha256=sO8WOOiUgrZOb4v0_wK5yPljUXZENXfYK92Ith842oI,110592
+numpy/core/_multiarray_umath.cp39-win_amd64.pyd,sha256=navrfVGsQlpiV0lbCvjwrilOKORcUtUSqY8h1yUV40g,2816000
+numpy/core/_operand_flag_tests.cp39-win_amd64.pyd,sha256=Vb06iOthZL46LTHpVUq_DD1vfDW7GyyslKDKiXaaTcM,13824
+numpy/core/_rational_tests.cp39-win_amd64.pyd,sha256=yItzvFpgoYDJhFljyz6_OObwMyNLCaEI0WUCSXC7gTg,47616
+numpy/core/_simd.cp39-win_amd64.pyd,sha256=bzsaphnNunFmlBSvmfpAir0LTWczjKRIC09jAcUliTs,1216000
+numpy/core/_string_helpers.py,sha256=xFVFp6go9I8O7PKRR2zwkOk2VJxlnXTFSYt4s7MwXGM,2955
+numpy/core/_struct_ufunc_tests.cp39-win_amd64.pyd,sha256=obxN4HJytibUCDTpblzIO-TwdndKoboTCimjCcKfnfQ,14848
+numpy/core/_type_aliases.py,sha256=r_1GCfxyoTUGZ7eqB9rFyk4wDNcckZmTbn67Diuonlc,8050
+numpy/core/_type_aliases.pyi,sha256=lhTyivGJcuyja-I-1rGx0Op_d_UdFt9kavPeCn_o49w,539
+numpy/core/_ufunc_config.py,sha256=K_L35alWVK-CBKiQDp2Bp2-7LgXPBNmGHVAg5gNJbCg,14271
+numpy/core/_ufunc_config.pyi,sha256=3AvHaqwY0JdSIk-vkagBwag-jh-5ZPdSnPiXAv-Fhf0,1293
+numpy/core/_umath_tests.cp39-win_amd64.pyd,sha256=KU8azfjKORfQB4HB0lLcdPabl6Xl0S8V5of5yCHqT4U,32256
+numpy/core/arrayprint.py,sha256=pNPRgU7-6sxGfFjgIwGwq63e1qBwC1DOYI9_FdNEE-U,61525
+numpy/core/cversions.py,sha256=FISv1d4R917Bi5xJjKKy8Lo6AlFkV00WvSoB7l3acA4,360
+numpy/core/defchararray.py,sha256=A1P1Nn3MwVaIOgeFsrHXVQMLJINdth9gHnE4CU-j4gY,72530
+numpy/core/einsumfunc.py,sha256=iHjDbD_IKRWVFzph2DFfPCEQnSrJhkIQLzv5wv6hVgY,52884
+numpy/core/fromnumeric.py,sha256=YM6L4CbxCAehD4ffYDPhcj0gGp2BlUCTKwQmTGqmK-U,125761
+numpy/core/fromnumeric.pyi,sha256=Wo1hVrGgkJNZYy5-uUfE88YPPj5cyDgF_uumbo8xick,13126
+numpy/core/function_base.py,sha256=kER123X44kuAaFvsJs9-dOMGHcexPCEWwFhF0UQg77Y,19550
+numpy/core/function_base.pyi,sha256=vJ2H4u6uwReiKTWEZUkIoUFcdh3ymofLxavxh2Qr9JI,1602
+numpy/core/generate_numpy_api.py,sha256=5auy8-Wg0VUIwCepuDwAL11gL1P-oiZl7exPIi5BfbU,7348
+numpy/core/getlimits.py,sha256=ifS2q5tI2upbxC3ayqitKERnFT0LjA0rY9hRWPpzdj8,20338
+numpy/core/include/numpy/__multiarray_api.h,sha256=MUlrBTUSGh-t_l7iNOXx9ibJHUYddbKudHdFp6Oxd-4,63548
+numpy/core/include/numpy/__ufunc_api.h,sha256=Jmeal3EUlXxBZFX1zAUFvO7jWFVhvIOyf2DG_TW0X2k,12739
+numpy/core/include/numpy/_neighborhood_iterator_imp.h,sha256=9QiCyQf-O1MEjBJQ7T4JUu_JyUyQhCBZHbwOr7sAlyk,1951
+numpy/core/include/numpy/_numpyconfig.h,sha256=2T66Co5gkAN9DD_kuhsoU9GsKfg5lIFuTi4GxtE71tw,891
+numpy/core/include/numpy/arrayobject.h,sha256=Xt8fnhPhTkbhB313Xj315N3fLi3uYBEPbqNrsF-MUXE,175
+numpy/core/include/numpy/arrayscalars.h,sha256=y624UltRg9QkKVAsdbxZ_nI2td9myIMr44TZk01P-3M,3912
+numpy/core/include/numpy/halffloat.h,sha256=AaeF7vnfAjeoIg5krxbhDn7j_T6CAQIx-HfMBYYmGiQ,1948
+numpy/core/include/numpy/multiarray_api.txt,sha256=XwNLmbQ19nX5b2rOH6cDsFLl6_JrUt1UfQDSBIy9lS8,58809
+numpy/core/include/numpy/ndarrayobject.h,sha256=3GqcdPD2qgESrcH1O5oFlY04HC3aZ_VdN2tuLl65BrQ,10956
+numpy/core/include/numpy/ndarraytypes.h,sha256=nZcsXab2tkm1OAgkKy4FmIqZ_lqQthtsAy7nIjf-WMM,71451
+numpy/core/include/numpy/noprefix.h,sha256=fg28OipEj4EaPsrNGWu4YNZoGK7Bxdm5o45pAO5HaSk,6998
+numpy/core/include/numpy/npy_1_7_deprecated_api.h,sha256=rVhu81d2cL3I3u7eMpWs5qKlYpxaq84VPK4gP0Yk1QM,4394
+numpy/core/include/numpy/npy_3kcompat.h,sha256=LT1FbrrMzRyz4IE_Kxl3SbQ58p5Bp3x1QUHW-PCiPag,16101
+numpy/core/include/numpy/npy_common.h,sha256=vKyvBMPV3BiJGqSYsvUhJoS8qok_VNBMaOkzhLIaOjU,39413
+numpy/core/include/numpy/npy_cpu.h,sha256=LqrGxmouzu91yaBRzpaGAC_WGi7x04EKB1yRYjsXP-0,4042
+numpy/core/include/numpy/npy_endian.h,sha256=_vfSgtUccP2UrI6ag77Gj2mWbBnMKQfsPS2ggNwmJ2A,2714
+numpy/core/include/numpy/npy_interrupt.h,sha256=CjwMAXyJjxLbpbPFpyHrTgT1QDa2mrzQ-5EhGA-feqk,1923
+numpy/core/include/numpy/npy_math.h,sha256=6Ayeks6UG8_61SA4Q1k9x2nCcm9tSmKgBG7hJZQ-AqI,21569
+numpy/core/include/numpy/npy_no_deprecated_api.h,sha256=4-ALjOYp43ACG7z4zdabmQtFsxxKDaqYuQFTbElty1o,586
+numpy/core/include/numpy/npy_os.h,sha256=g6I_-QEotWP0p9g1v-GA_Qibg5HRAhQj46WsZ19fIuw,847
+numpy/core/include/numpy/numpyconfig.h,sha256=k1lxNkL1fQLbGr8rqgUX-D8OzykzWrTiZPF1Qcg4FMU,1453
+numpy/core/include/numpy/old_defines.h,sha256=gxn96tn2uCpdL0yBFEO6H_JDkhikf8Bj-w3x8sOz5Go,6493
+numpy/core/include/numpy/oldnumeric.h,sha256=b2lR7L8Lajka8FQ3HrrkSnekPKYK0v4vsUduS8gWZqc,733
+numpy/core/include/numpy/random/bitgen.h,sha256=V0PTeCTsLhKTq_z0hM8VgDa7jTQUTPASD0MkMaGXrgk,409
+numpy/core/include/numpy/random/distributions.h,sha256=9JVj1WgcIBxzXhez8EO3JUlyMmCKGfCoQbS9PUCNE_Y,9910
+numpy/core/include/numpy/ufunc_api.txt,sha256=8gADu8fBcUgFZV0yMbJwa1CtJKJsPVrx8MjuXsu18aw,7397
+numpy/core/include/numpy/ufuncobject.h,sha256=P5b7oDLvsE4sYGLxQ8gNDSN-f__LR064FV4duDq97Uw,13127
+numpy/core/include/numpy/utils.h,sha256=LX_d9Fbe_BleyoYLy4wQgwrsF924qKLs7mAjejkdUCw,1161
+numpy/core/lib/npy-pkg-config/mlib.ini,sha256=mQBSOI6opCVmMZK4vwIhLe5J7YevO3PbaHsI0MlJGHs,151
+numpy/core/lib/npy-pkg-config/npymath.ini,sha256=5dwvhvbX3a_9toniEDvGPDGChbXIfFiLa36H4YOR-vw,380
+numpy/core/lib/npymath.lib,sha256=BWz5d_qR0XH2raDxQd_gZpOZ6pQYqOelgKt7L8Luxqg,106590
+numpy/core/machar.py,sha256=AhzxGy1gnrp-M-ikLzi9nm-Rb1vuUZsmqmnud8qen_g,11157
+numpy/core/memmap.py,sha256=WB-4tIRvywLS3rP2ueuroj4pbySSGWJe-Ww88D5mm4g,12061
+numpy/core/multiarray.py,sha256=1AcQPxGOSLkFEXSAn_PFX7l-W1ZyxIBHaRcXYHtoIu0,56546
+numpy/core/numeric.py,sha256=tJHnnSa6GLuDl6p7dJiRaAoqqMuTKEwEV-s_tu0loNk,79200
+numpy/core/numeric.pyi,sha256=BXJKW-n1k4xxRevqiCysWeyk8DQDBRgYARczr3hfibg,4933
+numpy/core/numerictypes.py,sha256=K9TPRmuwMuOJkpgPnKOhtyFTLe0YgQzg-0pM4XbZhnc,18039
+numpy/core/numerictypes.pyi,sha256=9Z1EQNv6G_Nd3rbQpidEUQzdlunUe6a_wrHiFiUZ19M,1077
+numpy/core/overrides.py,sha256=kF571-2fsMrWD1JgHIc_phB4nNPXTdRxoyLktEm2z18,8504
+numpy/core/records.py,sha256=LcIJr6jw3LmRq4aeKwHmQA4gMYn_7h_yMhKleGzW1eQ,38985
+numpy/core/setup.py,sha256=aDmpYk-1NFj8TE-83cJVTx60yLcQYOwNmhVdyletDFQ,45605
+numpy/core/setup_common.py,sha256=VyODljaWE-HUO8LJc90eac9gwNhsZUnfiooWHfUq8IU,20096
+numpy/core/shape_base.py,sha256=gHxRwsy1nLum7iEK_JyXfkswQByPUmFwASL1w4Jxz8c,29922
+numpy/core/shape_base.pyi,sha256=IZbT7mAiA3unDXKgd_tz3pp-Dg2p41sWInS5MWbbsuA,1180
+numpy/core/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/core/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/core/tests/__pycache__/_locales.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test__exceptions.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_abc.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_api.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_array_coercion.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_arrayprint.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_casting_unittests.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_conversion_utils.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_cpu_dispatcher.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_cpu_features.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_cython.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_datetime.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_defchararray.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_deprecations.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_dtype.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_einsum.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_errstate.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_extint128.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_function_base.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_getlimits.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_half.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_indexerrors.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_indexing.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_item_selection.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_longdouble.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_machar.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_mem_overlap.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_memmap.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_multiarray.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_nditer.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_numeric.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_numerictypes.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_overrides.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_print.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_protocols.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_records.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_scalar_ctors.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_scalar_methods.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_scalarbuffer.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_scalarinherit.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_scalarmath.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_scalarprint.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_shape_base.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_simd.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_simd_module.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_ufunc.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_umath.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_umath_accuracy.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_umath_complex.cpython-39.pyc,,
+numpy/core/tests/__pycache__/test_unicode.cpython-39.pyc,,
+numpy/core/tests/_locales.py,sha256=PAV24baH5MIl_gH_VBi5glF-7kgifkK00WnAP0Hhc60,2266
+numpy/core/tests/data/astype_copy.pkl,sha256=lWSzCcvzRB_wpuRGj92spGIw-rNPFcd9hwJaRVvfWdk,716
+numpy/core/tests/data/recarray_from_file.fits,sha256=NA0kliz31FlLnYxv3ppzeruONqNYkuEvts5wzXEeIc4,8640
+numpy/core/tests/data/umath-validation-set-README,sha256=hhKRS9byn4eKEJ_LHoHDYQnVArbEXPIKQtPdPBUtGbk,974
+numpy/core/tests/data/umath-validation-set-cos,sha256=WO94BFik3VcliW2QBStw3Srpfd5Ykcxd-7phRf0be4Y,23898
+numpy/core/tests/data/umath-validation-set-exp,sha256=mPhjF4KLe0bdwx38SJiNipD24ntLI_5aWc8h-V0UMgM,17903
+numpy/core/tests/data/umath-validation-set-log,sha256=CDPky64PjaURWhqkHxkLElmMiI21v5ugGGyzhdfUbnI,11963
+numpy/core/tests/data/umath-validation-set-sin,sha256=0nDRTZc1YG_zbDgpGYtMrf63nUTc8bzcCwEVWqkBqio,23705
+numpy/core/tests/examples/__pycache__/setup.cpython-39.pyc,,
+numpy/core/tests/examples/checks.pyx,sha256=nZXyjisKEKm2vVXM42k-P4h0BGLoa42ABHIGENJegC4,618
+numpy/core/tests/examples/setup.py,sha256=JvbvFHHdkZx_eajlwMTtqHijLD-TZwXCZlRySAe-y94,521
+numpy/core/tests/test__exceptions.py,sha256=_jJh6Xunn9GVkkRab3PJ5xzRn5mCdb5RHxE77F5ds5I,2063
+numpy/core/tests/test_abc.py,sha256=KbyIH9nsGOnXQ8VtnwU6QyUgaFDC0XfEs476CnJ_-Wg,2382
+numpy/core/tests/test_api.py,sha256=LOzoU-9GSjU6D0Tz2SXQEIaMG8GKmQJu98hM7lrbeuk,22227
+numpy/core/tests/test_array_coercion.py,sha256=x7g0Y9POUoVQJJRJ7iGjsVZsY0KHHgmZ760V1pjwpk4,28578
+numpy/core/tests/test_arrayprint.py,sha256=9YfFGZL22BAFQW-Zh3wzZlugzJuU_dN64hJWVDU1eSU,37869
+numpy/core/tests/test_casting_unittests.py,sha256=AvWa8TevaT9OY1vic6-7v2zmKCagKgbHHLUNe9Y1ois,12192
+numpy/core/tests/test_conversion_utils.py,sha256=HB-6IpP4XD5tL_FM5Oat--gQ02MI_WG8BX0P5eyvUZg,6616
+numpy/core/tests/test_cpu_dispatcher.py,sha256=gEEzMPLo057xBh7GmwXwV4ikBC2X1P0XtHUlAkbppU0,1561
+numpy/core/tests/test_cpu_features.py,sha256=wcKrzblzXmZxGg8gdtw1Vn3XAG3d0Kl7TW6Lz0oyprQ,6956
+numpy/core/tests/test_cython.py,sha256=SkCZWMLnSnDUKJjWLfbUHYx5EEgcZ8mghpAJbYs5fX0,3663
+numpy/core/tests/test_datetime.py,sha256=B5ufTlNeIAETvkIYaspc_RZ2lnn2DeJtmdCsSEfSWaY,112219
+numpy/core/tests/test_defchararray.py,sha256=VhAlRKEJSrcWcrZbZruagw1170409taptPGauwxp-HM,25256
+numpy/core/tests/test_deprecations.py,sha256=Ni2OF0djqEcSu0NbC6xmIEZoBHBkQAM-OkMmyOayhEQ,35158
+numpy/core/tests/test_dtype.py,sha256=07ZiqOtBnoj8E2Ss7eNDWB6dLpKNzulmnm1Xk9qsuq8,56019
+numpy/core/tests/test_einsum.py,sha256=GsmB2gxsAu9NQ3gg3ASWoYaUhFui91uHig-B5CXRqT4,47891
+numpy/core/tests/test_errstate.py,sha256=kNCMfKs1xgXUrIRQM4qB8fEkVbREVE-p-yG2hsuHjd4,2125
+numpy/core/tests/test_extint128.py,sha256=b8vP_hDPltdHoxWBn2vAmOgjJe2NVW_vjnatdCOtxu8,5862
+numpy/core/tests/test_function_base.py,sha256=FjbJ8JMRcbBxllRXRZhxbE6nlfP1HL8I4kfyW8RKr0s,14820
+numpy/core/tests/test_getlimits.py,sha256=m2xfs_MhozzD88pqRoD00GlMbA-biaK0tEMmBW0vt9g,4418
+numpy/core/tests/test_half.py,sha256=7vZngTRJJ45h4XUFws9fpHI_gYKPq9pz_DKUhZf8lEk,24370
+numpy/core/tests/test_indexerrors.py,sha256=iJu4EorQks1MmiwTV-fda-vd4HfCEwv9_Ba_rVea7xw,5263
+numpy/core/tests/test_indexing.py,sha256=Me2D_dpWvqaU_k1Ra1Q4gT2i57-3d2btL6JgVioTqtw,53821
+numpy/core/tests/test_item_selection.py,sha256=8AukBkttHRVkRBujEDDSW0AN1i6FvRDeJO5Cot9teFc,3665
+numpy/core/tests/test_longdouble.py,sha256=0xWqtJdc-MUfxxZutfuI9W9d-hv_LouFb3355QU0UHE,13410
+numpy/core/tests/test_machar.py,sha256=o4LNEPRU2p0fzok8AiO2Y9vIoZUfWQvqMN2_rJqLoKE,1096
+numpy/core/tests/test_mem_overlap.py,sha256=Sc29ERD4HWExeUA43J96-4QBTkZS4dS_RUrb_DJLbwM,29781
+numpy/core/tests/test_memmap.py,sha256=kJauOy8Wr7iakTXmS-RTaOWZAlglrn7aFGEcP-ThHuw,7808
+numpy/core/tests/test_multiarray.py,sha256=y_RsK1SlrwuaxLIlKJCU1o3ruk9SnivzTBqHI6lhHgc,336639
+numpy/core/tests/test_nditer.py,sha256=eLyB7MPlWIHwhEhjCk--26osphAJSbwjc3XjS4PESXo,118489
+numpy/core/tests/test_numeric.py,sha256=f_NR4X4HrIY4lMBPIPnLB1FdqpebsyHplbOaQL5vGzY,135038
+numpy/core/tests/test_numerictypes.py,sha256=c-xwoz-oawJff09G0tri2Q9FJQ0NLkH3vf_zmwGnheg,21400
+numpy/core/tests/test_overrides.py,sha256=G-eHLgc8Gp_Wj5d-oguoGadSqu7p4kziq7qgnkiQOTg,20527
+numpy/core/tests/test_print.py,sha256=I3-R4iNbFjmVdl5xHPb9ezYb4zDfdXNfzVZt3Lz3bqU,6937
+numpy/core/tests/test_protocols.py,sha256=Etu0M6T-xFJjAyXy2EcCH48Tbe5VRnZCySjMy0RhbPY,1212
+numpy/core/tests/test_records.py,sha256=910AOqDvIhCDsrmCQk737UhxDnQU3GSB5a2-w0h9hWM,20782
+numpy/core/tests/test_regression.py,sha256=qO4gCWkcfFbBam5BWVuumjGntBT-Hevih2BH1CU2bo4,92275
+numpy/core/tests/test_scalar_ctors.py,sha256=ilVfUULT72ALjt1WH0B54winaYbWrRy62AewkvugJao,3803
+numpy/core/tests/test_scalar_methods.py,sha256=3uNPtYl73DJBLGQxJJ1df4cyr90A5Sp0pcRtXMVTjac,4166
+numpy/core/tests/test_scalarbuffer.py,sha256=E7nYL8Hnbr3d_9-oxvGtkWte2q6ZeteJhmi0kOQ_u8k,5790
+numpy/core/tests/test_scalarinherit.py,sha256=xea-dgKGvMr-HjM9my-KpMN797sOegNhXni-62kw7m0,2504
+numpy/core/tests/test_scalarmath.py,sha256=dDGy7iZIcKokbyTytjG5N17tF3TQ-sMBEjkFHEZblwY,29768
+numpy/core/tests/test_scalarprint.py,sha256=VmPnnhMyFScjwUjEknjt5oF1YXR43oESZSYDuqbo614,15480
+numpy/core/tests/test_shape_base.py,sha256=fxb8d5kMhn9YazVg1h-prGUAO62FFImam250AP8DS4I,28251
+numpy/core/tests/test_simd.py,sha256=6YdEn72Nx_l0rw_z7ZEUUjOJf3ofsCqtF9aWOsJ4wjI,24568
+numpy/core/tests/test_simd_module.py,sha256=Bpbg_3YKO4Nu4Jm8p_QIlhrz_3tLIO6ketPhJmA_hZU,3855
+numpy/core/tests/test_ufunc.py,sha256=SPPnaYt2H7kG2zXknZu2sTSMmRrHN-UEcyuKlXO_qHg,91879
+numpy/core/tests/test_umath.py,sha256=VmybQuYViPMP7w8yEIUpZsEL1YgtRw7KaWOlcm45NEU,137309
+numpy/core/tests/test_umath_accuracy.py,sha256=_3N9e6662AmFLqIkyvTYFxeGL0HzM4lF4z2R00LnSoM,3103
+numpy/core/tests/test_umath_complex.py,sha256=7DMz_aYMufNED9OkyVHHbZP7akoZO6nR_ySWxPJ9JXs,23701
+numpy/core/tests/test_unicode.py,sha256=c6SB-PZaiNH7HvEZ2xIrfAMPmvuJmcTo79aBBkdCFvY,12915
+numpy/core/umath.py,sha256=IE9whDRUf3FOx3hdo6bGB0X_4OOJn_Wk6ajnbrc542A,2076
+numpy/core/umath_tests.py,sha256=IuFDModusxI6j5Qk-VWYHRZDIE806dzvju0qYlvwmfY,402
+numpy/ctypeslib.py,sha256=VdpIB-ytRoeVZfnt5TaJYn6y_rTc8GTvb9alp9d7B7w,17739
+numpy/ctypeslib.pyi,sha256=twksdb42mpN3Nc4WRJpcnwMqjNnvp_v02cZ9QiLQcI0,154
+numpy/distutils/__config__.py,sha256=IHRa3rupkgR7i9orKgDOiGPeOriQOaDHFF5q7kCETEc,3016
+numpy/distutils/__init__.py,sha256=kuNMyZmAP8MtuKKOGG5pMz5wWcLVzHkU7wW7CTwzNxY,1610
+numpy/distutils/__init__.pyi,sha256=6KiQIH85pUXaIlow3KW06e1_ZJBocVY6lIGghNaW33A,123
+numpy/distutils/__pycache__/__config__.cpython-39.pyc,,
+numpy/distutils/__pycache__/__init__.cpython-39.pyc,,
+numpy/distutils/__pycache__/_shell_utils.cpython-39.pyc,,
+numpy/distutils/__pycache__/ccompiler.cpython-39.pyc,,
+numpy/distutils/__pycache__/ccompiler_opt.cpython-39.pyc,,
+numpy/distutils/__pycache__/conv_template.cpython-39.pyc,,
+numpy/distutils/__pycache__/core.cpython-39.pyc,,
+numpy/distutils/__pycache__/cpuinfo.cpython-39.pyc,,
+numpy/distutils/__pycache__/exec_command.cpython-39.pyc,,
+numpy/distutils/__pycache__/extension.cpython-39.pyc,,
+numpy/distutils/__pycache__/from_template.cpython-39.pyc,,
+numpy/distutils/__pycache__/intelccompiler.cpython-39.pyc,,
+numpy/distutils/__pycache__/lib2def.cpython-39.pyc,,
+numpy/distutils/__pycache__/line_endings.cpython-39.pyc,,
+numpy/distutils/__pycache__/log.cpython-39.pyc,,
+numpy/distutils/__pycache__/mingw32ccompiler.cpython-39.pyc,,
+numpy/distutils/__pycache__/misc_util.cpython-39.pyc,,
+numpy/distutils/__pycache__/msvc9compiler.cpython-39.pyc,,
+numpy/distutils/__pycache__/msvccompiler.cpython-39.pyc,,
+numpy/distutils/__pycache__/npy_pkg_config.cpython-39.pyc,,
+numpy/distutils/__pycache__/numpy_distribution.cpython-39.pyc,,
+numpy/distutils/__pycache__/pathccompiler.cpython-39.pyc,,
+numpy/distutils/__pycache__/setup.cpython-39.pyc,,
+numpy/distutils/__pycache__/system_info.cpython-39.pyc,,
+numpy/distutils/__pycache__/unixccompiler.cpython-39.pyc,,
+numpy/distutils/_shell_utils.py,sha256=9pI0lXlRJxB22TPVBNUhWe7EnE-V6xIhMNQSR8LOw40,2704
+numpy/distutils/ccompiler.py,sha256=_sx0zV6AlYpxqN7Pr_7Wwc4k98a3GM6MFBdDPironCE,27805
+numpy/distutils/ccompiler_opt.py,sha256=aMyFbrZDK-ykCsT8mEN2XgkHYHtmveeGwVTBsbhOlTc,97804
+numpy/distutils/checks/cpu_asimd.c,sha256=sUn-v9fLpUUEtsrAfbGor76uYGhCINzXgkz0v3alZhQ,729
+numpy/distutils/checks/cpu_asimddp.c,sha256=7_HRp5jMJBSz02PcmAaH6m07zAbtcjMgkw7-4vhTZI4,395
+numpy/distutils/checks/cpu_asimdfhm.c,sha256=I7dTWSITAGwxHaLULZkh0nqnf-v9NF2kfQu7Tu90aB4,448
+numpy/distutils/checks/cpu_asimdhp.c,sha256=BD9NPwN4mcUZE_KydEQ0b7GtTkfEljl4u0KbrohLYcU,343
+numpy/distutils/checks/cpu_avx.c,sha256=AchhlKaX-7TJBTdLPxizv0kBQgpDlJfHsgu0vAVpxiw,180
+numpy/distutils/checks/cpu_avx2.c,sha256=ceEOVmmjXG3RvOJ5CFm_Ci3migjjxyXMkGootol5f5I,165
+numpy/distutils/checks/cpu_avx512_clx.c,sha256=6YL7X8fPLx4tdmVf87yEJcE0scrWmN8GKMWbU2H_eI4,232
+numpy/distutils/checks/cpu_avx512_cnl.c,sha256=FQgnUfGPJIxwb_QgggyN_eqDbVIO0Fg5S8yTSOVavBs,336
+numpy/distutils/checks/cpu_avx512_icl.c,sha256=NiAeMDgsiY3xjJ2orMHxrFJSbE-ZCxuq38dtjnQ_Zf0,336
+numpy/distutils/checks/cpu_avx512_knl.c,sha256=9bdrxCQfeL8sNAX8cQ_9lr_JxDU1TSl2J4XUQu9xjP4,292
+numpy/distutils/checks/cpu_avx512_knm.c,sha256=AWsXafv1lP1BI_APmXFYOXk5SyHGYBvjodVcxduOfHA,432
+numpy/distutils/checks/cpu_avx512_skx.c,sha256=drVMoRW8SWhwgcTMiVjMuN34v6ZSZmWe3cf0JGa7shM,281
+numpy/distutils/checks/cpu_avx512cd.c,sha256=ToPmk0tu_6gPdWNcKJYILjtRx4vIc6ShECfNM2-l7bY,167
+numpy/distutils/checks/cpu_avx512f.c,sha256=KewXn3NHK7SGboqTSBqO-64rYDY161pMeGY833MCoaw,165
+numpy/distutils/checks/cpu_f16c.c,sha256=pSq0FnDJYTbx2K9Cs7bJX2vGfEc8q7cvw5lC8rdevP0,260
+numpy/distutils/checks/cpu_fma3.c,sha256=mh3efYJ-hmv6z7b1j9I_WChae1RFMGtXWHgLqQp7_pY,227
+numpy/distutils/checks/cpu_fma4.c,sha256=tbalvI_RCIWy4X-BzRbZ9AVV1eCgm7UMJYbN7NM9vfs,290
+numpy/distutils/checks/cpu_neon.c,sha256=3lc70da2_XbT1hA36YY7vGbapW3dDZlG8xoNXp2rMzY,387
+numpy/distutils/checks/cpu_neon_fp16.c,sha256=XeOsWVVTmFecSl_luw2lNBGKxHaB2TtL7YnyIv8W0OU,262
+numpy/distutils/checks/cpu_neon_vfpv4.c,sha256=oJ1NvRYfF7Yf6S_bZuaUntE0iOnkbmTNNVR_sbE4NV8,512
+numpy/distutils/checks/cpu_popcnt.c,sha256=PuEpVkvM-tAyA8TzERvODpvEqWU0qhxLJLyW-Lj-Zc4,393
+numpy/distutils/checks/cpu_sse.c,sha256=WG79fJMG4JcbZnxVNUGSuGF8tHJ6IUyAVNFZM3eDSDg,147
+numpy/distutils/checks/cpu_sse2.c,sha256=Urd4Xcq_2oXqMxftLWnr7fXfnaPyCHxMb1dLOBxgCU4,156
+numpy/distutils/checks/cpu_sse3.c,sha256=FQCCU27JvQvNPmhlEr6kA_omlT6R6PFSk9Fz4xptyXg,148
+numpy/distutils/checks/cpu_sse41.c,sha256=S3IVKzcRmYp0Gjtc_LTfdAjjg9HjQgP_DDJTLVz6Ii8,131
+numpy/distutils/checks/cpu_sse42.c,sha256=NsXFPtSuGygm-KdkPcJRAncKQz58S5qXpa8SG_urgwU,148
+numpy/distutils/checks/cpu_ssse3.c,sha256=wWm9_w0v8Y4230p83AGXJgiDlAjg3UZ2dVX-T9ebBDs,162
+numpy/distutils/checks/cpu_vsx.c,sha256=gxWpdnkMeoaBCzlU_j56brB38KFo4ItFsjyiyo3YrKk,499
+numpy/distutils/checks/cpu_vsx2.c,sha256=ycKoKXszrZkECYmonzKd7TgflpZyVc1Xq-gtJqyPKxs,276
+numpy/distutils/checks/cpu_vsx3.c,sha256=pNA4w2odwo-mUfSnKnXl5SVY1z2nOxPZZcNC-L2YX1w,263
+numpy/distutils/checks/cpu_xop.c,sha256=sPhOvyT-mdlbf6RlbZvMrslRwHnTFgP-HXLjueS7nwU,246
+numpy/distutils/checks/extra_avx512bw_mask.c,sha256=7IRO24mpcuXRhm3refGWP91sy0e6RmSkmUQCWyxy__0,654
+numpy/distutils/checks/extra_avx512dq_mask.c,sha256=jFtOKEtZl3iTpfbmFNB-u4DQNXXBST2toKCpxFIjEa0,520
+numpy/distutils/checks/extra_avx512f_reduce.c,sha256=loHAibDU3STIihz3VNshKx0_cA2_yxq2aWc5nS6ILnc,1638
+numpy/distutils/checks/test_flags.c,sha256=7rgVefVOKOBaefG_6riau_tT2IqI4MFrbSMGNFnqUBQ,17
+numpy/distutils/command/__init__.py,sha256=DCxnKqTLrauOD3Fc8b7qg9U3gV2k9SADevE_Q3H78ng,1073
+numpy/distutils/command/__pycache__/__init__.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/autodist.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/bdist_rpm.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/build.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/build_clib.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/build_ext.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/build_py.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/build_scripts.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/build_src.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/config.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/config_compiler.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/develop.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/egg_info.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/install.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/install_clib.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/install_data.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/install_headers.cpython-39.pyc,,
+numpy/distutils/command/__pycache__/sdist.cpython-39.pyc,,
+numpy/distutils/command/autodist.py,sha256=i2ip0Zru8_AFx3lNQhlZfj6o_vg-RQ8yu1WNstcIYhE,3866
+numpy/distutils/command/bdist_rpm.py,sha256=9uZfOzdHV0_PRUD8exNNwafc0qUqUjHuTDxQcZXLIbg,731
+numpy/distutils/command/build.py,sha256=48vCxFz9tA0EWAtP9BiFTzpz6l91qXa0z3O3pC_QMis,2627
+numpy/distutils/command/build_clib.py,sha256=tKyaJypY97T4KJ2IAyUKhCU09diq8JaPeEh_JKX_5h8,17587
+numpy/distutils/command/build_ext.py,sha256=Vm6ZMSBPeljNp5AMJxiFEVpqUHbIuvu7djcxGjY9Bpk,30893
+numpy/distutils/command/build_py.py,sha256=xBHZCtx91GqucanjIBETPeXmR-gyUKPDyr1iMx1ARWE,1175
+numpy/distutils/command/build_scripts.py,sha256=AEQLNmO2v5N-GXl4lwd8v_nHlrauBx9Y-UudDcdCs_A,1714
+numpy/distutils/command/build_src.py,sha256=TbN3yNLm_FafCLv2Dx0RHkvYzaPsF1UwPINe1TUepgI,31953
+numpy/distutils/command/config.py,sha256=zczmFmKmYMnv1DMlJzUGtFTOascA1ZLh6Sr-EEcXSVk,21144
+numpy/distutils/command/config_compiler.py,sha256=I-xAL3JxaGFfpR4lg7g0tDdA_t7zCt-D4JtOACCP_Ak,4495
+numpy/distutils/command/develop.py,sha256=5ro-Sudt8l58JpKvH9FauH6vIfYRv2ohHLz-9eHytbc,590
+numpy/distutils/command/egg_info.py,sha256=n6trbjRfD1qWc_hRtMFkOJsg82BCiLvdl-NeXyuceGc,946
+numpy/distutils/command/install.py,sha256=s_0Uf39tFoRLUBlkrRK4YlROZsLdkI-IsuiFFaiS3ls,3157
+numpy/distutils/command/install_clib.py,sha256=q3yrfJY9EBaxOIYUQoiu2-juNKLKAKKfXC0nrd4t6z0,1439
+numpy/distutils/command/install_data.py,sha256=r8EVbIaXyN3aOmRugT3kp_F4Z03PsVX2l_x4RjTOWU4,872
+numpy/distutils/command/install_headers.py,sha256=g5Ag2H3j3dz-qSwWegxiZSAnvAf0thYYFwfPVHf9rxc,944
+numpy/distutils/command/sdist.py,sha256=XQM39b-MMO08bfE3SJrrtDWwX0XVnzCZqfAoVuuaFuE,760
+numpy/distutils/conv_template.py,sha256=q60i2Jf0PlQGHmjr7pu5zwBUnoYiLhtfcdgV94uLSaw,9888
+numpy/distutils/core.py,sha256=baf9SXdCVV8fA0lhLpOV4yEEWQP4ZwMTeeWoXHMg9LE,8374
+numpy/distutils/cpuinfo.py,sha256=frzEtCIEsSbQzGmNUXdWctiFqRcNFeLurzbvyCh8thY,23340
+numpy/distutils/exec_command.py,sha256=xMR7Dou5VZp2cP23xNd2TlXqexppXzBUd1wLMEAD2is,10668
+numpy/distutils/extension.py,sha256=E6m-GBUisj8kWbZlKlQhe6UUQvZOQ6JBGS5eqaSU7lY,3463
+numpy/distutils/fcompiler/__init__.py,sha256=vxt_-VqmNldCccva6d5WNVU_ztPIHipvny0NaYT8CGc,41110
+numpy/distutils/fcompiler/__pycache__/__init__.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/absoft.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/compaq.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/environment.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/fujitsu.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/g95.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/gnu.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/hpux.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/ibm.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/intel.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/lahey.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/mips.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/nag.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/none.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/nv.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/pathf95.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/pg.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/sun.cpython-39.pyc,,
+numpy/distutils/fcompiler/__pycache__/vast.cpython-39.pyc,,
+numpy/distutils/fcompiler/absoft.py,sha256=4UKxvpWQIphSdi6vJb3qILML_zyM3K_m7ddhAMS5dBI,5655
+numpy/distutils/fcompiler/compaq.py,sha256=nBN5tnyvvVDtiybSbSlvaPwo5LNZ9uXxs72plYU09No,4031
+numpy/distutils/fcompiler/environment.py,sha256=PVS1al3wahDNnneNVSl1sQhMPfz2dUXaIDVJfy0wZBU,3168
+numpy/distutils/fcompiler/fujitsu.py,sha256=g4dTLDFfLRAzhYayIwyHGBw1Y36DKtPOCYfA823ldNA,1379
+numpy/distutils/fcompiler/g95.py,sha256=1TJe4IynWYqqYBy8gJ-nz8WQ_TaSbv8k2UzUIY5Erqc,1372
+numpy/distutils/fcompiler/gnu.py,sha256=k0PYSVpEbgjFszkaMTcD0HvQim_isx8KK7gQYW1_GDI,20775
+numpy/distutils/fcompiler/hpux.py,sha256=SLbDOPYgiixqE32GgUrAJjpDLFy9g7E01vGNZCGv6Pc,1394
+numpy/distutils/fcompiler/ibm.py,sha256=jL9fOpUU9g1Qx3wFqv34ow6LMq8TOSZ3EAwUb1bXs_c,3638
+numpy/distutils/fcompiler/intel.py,sha256=3nBmdhH8pRMyNZfkMU0MaJGkRxVQg3wh8AOduXCjRRs,7029
+numpy/distutils/fcompiler/lahey.py,sha256=EV3Zhwq-iowWAu4BFBPv_UGJ-IB-qxlxmi6WU1qHDOs,1372
+numpy/distutils/fcompiler/mips.py,sha256=mlUNgGrRSLnNhtxQXWVfC9l4_OP2GMvOkgbZQwBon0A,1768
+numpy/distutils/fcompiler/nag.py,sha256=3ViQnBrZBhgm-t-jvjZ_Hl_fq9s2O5FBMNwW6wOmU2Q,2624
+numpy/distutils/fcompiler/none.py,sha256=auMK2ou1WtJ20LeMbwCZJ3XofpT9A0YYbMVd-62Mi_E,786
+numpy/distutils/fcompiler/nv.py,sha256=ml2xco_01pGH9x23Qv-3yalFzTk-GK45BVJoDMlGod4,1627
+numpy/distutils/fcompiler/pathf95.py,sha256=ipbaZIO8sqPJ1lUppOurnboiTwRzIasWNAJvKmktvv4,1094
+numpy/distutils/fcompiler/pg.py,sha256=cVcSFM9oR0KmO5AIb4Odw9OGslW6zvDGP88n-uEwxvQ,3696
+numpy/distutils/fcompiler/sun.py,sha256=JMdFfKldTYlfW1DxV7nR09k5PZypKLWpP7wmQzmlnH0,1628
+numpy/distutils/fcompiler/vast.py,sha256=JUGP68JGOUOBS9WbXftE-qCVUD13fpLyPnhpHfTL5y0,1719
+numpy/distutils/from_template.py,sha256=lL0BhwJHz7OrMwocJnnUElgzv8vVkZdr6NupI1ZnsLw,8224
+numpy/distutils/intelccompiler.py,sha256=kVXrdCVY7YA6HdYI89De3Fy5lCjAwDpy2mrbpK7Lc10,4336
+numpy/distutils/lib2def.py,sha256=HQ7i5FUtBcFGNlSlN20lgVtiBAHQbGXxmYdvkaJTjLI,3760
+numpy/distutils/line_endings.py,sha256=hlI71r840mhfu8lmzdHPVZ4NFm-kJDDUMV3lETblVTY,2109
+numpy/distutils/log.py,sha256=9tqE2Tq55mugFj_pn-RwV1xFoejmk0yWvVQHBL1e-Gc,2652
+numpy/distutils/mingw/gfortran_vs2003_hack.c,sha256=FDTA53KYTIhil9ytvZlocOqghQVp9LacLHn1IurV0wI,83
+numpy/distutils/mingw32ccompiler.py,sha256=Pt2fhKRw6axhlV2ahCS3Ep0vj-LfCdnCOEfvLRsCMFM,26073
+numpy/distutils/misc_util.py,sha256=RYrU7Fhutl-ClKdWkgllGzXPL1Ky7hsjbrgkDD5elJ0,87912
+numpy/distutils/msvc9compiler.py,sha256=bCtCVJmGrBHPm9sOoxa3oSrdrEVCNQFEM5O5hdqX8Hc,2255
+numpy/distutils/msvccompiler.py,sha256=sGGkjB-iSQFEfsMfQY8ZJfPKs6vm2DY9Y_OKi0Fk__0,1986
+numpy/distutils/npy_pkg_config.py,sha256=4CMG6sN7HAFSmw2ljPAAN5f04wdnZECkFXZcKoX06f0,13409
+numpy/distutils/numpy_distribution.py,sha256=nrdp8rlyjEBBV1tzzi5cE-aYeXB5U3X8T5-G0akXSoY,651
+numpy/distutils/pathccompiler.py,sha256=a5CYDXilCaIC85v0fVh-wrb0fClv0A7mPS87aF1inUc,734
+numpy/distutils/setup.py,sha256=zd5_kD7uTEOTgC8Fe93g9A_5AOBEySWwr-2OxHsBBEc,651
+numpy/distutils/system_info.py,sha256=4V-OxZ6-rlUBGTuUPn0_sFiQ4MHsuNCdCxXMDCOW6_U,111097
+numpy/distutils/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/distutils/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_build_ext.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_ccompiler_opt.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_ccompiler_opt_conf.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_exec_command.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_fcompiler.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_fcompiler_gnu.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_fcompiler_intel.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_fcompiler_nagfor.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_from_template.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_mingw32ccompiler.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_misc_util.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_npy_pkg_config.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_shell_utils.cpython-39.pyc,,
+numpy/distutils/tests/__pycache__/test_system_info.cpython-39.pyc,,
+numpy/distutils/tests/test_build_ext.py,sha256=te4h-jzABgSF_efL2LC-Hwc3hlq8lfqg5JEeHGQgV3A,2736
+numpy/distutils/tests/test_ccompiler_opt.py,sha256=XSKyD1o3GsQOO0MiVBHSrIOBwTk1Z1f9_3BfdpZWlSA,28676
+numpy/distutils/tests/test_ccompiler_opt_conf.py,sha256=LmFqpGwqGFgUwLQdV5xJQhs_xB9gnL7_P-7oOOUqa78,6521
+numpy/distutils/tests/test_exec_command.py,sha256=Ltd4T3A_t3Oo_QSYjOkWKqPj-LttXEumEVKhLxVfZEU,7515
+numpy/distutils/tests/test_fcompiler.py,sha256=SS5HOLIg0eqkmZTRKeWq9_ahW2tmV9c9piwYfzcBPmc,1320
+numpy/distutils/tests/test_fcompiler_gnu.py,sha256=RlRHZbyazgKGY17NmdYSF3ehO0M0xXN4UkbsJzJz4i8,2191
+numpy/distutils/tests/test_fcompiler_intel.py,sha256=4cppjLugoa8P4bjzYdiPxmyCywmP9plXOkfsklhnYsQ,1088
+numpy/distutils/tests/test_fcompiler_nagfor.py,sha256=ntyr8f-67dNI0OF_l6-aeTwu9wW-vnxpheqrc4cXAUI,1124
+numpy/distutils/tests/test_from_template.py,sha256=ZzUSEPyZIG4Zak3-TFqmRGXHMp58aKTuLKb0t-5XpDg,1147
+numpy/distutils/tests/test_mingw32ccompiler.py,sha256=7X8V4hLMtsNj1pYoLkSSla04gJu66e87E_k-6ce3PrA,1651
+numpy/distutils/tests/test_misc_util.py,sha256=YKK2WrJqVJ5o71mWL5oP0l-EVQmqKlf3XU8y7co0KYc,3300
+numpy/distutils/tests/test_npy_pkg_config.py,sha256=1pQh-mApHjj0y9Ba2tqns79U8dsfDpJ9zcPdsa2qbps,2641
+numpy/distutils/tests/test_shell_utils.py,sha256=okNSfjFSAvY3XyBsyZrKXAtV9RBmb7vX9o4ZLJc28Ds,2030
+numpy/distutils/tests/test_system_info.py,sha256=ALNf8Vqw6d9Gv6ELtWmQT9Byy5LWv4ZIPMOVXQfIqsk,11065
+numpy/distutils/unixccompiler.py,sha256=9ug-F8LGBrrwuC8U00JhjokgH7L0BPvLhFJLg6REQ1I,5517
+numpy/doc/__init__.py,sha256=llSbqjSXybPuXqt6WJFZhgYnscgYl4m1tUBy_LhfCE0,534
+numpy/doc/__pycache__/__init__.cpython-39.pyc,,
+numpy/doc/__pycache__/constants.cpython-39.pyc,,
+numpy/doc/__pycache__/ufuncs.cpython-39.pyc,,
+numpy/doc/constants.py,sha256=OtjYHSs9p_DxLDqhlbauLMt-WWVrnewaHlUJCi3Qw_Y,9592
+numpy/doc/ufuncs.py,sha256=jL-idm49Qd8xNns12ZPp533jorDuDnUN2I96hbmFZoo,5497
+numpy/dual.py,sha256=RgoFIabqn8Hu9lSRakjO1plfDdYBJQq_8Gn__rE8TqQ,2297
+numpy/emath.pyi,sha256=-9BhMfuGE3vYfdpqbHDXyQsFeUzydkfHbRWxSFJhLA8,161
+numpy/f2py/__init__.py,sha256=eBq1wR_5aSMEhbF4COOM2uBW70GBP_WLBlgyFZBVj1M,4377
+numpy/f2py/__init__.pyi,sha256=c7BkZSruptvVxdLmt_6FgxgMSVS4A8FgaQnx9V4dYdw,102
+numpy/f2py/__main__.py,sha256=XSvcMI54qWQiicJ51nRxK8L8PGzuUy3c2NGTVg1tzyk,89
+numpy/f2py/__pycache__/__init__.cpython-39.pyc,,
+numpy/f2py/__pycache__/__main__.cpython-39.pyc,,
+numpy/f2py/__pycache__/__version__.cpython-39.pyc,,
+numpy/f2py/__pycache__/auxfuncs.cpython-39.pyc,,
+numpy/f2py/__pycache__/capi_maps.cpython-39.pyc,,
+numpy/f2py/__pycache__/cb_rules.cpython-39.pyc,,
+numpy/f2py/__pycache__/cfuncs.cpython-39.pyc,,
+numpy/f2py/__pycache__/common_rules.cpython-39.pyc,,
+numpy/f2py/__pycache__/crackfortran.cpython-39.pyc,,
+numpy/f2py/__pycache__/diagnose.cpython-39.pyc,,
+numpy/f2py/__pycache__/f2py2e.cpython-39.pyc,,
+numpy/f2py/__pycache__/f2py_testing.cpython-39.pyc,,
+numpy/f2py/__pycache__/f90mod_rules.cpython-39.pyc,,
+numpy/f2py/__pycache__/func2subr.cpython-39.pyc,,
+numpy/f2py/__pycache__/rules.cpython-39.pyc,,
+numpy/f2py/__pycache__/setup.cpython-39.pyc,,
+numpy/f2py/__pycache__/use_rules.cpython-39.pyc,,
+numpy/f2py/__version__.py,sha256=N_m8jjlfteJqqS8jfRZQaJMGbiuulC4RyDX1BCqmDy8,196
+numpy/f2py/auxfuncs.py,sha256=d8xZkZ2Jom_FX4ALxQO4v2Uqsfi62rZEiqSH30AGpyA,22701
+numpy/f2py/capi_maps.py,sha256=QmqD140JWMl62KQb3XxDht51F14nwWx3NaWNp4jXPQk,32297
+numpy/f2py/cb_rules.py,sha256=0eIg-6lB4NkTvarfxuanGPoWTaRKNc4ascvf3wWt3WM,24673
+numpy/f2py/cfuncs.py,sha256=RuvcV95bSsw0RdKJOjrWDPYtOqiIdLBaohzIfp8aKqc,47984
+numpy/f2py/common_rules.py,sha256=W7rKmlCBJgcgs9U14Yyz79k4U5VgNxgOQV-WN4VrAQ0,5114
+numpy/f2py/crackfortran.py,sha256=xKWyjNI5g9XTgoU9qaZmEdrXtGXLQgydDAOp9Av089Q,134117
+numpy/f2py/diagnose.py,sha256=LmGu6iZKr9WHfMZFIIEobZvRJd9Ktdqx0nYekWk4N7g,5384
+numpy/f2py/f2py2e.py,sha256=PGa67qkKSPaLwuPE1sgpnt7uGmcxHrwe-pn8TWHttnU,25143
+numpy/f2py/f2py_testing.py,sha256=vybOK-G_b0KYFNNZdhOCUf5pZExEdWfcIueIKODu024,1503
+numpy/f2py/f90mod_rules.py,sha256=umkXYf5Y6TrJ77DIZX0L0xemyFQ2sfe7M63f71A94hs,10017
+numpy/f2py/func2subr.py,sha256=-e2VG2t0YDEOO_jIhLZRFLg5uoIoPGtcjir-4BzdNCs,9655
+numpy/f2py/rules.py,sha256=e4y5c19Gk2BHPni8yVCKkEfSZtuS9GyWPv0RsJSG-6g,60236
+numpy/f2py/setup.py,sha256=Qoa3e1-WsSeayGHlVqZ9x5eIEOBeMAOtqTP331STQAk,2533
+numpy/f2py/src/fortranobject.c,sha256=adBCuP5jDLobVYK4Xb3Byq9SXABQqy0V2fKPtMw9jIs,37464
+numpy/f2py/src/fortranobject.h,sha256=kwkaaaO0nsg7I-I0HpVAlOy-eiuvhKbhSZrEUWJvBaU,4656
+numpy/f2py/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/f2py/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_array_from_pyobj.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_assumed_shape.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_block_docstring.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_callback.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_common.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_compile_function.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_crackfortran.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_kind.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_mixed.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_module_doc.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_parameter.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_quoted_character.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_return_character.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_return_complex.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_return_integer.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_return_logical.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_return_real.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_semicolon_split.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_size.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/test_string.cpython-39.pyc,,
+numpy/f2py/tests/__pycache__/util.cpython-39.pyc,,
+numpy/f2py/tests/src/array_from_pyobj/wrapmodule.c,sha256=56WWwGvAipTqHyshtz8jLLZ7gNHpzC5h_jCyIciFGLc,7511
+numpy/f2py/tests/src/assumed_shape/.f2py_f2cmap,sha256=zfuOShmuotzcLIQDnVFaARwvM66iLrOYzpquIGDbiKU,30
+numpy/f2py/tests/src/assumed_shape/foo_free.f90,sha256=fqbSr7VlKfVrBulFgQtQA9fQf0mQvVbLi94e4FTST3k,494
+numpy/f2py/tests/src/assumed_shape/foo_mod.f90,sha256=9pbi88-uSNP5IwS49Kim982jDAuopo3tpEhg2SOU7no,540
+numpy/f2py/tests/src/assumed_shape/foo_use.f90,sha256=9Cl1sdrihB8cCSsjoQGmOO8VRv9ni8Fjr0Aku1UdEWM,288
+numpy/f2py/tests/src/assumed_shape/precision.f90,sha256=3L_F7n5ju9F0nxw95uBUaPeuiDOw6uHvB580eIj7bqI,134
+numpy/f2py/tests/src/common/block.f,sha256=tcGKa42S-6bfA6fybpM0Su_xjysEVustkEJoF51o_pE,235
+numpy/f2py/tests/src/kind/foo.f90,sha256=6_zq3OAWsuNJ5ftGTQAEynkHy-MnuLgBXmMIgbvL7yU,367
+numpy/f2py/tests/src/mixed/foo.f,sha256=Zgn0xDhhzfas3HrzgVSxIL1lGEF2mFRVohrvXN1thU0,90
+numpy/f2py/tests/src/mixed/foo_fixed.f90,sha256=6eEEYCH71gPp6lZ6e2afLrfS6F_fdP7GZDbgGJJ_6ns,187
+numpy/f2py/tests/src/mixed/foo_free.f90,sha256=UC6iVRcm0-aVXAILE5jZhivoGQbKU-prqv59HTbxUJA,147
+numpy/f2py/tests/src/module_data/mod.mod,sha256=EkjrU7NTZrOH68yKrz6C_eyJMSFSxGgC2yMQT9Zscek,412
+numpy/f2py/tests/src/module_data/module_data_docstring.f90,sha256=-asnMH7vZMwVIeMU2YiLWgYCUUUxZgPTpbAomgWByHs,236
+numpy/f2py/tests/src/parameter/constant_both.f90,sha256=L0rG6-ClvHx7Qsch46BUXRi_oIEL0uw5dpRHdOUQuv0,1996
+numpy/f2py/tests/src/parameter/constant_compound.f90,sha256=lAT76HcXGMgr1NfKof-RIX3W2P_ik1PPqkRdJ6EyBmM,484
+numpy/f2py/tests/src/parameter/constant_integer.f90,sha256=42jROArrG7vIag9wFa_Rr5DBnnNvGsrEUgpPU14vfIo,634
+numpy/f2py/tests/src/parameter/constant_non_compound.f90,sha256=u9MRf894Cw0MVlSOUbMSnFSHP4Icz7RBO21QfMkIl-Q,632
+numpy/f2py/tests/src/parameter/constant_real.f90,sha256=QoPgKiHWrwI7w5ctYZugXWzaQsqSfGMO7Jskbg4CLTc,633
+numpy/f2py/tests/src/regression/inout.f90,sha256=TlMxJjhjjiuLI--Tg2LshLnbfZpiKz37EpR_tPKKSx8,286
+numpy/f2py/tests/src/size/foo.f90,sha256=nK_767f1TtqVr-dMalNkXmcKbSbLCiabhRkxSDCzLz0,859
+numpy/f2py/tests/src/string/char.f90,sha256=X_soOEV8cKsVZefi3iLT7ilHljjvJJ_i9VEHWOt0T9Y,647
+numpy/f2py/tests/test_array_from_pyobj.py,sha256=3rASd81apCvTWbWR0yA6OVW7ZXjK1Qi7l2vDFb5OUC4,22556
+numpy/f2py/tests/test_assumed_shape.py,sha256=TDLfEzJc7tlfiqFzmonD8LO85PXySgJ4JE_5IZTzinA,1637
+numpy/f2py/tests/test_block_docstring.py,sha256=AFgfCimjB0gcmqfyHhTmfRVCrMZunkIueoZGrV9SbaA,650
+numpy/f2py/tests/test_callback.py,sha256=MIish0IuwFNn-m0-a8VQkEUld5pSXl03eG0JyAf1GX0,7109
+numpy/f2py/tests/test_common.py,sha256=tRwTdz6aQ0RYREFC-T-SfEyq25wWYo5pknVAqvvvBjM,827
+numpy/f2py/tests/test_compile_function.py,sha256=d2zOi1oPKwqSMBILFSUuJeIX3BY6uAOBZnvYw5h3K54,4434
+numpy/f2py/tests/test_crackfortran.py,sha256=EzSfkWzFM7Kf6fNXZYuplp83KtRegEbP0umoHaPOmQY,2885
+numpy/f2py/tests/test_kind.py,sha256=eH_sM5X5wIwe3T9yVMH6DH8I4spsgRaeIork_FJG-8Q,1044
+numpy/f2py/tests/test_mixed.py,sha256=faYM1laPKwStbz-RY-6b9LCuj2kFojTPIR0wxsosXoI,946
+numpy/f2py/tests/test_module_doc.py,sha256=Qz_TonbInzgdY8KsnC2Y8mxmiqLWMruZKDPa0FPMbrE,980
+numpy/f2py/tests/test_parameter.py,sha256=S1K9K9Uj5dWjmWF8euBUMJdGilIqn1nNH2FftcS1INU,4026
+numpy/f2py/tests/test_quoted_character.py,sha256=81CR1ZIyKygz7noFJMcgaLdg18nY8zcFfrSN2L_U9xg,959
+numpy/f2py/tests/test_regression.py,sha256=AbSCx5JfsiM2VeRRmVk1G3AbHPOS7FIqhCYBlSVquSY,1690
+numpy/f2py/tests/test_return_character.py,sha256=bpuHEjBj53YpvsI_aLQOcSVdoGAEtgtmAK8kbHKdcgc,4064
+numpy/f2py/tests/test_return_complex.py,sha256=jYcoM3pZj0opGXXF69EsGQ6HD5SPaRhBeGx3RhnJx8c,4778
+numpy/f2py/tests/test_return_integer.py,sha256=MpdNZLxeQwER4M4w5utHYe08gDzrjAWOq_z5wRO8hP8,4751
+numpy/f2py/tests/test_return_logical.py,sha256=uP9rWNyA3UARKwaQ6Fsc8grh72G5xnp9XXFSWLdPZQ8,5028
+numpy/f2py/tests/test_return_real.py,sha256=05OwUsgmI_G_pr197xUXgIgTNVOHygtY2kPqRiexeSY,5605
+numpy/f2py/tests/test_semicolon_split.py,sha256=Ap6S5tGL6R8I2i9iUlVxElW4IMNoz0LxIHK1hLIYZhQ,1577
+numpy/f2py/tests/test_size.py,sha256=ukbP0NlzqpfD6M_K58WK6IERSXc_6nHpyUqbYfEbk8M,1335
+numpy/f2py/tests/test_string.py,sha256=w2GiZmdwNAaWOBhak9IuUnnVktMhUq_Y0ajI0SX9YNY,632
+numpy/f2py/tests/util.py,sha256=QkIepB1CsYTTHl-F9Quvwg2uV5gBmpuGMn-VOVrJLvw,9947
+numpy/f2py/use_rules.py,sha256=ROzvjl0-GUOkT3kJS5KkYq8PsFxGjebA6uPq9-CyZEQ,3700
+numpy/fft/__init__.py,sha256=bxBM1d7FfUlcIr0dF-zJ_UjXDNzc0FFnopv6WdwcQvg,8287
+numpy/fft/__init__.pyi,sha256=ETk_OFyBtOJDyQ7ImyZOnm_dXUdE89wSkyxxbLU0Sq0,249
+numpy/fft/__pycache__/__init__.cpython-39.pyc,,
+numpy/fft/__pycache__/_pocketfft.cpython-39.pyc,,
+numpy/fft/__pycache__/helper.cpython-39.pyc,,
+numpy/fft/__pycache__/setup.cpython-39.pyc,,
+numpy/fft/_pocketfft.py,sha256=2AvZn4Oga8NNVxxu5Kjq692QElycysShG3jqhbJvHWY,53572
+numpy/fft/_pocketfft_internal.cp39-win_amd64.pyd,sha256=lLwdFpNN_JNKDmUaIuhrlwsPzH-kjg2WQJXmTp-47mc,112640
+numpy/fft/helper.py,sha256=divqfKoOb0p-Zojqokhj3fQ5HzgWTigxDxZIQnN_TUQ,6375
+numpy/fft/setup.py,sha256=-aF3b5s_eL6Jl0rS_jMFtFPzbYyT55FQE2SgblAawf0,750
+numpy/fft/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/fft/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/fft/tests/__pycache__/test_helper.cpython-39.pyc,,
+numpy/fft/tests/__pycache__/test_pocketfft.cpython-39.pyc,,
+numpy/fft/tests/test_helper.py,sha256=iopdl7-SHA5E1Ex13rYdceskgoDI5T8_Kg12LfqK1HA,6315
+numpy/fft/tests/test_pocketfft.py,sha256=GraHId7HW81sK62wFoF2y4nt2bL6MqkPjkG12OPmgNo,13135
+numpy/lib/__init__.py,sha256=D_APB98cfipadeVf9KXXCg4MRYwNl_JrjbrJ_Fityhc,1840
+numpy/lib/__init__.pyi,sha256=0n-Lho5EqioLc_YfLxyHdNgWbBmaj7607fH-w8w8SHY,2735
+numpy/lib/__pycache__/__init__.cpython-39.pyc,,
+numpy/lib/__pycache__/_datasource.cpython-39.pyc,,
+numpy/lib/__pycache__/_iotools.cpython-39.pyc,,
+numpy/lib/__pycache__/_version.cpython-39.pyc,,
+numpy/lib/__pycache__/arraypad.cpython-39.pyc,,
+numpy/lib/__pycache__/arraysetops.cpython-39.pyc,,
+numpy/lib/__pycache__/arrayterator.cpython-39.pyc,,
+numpy/lib/__pycache__/format.cpython-39.pyc,,
+numpy/lib/__pycache__/function_base.cpython-39.pyc,,
+numpy/lib/__pycache__/histograms.cpython-39.pyc,,
+numpy/lib/__pycache__/index_tricks.cpython-39.pyc,,
+numpy/lib/__pycache__/mixins.cpython-39.pyc,,
+numpy/lib/__pycache__/nanfunctions.cpython-39.pyc,,
+numpy/lib/__pycache__/npyio.cpython-39.pyc,,
+numpy/lib/__pycache__/polynomial.cpython-39.pyc,,
+numpy/lib/__pycache__/recfunctions.cpython-39.pyc,,
+numpy/lib/__pycache__/scimath.cpython-39.pyc,,
+numpy/lib/__pycache__/setup.cpython-39.pyc,,
+numpy/lib/__pycache__/shape_base.cpython-39.pyc,,
+numpy/lib/__pycache__/stride_tricks.cpython-39.pyc,,
+numpy/lib/__pycache__/twodim_base.cpython-39.pyc,,
+numpy/lib/__pycache__/type_check.cpython-39.pyc,,
+numpy/lib/__pycache__/ufunclike.cpython-39.pyc,,
+numpy/lib/__pycache__/user_array.cpython-39.pyc,,
+numpy/lib/__pycache__/utils.cpython-39.pyc,,
+numpy/lib/_datasource.py,sha256=cfOLMUd6-hFI7HYrm8DJHJSGOBZZ49kEWWXB9aagPr4,23337
+numpy/lib/_iotools.py,sha256=PYVfEUIITyUmIvWS8-0CSLegJjKgDysKwYmro1yVrZ8,31834
+numpy/lib/_version.py,sha256=syCq5PJX3QCmhjIR4nO1HG2YWPTarArAR-7m8dv93gk,5010
+numpy/lib/arraypad.py,sha256=V4iW49CT3KyPHdVK-4Q2kjJqgEb-N35LusA6G-Q2LKU,32102
+numpy/lib/arraysetops.py,sha256=_mkMzedSHws9E5Dnw0s6fUyaQAvFeRqbuQuw4XsNdII,26111
+numpy/lib/arrayterator.py,sha256=29pO5S0ciEZwt1402Q0-5cRbyKspV4tlPX1-m_D_Hgc,7282
+numpy/lib/format.py,sha256=sSf6H4mcz-SI7cMw31VYJwIwapFCLWacCObkccP3pYw,32192
+numpy/lib/function_base.py,sha256=oa092RcFcRJp7JN1jP9eLOzTLbzOYEsW908IAUW9FPc,163639
+numpy/lib/histograms.py,sha256=sJNjLvJLQCmPTIlwMsrtOmFK2SxxyQn6-9gmBBsQa14,41261
+numpy/lib/index_tricks.py,sha256=kPia5ya0_USggzPtyvPNFwGmz1-WNk4Gtjrf3XmDXbQ,31655
+numpy/lib/mixins.py,sha256=j_Hfrfp6d6lJAVFlM9y2lu6HHsK_yDInyU74SJWsZDQ,7228
+numpy/lib/nanfunctions.py,sha256=j4ziL7zNzjW4YMOadZxaa6kRcauErJCOBGZhZLbbwq8,60599
+numpy/lib/npyio.py,sha256=AeeyiEWUX1QdkMi1HuwMzS2NB221hLQXeCiK_zjIg2M,91899
+numpy/lib/polynomial.py,sha256=uDsiJVN8lrKVyZcVfqAMTudO7otOMCoLd9G3tHKq6NE,45253
+numpy/lib/recfunctions.py,sha256=G_GYahtsPjRK7uknYmXMpm1p96eHPzguzWBVtldi_uw,58119
+numpy/lib/scimath.py,sha256=JSMIr5maF4dBwvCHM6MOHa7kgOSXtwxb1QxEV09qs6A,15484
+numpy/lib/setup.py,sha256=1s3corE4egZnDZ6I8au_mx7muRPgb3ZxL4Ko2SHt_2Q,417
+numpy/lib/shape_base.py,sha256=7p8SSRXNk5BdcwuEwINFtq60mYQY6vFfMvTO8Cubvro,39627
+numpy/lib/stride_tricks.py,sha256=-hzSjUTw_0VXfzdHZ3afGQlP6UP3oHBdX0VcGE0PMgg,18389
+numpy/lib/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/lib/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test__datasource.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test__iotools.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test__version.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_arraypad.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_arraysetops.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_arrayterator.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_financial_expired.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_format.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_function_base.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_histograms.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_index_tricks.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_io.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_mixins.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_nanfunctions.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_packbits.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_polynomial.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_recfunctions.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_shape_base.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_stride_tricks.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_twodim_base.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_type_check.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_ufunclike.cpython-39.pyc,,
+numpy/lib/tests/__pycache__/test_utils.cpython-39.pyc,,
+numpy/lib/tests/data/py2-objarr.npy,sha256=F4cyUC-_TB9QSFLAo2c7c44rC6NUYIgrfGx9PqWPSKk,258
+numpy/lib/tests/data/py2-objarr.npz,sha256=xo13HBT0FbFZ2qvZz0LWGDb3SuQASSaXh7rKfVcJjx4,366
+numpy/lib/tests/data/py3-objarr.npy,sha256=pTTVh8ezp-lwAK3fkgvdKU8Arp5NMKznVD-M6Ex_uA0,341
+numpy/lib/tests/data/py3-objarr.npz,sha256=qQR0gS57e9ta16d_vCQjaaKM74gPdlwCPkp55P-qrdw,449
+numpy/lib/tests/data/python3.npy,sha256=X0ad3hAaLGXig9LtSHAo-BgOvLlFfPYMnZuVIxRmj-0,96
+numpy/lib/tests/data/win64python2.npy,sha256=agOcgHVYFJrV-nrRJDbGnUnF4ZTPYXuSeF-Mtg7GMpc,96
+numpy/lib/tests/test__datasource.py,sha256=OYm6qsPy7Q8yXV_5GfSMMNQKon4izf_T9ULaqjHLJA4,10837
+numpy/lib/tests/test__iotools.py,sha256=q44VFSi9VzWaf_dJ-MGBtYA7z7TFR0j0AF-rbzhLXoo,14096
+numpy/lib/tests/test__version.py,sha256=WwCOmobk2UN6Hlp93bXsd7RR1UmjJlE4r9ol8d87ctg,2053
+numpy/lib/tests/test_arraypad.py,sha256=ZoqM25xb5iI_K6ampX5cov2zFUwQZ8i0Xu3gY_ncdk0,55647
+numpy/lib/tests/test_arraysetops.py,sha256=ovgWXCWzaKvC-OXtWJx8MrSsdQsLTj3NjqLbxhhHEv0,25173
+numpy/lib/tests/test_arrayterator.py,sha256=IRVmzxbr9idboJjOHKuX_8NQhMAKs7pD1xWqmU3ZERw,1337
+numpy/lib/tests/test_financial_expired.py,sha256=JfDHAoEDLPcKzcpzRsj8pijDSaFmQRWM6BiOjL4QFTs,371
+numpy/lib/tests/test_format.py,sha256=E5ISt5uKyqXCwLD7UZK1TM4SagXAdxxHav7yKz6TIls,39223
+numpy/lib/tests/test_function_base.py,sha256=N78mv4u7xUGsRgR6hBQ0zoZNFxSWOj3cwUoFwIkqJqc,136484
+numpy/lib/tests/test_histograms.py,sha256=_uKM8dtMWCwGtIgIwog3s3jyPb8w804TWqy9iOkYeSI,34510
+numpy/lib/tests/test_index_tricks.py,sha256=eqVGE3ML61U9zOepbPF2X24qVDCaOr2eWnR5p5CzFcw,19832
+numpy/lib/tests/test_io.py,sha256=ZEYwCEDx8SEa_EPhHjCRLlNsa-ONI1Cis_opkGs7V3Y,105599
+numpy/lib/tests/test_mixins.py,sha256=nIec_DZIDx7ONnlpq_Y2TLkIULAPvQ7LPqtMwEHuV4U,7246
+numpy/lib/tests/test_nanfunctions.py,sha256=d26Ynihtb2BIZ1N-qfBagm8lkba0hR-m3g2GtngbTRE,39066
+numpy/lib/tests/test_packbits.py,sha256=XpFIaL8mOWfzD3WQaxd6WrDFWh4Mc51EPXIOqxt3wS0,17922
+numpy/lib/tests/test_polynomial.py,sha256=fxIQBimaH0ZYXcWJYPBBtpWDpYzstABF_BBROu-vCfc,10995
+numpy/lib/tests/test_recfunctions.py,sha256=f9J49n_8ot0zG0Bw4XXFx3l1XN2VeAu9ROgn0dV4GLY,42134
+numpy/lib/tests/test_regression.py,sha256=NXKpFka0DPE7z0-DID-FGh0ITFXi8nEj6Pg_-uBcDIg,8504
+numpy/lib/tests/test_shape_base.py,sha256=kC4k86CdiwUoqBs_KjAc_JekFJLVtlbanlPrXXXpWRU,25020
+numpy/lib/tests/test_stride_tricks.py,sha256=1zeBcvhltePbeE6SBoF4gomAYaZzwaHjvbWqcgI2JiY,23494
+numpy/lib/tests/test_twodim_base.py,sha256=USISKs6mDYgEl20k4_k899_pWSkFjZkPkafA_BUQxng,18890
+numpy/lib/tests/test_type_check.py,sha256=ffuA-ndaMsUb0IvPalBMwGkoukIP9OZVJXCuq299qB8,15597
+numpy/lib/tests/test_ufunclike.py,sha256=rpZTDbKPBVg5-byY1SKhkukyxB2Lvonw15ZARPE3mc0,3382
+numpy/lib/tests/test_utils.py,sha256=3uWGoBytyV-jtAt6Fnp812iVWKZw5KI9TV_7ApS3u98,4407
+numpy/lib/twodim_base.py,sha256=BcZwBkPLX7-3aeNyScIbhH28JmzPypMdMZH4FExNbSo,29366
+numpy/lib/type_check.py,sha256=WK5a3RgaIVoKqskfvG-U6VHiZyMNrfswV-9SBb5RxbU,20500
+numpy/lib/ufunclike.py,sha256=D6NgciDjA0ETqfzX9lDzuArgPOWccl3-nws48_IMwYo,8211
+numpy/lib/user_array.py,sha256=5yqkyjCmUIASGNx2bt7_ZMWJQJszkbD1Kn06qqv7POA,8007
+numpy/lib/utils.py,sha256=DYd-12yhdzf1l8CLSZ8gOBNBItYLvsX0mHgXMaehuY0,32675
+numpy/linalg/__init__.py,sha256=nziJvIBC-t0x_9SjOrlgcorUR03gdviaCWhbvvPIT7s,1836
+numpy/linalg/__init__.pyi,sha256=WL2hPYvsgtbNG0rKAhZl9h6eLL1nw1ZCp8dNiarGHYk,306
+numpy/linalg/__pycache__/__init__.cpython-39.pyc,,
+numpy/linalg/__pycache__/linalg.cpython-39.pyc,,
+numpy/linalg/__pycache__/setup.cpython-39.pyc,,
+numpy/linalg/_umath_linalg.cp39-win_amd64.pyd,sha256=ulyvB6CsmmBfENAxuc1pO5a32Lfq3eUIwvHM_Be7Kjk,155648
+numpy/linalg/lapack_lite.cp39-win_amd64.pyd,sha256=U3EYxZUORnnrTfM_lUbZUYHzGBxIisvGQ5ZOiocH9js,22016
+numpy/linalg/linalg.py,sha256=o3Z3tshOr_bUalTPpD-oAy4ESZDIg-ZlqBGCjqfcLto,92311
+numpy/linalg/setup.py,sha256=fxvs0sWTe4atefglbXBWPei5KSWhHsqSXXJ_3DphVYk,3186
+numpy/linalg/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/linalg/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/linalg/tests/__pycache__/test_build.cpython-39.pyc,,
+numpy/linalg/tests/__pycache__/test_deprecations.cpython-39.pyc,,
+numpy/linalg/tests/__pycache__/test_linalg.cpython-39.pyc,,
+numpy/linalg/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/linalg/tests/test_build.py,sha256=8cUlHATPUuy3Y2zYWuWhYQnNjdAAegcPRsUUC_tgujE,1671
+numpy/linalg/tests/test_deprecations.py,sha256=GaeE3JnQlJLoAfbY93LmgCFUlV5M8IFmQ7EhF4WbqwU,660
+numpy/linalg/tests/test_linalg.py,sha256=lczSdwO0vQWSfIUxQyScg8wRbYtC2yfKUJ973G3CBM8,76437
+numpy/linalg/tests/test_regression.py,sha256=T0iQkRUhOoxIHHro5kyxU7GFRhN3pZov6UaJGXxtvu0,5745
+numpy/ma/__init__.py,sha256=9i-au2uOZ_K9q2t9Ezc9nEAS74Y4TXQZMoP9601UitU,1458
+numpy/ma/__init__.pyi,sha256=54sTW5hidbnf0Mt2lxr1EkqpUhF4ZCyIUHSfIDEBVm4,3443
+numpy/ma/__pycache__/__init__.cpython-39.pyc,,
+numpy/ma/__pycache__/bench.cpython-39.pyc,,
+numpy/ma/__pycache__/core.cpython-39.pyc,,
+numpy/ma/__pycache__/extras.cpython-39.pyc,,
+numpy/ma/__pycache__/mrecords.cpython-39.pyc,,
+numpy/ma/__pycache__/setup.cpython-39.pyc,,
+numpy/ma/__pycache__/testutils.cpython-39.pyc,,
+numpy/ma/__pycache__/timer_comparison.cpython-39.pyc,,
+numpy/ma/bench.py,sha256=wOg52Iu6JHqHWzKS2N0LpdPPUJciEZAePgmZd_mMgpM,5014
+numpy/ma/core.py,sha256=rrQ5xLgjZlo9sQt_azDhNkX-5fNETN78shJxRE5migg,272660
+numpy/ma/extras.py,sha256=NSaXcpGtjv5PoXQ2j3kbKiE6018TDY0pGQ88WZol2oo,60269
+numpy/ma/mrecords.py,sha256=B3HcVpKf0kRu4DG3YreZ6NY5zrBD9kTMBkU7tRJCKKY,27449
+numpy/ma/setup.py,sha256=DCi5FtZTlkhR3ByJH5Sp5B962bfcWpaOjA-y7ueyoog,430
+numpy/ma/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/ma/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_core.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_deprecations.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_extras.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_mrecords.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_old_ma.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/ma/tests/__pycache__/test_subclassing.cpython-39.pyc,,
+numpy/ma/tests/test_core.py,sha256=riuUcctlM19sGwaJ5GVkkqIyVTt4RklabpsYiFYFywc,205930
+numpy/ma/tests/test_deprecations.py,sha256=Dv-fqcxKJ_tfxyk-DyK2rA5onOl-7YC06Pu9nkvECt0,2326
+numpy/ma/tests/test_extras.py,sha256=_uTlvEtwEcLyYw3dS657rlP3nUz2p697aspFW9kze48,68630
+numpy/ma/tests/test_mrecords.py,sha256=KeUfhLLwjwhX-Wh1UvViiFdOO3JFj44BQDtiC4ZZUrE,20363
+numpy/ma/tests/test_old_ma.py,sha256=v99zHnxhbwdxqnzmUCZFy5hbzAPkZG6UcA3ijmnuvlE,33123
+numpy/ma/tests/test_regression.py,sha256=Hi-p5QdcivsxUDSpTl3MGtAnmJCJPhhIj3c5nYI9rw8,3170
+numpy/ma/tests/test_subclassing.py,sha256=_7LEDWP0uruXofBfuKotk_xPz7JSPd8FZ-WfF27IrOs,13181
+numpy/ma/testutils.py,sha256=94gtPCIs6pBrtt1w51rG-aH3Z_XCdYzete8uu1oeQdc,10565
+numpy/ma/timer_comparison.py,sha256=xhRDTkkqvVLvB5HeFKIQqGuicRerabKKX3VmBUGc4Zs,16101
+numpy/matlib.py,sha256=l-292Lvk_yUCK5Y_U9u1Xa8grW8Ss0uh23o8kj-Hhd8,10741
+numpy/matrixlib/__init__.py,sha256=OYwN1yrpX0doHcXpzdRm2moAUO8BCmgufnmd6DS43pI,228
+numpy/matrixlib/__init__.pyi,sha256=gkHjB8o5QIAq39IumANapcGnYj2FCihAUrqvIADp0t0,103
+numpy/matrixlib/__pycache__/__init__.cpython-39.pyc,,
+numpy/matrixlib/__pycache__/defmatrix.cpython-39.pyc,,
+numpy/matrixlib/__pycache__/setup.cpython-39.pyc,,
+numpy/matrixlib/defmatrix.py,sha256=zDXeDEu5DcW3R5ijl_MjGzp9bXM36uhWm3s0hbMTzJc,31780
+numpy/matrixlib/setup.py,sha256=DEY5vWe-ReFP31junY0nZ7HwDpRIVuHLUtiTXL_Kr3A,438
+numpy/matrixlib/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/matrixlib/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_defmatrix.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_interaction.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_masked_matrix.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_matrix_linalg.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_multiarray.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_numeric.cpython-39.pyc,,
+numpy/matrixlib/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/matrixlib/tests/test_defmatrix.py,sha256=nbY_HkwzoJbhYhACiEN-cZmR644sVJvMKWUcsANPayQ,15435
+numpy/matrixlib/tests/test_interaction.py,sha256=C1YtIubO6Qh8RR-XONzo8Mle4bu4SvwsvBnB0x0Gy4g,12229
+numpy/matrixlib/tests/test_masked_matrix.py,sha256=aKC-imVpBSyjnokr0Ntn-e47P1MXhKzOSnGz1ji9J_c,9156
+numpy/matrixlib/tests/test_matrix_linalg.py,sha256=9S9Zrk8PMLfEEo9wBx5LyrV_TbXhI6r-Hc5t594lQFY,2152
+numpy/matrixlib/tests/test_multiarray.py,sha256=E5jvWX9ypWYNHH7iqAW3xz3tMrEV-oNgjN3_oPzZzws,570
+numpy/matrixlib/tests/test_numeric.py,sha256=l-LFBKPoP3_O1iea23MmaACBLx_tSSdPcUBBRTiTbzk,458
+numpy/matrixlib/tests/test_regression.py,sha256=FgYV3hwkpO0qyshDzG7n1JfQ-kKwnSZnA68jJHS7TeM,958
+numpy/polynomial/__init__.py,sha256=SG2szESWgc9tqBY4dO_2EcidOI4EWX25cM1E-7cqCS4,6603
+numpy/polynomial/__init__.pyi,sha256=o9K9xMfY0s8yfzxY3gGns6X1-2iRZUiVe6Dc7sUwJM4,147
+numpy/polynomial/__pycache__/__init__.cpython-39.pyc,,
+numpy/polynomial/__pycache__/_polybase.cpython-39.pyc,,
+numpy/polynomial/__pycache__/chebyshev.cpython-39.pyc,,
+numpy/polynomial/__pycache__/hermite.cpython-39.pyc,,
+numpy/polynomial/__pycache__/hermite_e.cpython-39.pyc,,
+numpy/polynomial/__pycache__/laguerre.cpython-39.pyc,,
+numpy/polynomial/__pycache__/legendre.cpython-39.pyc,,
+numpy/polynomial/__pycache__/polynomial.cpython-39.pyc,,
+numpy/polynomial/__pycache__/polyutils.cpython-39.pyc,,
+numpy/polynomial/__pycache__/setup.cpython-39.pyc,,
+numpy/polynomial/_polybase.py,sha256=0wJm5LbxcKNDEGa0xlho2LGkdOavwCBebsDaWmr8Vjw,37563
+numpy/polynomial/chebyshev.py,sha256=ylrydE6-AZb_jA-l8O3verfgVb6Ixgab32kXczyS5Bo,64492
+numpy/polynomial/hermite.py,sha256=72K9DSzx_Vcc5vKWIeW_zqV882_MQGcbGzBK_BhdBao,53820
+numpy/polynomial/hermite_e.py,sha256=LKEsRUkJvWizLngby0-qX_rnIgHHX5xZBYelDTkCsrM,53936
+numpy/polynomial/laguerre.py,sha256=wDRL-qxMLaIogQvT_ANjOaRDfJqE3cdbAfx-K9F6DT4,52096
+numpy/polynomial/legendre.py,sha256=nGumaDhnaAyargOW-G9g_AaJvnDR5oRmNlDePhVo1v0,52880
+numpy/polynomial/polynomial.py,sha256=ZWG5Z_11BwDFPLll6ksYbYiIfx4HYSCHjxKKBjpYWko,50100
+numpy/polynomial/polyutils.py,sha256=psxFjmYv1nrpFewtEPNIQfCE-umH6PumsQ1_CB0Vu9k,23932
+numpy/polynomial/setup.py,sha256=3MP1VT1AVy8_MdlhErP-lS0Rq5fActYCkxYeHJU88Vg,383
+numpy/polynomial/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/polynomial/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_chebyshev.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_classes.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_hermite.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_hermite_e.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_laguerre.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_legendre.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_polynomial.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_polyutils.cpython-39.pyc,,
+numpy/polynomial/tests/__pycache__/test_printing.cpython-39.pyc,,
+numpy/polynomial/tests/test_chebyshev.py,sha256=PI2XwvGGqQKEB1RxbsYRgeTG0cunB_8Otd9SBJozq-8,21141
+numpy/polynomial/tests/test_classes.py,sha256=J6abNzhFKwaagzv_x53xN0whCfr5nMwqZ---Jrd9oxY,18931
+numpy/polynomial/tests/test_hermite.py,sha256=zGYN24ia2xx4IH16D6sfAxIipnZrGrIe7D8QMJZPw4Y,19132
+numpy/polynomial/tests/test_hermite_e.py,sha256=5ZBtGi2gkeldYVSh8xlQOLUDW6fcT4YdZiTrB6AaGJU,19467
+numpy/polynomial/tests/test_laguerre.py,sha256=hBgo8w_3iEQosX2CqjTkUstTiuTPLZmfQNQtyKudZLo,18048
+numpy/polynomial/tests/test_legendre.py,sha256=mJcXkot3E2uhcIZY-Bvb3EfWbOo601NG_gq0OwObuNk,18831
+numpy/polynomial/tests/test_polynomial.py,sha256=BHR8Cy7nhcxdsgrhEwyPRdswgQhDRZmnaoT9gb5O1VU,20628
+numpy/polynomial/tests/test_polyutils.py,sha256=F9Tghiw2LM1wqEHFHxCuFAR9rueLe-i-dakoEvsLgJE,3105
+numpy/polynomial/tests/test_printing.py,sha256=o0D4bNFYlFo0YpPYMB6RZwH5zEFpE6qjdeZ-j-D0YsI,16176
+numpy/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/random/__init__.pxd,sha256=g3EaMi3yfmnqT-KEWj0cp6SWIxVN9ChFjEYXGOfOifE,445
+numpy/random/__init__.py,sha256=rYnpCdx2jY6FC1tn4ev_5SekdgjT_xgl5X0dinpzLj4,7673
+numpy/random/__init__.pyi,sha256=uszjens-em1PfQ4dxIl0Tm7taoKi2dxI7C6_g40cWNI,990
+numpy/random/__pycache__/__init__.cpython-39.pyc,,
+numpy/random/__pycache__/_pickle.cpython-39.pyc,,
+numpy/random/__pycache__/setup.cpython-39.pyc,,
+numpy/random/_bounded_integers.cp39-win_amd64.pyd,sha256=Ol3frJV-8AxaPYedafhqQdTBWP4aKEP_45AXbW84_pw,239616
+numpy/random/_bounded_integers.pxd,sha256=ugYlh8FvGggHCjEaqgO4S_MeRcZg3mw40sDYEqx07QQ,1698
+numpy/random/_common.cp39-win_amd64.pyd,sha256=McVm7lGYVokiZ8jww9wfR5IJmLvKpB2fl6ycYkMP6RI,181760
+numpy/random/_common.pxd,sha256=N2NZYlMYNh7FzFbJ6Mr2DH3MkrG67HUwqOu-XX_ouAA,4855
+numpy/random/_examples/cffi/__pycache__/extending.cpython-39.pyc,,
+numpy/random/_examples/cffi/__pycache__/parse.cpython-39.pyc,,
+numpy/random/_examples/cffi/extending.py,sha256=BgydYEYBb6hDghMF-KQFVc8ssUU1F5Dg-3GyeilT3Vg,920
+numpy/random/_examples/cffi/parse.py,sha256=Jb5SRj8As2P07PtoeuiZHZctaY0oAb065PXbG4-T8fI,1884
+numpy/random/_examples/cython/__pycache__/setup.cpython-39.pyc,,
+numpy/random/_examples/cython/extending.pyx,sha256=_pKBslBsb8rGeFZkuQeAIhBdeIjDcX3roGqV_Jev7NE,2371
+numpy/random/_examples/cython/extending_distributions.pyx,sha256=1zrMvPbKi0RinyZ93Syyy4OXGEOzAAKHSzTmDtN09ZY,3987
+numpy/random/_examples/cython/setup.py,sha256=dvXjPDXSiWZwgq_Myapi2VggTzV0AGdSrEhrMmJmT0s,1366
+numpy/random/_examples/numba/__pycache__/extending.cpython-39.pyc,,
+numpy/random/_examples/numba/__pycache__/extending_distributions.cpython-39.pyc,,
+numpy/random/_examples/numba/extending.py,sha256=vnqUqQRvlAI-3VYDzIxSQDlb-smBAyj8fA1-M2IrOQw,2041
+numpy/random/_examples/numba/extending_distributions.py,sha256=tU62JEW13VyNuBPhSpDWqd9W9ammHJCLv61apg90lMc,2101
+numpy/random/_generator.cp39-win_amd64.pyd,sha256=OJHUryNmbxHpHQ_Jbx_AL2JfObl3dsr15VYAjkYaMaw,666112
+numpy/random/_mt19937.cp39-win_amd64.pyd,sha256=qzAee2h_hwkW1fABx44qZ-rYai0TBXRftX1fFFecekI,79360
+numpy/random/_pcg64.cp39-win_amd64.pyd,sha256=v5U4w6V_Ax42mQxI_VObPmr4YylQd_nxPR6Id8--Frg,65536
+numpy/random/_philox.cp39-win_amd64.pyd,sha256=BUVK63R9yZJ2QPhKNSyTnZrrFbiyvhH_VYDDkmzNv5Y,72704
+numpy/random/_pickle.py,sha256=X1IKY4xyLBsWLG1vubCWyRRn-QsV-jm5McUH-Zc-uiU,2329
+numpy/random/_sfc64.cp39-win_amd64.pyd,sha256=pxbRxPYhRTClv3iKYel8XzdvLdAGMLd0a_loFBaDBH8,53248
+numpy/random/bit_generator.cp39-win_amd64.pyd,sha256=-I1XyauV25k_NUBWzS3kA74haoqhBRX09MwQv7asVKQ,152576
+numpy/random/bit_generator.pxd,sha256=LJpeB-EKeVV8_JO69sS33XJLZQ3DAhrUCNzs_ei7AoI,1042
+numpy/random/c_distributions.pxd,sha256=N8O_29MDGDOyMqmSKoaoooo4OJRRerBwsBXLw7_4j54,6147
+numpy/random/lib/npyrandom.lib,sha256=1qrbqDhmaUraO_G5IH8aRuvOnFgVSV38cLKp4wX6cts,110126
+numpy/random/mtrand.cp39-win_amd64.pyd,sha256=nLdqP-W_INMP3kFjXc7eWdqYdl5i0A9zeAOxofq2gwI,564224
+numpy/random/setup.py,sha256=5JHmw9X-POJdt07i8sFUMpZLB2p0vh4dRU05xtEdtS0,6258
+numpy/random/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/random/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_direct.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_extending.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_generator_mt19937.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_generator_mt19937_regressions.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_random.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_randomstate.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_randomstate_regression.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_regression.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_seed_sequence.cpython-39.pyc,,
+numpy/random/tests/__pycache__/test_smoke.cpython-39.pyc,,
+numpy/random/tests/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/random/tests/data/__pycache__/__init__.cpython-39.pyc,,
+numpy/random/tests/data/mt19937-testset-1.csv,sha256=bA5uuOXgLpkAwJjfV8oUePg3-eyaH4-gKe8AMcl2Xn0,16845
+numpy/random/tests/data/mt19937-testset-2.csv,sha256=SnOL1nyRbblYlC254PBUSc37NguV5xN-0W_B32IxDGE,16826
+numpy/random/tests/data/pcg64-testset-1.csv,sha256=wHoS7fIR3hMEdta7MtJ8EpIWX-Bw1yfSaVxiC15vxVs,24840
+numpy/random/tests/data/pcg64-testset-2.csv,sha256=6vlnVuW_4i6LEsVn6b40HjcBWWjoX5lboSCBDpDrzFs,24846
+numpy/random/tests/data/philox-testset-1.csv,sha256=QvpTynWHQjqTz3P2MPvtMLdg2VnM6TGTpXgp-_LeJ5g,24853
+numpy/random/tests/data/philox-testset-2.csv,sha256=-BNO1OCYtDIjnN5Q-AsQezBCGmVJUIs3qAMyj8SNtsA,24839
+numpy/random/tests/data/sfc64-testset-1.csv,sha256=sgkemW0lbKJ2wh1sBj6CfmXwFYTqfAk152P0r8emO38,24841
+numpy/random/tests/data/sfc64-testset-2.csv,sha256=mkp21SG8eCqsfNyQZdmiV41-xKcsV8eutT7rVnVEG50,24834
+numpy/random/tests/test_direct.py,sha256=7pjpeUADs8HTtEtbNbBTKi1EMsmO21lvYoMqHyoucdQ,14827
+numpy/random/tests/test_extending.py,sha256=FSv8xJt8fd1-clX6rOwrMhn66PfMn4JJRbJH46ptwVo,3598
+numpy/random/tests/test_generator_mt19937.py,sha256=NZp5ePTiw0N2R8j1wNTshrv8Gq3qdPxRFlmxYwzpEiM,108419
+numpy/random/tests/test_generator_mt19937_regressions.py,sha256=NErTZy-83MM4jMdguaE_5msKf1dhD2UyyXZsvTjtKS0,5803
+numpy/random/tests/test_random.py,sha256=wwyX-oMKUOp17kuObzZFrWYC_ImhVc79NPdqm1ufJlU,69907
+numpy/random/tests/test_randomstate.py,sha256=XLhtIFIhM3vWtXy6hQUTh-ek44kibgnbcdwm8jYne9U,82720
+numpy/random/tests/test_randomstate_regression.py,sha256=t-4vAs8vZbrmIHzMcSpzsgelRVu5gjYq8ZqDUY0PfHc,7758
+numpy/random/tests/test_regression.py,sha256=yRzgK9Nz0kc5gZgzoNKJExc8voyXIU0GworGVFQ2-QA,5602
+numpy/random/tests/test_seed_sequence.py,sha256=zWUvhWDxBmTN2WteSFQeJ29W0-2k3ZUze_3YtL4Kgms,3391
+numpy/random/tests/test_smoke.py,sha256=C9khpy2DZnpE5g0s5bSliun4GOTq-576faz0jmxpsWQ,28621
+numpy/rec.pyi,sha256=pEAReiHy1PylZO3YYKqJY-8nHM0Rq6Jgdcxyw1orbKs,181
+numpy/setup.py,sha256=fBEg6S2o6H9mmLBfVJOonPwEIN70qlxH5TQVdSb3yao,1012
+numpy/testing/__init__.py,sha256=s9TGtO8tH0kG8emfVLC1pBRUrgsb4ueWAwtIb6XQXLg,586
+numpy/testing/__init__.pyi,sha256=Ixqmb0Ve3ZxTLgJjN2l6Izh2uoJYiDjELFooTPCLXmU,956
+numpy/testing/__pycache__/__init__.cpython-39.pyc,,
+numpy/testing/__pycache__/print_coercion_tables.cpython-39.pyc,,
+numpy/testing/__pycache__/setup.cpython-39.pyc,,
+numpy/testing/__pycache__/utils.cpython-39.pyc,,
+numpy/testing/_private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/testing/_private/__pycache__/__init__.cpython-39.pyc,,
+numpy/testing/_private/__pycache__/decorators.cpython-39.pyc,,
+numpy/testing/_private/__pycache__/noseclasses.cpython-39.pyc,,
+numpy/testing/_private/__pycache__/nosetester.cpython-39.pyc,,
+numpy/testing/_private/__pycache__/parameterized.cpython-39.pyc,,
+numpy/testing/_private/__pycache__/utils.cpython-39.pyc,,
+numpy/testing/_private/decorators.py,sha256=e_ylVQtyN_MjuOsd0AFaFmQ9wB7mtdHy8f0LBKj8u6s,9005
+numpy/testing/_private/noseclasses.py,sha256=OqMSWVZEg5GGgz8bsoDWKa3oxvXYoqPst6U423s8yBM,14880
+numpy/testing/_private/nosetester.py,sha256=35S7suLWVzYBZ-zOt3ugthNZcMBCP7AjA-Z-4jqmtus,19980
+numpy/testing/_private/parameterized.py,sha256=c5BMUIU86FLdsvouqOBT4t8BLk1q8F32KaXEcPgfi-c,16958
+numpy/testing/_private/utils.py,sha256=dH7BXvx3q55ktBlhM6f7pjc9H2phBr3SzfQP_D2xCdw,87843
+numpy/testing/print_coercion_tables.py,sha256=GnC-nt2Sw2D7TJOoIgK3b2Nj63r9VFqGzPStMfdOBgs,6367
+numpy/testing/setup.py,sha256=LRtPNvo1V4Eh_gCq0ScQXSxv3P428c4rAKOVj1JK3MI,685
+numpy/testing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/testing/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/testing/tests/__pycache__/test_decorators.cpython-39.pyc,,
+numpy/testing/tests/__pycache__/test_doctesting.cpython-39.pyc,,
+numpy/testing/tests/__pycache__/test_utils.cpython-39.pyc,,
+numpy/testing/tests/test_decorators.py,sha256=zR2-CPT4vK_KE1st9LuaAAkP1PFthUkBCefjng088uI,6045
+numpy/testing/tests/test_doctesting.py,sha256=wUauOPx75yuJgIHNWlPCpF0EUIGKDI-nzlImCwGeYo0,1404
+numpy/testing/tests/test_utils.py,sha256=GwIHxAcqT570qsnTIo4lNZq8NJP5_scLS7-YmcreToU,57311
+numpy/testing/utils.py,sha256=LhIaw_3hG1jUW98rUrBhOxRi1SjOUgVIr5--kwp0XZc,1260
+numpy/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/tests/__pycache__/test_ctypeslib.cpython-39.pyc,,
+numpy/tests/__pycache__/test_matlib.cpython-39.pyc,,
+numpy/tests/__pycache__/test_numpy_version.cpython-39.pyc,,
+numpy/tests/__pycache__/test_public_api.cpython-39.pyc,,
+numpy/tests/__pycache__/test_reloading.cpython-39.pyc,,
+numpy/tests/__pycache__/test_scripts.cpython-39.pyc,,
+numpy/tests/__pycache__/test_warnings.cpython-39.pyc,,
+numpy/tests/test_ctypeslib.py,sha256=4hdwdxDArcTLHpinigBSLLGb_ppGtksPWRsvkRD0Z84,12535
+numpy/tests/test_matlib.py,sha256=TUaQmGoz9fvQQ8FrooTq-g9BFiViGWjoTIGQSUUF6-Y,1910
+numpy/tests/test_numpy_version.py,sha256=EzH8x1xpoowIlHlXQ-TEQaIJlmnx_rgrJtOCwdBXYyY,598
+numpy/tests/test_public_api.py,sha256=TE5Hcc-in2KYgUwkApnOlKG6VEnl_Vds9bK_zuov-H0,15456
+numpy/tests/test_reloading.py,sha256=WuaGiMPNSmoS2_cKKcsLFNI2iSIvxxR0O0f1Id7qW40,2007
+numpy/tests/test_scripts.py,sha256=jZHCW1jQrXwXycEUp4ntzQzm_DDscJXDsQL_moonq98,1567
+numpy/tests/test_warnings.py,sha256=IMFVROBQqYZPibnHmwepGqEUQoBlDtdC8DlRulbMAd8,2354
+numpy/typing/__init__.py,sha256=SlrqSQGbOqvd6fkem4mHf7nyU1y75zd0AIwNNVJEzbc,7379
+numpy/typing/__pycache__/__init__.cpython-39.pyc,,
+numpy/typing/__pycache__/_add_docstring.cpython-39.pyc,,
+numpy/typing/__pycache__/_array_like.cpython-39.pyc,,
+numpy/typing/__pycache__/_callable.cpython-39.pyc,,
+numpy/typing/__pycache__/_dtype_like.cpython-39.pyc,,
+numpy/typing/__pycache__/_scalars.cpython-39.pyc,,
+numpy/typing/__pycache__/_shape.cpython-39.pyc,,
+numpy/typing/__pycache__/setup.cpython-39.pyc,,
+numpy/typing/_add_docstring.py,sha256=1qcfzFKkMl7vms4mztFapPC0Wwvjhe8ANxUOpYi_Fu4,2701
+numpy/typing/_array_like.py,sha256=na2mbjXRfOGOIHY5R7mxx7_Jr8__hpCKuIRdJGC7w1Q,1061
+numpy/typing/_callable.py,sha256=skqiR8PkO1NHBUCyrzqS26e07vMslOtqQg3jLeBfkhY,11835
+numpy/typing/_dtype_like.py,sha256=MUQRBlzWwksVcLhvTduFxLr0No5VjIYEgJ1wyumX61I,2557
+numpy/typing/_scalars.py,sha256=pq1Y9MH0THa2Y0WZ26HDb7NGNIB5p-khAy70B8M8zuI,694
+numpy/typing/_shape.py,sha256=XHT8qONsphjVLrJVhI7KoiUBVIwzWhKgESvs9E_pPcw,162
+numpy/typing/setup.py,sha256=NpNqwxDwSxWBInw-7TJHIqEf3scDAczZwmzGxI_Ftn0,385
+numpy/typing/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+numpy/typing/tests/__pycache__/__init__.cpython-39.pyc,,
+numpy/typing/tests/__pycache__/test_isfile.cpython-39.pyc,,
+numpy/typing/tests/__pycache__/test_typing.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/arithmetic.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/array_constructors.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/array_like.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/bitwise_ops.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/constants.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/dtype.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/flatiter.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/fromnumeric.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/modules.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/ndarray.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/ndarray_misc.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/numerictypes.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/scalars.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/ufunc_config.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/ufuncs.cpython-39.pyc,,
+numpy/typing/tests/data/fail/__pycache__/warnings_and_errors.cpython-39.pyc,,
+numpy/typing/tests/data/fail/arithmetic.py,sha256=aVKC-80x7Jj3V7cn5vaM2O-Sewsj0lT9NBnH7wQvANA,399
+numpy/typing/tests/data/fail/array_constructors.py,sha256=QWbSPp90Bhczb0Lz9pfnilQh7MeCgwzdXhQIUXUBQU0,1021
+numpy/typing/tests/data/fail/array_like.py,sha256=kpQ9GYpCyNQnpCVNJfjzcjuyRaWcRSk5I3vwobto5Ik,486
+numpy/typing/tests/data/fail/bitwise_ops.py,sha256=6cpzCLl1EH81UiJwo5Qs-HkvUByG9V5MNLpk8nVrLLo,534
+numpy/typing/tests/data/fail/constants.py,sha256=rm5lDmBIS2M3CYKKvrZuzW_jKwGknLgc2Ih8bpDrOPc,274
+numpy/typing/tests/data/fail/dtype.py,sha256=mijyTgWwSqw6pgvd_cJ8XUYfjbsVa0-RfBhZkfynD2I,344
+numpy/typing/tests/data/fail/flatiter.py,sha256=YpW-SsU6ti1Pt2Adj-BgE0wQ9PAMYBylSN7y61Ujtfw,867
+numpy/typing/tests/data/fail/fromnumeric.py,sha256=weUR_bwWaqesICBarUC0-K7beFnUZ-nt00mld6zbogE,7908
+numpy/typing/tests/data/fail/modules.py,sha256=VF5g2y96mxBdb6pxNlgjKtfMeq4DKqYiIjgrABubAlE,312
+numpy/typing/tests/data/fail/ndarray.py,sha256=2I4smD6MlUD23Xx8Rt1gCtjj_m-tI5JEma-Z0unrgas,416
+numpy/typing/tests/data/fail/ndarray_misc.py,sha256=_DySvTQjAbHH460tAURU_-EqOkfGFiR_10F20DMSd4w,587
+numpy/typing/tests/data/fail/numerictypes.py,sha256=S6Xn_z1KoI8tSVSZ0aM7alvDfyAxNxEQuhMjXVW1Uws,397
+numpy/typing/tests/data/fail/scalars.py,sha256=0SkWYaG2yGON82lcOzoU1EX2UrNrbtVvQA9MsxyV_V0,2558
+numpy/typing/tests/data/fail/ufunc_config.py,sha256=V5R7wY_P7KWn4IRxbLx42b1YF3wbIYzHEMr9BC41JHE,754
+numpy/typing/tests/data/fail/ufuncs.py,sha256=nJ0vP3zPzaC7-U8veFZlSXEjRFlhJTPaFgRJBGM39sc,235
+numpy/typing/tests/data/fail/warnings_and_errors.py,sha256=UhM-s2DqkkD-Nd2O7_y_34_ygn4w4nEip6AXsQ1kQ4k,287
+numpy/typing/tests/data/mypy.ini,sha256=eiFW-OwC4m5btqviLfeISc-OZHWfnzQWOo9gdDi4Ic8,108
+numpy/typing/tests/data/pass/__pycache__/arithmetic.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/array_constructors.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/array_like.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/bitwise_ops.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/dtype.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/flatiter.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/fromnumeric.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/literal.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/mod.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/modules.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/ndarray_conversion.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/ndarray_misc.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/ndarray_shape_manipulation.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/numeric.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/numerictypes.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/scalars.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/simple.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/simple_py3.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/ufunc_config.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/ufuncs.cpython-39.pyc,,
+numpy/typing/tests/data/pass/__pycache__/warnings_and_errors.cpython-39.pyc,,
+numpy/typing/tests/data/pass/arithmetic.py,sha256=yffdMBRbA2DSbEl9zh2ebMi_9G-3ToVKW9CDT5auezA,2495
+numpy/typing/tests/data/pass/array_constructors.py,sha256=4PUMvHtZQ0f1-qgba_-CmJNaCQ9KaHTeDjWgAtug7ww,2490
+numpy/typing/tests/data/pass/array_like.py,sha256=PvPiNZmIbiwTNa5pleaF_azkp8Wkt-FnWMxhb90tnZc,976
+numpy/typing/tests/data/pass/bitwise_ops.py,sha256=zYz-ZNXpxjXDdo4fYWv_RQZq5af581dnaZrlu0-sSC8,1101
+numpy/typing/tests/data/pass/dtype.py,sha256=oNtzFIp5lwm205Dmy7_wtkUn8vpmTSuR4eNKMxt1BsQ,718
+numpy/typing/tests/data/pass/flatiter.py,sha256=IeJY7T1G2yE5sYFwEylBQxqzr8bBGnzWm1Uxx-aRooY,140
+numpy/typing/tests/data/pass/fromnumeric.py,sha256=eM6RUBjVInsShXlblqq07-I0QwoST8n6g8WWuPSgYtA,4002
+numpy/typing/tests/data/pass/literal.py,sha256=wtFjvftYilKJcuehgIWJTL0yXOO72gJKZBfrw_yjNMY,1344
+numpy/typing/tests/data/pass/mod.py,sha256=Intb9Ni_LlHhEka8kk81-601JCOl85jz_4_BQDA6iYI,1727
+numpy/typing/tests/data/pass/modules.py,sha256=SUH36dM5GU4Q9NNwgGU6ieEabuJ3BV3-EmI8ei8Y8HY,387
+numpy/typing/tests/data/pass/ndarray_conversion.py,sha256=-1iJDSvdD86k3yJCrWf1nouQrRHStf4cheiZ5OHFE78,1720
+numpy/typing/tests/data/pass/ndarray_misc.py,sha256=fvfAffZ5ebefXKZzTm2SMmi0xrhjlBVTd6dieI_fjsQ,2414
+numpy/typing/tests/data/pass/ndarray_shape_manipulation.py,sha256=yaBK3hW5fe2VpvARkn_NMeF-JX-OajI8JiRWOA_Uk7Y,687
+numpy/typing/tests/data/pass/numeric.py,sha256=VCJ993mY9u8v4eNhJOJuOtc9Ics8AsAlAQtrsaTXth8,1567
+numpy/typing/tests/data/pass/numerictypes.py,sha256=cyObIdejhEzrwA_awjstkvO-_b79iBJZ20nf9XlCMY8,749
+numpy/typing/tests/data/pass/scalars.py,sha256=i56q74NseMyjboftJfWw_BkRp-lDzQuM2cpYMQR9oqY,2662
+numpy/typing/tests/data/pass/simple.py,sha256=ChlX7VN0SPpa877JwPRb-JpBUgpwhDHJuQLbRBY75FM,2855
+numpy/typing/tests/data/pass/simple_py3.py,sha256=OBpoDmf5u4bRblugokiOZzufESsEmoU03MqipERrjLg,102
+numpy/typing/tests/data/pass/ufunc_config.py,sha256=l1JiZe3VXYLzgvbuk42Mk6fd_nvLsc9aJ233W0_MLm0,1170
+numpy/typing/tests/data/pass/ufuncs.py,sha256=NUCjNCXprCD0iQHbmCyft_vLGrCb5dwyf-86dNZF4S8,460
+numpy/typing/tests/data/pass/warnings_and_errors.py,sha256=CtuAoGmmjsiWw34jjPsFUMZDrmMsVssQ6KHBWsDk7Jw,179
+numpy/typing/tests/data/reveal/__pycache__/arithmetic.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/array_constructors.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/bitwise_ops.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/constants.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/dtype.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/flatiter.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/fromnumeric.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/mod.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/modules.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/nbit_base_example.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/ndarray_conversion.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/ndarray_misc.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/ndarray_shape_manipulation.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/numeric.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/numerictypes.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/scalars.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/ufunc_config.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/__pycache__/warnings_and_errors.cpython-39.pyc,,
+numpy/typing/tests/data/reveal/arithmetic.py,sha256=HZaJeMJXIYvFR9fac7k76jpAbDHmx6aiPiFasmQnrXk,16426
+numpy/typing/tests/data/reveal/array_constructors.py,sha256=6py1-UOF4LMel4ps3AdQGppTWNM_EfGcP99x25OOVuc,3936
+numpy/typing/tests/data/reveal/bitwise_ops.py,sha256=GJ4oIEaoqniGRnMJTo1XgJ1pJpKgNPnB_OqS4GFWg3M,5786
+numpy/typing/tests/data/reveal/constants.py,sha256=KA1cM3BLqwq4cjoFt2-oOkOEyEj05kv1Zm_usnN7POI,1794
+numpy/typing/tests/data/reveal/dtype.py,sha256=HiG5R8r23ejeWy2T0eC2MtgTtSlZmQEQ33oSb1svO48,1597
+numpy/typing/tests/data/reveal/flatiter.py,sha256=6XVwZ8MESoV3IGF0C8mUZg87ZPmsuGtm5yS7FCWphEE,485
+numpy/typing/tests/data/reveal/fromnumeric.py,sha256=_PEc6fW9IlzCASf-fjen65e3Nq_j5pGr3eIajHCqq0s,12859
+numpy/typing/tests/data/reveal/mod.py,sha256=wlCsZkKMoiA3Oh1M2Azr5hC3aY77cyRLtLahaiDZ3-o,9037
+numpy/typing/tests/data/reveal/modules.py,sha256=khi3_SYRbnYLiHQ2Z0Vk4Nr10_nYbXeFWz0hiHefLJw,1382
+numpy/typing/tests/data/reveal/nbit_base_example.py,sha256=lV-J8KPlamCkRIkTm8Lzgywq7zOz1elplWw2516lmIo,544
+numpy/typing/tests/data/reveal/ndarray_conversion.py,sha256=mTbv2cNYU05dH7wxuPWFlhhMi4N0adi5ocF6MUyNCtc,1630
+numpy/typing/tests/data/reveal/ndarray_misc.py,sha256=Lb_5aX89zEuWrgYkr0_9k9c3S16DK_oeNUCGlQLqWIE,6148
+numpy/typing/tests/data/reveal/ndarray_shape_manipulation.py,sha256=hRbNwpFuiWKPZ5YcOlFeER72qLOJzHle_IZQ0wj-Rfk,1041
+numpy/typing/tests/data/reveal/numeric.py,sha256=2bACWCxtfKFGgfrhy2UHlauX3Pq2zU2F-USR7Fx79F4,3066
+numpy/typing/tests/data/reveal/numerictypes.py,sha256=NXDYYJTvLP-aCNbSNQe7yuFWSmp_sbdCKVkYsQPd0Hg,666
+numpy/typing/tests/data/reveal/scalars.py,sha256=TG-L69AUViCSeSFSGkCV5FMnNc_8IugMXO4417AlCks,1156
+numpy/typing/tests/data/reveal/ufunc_config.py,sha256=dcIwOjSa4B2DWffbRTCFsgRUxQJWkfeKlTAgIlcLDeQ,1416
+numpy/typing/tests/data/reveal/warnings_and_errors.py,sha256=vgKMl6HOqJqp0kijIx9bOVY1p_0yNxZqnNJQHl4Bw3U,438
+numpy/typing/tests/test_isfile.py,sha256=_QxXdUtcEpjFYbJSL9JlEP73ghbS9QjvUgtCw04GDb0,914
+numpy/typing/tests/test_typing.py,sha256=St99JVX9g1U7yyWe--IFnhJJuu_uCNwgpzh7PLEnJy0,5452
+numpy/version.py,sha256=-VQZM8geWnS_4Uhf4YKcxdU8JKoEthuw0kZqLRAhGaM,332
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/WHEEL b/venv/Lib/site-packages/numpy-1.20.1.dist-info/WHEEL
new file mode 100644
index 0000000..d1267fc
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.36.2)
+Root-Is-Purelib: false
+Tag: cp39-cp39-win_amd64
+
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/entry_points.txt b/venv/Lib/site-packages/numpy-1.20.1.dist-info/entry_points.txt
new file mode 100644
index 0000000..1010c24
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/entry_points.txt
@@ -0,0 +1,3 @@
+[console_scripts]
+f2py = numpy.f2py.f2py2e:main
+
diff --git a/venv/Lib/site-packages/numpy-1.20.1.dist-info/top_level.txt b/venv/Lib/site-packages/numpy-1.20.1.dist-info/top_level.txt
new file mode 100644
index 0000000..24ce15a
--- /dev/null
+++ b/venv/Lib/site-packages/numpy-1.20.1.dist-info/top_level.txt
@@ -0,0 +1 @@
+numpy
diff --git a/venv/Lib/site-packages/numpy/.libs/libopenblas.JPIJNSWNNAN3CE6LLI5FWSPHUT2VXMTH.gfortran-win_amd64.dll b/venv/Lib/site-packages/numpy/.libs/libopenblas.JPIJNSWNNAN3CE6LLI5FWSPHUT2VXMTH.gfortran-win_amd64.dll
new file mode 100644
index 0000000..f20bc5a
Binary files /dev/null and b/venv/Lib/site-packages/numpy/.libs/libopenblas.JPIJNSWNNAN3CE6LLI5FWSPHUT2VXMTH.gfortran-win_amd64.dll differ
diff --git a/venv/Lib/site-packages/numpy/LICENSE.txt b/venv/Lib/site-packages/numpy/LICENSE.txt
new file mode 100644
index 0000000..04738ae
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/LICENSE.txt
@@ -0,0 +1,938 @@
+
+----
+
+This binary distribution of NumPy also bundles the following software:
+
+
+Name: OpenBLAS
+Files: extra-dll\libopenb*.dll
+Description: bundled as a dynamically linked library
+Availability: https://github.com/xianyi/OpenBLAS/
+License: 3-clause BSD
+ Copyright (c) 2011-2014, The OpenBLAS Project
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. Neither the name of the OpenBLAS project nor the names of
+ its contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Name: LAPACK
+Files: extra-dll\libopenb*.dll
+Description: bundled in OpenBLAS
+Availability: https://github.com/xianyi/OpenBLAS/
+License 3-clause BSD
+ Copyright (c) 1992-2013 The University of Tennessee and The University
+ of Tennessee Research Foundation. All rights
+ reserved.
+ Copyright (c) 2000-2013 The University of California Berkeley. All
+ rights reserved.
+ Copyright (c) 2006-2013 The University of Colorado Denver. All rights
+ reserved.
+
+ $COPYRIGHT$
+
+ Additional copyrights may follow
+
+ $HEADER$
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer listed
+ in this license in the documentation and/or other materials
+ provided with the distribution.
+
+ - Neither the name of the copyright holders nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ The copyright holders provide no reassurances that the source code
+ provided does not infringe any patent, copyright, or any other
+ intellectual property rights of third parties. The copyright holders
+ disclaim any liability to any recipient for claims brought against
+ recipient by any third party for infringement of that parties
+ intellectual property rights.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Name: GCC runtime library
+Files: extra-dll\*.dll
+Description: statically linked, in DLL files compiled with gfortran only
+Availability: https://gcc.gnu.org/viewcvs/gcc/
+License: GPLv3 + runtime exception
+ Copyright (C) 2002-2017 Free Software Foundation, Inc.
+
+ Libgfortran is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Libgfortran is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ .
+
+
+Name: Microsoft Visual C++ Runtime Files
+Files: extra-dll\msvcp140.dll
+License: MSVC
+ https://www.visualstudio.com/license-terms/distributable-code-microsoft-visual-studio-2015-rc-microsoft-visual-studio-2015-sdk-rc-includes-utilities-buildserver-files/#visual-c-runtime
+
+ Subject to the License Terms for the software, you may copy and
+ distribute with your program any of the files within the followng
+ folder and its subfolders except as noted below. You may not modify
+ these files.
+
+ C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist
+
+ You may not distribute the contents of the following folders:
+
+ C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\debug_nonredist
+ C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\redist\onecore\debug_nonredist
+
+ Subject to the License Terms for the software, you may copy and
+ distribute the following files with your program in your program’s
+ application local folder or by deploying them into the Global
+ Assembly Cache (GAC):
+
+ VC\atlmfc\lib\mfcmifc80.dll
+ VC\atlmfc\lib\amd64\mfcmifc80.dll
+
+
+Name: Microsoft Visual C++ Runtime Files
+Files: extra-dll\msvc*90.dll, extra-dll\Microsoft.VC90.CRT.manifest
+License: MSVC
+ For your convenience, we have provided the following folders for
+ use when redistributing VC++ runtime files. Subject to the license
+ terms for the software, you may redistribute the folder
+ (unmodified) in the application local folder as a sub-folder with
+ no change to the folder name. You may also redistribute all the
+ files (*.dll and *.manifest) within a folder, listed below the
+ folder for your convenience, as an entire set.
+
+ \VC\redist\x86\Microsoft.VC90.ATL\
+ atl90.dll
+ Microsoft.VC90.ATL.manifest
+ \VC\redist\ia64\Microsoft.VC90.ATL\
+ atl90.dll
+ Microsoft.VC90.ATL.manifest
+ \VC\redist\amd64\Microsoft.VC90.ATL\
+ atl90.dll
+ Microsoft.VC90.ATL.manifest
+ \VC\redist\x86\Microsoft.VC90.CRT\
+ msvcm90.dll
+ msvcp90.dll
+ msvcr90.dll
+ Microsoft.VC90.CRT.manifest
+ \VC\redist\ia64\Microsoft.VC90.CRT\
+ msvcm90.dll
+ msvcp90.dll
+ msvcr90.dll
+ Microsoft.VC90.CRT.manifest
+
+----
+
+Full text of license texts referred to above follows (that they are
+listed below does not necessarily imply the conditions apply to the
+present binary release):
+
+----
+
+GCC RUNTIME LIBRARY EXCEPTION
+
+Version 3.1, 31 March 2009
+
+Copyright (C) 2009 Free Software Foundation, Inc.
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+This GCC Runtime Library Exception ("Exception") is an additional
+permission under section 7 of the GNU General Public License, version
+3 ("GPLv3"). It applies to a given file (the "Runtime Library") that
+bears a notice placed by the copyright holder of the file stating that
+the file is governed by GPLv3 along with this Exception.
+
+When you use GCC to compile a program, GCC may combine portions of
+certain GCC header files and runtime libraries with the compiled
+program. The purpose of this Exception is to allow compilation of
+non-GPL (including proprietary) programs to use, in this way, the
+header files and runtime libraries covered by this Exception.
+
+0. Definitions.
+
+A file is an "Independent Module" if it either requires the Runtime
+Library for execution after a Compilation Process, or makes use of an
+interface provided by the Runtime Library, but is not otherwise based
+on the Runtime Library.
+
+"GCC" means a version of the GNU Compiler Collection, with or without
+modifications, governed by version 3 (or a specified later version) of
+the GNU General Public License (GPL) with the option of using any
+subsequent versions published by the FSF.
+
+"GPL-compatible Software" is software whose conditions of propagation,
+modification and use would permit combination with GCC in accord with
+the license of GCC.
+
+"Target Code" refers to output from any compiler for a real or virtual
+target processor architecture, in executable form or suitable for
+input to an assembler, loader, linker and/or execution
+phase. Notwithstanding that, Target Code does not include data in any
+format that is used as a compiler intermediate representation, or used
+for producing a compiler intermediate representation.
+
+The "Compilation Process" transforms code entirely represented in
+non-intermediate languages designed for human-written code, and/or in
+Java Virtual Machine byte code, into Target Code. Thus, for example,
+use of source code generators and preprocessors need not be considered
+part of the Compilation Process, since the Compilation Process can be
+understood as starting with the output of the generators or
+preprocessors.
+
+A Compilation Process is "Eligible" if it is done using GCC, alone or
+with other GPL-compatible software, or if it is done without using any
+work based on GCC. For example, using non-GPL-compatible Software to
+optimize any GCC intermediate representations would not qualify as an
+Eligible Compilation Process.
+
+1. Grant of Additional Permission.
+
+You have permission to propagate a work of Target Code formed by
+combining the Runtime Library with Independent Modules, even if such
+propagation would otherwise violate the terms of GPLv3, provided that
+all Target Code was generated by Eligible Compilation Processes. You
+may then convey such a combination under terms of your choice,
+consistent with the licensing of the Independent Modules.
+
+2. No Weakening of GCC Copyleft.
+
+The availability of this Exception does not imply any general
+presumption that third-party software is unaffected by the copyleft
+requirements of the license of GCC.
+
+----
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+ .
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/venv/Lib/site-packages/numpy/__config__.py b/venv/Lib/site-packages/numpy/__config__.py
new file mode 100644
index 0000000..7964c96
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/__config__.py
@@ -0,0 +1,78 @@
+# This file is generated by numpy's setup.py
+# It contains system_info results at the time of building this package.
+__all__ = ["get_info","show"]
+
+
+import os
+import sys
+
+extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs')
+
+if sys.platform == 'win32' and os.path.isdir(extra_dll_dir):
+ if sys.version_info >= (3, 8):
+ os.add_dll_directory(extra_dll_dir)
+ else:
+ os.environ.setdefault('PATH', '')
+ os.environ['PATH'] += os.pathsep + extra_dll_dir
+
+blas_mkl_info={}
+blis_info={}
+openblas_info={'library_dirs': ['D:\\a\\1\\s\\numpy\\build\\openblas_info'], 'libraries': ['openblas_info'], 'language': 'f77', 'define_macros': [('HAVE_CBLAS', None)]}
+blas_opt_info={'library_dirs': ['D:\\a\\1\\s\\numpy\\build\\openblas_info'], 'libraries': ['openblas_info'], 'language': 'f77', 'define_macros': [('HAVE_CBLAS', None)]}
+lapack_mkl_info={}
+openblas_lapack_info={'library_dirs': ['D:\\a\\1\\s\\numpy\\build\\openblas_lapack_info'], 'libraries': ['openblas_lapack_info'], 'language': 'f77', 'define_macros': [('HAVE_CBLAS', None)]}
+lapack_opt_info={'library_dirs': ['D:\\a\\1\\s\\numpy\\build\\openblas_lapack_info'], 'libraries': ['openblas_lapack_info'], 'language': 'f77', 'define_macros': [('HAVE_CBLAS', None)]}
+
+def get_info(name):
+ g = globals()
+ return g.get(name, g.get(name + "_info", {}))
+
+def show():
+ """
+ Show libraries in the system on which NumPy was built.
+
+ Print information about various resources (libraries, library
+ directories, include directories, etc.) in the system on which
+ NumPy was built.
+
+ See Also
+ --------
+ get_include : Returns the directory containing NumPy C
+ header files.
+
+ Notes
+ -----
+ Classes specifying the information to be printed are defined
+ in the `numpy.distutils.system_info` module.
+
+ Information may include:
+
+ * ``language``: language used to write the libraries (mostly
+ C or f77)
+ * ``libraries``: names of libraries found in the system
+ * ``library_dirs``: directories containing the libraries
+ * ``include_dirs``: directories containing library header files
+ * ``src_dirs``: directories containing library source files
+ * ``define_macros``: preprocessor macros used by
+ ``distutils.setup``
+
+ Examples
+ --------
+ >>> import numpy as np
+ >>> np.show_config()
+ blas_opt_info:
+ language = c
+ define_macros = [('HAVE_CBLAS', None)]
+ libraries = ['openblas', 'openblas']
+ library_dirs = ['/usr/local/lib']
+ """
+ for name,info_dict in globals().items():
+ if name[0] == "_" or type(info_dict) is not type({}): continue
+ print(name + ":")
+ if not info_dict:
+ print(" NOT AVAILABLE")
+ for k,v in info_dict.items():
+ v = str(v)
+ if k == "sources" and len(v) > 200:
+ v = v[:60] + " ...\n... " + v[-60:]
+ print(" %s = %s" % (k,v))
diff --git a/venv/Lib/site-packages/numpy/__init__.cython-30.pxd b/venv/Lib/site-packages/numpy/__init__.cython-30.pxd
new file mode 100644
index 0000000..f3e7c9c
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/__init__.cython-30.pxd
@@ -0,0 +1,1055 @@
+# NumPy static imports for Cython >= 3.0
+#
+# If any of the PyArray_* functions are called, import_array must be
+# called first. This is done automatically by Cython 3.0+ if a call
+# is not detected inside of the module.
+#
+# Author: Dag Sverre Seljebotn
+#
+
+from cpython.ref cimport Py_INCREF
+from cpython.object cimport PyObject, PyTypeObject, PyObject_TypeCheck
+cimport libc.stdio as stdio
+
+
+cdef extern from *:
+ # Leave a marker that the NumPy declarations came from NumPy itself and not from Cython.
+ # See https://github.com/cython/cython/issues/3573
+ """
+ /* Using NumPy API declarations from "numpy/__init__.cython-30.pxd" */
+ """
+
+
+cdef extern from "Python.h":
+ ctypedef Py_ssize_t Py_intptr_t
+
+cdef extern from "numpy/arrayobject.h":
+ ctypedef Py_intptr_t npy_intp
+ ctypedef size_t npy_uintp
+
+ cdef enum NPY_TYPES:
+ NPY_BOOL
+ NPY_BYTE
+ NPY_UBYTE
+ NPY_SHORT
+ NPY_USHORT
+ NPY_INT
+ NPY_UINT
+ NPY_LONG
+ NPY_ULONG
+ NPY_LONGLONG
+ NPY_ULONGLONG
+ NPY_FLOAT
+ NPY_DOUBLE
+ NPY_LONGDOUBLE
+ NPY_CFLOAT
+ NPY_CDOUBLE
+ NPY_CLONGDOUBLE
+ NPY_OBJECT
+ NPY_STRING
+ NPY_UNICODE
+ NPY_VOID
+ NPY_DATETIME
+ NPY_TIMEDELTA
+ NPY_NTYPES
+ NPY_NOTYPE
+
+ NPY_INT8
+ NPY_INT16
+ NPY_INT32
+ NPY_INT64
+ NPY_INT128
+ NPY_INT256
+ NPY_UINT8
+ NPY_UINT16
+ NPY_UINT32
+ NPY_UINT64
+ NPY_UINT128
+ NPY_UINT256
+ NPY_FLOAT16
+ NPY_FLOAT32
+ NPY_FLOAT64
+ NPY_FLOAT80
+ NPY_FLOAT96
+ NPY_FLOAT128
+ NPY_FLOAT256
+ NPY_COMPLEX32
+ NPY_COMPLEX64
+ NPY_COMPLEX128
+ NPY_COMPLEX160
+ NPY_COMPLEX192
+ NPY_COMPLEX256
+ NPY_COMPLEX512
+
+ NPY_INTP
+
+ ctypedef enum NPY_ORDER:
+ NPY_ANYORDER
+ NPY_CORDER
+ NPY_FORTRANORDER
+ NPY_KEEPORDER
+
+ ctypedef enum NPY_CASTING:
+ NPY_NO_CASTING
+ NPY_EQUIV_CASTING
+ NPY_SAFE_CASTING
+ NPY_SAME_KIND_CASTING
+ NPY_UNSAFE_CASTING
+
+ ctypedef enum NPY_CLIPMODE:
+ NPY_CLIP
+ NPY_WRAP
+ NPY_RAISE
+
+ ctypedef enum NPY_SCALARKIND:
+ NPY_NOSCALAR,
+ NPY_BOOL_SCALAR,
+ NPY_INTPOS_SCALAR,
+ NPY_INTNEG_SCALAR,
+ NPY_FLOAT_SCALAR,
+ NPY_COMPLEX_SCALAR,
+ NPY_OBJECT_SCALAR
+
+ ctypedef enum NPY_SORTKIND:
+ NPY_QUICKSORT
+ NPY_HEAPSORT
+ NPY_MERGESORT
+
+ ctypedef enum NPY_SEARCHSIDE:
+ NPY_SEARCHLEFT
+ NPY_SEARCHRIGHT
+
+ enum:
+ # DEPRECATED since NumPy 1.7 ! Do not use in new code!
+ NPY_C_CONTIGUOUS
+ NPY_F_CONTIGUOUS
+ NPY_CONTIGUOUS
+ NPY_FORTRAN
+ NPY_OWNDATA
+ NPY_FORCECAST
+ NPY_ENSURECOPY
+ NPY_ENSUREARRAY
+ NPY_ELEMENTSTRIDES
+ NPY_ALIGNED
+ NPY_NOTSWAPPED
+ NPY_WRITEABLE
+ NPY_UPDATEIFCOPY
+ NPY_ARR_HAS_DESCR
+
+ NPY_BEHAVED
+ NPY_BEHAVED_NS
+ NPY_CARRAY
+ NPY_CARRAY_RO
+ NPY_FARRAY
+ NPY_FARRAY_RO
+ NPY_DEFAULT
+
+ NPY_IN_ARRAY
+ NPY_OUT_ARRAY
+ NPY_INOUT_ARRAY
+ NPY_IN_FARRAY
+ NPY_OUT_FARRAY
+ NPY_INOUT_FARRAY
+
+ NPY_UPDATE_ALL
+
+ enum:
+ # Added in NumPy 1.7 to replace the deprecated enums above.
+ NPY_ARRAY_C_CONTIGUOUS
+ NPY_ARRAY_F_CONTIGUOUS
+ NPY_ARRAY_OWNDATA
+ NPY_ARRAY_FORCECAST
+ NPY_ARRAY_ENSURECOPY
+ NPY_ARRAY_ENSUREARRAY
+ NPY_ARRAY_ELEMENTSTRIDES
+ NPY_ARRAY_ALIGNED
+ NPY_ARRAY_NOTSWAPPED
+ NPY_ARRAY_WRITEABLE
+ NPY_ARRAY_UPDATEIFCOPY
+
+ NPY_ARRAY_BEHAVED
+ NPY_ARRAY_BEHAVED_NS
+ NPY_ARRAY_CARRAY
+ NPY_ARRAY_CARRAY_RO
+ NPY_ARRAY_FARRAY
+ NPY_ARRAY_FARRAY_RO
+ NPY_ARRAY_DEFAULT
+
+ NPY_ARRAY_IN_ARRAY
+ NPY_ARRAY_OUT_ARRAY
+ NPY_ARRAY_INOUT_ARRAY
+ NPY_ARRAY_IN_FARRAY
+ NPY_ARRAY_OUT_FARRAY
+ NPY_ARRAY_INOUT_FARRAY
+
+ NPY_ARRAY_UPDATE_ALL
+
+ cdef enum:
+ NPY_MAXDIMS
+
+ npy_intp NPY_MAX_ELSIZE
+
+ ctypedef void (*PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *, void *)
+
+ ctypedef struct PyArray_ArrayDescr:
+ # shape is a tuple, but Cython doesn't support "tuple shape"
+ # inside a non-PyObject declaration, so we have to declare it
+ # as just a PyObject*.
+ PyObject* shape
+
+ ctypedef struct PyArray_Descr:
+ pass
+
+ ctypedef class numpy.dtype [object PyArray_Descr, check_size ignore]:
+ # Use PyDataType_* macros when possible, however there are no macros
+ # for accessing some of the fields, so some are defined.
+ cdef PyTypeObject* typeobj
+ cdef char kind
+ cdef char type
+ # Numpy sometimes mutates this without warning (e.g. it'll
+ # sometimes change "|" to "<" in shared dtype objects on
+ # little-endian machines). If this matters to you, use
+ # PyArray_IsNativeByteOrder(dtype.byteorder) instead of
+ # directly accessing this field.
+ cdef char byteorder
+ cdef char flags
+ cdef int type_num
+ cdef int itemsize "elsize"
+ cdef int alignment
+ cdef object fields
+ cdef tuple names
+ # Use PyDataType_HASSUBARRAY to test whether this field is
+ # valid (the pointer can be NULL). Most users should access
+ # this field via the inline helper method PyDataType_SHAPE.
+ cdef PyArray_ArrayDescr* subarray
+
+ ctypedef class numpy.flatiter [object PyArrayIterObject, check_size ignore]:
+ # Use through macros
+ pass
+
+ ctypedef class numpy.broadcast [object PyArrayMultiIterObject, check_size ignore]:
+ # Use through macros
+ pass
+
+ ctypedef struct PyArrayObject:
+ # For use in situations where ndarray can't replace PyArrayObject*,
+ # like PyArrayObject**.
+ pass
+
+ ctypedef class numpy.ndarray [object PyArrayObject, check_size ignore]:
+ cdef __cythonbufferdefaults__ = {"mode": "strided"}
+
+ # NOTE: no field declarations since direct access is deprecated since NumPy 1.7
+ # Instead, we use properties that map to the corresponding C-API functions.
+
+ @property
+ cdef inline PyObject* base(self) nogil:
+ """Returns a borrowed reference to the object owning the data/memory.
+ """
+ return PyArray_BASE(self)
+
+ @property
+ cdef inline dtype descr(self):
+ """Returns an owned reference to the dtype of the array.
+ """
+ return PyArray_DESCR(self)
+
+ @property
+ cdef inline int ndim(self) nogil:
+ """Returns the number of dimensions in the array.
+ """
+ return PyArray_NDIM(self)
+
+ @property
+ cdef inline npy_intp *shape(self) nogil:
+ """Returns a pointer to the dimensions/shape of the array.
+ The number of elements matches the number of dimensions of the array (ndim).
+ Can return NULL for 0-dimensional arrays.
+ """
+ return PyArray_DIMS(self)
+
+ @property
+ cdef inline npy_intp *strides(self) nogil:
+ """Returns a pointer to the strides of the array.
+ The number of elements matches the number of dimensions of the array (ndim).
+ """
+ return PyArray_STRIDES(self)
+
+ @property
+ cdef inline npy_intp size(self) nogil:
+ """Returns the total size (in number of elements) of the array.
+ """
+ return PyArray_SIZE(self)
+
+ @property
+ cdef inline char* data(self) nogil:
+ """The pointer to the data buffer as a char*.
+ This is provided for legacy reasons to avoid direct struct field access.
+ For new code that needs this access, you probably want to cast the result
+ of `PyArray_DATA()` instead, which returns a 'void*'.
+ """
+ return PyArray_BYTES(self)
+
+ ctypedef unsigned char npy_bool
+
+ ctypedef signed char npy_byte
+ ctypedef signed short npy_short
+ ctypedef signed int npy_int
+ ctypedef signed long npy_long
+ ctypedef signed long long npy_longlong
+
+ ctypedef unsigned char npy_ubyte
+ ctypedef unsigned short npy_ushort
+ ctypedef unsigned int npy_uint
+ ctypedef unsigned long npy_ulong
+ ctypedef unsigned long long npy_ulonglong
+
+ ctypedef float npy_float
+ ctypedef double npy_double
+ ctypedef long double npy_longdouble
+
+ ctypedef signed char npy_int8
+ ctypedef signed short npy_int16
+ ctypedef signed int npy_int32
+ ctypedef signed long long npy_int64
+ ctypedef signed long long npy_int96
+ ctypedef signed long long npy_int128
+
+ ctypedef unsigned char npy_uint8
+ ctypedef unsigned short npy_uint16
+ ctypedef unsigned int npy_uint32
+ ctypedef unsigned long long npy_uint64
+ ctypedef unsigned long long npy_uint96
+ ctypedef unsigned long long npy_uint128
+
+ ctypedef float npy_float32
+ ctypedef double npy_float64
+ ctypedef long double npy_float80
+ ctypedef long double npy_float96
+ ctypedef long double npy_float128
+
+ ctypedef struct npy_cfloat:
+ float real
+ float imag
+
+ ctypedef struct npy_cdouble:
+ double real
+ double imag
+
+ ctypedef struct npy_clongdouble:
+ long double real
+ long double imag
+
+ ctypedef struct npy_complex64:
+ float real
+ float imag
+
+ ctypedef struct npy_complex128:
+ double real
+ double imag
+
+ ctypedef struct npy_complex160:
+ long double real
+ long double imag
+
+ ctypedef struct npy_complex192:
+ long double real
+ long double imag
+
+ ctypedef struct npy_complex256:
+ long double real
+ long double imag
+
+ ctypedef struct PyArray_Dims:
+ npy_intp *ptr
+ int len
+
+ int _import_array() except -1
+ # A second definition so _import_array isn't marked as used when we use it here.
+ # Do not use - subject to change any time.
+ int __pyx_import_array "_import_array"() except -1
+
+ #
+ # Macros from ndarrayobject.h
+ #
+ bint PyArray_CHKFLAGS(ndarray m, int flags) nogil
+ bint PyArray_IS_C_CONTIGUOUS(ndarray arr) nogil
+ bint PyArray_IS_F_CONTIGUOUS(ndarray arr) nogil
+ bint PyArray_ISCONTIGUOUS(ndarray m) nogil
+ bint PyArray_ISWRITEABLE(ndarray m) nogil
+ bint PyArray_ISALIGNED(ndarray m) nogil
+
+ int PyArray_NDIM(ndarray) nogil
+ bint PyArray_ISONESEGMENT(ndarray) nogil
+ bint PyArray_ISFORTRAN(ndarray) nogil
+ int PyArray_FORTRANIF(ndarray) nogil
+
+ void* PyArray_DATA(ndarray) nogil
+ char* PyArray_BYTES(ndarray) nogil
+
+ npy_intp* PyArray_DIMS(ndarray) nogil
+ npy_intp* PyArray_STRIDES(ndarray) nogil
+ npy_intp PyArray_DIM(ndarray, size_t) nogil
+ npy_intp PyArray_STRIDE(ndarray, size_t) nogil
+
+ PyObject *PyArray_BASE(ndarray) nogil # returns borrowed reference!
+ PyArray_Descr *PyArray_DESCR(ndarray) nogil # returns borrowed reference to dtype!
+ PyArray_Descr *PyArray_DTYPE(ndarray) nogil # returns borrowed reference to dtype! NP 1.7+ alias for descr.
+ int PyArray_FLAGS(ndarray) nogil
+ void PyArray_CLEARFLAGS(ndarray, int flags) nogil # Added in NumPy 1.7
+ void PyArray_ENABLEFLAGS(ndarray, int flags) nogil # Added in NumPy 1.7
+ npy_intp PyArray_ITEMSIZE(ndarray) nogil
+ int PyArray_TYPE(ndarray arr) nogil
+
+ object PyArray_GETITEM(ndarray arr, void *itemptr)
+ int PyArray_SETITEM(ndarray arr, void *itemptr, object obj)
+
+ bint PyTypeNum_ISBOOL(int) nogil
+ bint PyTypeNum_ISUNSIGNED(int) nogil
+ bint PyTypeNum_ISSIGNED(int) nogil
+ bint PyTypeNum_ISINTEGER(int) nogil
+ bint PyTypeNum_ISFLOAT(int) nogil
+ bint PyTypeNum_ISNUMBER(int) nogil
+ bint PyTypeNum_ISSTRING(int) nogil
+ bint PyTypeNum_ISCOMPLEX(int) nogil
+ bint PyTypeNum_ISPYTHON(int) nogil
+ bint PyTypeNum_ISFLEXIBLE(int) nogil
+ bint PyTypeNum_ISUSERDEF(int) nogil
+ bint PyTypeNum_ISEXTENDED(int) nogil
+ bint PyTypeNum_ISOBJECT(int) nogil
+
+ bint PyDataType_ISBOOL(dtype) nogil
+ bint PyDataType_ISUNSIGNED(dtype) nogil
+ bint PyDataType_ISSIGNED(dtype) nogil
+ bint PyDataType_ISINTEGER(dtype) nogil
+ bint PyDataType_ISFLOAT(dtype) nogil
+ bint PyDataType_ISNUMBER(dtype) nogil
+ bint PyDataType_ISSTRING(dtype) nogil
+ bint PyDataType_ISCOMPLEX(dtype) nogil
+ bint PyDataType_ISPYTHON(dtype) nogil
+ bint PyDataType_ISFLEXIBLE(dtype) nogil
+ bint PyDataType_ISUSERDEF(dtype) nogil
+ bint PyDataType_ISEXTENDED(dtype) nogil
+ bint PyDataType_ISOBJECT(dtype) nogil
+ bint PyDataType_HASFIELDS(dtype) nogil
+ bint PyDataType_HASSUBARRAY(dtype) nogil
+
+ bint PyArray_ISBOOL(ndarray) nogil
+ bint PyArray_ISUNSIGNED(ndarray) nogil
+ bint PyArray_ISSIGNED(ndarray) nogil
+ bint PyArray_ISINTEGER(ndarray) nogil
+ bint PyArray_ISFLOAT(ndarray) nogil
+ bint PyArray_ISNUMBER(ndarray) nogil
+ bint PyArray_ISSTRING(ndarray) nogil
+ bint PyArray_ISCOMPLEX(ndarray) nogil
+ bint PyArray_ISPYTHON(ndarray) nogil
+ bint PyArray_ISFLEXIBLE(ndarray) nogil
+ bint PyArray_ISUSERDEF(ndarray) nogil
+ bint PyArray_ISEXTENDED(ndarray) nogil
+ bint PyArray_ISOBJECT(ndarray) nogil
+ bint PyArray_HASFIELDS(ndarray) nogil
+
+ bint PyArray_ISVARIABLE(ndarray) nogil
+
+ bint PyArray_SAFEALIGNEDCOPY(ndarray) nogil
+ bint PyArray_ISNBO(char) nogil # works on ndarray.byteorder
+ bint PyArray_IsNativeByteOrder(char) nogil # works on ndarray.byteorder
+ bint PyArray_ISNOTSWAPPED(ndarray) nogil
+ bint PyArray_ISBYTESWAPPED(ndarray) nogil
+
+ bint PyArray_FLAGSWAP(ndarray, int) nogil
+
+ bint PyArray_ISCARRAY(ndarray) nogil
+ bint PyArray_ISCARRAY_RO(ndarray) nogil
+ bint PyArray_ISFARRAY(ndarray) nogil
+ bint PyArray_ISFARRAY_RO(ndarray) nogil
+ bint PyArray_ISBEHAVED(ndarray) nogil
+ bint PyArray_ISBEHAVED_RO(ndarray) nogil
+
+
+ bint PyDataType_ISNOTSWAPPED(dtype) nogil
+ bint PyDataType_ISBYTESWAPPED(dtype) nogil
+
+ bint PyArray_DescrCheck(object)
+
+ bint PyArray_Check(object)
+ bint PyArray_CheckExact(object)
+
+ # Cannot be supported due to out arg:
+ # bint PyArray_HasArrayInterfaceType(object, dtype, object, object&)
+ # bint PyArray_HasArrayInterface(op, out)
+
+
+ bint PyArray_IsZeroDim(object)
+ # Cannot be supported due to ## ## in macro:
+ # bint PyArray_IsScalar(object, verbatim work)
+ bint PyArray_CheckScalar(object)
+ bint PyArray_IsPythonNumber(object)
+ bint PyArray_IsPythonScalar(object)
+ bint PyArray_IsAnyScalar(object)
+ bint PyArray_CheckAnyScalar(object)
+
+ ndarray PyArray_GETCONTIGUOUS(ndarray)
+ bint PyArray_SAMESHAPE(ndarray, ndarray) nogil
+ npy_intp PyArray_SIZE(ndarray) nogil
+ npy_intp PyArray_NBYTES(ndarray) nogil
+
+ object PyArray_FROM_O(object)
+ object PyArray_FROM_OF(object m, int flags)
+ object PyArray_FROM_OT(object m, int type)
+ object PyArray_FROM_OTF(object m, int type, int flags)
+ object PyArray_FROMANY(object m, int type, int min, int max, int flags)
+ object PyArray_ZEROS(int nd, npy_intp* dims, int type, int fortran)
+ object PyArray_EMPTY(int nd, npy_intp* dims, int type, int fortran)
+ void PyArray_FILLWBYTE(object, int val)
+ npy_intp PyArray_REFCOUNT(object)
+ object PyArray_ContiguousFromAny(op, int, int min_depth, int max_depth)
+ unsigned char PyArray_EquivArrTypes(ndarray a1, ndarray a2)
+ bint PyArray_EquivByteorders(int b1, int b2) nogil
+ object PyArray_SimpleNew(int nd, npy_intp* dims, int typenum)
+ object PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data)
+ #object PyArray_SimpleNewFromDescr(int nd, npy_intp* dims, dtype descr)
+ object PyArray_ToScalar(void* data, ndarray arr)
+
+ void* PyArray_GETPTR1(ndarray m, npy_intp i) nogil
+ void* PyArray_GETPTR2(ndarray m, npy_intp i, npy_intp j) nogil
+ void* PyArray_GETPTR3(ndarray m, npy_intp i, npy_intp j, npy_intp k) nogil
+ void* PyArray_GETPTR4(ndarray m, npy_intp i, npy_intp j, npy_intp k, npy_intp l) nogil
+
+ void PyArray_XDECREF_ERR(ndarray)
+ # Cannot be supported due to out arg
+ # void PyArray_DESCR_REPLACE(descr)
+
+
+ object PyArray_Copy(ndarray)
+ object PyArray_FromObject(object op, int type, int min_depth, int max_depth)
+ object PyArray_ContiguousFromObject(object op, int type, int min_depth, int max_depth)
+ object PyArray_CopyFromObject(object op, int type, int min_depth, int max_depth)
+
+ object PyArray_Cast(ndarray mp, int type_num)
+ object PyArray_Take(ndarray ap, object items, int axis)
+ object PyArray_Put(ndarray ap, object items, object values)
+
+ void PyArray_ITER_RESET(flatiter it) nogil
+ void PyArray_ITER_NEXT(flatiter it) nogil
+ void PyArray_ITER_GOTO(flatiter it, npy_intp* destination) nogil
+ void PyArray_ITER_GOTO1D(flatiter it, npy_intp ind) nogil
+ void* PyArray_ITER_DATA(flatiter it) nogil
+ bint PyArray_ITER_NOTDONE(flatiter it) nogil
+
+ void PyArray_MultiIter_RESET(broadcast multi) nogil
+ void PyArray_MultiIter_NEXT(broadcast multi) nogil
+ void PyArray_MultiIter_GOTO(broadcast multi, npy_intp dest) nogil
+ void PyArray_MultiIter_GOTO1D(broadcast multi, npy_intp ind) nogil
+ void* PyArray_MultiIter_DATA(broadcast multi, npy_intp i) nogil
+ void PyArray_MultiIter_NEXTi(broadcast multi, npy_intp i) nogil
+ bint PyArray_MultiIter_NOTDONE(broadcast multi) nogil
+
+ # Functions from __multiarray_api.h
+
+ # Functions taking dtype and returning object/ndarray are disabled
+ # for now as they steal dtype references. I'm conservative and disable
+ # more than is probably needed until it can be checked further.
+ int PyArray_SetNumericOps (object)
+ object PyArray_GetNumericOps ()
+ int PyArray_INCREF (ndarray)
+ int PyArray_XDECREF (ndarray)
+ void PyArray_SetStringFunction (object, int)
+ dtype PyArray_DescrFromType (int)
+ object PyArray_TypeObjectFromType (int)
+ char * PyArray_Zero (ndarray)
+ char * PyArray_One (ndarray)
+ #object PyArray_CastToType (ndarray, dtype, int)
+ int PyArray_CastTo (ndarray, ndarray)
+ int PyArray_CastAnyTo (ndarray, ndarray)
+ int PyArray_CanCastSafely (int, int)
+ npy_bool PyArray_CanCastTo (dtype, dtype)
+ int PyArray_ObjectType (object, int)
+ dtype PyArray_DescrFromObject (object, dtype)
+ #ndarray* PyArray_ConvertToCommonType (object, int *)
+ dtype PyArray_DescrFromScalar (object)
+ dtype PyArray_DescrFromTypeObject (object)
+ npy_intp PyArray_Size (object)
+ #object PyArray_Scalar (void *, dtype, object)
+ #object PyArray_FromScalar (object, dtype)
+ void PyArray_ScalarAsCtype (object, void *)
+ #int PyArray_CastScalarToCtype (object, void *, dtype)
+ #int PyArray_CastScalarDirect (object, dtype, void *, int)
+ object PyArray_ScalarFromObject (object)
+ #PyArray_VectorUnaryFunc * PyArray_GetCastFunc (dtype, int)
+ object PyArray_FromDims (int, int *, int)
+ #object PyArray_FromDimsAndDataAndDescr (int, int *, dtype, char *)
+ #object PyArray_FromAny (object, dtype, int, int, int, object)
+ object PyArray_EnsureArray (object)
+ object PyArray_EnsureAnyArray (object)
+ #object PyArray_FromFile (stdio.FILE *, dtype, npy_intp, char *)
+ #object PyArray_FromString (char *, npy_intp, dtype, npy_intp, char *)
+ #object PyArray_FromBuffer (object, dtype, npy_intp, npy_intp)
+ #object PyArray_FromIter (object, dtype, npy_intp)
+ object PyArray_Return (ndarray)
+ #object PyArray_GetField (ndarray, dtype, int)
+ #int PyArray_SetField (ndarray, dtype, int, object)
+ object PyArray_Byteswap (ndarray, npy_bool)
+ object PyArray_Resize (ndarray, PyArray_Dims *, int, NPY_ORDER)
+ int PyArray_MoveInto (ndarray, ndarray)
+ int PyArray_CopyInto (ndarray, ndarray)
+ int PyArray_CopyAnyInto (ndarray, ndarray)
+ int PyArray_CopyObject (ndarray, object)
+ object PyArray_NewCopy (ndarray, NPY_ORDER)
+ object PyArray_ToList (ndarray)
+ object PyArray_ToString (ndarray, NPY_ORDER)
+ int PyArray_ToFile (ndarray, stdio.FILE *, char *, char *)
+ int PyArray_Dump (object, object, int)
+ object PyArray_Dumps (object, int)
+ int PyArray_ValidType (int)
+ void PyArray_UpdateFlags (ndarray, int)
+ object PyArray_New (type, int, npy_intp *, int, npy_intp *, void *, int, int, object)
+ #object PyArray_NewFromDescr (type, dtype, int, npy_intp *, npy_intp *, void *, int, object)
+ #dtype PyArray_DescrNew (dtype)
+ dtype PyArray_DescrNewFromType (int)
+ double PyArray_GetPriority (object, double)
+ object PyArray_IterNew (object)
+ object PyArray_MultiIterNew (int, ...)
+
+ int PyArray_PyIntAsInt (object)
+ npy_intp PyArray_PyIntAsIntp (object)
+ int PyArray_Broadcast (broadcast)
+ void PyArray_FillObjectArray (ndarray, object)
+ int PyArray_FillWithScalar (ndarray, object)
+ npy_bool PyArray_CheckStrides (int, int, npy_intp, npy_intp, npy_intp *, npy_intp *)
+ dtype PyArray_DescrNewByteorder (dtype, char)
+ object PyArray_IterAllButAxis (object, int *)
+ #object PyArray_CheckFromAny (object, dtype, int, int, int, object)
+ #object PyArray_FromArray (ndarray, dtype, int)
+ object PyArray_FromInterface (object)
+ object PyArray_FromStructInterface (object)
+ #object PyArray_FromArrayAttr (object, dtype, object)
+ #NPY_SCALARKIND PyArray_ScalarKind (int, ndarray*)
+ int PyArray_CanCoerceScalar (int, int, NPY_SCALARKIND)
+ object PyArray_NewFlagsObject (object)
+ npy_bool PyArray_CanCastScalar (type, type)
+ #int PyArray_CompareUCS4 (npy_ucs4 *, npy_ucs4 *, register size_t)
+ int PyArray_RemoveSmallest (broadcast)
+ int PyArray_ElementStrides (object)
+ void PyArray_Item_INCREF (char *, dtype)
+ void PyArray_Item_XDECREF (char *, dtype)
+ object PyArray_FieldNames (object)
+ object PyArray_Transpose (ndarray, PyArray_Dims *)
+ object PyArray_TakeFrom (ndarray, object, int, ndarray, NPY_CLIPMODE)
+ object PyArray_PutTo (ndarray, object, object, NPY_CLIPMODE)
+ object PyArray_PutMask (ndarray, object, object)
+ object PyArray_Repeat (ndarray, object, int)
+ object PyArray_Choose (ndarray, object, ndarray, NPY_CLIPMODE)
+ int PyArray_Sort (ndarray, int, NPY_SORTKIND)
+ object PyArray_ArgSort (ndarray, int, NPY_SORTKIND)
+ object PyArray_SearchSorted (ndarray, object, NPY_SEARCHSIDE, PyObject *)
+ object PyArray_ArgMax (ndarray, int, ndarray)
+ object PyArray_ArgMin (ndarray, int, ndarray)
+ object PyArray_Reshape (ndarray, object)
+ object PyArray_Newshape (ndarray, PyArray_Dims *, NPY_ORDER)
+ object PyArray_Squeeze (ndarray)
+ #object PyArray_View (ndarray, dtype, type)
+ object PyArray_SwapAxes (ndarray, int, int)
+ object PyArray_Max (ndarray, int, ndarray)
+ object PyArray_Min (ndarray, int, ndarray)
+ object PyArray_Ptp (ndarray, int, ndarray)
+ object PyArray_Mean (ndarray, int, int, ndarray)
+ object PyArray_Trace (ndarray, int, int, int, int, ndarray)
+ object PyArray_Diagonal (ndarray, int, int, int)
+ object PyArray_Clip (ndarray, object, object, ndarray)
+ object PyArray_Conjugate (ndarray, ndarray)
+ object PyArray_Nonzero (ndarray)
+ object PyArray_Std (ndarray, int, int, ndarray, int)
+ object PyArray_Sum (ndarray, int, int, ndarray)
+ object PyArray_CumSum (ndarray, int, int, ndarray)
+ object PyArray_Prod (ndarray, int, int, ndarray)
+ object PyArray_CumProd (ndarray, int, int, ndarray)
+ object PyArray_All (ndarray, int, ndarray)
+ object PyArray_Any (ndarray, int, ndarray)
+ object PyArray_Compress (ndarray, object, int, ndarray)
+ object PyArray_Flatten (ndarray, NPY_ORDER)
+ object PyArray_Ravel (ndarray, NPY_ORDER)
+ npy_intp PyArray_MultiplyList (npy_intp *, int)
+ int PyArray_MultiplyIntList (int *, int)
+ void * PyArray_GetPtr (ndarray, npy_intp*)
+ int PyArray_CompareLists (npy_intp *, npy_intp *, int)
+ #int PyArray_AsCArray (object*, void *, npy_intp *, int, dtype)
+ #int PyArray_As1D (object*, char **, int *, int)
+ #int PyArray_As2D (object*, char ***, int *, int *, int)
+ int PyArray_Free (object, void *)
+ #int PyArray_Converter (object, object*)
+ int PyArray_IntpFromSequence (object, npy_intp *, int)
+ object PyArray_Concatenate (object, int)
+ object PyArray_InnerProduct (object, object)
+ object PyArray_MatrixProduct (object, object)
+ object PyArray_CopyAndTranspose (object)
+ object PyArray_Correlate (object, object, int)
+ int PyArray_TypestrConvert (int, int)
+ #int PyArray_DescrConverter (object, dtype*)
+ #int PyArray_DescrConverter2 (object, dtype*)
+ int PyArray_IntpConverter (object, PyArray_Dims *)
+ #int PyArray_BufferConverter (object, chunk)
+ int PyArray_AxisConverter (object, int *)
+ int PyArray_BoolConverter (object, npy_bool *)
+ int PyArray_ByteorderConverter (object, char *)
+ int PyArray_OrderConverter (object, NPY_ORDER *)
+ unsigned char PyArray_EquivTypes (dtype, dtype)
+ #object PyArray_Zeros (int, npy_intp *, dtype, int)
+ #object PyArray_Empty (int, npy_intp *, dtype, int)
+ object PyArray_Where (object, object, object)
+ object PyArray_Arange (double, double, double, int)
+ #object PyArray_ArangeObj (object, object, object, dtype)
+ int PyArray_SortkindConverter (object, NPY_SORTKIND *)
+ object PyArray_LexSort (object, int)
+ object PyArray_Round (ndarray, int, ndarray)
+ unsigned char PyArray_EquivTypenums (int, int)
+ int PyArray_RegisterDataType (dtype)
+ int PyArray_RegisterCastFunc (dtype, int, PyArray_VectorUnaryFunc *)
+ int PyArray_RegisterCanCast (dtype, int, NPY_SCALARKIND)
+ #void PyArray_InitArrFuncs (PyArray_ArrFuncs *)
+ object PyArray_IntTupleFromIntp (int, npy_intp *)
+ int PyArray_TypeNumFromName (char *)
+ int PyArray_ClipmodeConverter (object, NPY_CLIPMODE *)
+ #int PyArray_OutputConverter (object, ndarray*)
+ object PyArray_BroadcastToShape (object, npy_intp *, int)
+ void _PyArray_SigintHandler (int)
+ void* _PyArray_GetSigintBuf ()
+ #int PyArray_DescrAlignConverter (object, dtype*)
+ #int PyArray_DescrAlignConverter2 (object, dtype*)
+ int PyArray_SearchsideConverter (object, void *)
+ object PyArray_CheckAxis (ndarray, int *, int)
+ npy_intp PyArray_OverflowMultiplyList (npy_intp *, int)
+ int PyArray_CompareString (char *, char *, size_t)
+ int PyArray_SetBaseObject(ndarray, base) # NOTE: steals a reference to base! Use "set_array_base()" instead.
+
+
+# Typedefs that matches the runtime dtype objects in
+# the numpy module.
+
+# The ones that are commented out needs an IFDEF function
+# in Cython to enable them only on the right systems.
+
+ctypedef npy_int8 int8_t
+ctypedef npy_int16 int16_t
+ctypedef npy_int32 int32_t
+ctypedef npy_int64 int64_t
+#ctypedef npy_int96 int96_t
+#ctypedef npy_int128 int128_t
+
+ctypedef npy_uint8 uint8_t
+ctypedef npy_uint16 uint16_t
+ctypedef npy_uint32 uint32_t
+ctypedef npy_uint64 uint64_t
+#ctypedef npy_uint96 uint96_t
+#ctypedef npy_uint128 uint128_t
+
+ctypedef npy_float32 float32_t
+ctypedef npy_float64 float64_t
+#ctypedef npy_float80 float80_t
+#ctypedef npy_float128 float128_t
+
+ctypedef float complex complex64_t
+ctypedef double complex complex128_t
+
+# The int types are mapped a bit surprising --
+# numpy.int corresponds to 'l' and numpy.long to 'q'
+ctypedef npy_long int_t
+ctypedef npy_longlong long_t
+ctypedef npy_longlong longlong_t
+
+ctypedef npy_ulong uint_t
+ctypedef npy_ulonglong ulong_t
+ctypedef npy_ulonglong ulonglong_t
+
+ctypedef npy_intp intp_t
+ctypedef npy_uintp uintp_t
+
+ctypedef npy_double float_t
+ctypedef npy_double double_t
+ctypedef npy_longdouble longdouble_t
+
+ctypedef npy_cfloat cfloat_t
+ctypedef npy_cdouble cdouble_t
+ctypedef npy_clongdouble clongdouble_t
+
+ctypedef npy_cdouble complex_t
+
+cdef inline object PyArray_MultiIterNew1(a):
+ return PyArray_MultiIterNew(1, a)
+
+cdef inline object PyArray_MultiIterNew2(a, b):
+ return PyArray_MultiIterNew(2, a, b)
+
+cdef inline object PyArray_MultiIterNew3(a, b, c):
+ return PyArray_MultiIterNew(3, a, b, c)
+
+cdef inline object PyArray_MultiIterNew4(a, b, c, d):
+ return PyArray_MultiIterNew(4, a, b, c, d)
+
+cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
+ return PyArray_MultiIterNew(5, a, b, c, d, e)
+
+cdef inline tuple PyDataType_SHAPE(dtype d):
+ if PyDataType_HASSUBARRAY(d):
+ return d.subarray.shape
+ else:
+ return ()
+
+
+cdef extern from "numpy/ndarrayobject.h":
+ PyTypeObject PyTimedeltaArrType_Type
+ PyTypeObject PyDatetimeArrType_Type
+ ctypedef int64_t npy_timedelta
+ ctypedef int64_t npy_datetime
+
+cdef extern from "numpy/ndarraytypes.h":
+ ctypedef struct PyArray_DatetimeMetaData:
+ NPY_DATETIMEUNIT base
+ int64_t num
+
+cdef extern from "numpy/arrayscalars.h":
+
+ # abstract types
+ ctypedef class numpy.generic [object PyObject]:
+ pass
+ ctypedef class numpy.number [object PyObject]:
+ pass
+ ctypedef class numpy.integer [object PyObject]:
+ pass
+ ctypedef class numpy.signedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.unsignedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.inexact [object PyObject]:
+ pass
+ ctypedef class numpy.floating [object PyObject]:
+ pass
+ ctypedef class numpy.complexfloating [object PyObject]:
+ pass
+ ctypedef class numpy.flexible [object PyObject]:
+ pass
+ ctypedef class numpy.character [object PyObject]:
+ pass
+
+ ctypedef struct PyDatetimeScalarObject:
+ # PyObject_HEAD
+ npy_datetime obval
+ PyArray_DatetimeMetaData obmeta
+
+ ctypedef struct PyTimedeltaScalarObject:
+ # PyObject_HEAD
+ npy_timedelta obval
+ PyArray_DatetimeMetaData obmeta
+
+ ctypedef enum NPY_DATETIMEUNIT:
+ NPY_FR_Y
+ NPY_FR_M
+ NPY_FR_W
+ NPY_FR_D
+ NPY_FR_B
+ NPY_FR_h
+ NPY_FR_m
+ NPY_FR_s
+ NPY_FR_ms
+ NPY_FR_us
+ NPY_FR_ns
+ NPY_FR_ps
+ NPY_FR_fs
+ NPY_FR_as
+
+
+#
+# ufunc API
+#
+
+cdef extern from "numpy/ufuncobject.h":
+
+ ctypedef void (*PyUFuncGenericFunction) (char **, npy_intp *, npy_intp *, void *)
+
+ ctypedef class numpy.ufunc [object PyUFuncObject, check_size ignore]:
+ cdef:
+ int nin, nout, nargs
+ int identity
+ PyUFuncGenericFunction *functions
+ void **data
+ int ntypes
+ int check_return
+ char *name
+ char *types
+ char *doc
+ void *ptr
+ PyObject *obj
+ PyObject *userloops
+
+ cdef enum:
+ PyUFunc_Zero
+ PyUFunc_One
+ PyUFunc_None
+ UFUNC_ERR_IGNORE
+ UFUNC_ERR_WARN
+ UFUNC_ERR_RAISE
+ UFUNC_ERR_CALL
+ UFUNC_ERR_PRINT
+ UFUNC_ERR_LOG
+ UFUNC_MASK_DIVIDEBYZERO
+ UFUNC_MASK_OVERFLOW
+ UFUNC_MASK_UNDERFLOW
+ UFUNC_MASK_INVALID
+ UFUNC_SHIFT_DIVIDEBYZERO
+ UFUNC_SHIFT_OVERFLOW
+ UFUNC_SHIFT_UNDERFLOW
+ UFUNC_SHIFT_INVALID
+ UFUNC_FPE_DIVIDEBYZERO
+ UFUNC_FPE_OVERFLOW
+ UFUNC_FPE_UNDERFLOW
+ UFUNC_FPE_INVALID
+ UFUNC_ERR_DEFAULT
+ UFUNC_ERR_DEFAULT2
+
+ object PyUFunc_FromFuncAndData(PyUFuncGenericFunction *,
+ void **, char *, int, int, int, int, char *, char *, int)
+ int PyUFunc_RegisterLoopForType(ufunc, int,
+ PyUFuncGenericFunction, int *, void *)
+ int PyUFunc_GenericFunction \
+ (ufunc, PyObject *, PyObject *, PyArrayObject **)
+ void PyUFunc_f_f_As_d_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_d_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_f_f \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_g_g \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_F_F_As_D_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_F_F \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_D_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_G_G \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_O_O \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_ff_f_As_dd_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_ff_f \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_dd_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_gg_g \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_FF_F_As_DD_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_DD_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_FF_F \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_GG_G \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_OO_O \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_O_O_method \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_OO_O_method \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_On_Om \
+ (char **, npy_intp *, npy_intp *, void *)
+ int PyUFunc_GetPyValues \
+ (char *, int *, int *, PyObject **)
+ int PyUFunc_checkfperr \
+ (int, PyObject *, int *)
+ void PyUFunc_clearfperr()
+ int PyUFunc_getfperr()
+ int PyUFunc_handlefperr \
+ (int, PyObject *, int, int *)
+ int PyUFunc_ReplaceLoopBySignature \
+ (ufunc, PyUFuncGenericFunction, int *, PyUFuncGenericFunction *)
+ object PyUFunc_FromFuncAndDataAndSignature \
+ (PyUFuncGenericFunction *, void **, char *, int, int, int,
+ int, char *, char *, int, char *)
+
+ int _import_umath() except -1
+
+cdef inline void set_array_base(ndarray arr, object base):
+ Py_INCREF(base) # important to do this before stealing the reference below!
+ PyArray_SetBaseObject(arr, base)
+
+cdef inline object get_array_base(ndarray arr):
+ base = PyArray_BASE(arr)
+ if base is NULL:
+ return None
+ return base
+
+# Versions of the import_* functions which are more suitable for
+# Cython code.
+cdef inline int import_array() except -1:
+ try:
+ __pyx_import_array()
+ except Exception:
+ raise ImportError("numpy.core.multiarray failed to import")
+
+cdef inline int import_umath() except -1:
+ try:
+ _import_umath()
+ except Exception:
+ raise ImportError("numpy.core.umath failed to import")
+
+cdef inline int import_ufunc() except -1:
+ try:
+ _import_umath()
+ except Exception:
+ raise ImportError("numpy.core.umath failed to import")
+
+
+cdef inline bint is_timedelta64_object(object obj):
+ """
+ Cython equivalent of `isinstance(obj, np.timedelta64)`
+
+ Parameters
+ ----------
+ obj : object
+
+ Returns
+ -------
+ bool
+ """
+ return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type)
+
+
+cdef inline bint is_datetime64_object(object obj):
+ """
+ Cython equivalent of `isinstance(obj, np.datetime64)`
+
+ Parameters
+ ----------
+ obj : object
+
+ Returns
+ -------
+ bool
+ """
+ return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type)
+
+
+cdef inline npy_datetime get_datetime64_value(object obj) nogil:
+ """
+ returns the int64 value underlying scalar numpy datetime64 object
+
+ Note that to interpret this as a datetime, the corresponding unit is
+ also needed. That can be found using `get_datetime64_unit`.
+ """
+ return (obj).obval
+
+
+cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:
+ """
+ returns the int64 value underlying scalar numpy timedelta64 object
+ """
+ return (obj).obval
+
+
+cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:
+ """
+ returns the unit part of the dtype for a numpy datetime64 object.
+ """
+ return (obj).obmeta.base
diff --git a/venv/Lib/site-packages/numpy/__init__.pxd b/venv/Lib/site-packages/numpy/__init__.pxd
new file mode 100644
index 0000000..5434348
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/__init__.pxd
@@ -0,0 +1,1020 @@
+# NumPy static imports for Cython < 3.0
+#
+# If any of the PyArray_* functions are called, import_array must be
+# called first.
+#
+# Author: Dag Sverre Seljebotn
+#
+
+DEF _buffer_format_string_len = 255
+
+cimport cpython.buffer as pybuf
+from cpython.ref cimport Py_INCREF
+from cpython.mem cimport PyObject_Malloc, PyObject_Free
+from cpython.object cimport PyObject, PyTypeObject
+from cpython.buffer cimport PyObject_GetBuffer
+from cpython.type cimport type
+cimport libc.stdio as stdio
+
+cdef extern from "Python.h":
+ ctypedef int Py_intptr_t
+ bint PyObject_TypeCheck(object obj, PyTypeObject* type)
+
+cdef extern from "numpy/arrayobject.h":
+ ctypedef Py_intptr_t npy_intp
+ ctypedef size_t npy_uintp
+
+ cdef enum NPY_TYPES:
+ NPY_BOOL
+ NPY_BYTE
+ NPY_UBYTE
+ NPY_SHORT
+ NPY_USHORT
+ NPY_INT
+ NPY_UINT
+ NPY_LONG
+ NPY_ULONG
+ NPY_LONGLONG
+ NPY_ULONGLONG
+ NPY_FLOAT
+ NPY_DOUBLE
+ NPY_LONGDOUBLE
+ NPY_CFLOAT
+ NPY_CDOUBLE
+ NPY_CLONGDOUBLE
+ NPY_OBJECT
+ NPY_STRING
+ NPY_UNICODE
+ NPY_VOID
+ NPY_DATETIME
+ NPY_TIMEDELTA
+ NPY_NTYPES
+ NPY_NOTYPE
+
+ NPY_INT8
+ NPY_INT16
+ NPY_INT32
+ NPY_INT64
+ NPY_INT128
+ NPY_INT256
+ NPY_UINT8
+ NPY_UINT16
+ NPY_UINT32
+ NPY_UINT64
+ NPY_UINT128
+ NPY_UINT256
+ NPY_FLOAT16
+ NPY_FLOAT32
+ NPY_FLOAT64
+ NPY_FLOAT80
+ NPY_FLOAT96
+ NPY_FLOAT128
+ NPY_FLOAT256
+ NPY_COMPLEX32
+ NPY_COMPLEX64
+ NPY_COMPLEX128
+ NPY_COMPLEX160
+ NPY_COMPLEX192
+ NPY_COMPLEX256
+ NPY_COMPLEX512
+
+ NPY_INTP
+
+ ctypedef enum NPY_ORDER:
+ NPY_ANYORDER
+ NPY_CORDER
+ NPY_FORTRANORDER
+ NPY_KEEPORDER
+
+ ctypedef enum NPY_CASTING:
+ NPY_NO_CASTING
+ NPY_EQUIV_CASTING
+ NPY_SAFE_CASTING
+ NPY_SAME_KIND_CASTING
+ NPY_UNSAFE_CASTING
+
+ ctypedef enum NPY_CLIPMODE:
+ NPY_CLIP
+ NPY_WRAP
+ NPY_RAISE
+
+ ctypedef enum NPY_SCALARKIND:
+ NPY_NOSCALAR,
+ NPY_BOOL_SCALAR,
+ NPY_INTPOS_SCALAR,
+ NPY_INTNEG_SCALAR,
+ NPY_FLOAT_SCALAR,
+ NPY_COMPLEX_SCALAR,
+ NPY_OBJECT_SCALAR
+
+ ctypedef enum NPY_SORTKIND:
+ NPY_QUICKSORT
+ NPY_HEAPSORT
+ NPY_MERGESORT
+
+ ctypedef enum NPY_SEARCHSIDE:
+ NPY_SEARCHLEFT
+ NPY_SEARCHRIGHT
+
+ enum:
+ # DEPRECATED since NumPy 1.7 ! Do not use in new code!
+ NPY_C_CONTIGUOUS
+ NPY_F_CONTIGUOUS
+ NPY_CONTIGUOUS
+ NPY_FORTRAN
+ NPY_OWNDATA
+ NPY_FORCECAST
+ NPY_ENSURECOPY
+ NPY_ENSUREARRAY
+ NPY_ELEMENTSTRIDES
+ NPY_ALIGNED
+ NPY_NOTSWAPPED
+ NPY_WRITEABLE
+ NPY_UPDATEIFCOPY
+ NPY_ARR_HAS_DESCR
+
+ NPY_BEHAVED
+ NPY_BEHAVED_NS
+ NPY_CARRAY
+ NPY_CARRAY_RO
+ NPY_FARRAY
+ NPY_FARRAY_RO
+ NPY_DEFAULT
+
+ NPY_IN_ARRAY
+ NPY_OUT_ARRAY
+ NPY_INOUT_ARRAY
+ NPY_IN_FARRAY
+ NPY_OUT_FARRAY
+ NPY_INOUT_FARRAY
+
+ NPY_UPDATE_ALL
+
+ enum:
+ # Added in NumPy 1.7 to replace the deprecated enums above.
+ NPY_ARRAY_C_CONTIGUOUS
+ NPY_ARRAY_F_CONTIGUOUS
+ NPY_ARRAY_OWNDATA
+ NPY_ARRAY_FORCECAST
+ NPY_ARRAY_ENSURECOPY
+ NPY_ARRAY_ENSUREARRAY
+ NPY_ARRAY_ELEMENTSTRIDES
+ NPY_ARRAY_ALIGNED
+ NPY_ARRAY_NOTSWAPPED
+ NPY_ARRAY_WRITEABLE
+ NPY_ARRAY_UPDATEIFCOPY
+
+ NPY_ARRAY_BEHAVED
+ NPY_ARRAY_BEHAVED_NS
+ NPY_ARRAY_CARRAY
+ NPY_ARRAY_CARRAY_RO
+ NPY_ARRAY_FARRAY
+ NPY_ARRAY_FARRAY_RO
+ NPY_ARRAY_DEFAULT
+
+ NPY_ARRAY_IN_ARRAY
+ NPY_ARRAY_OUT_ARRAY
+ NPY_ARRAY_INOUT_ARRAY
+ NPY_ARRAY_IN_FARRAY
+ NPY_ARRAY_OUT_FARRAY
+ NPY_ARRAY_INOUT_FARRAY
+
+ NPY_ARRAY_UPDATE_ALL
+
+ cdef enum:
+ NPY_MAXDIMS
+
+ npy_intp NPY_MAX_ELSIZE
+
+ ctypedef void (*PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *, void *)
+
+ ctypedef struct PyArray_ArrayDescr:
+ # shape is a tuple, but Cython doesn't support "tuple shape"
+ # inside a non-PyObject declaration, so we have to declare it
+ # as just a PyObject*.
+ PyObject* shape
+
+ ctypedef struct PyArray_Descr:
+ pass
+
+ ctypedef class numpy.dtype [object PyArray_Descr, check_size ignore]:
+ # Use PyDataType_* macros when possible, however there are no macros
+ # for accessing some of the fields, so some are defined.
+ cdef PyTypeObject* typeobj
+ cdef char kind
+ cdef char type
+ # Numpy sometimes mutates this without warning (e.g. it'll
+ # sometimes change "|" to "<" in shared dtype objects on
+ # little-endian machines). If this matters to you, use
+ # PyArray_IsNativeByteOrder(dtype.byteorder) instead of
+ # directly accessing this field.
+ cdef char byteorder
+ cdef char flags
+ cdef int type_num
+ cdef int itemsize "elsize"
+ cdef int alignment
+ cdef object fields
+ cdef tuple names
+ # Use PyDataType_HASSUBARRAY to test whether this field is
+ # valid (the pointer can be NULL). Most users should access
+ # this field via the inline helper method PyDataType_SHAPE.
+ cdef PyArray_ArrayDescr* subarray
+
+ ctypedef class numpy.flatiter [object PyArrayIterObject, check_size ignore]:
+ # Use through macros
+ pass
+
+ ctypedef class numpy.broadcast [object PyArrayMultiIterObject, check_size ignore]:
+ cdef int numiter
+ cdef npy_intp size, index
+ cdef int nd
+ cdef npy_intp *dimensions
+ cdef void **iters
+
+ ctypedef struct PyArrayObject:
+ # For use in situations where ndarray can't replace PyArrayObject*,
+ # like PyArrayObject**.
+ pass
+
+ ctypedef class numpy.ndarray [object PyArrayObject, check_size ignore]:
+ cdef __cythonbufferdefaults__ = {"mode": "strided"}
+
+ cdef:
+ # Only taking a few of the most commonly used and stable fields.
+ # One should use PyArray_* macros instead to access the C fields.
+ char *data
+ int ndim "nd"
+ npy_intp *shape "dimensions"
+ npy_intp *strides
+ dtype descr # deprecated since NumPy 1.7 !
+ PyObject* base # NOT PUBLIC, DO NOT USE !
+
+
+
+ ctypedef unsigned char npy_bool
+
+ ctypedef signed char npy_byte
+ ctypedef signed short npy_short
+ ctypedef signed int npy_int
+ ctypedef signed long npy_long
+ ctypedef signed long long npy_longlong
+
+ ctypedef unsigned char npy_ubyte
+ ctypedef unsigned short npy_ushort
+ ctypedef unsigned int npy_uint
+ ctypedef unsigned long npy_ulong
+ ctypedef unsigned long long npy_ulonglong
+
+ ctypedef float npy_float
+ ctypedef double npy_double
+ ctypedef long double npy_longdouble
+
+ ctypedef signed char npy_int8
+ ctypedef signed short npy_int16
+ ctypedef signed int npy_int32
+ ctypedef signed long long npy_int64
+ ctypedef signed long long npy_int96
+ ctypedef signed long long npy_int128
+
+ ctypedef unsigned char npy_uint8
+ ctypedef unsigned short npy_uint16
+ ctypedef unsigned int npy_uint32
+ ctypedef unsigned long long npy_uint64
+ ctypedef unsigned long long npy_uint96
+ ctypedef unsigned long long npy_uint128
+
+ ctypedef float npy_float32
+ ctypedef double npy_float64
+ ctypedef long double npy_float80
+ ctypedef long double npy_float96
+ ctypedef long double npy_float128
+
+ ctypedef struct npy_cfloat:
+ float real
+ float imag
+
+ ctypedef struct npy_cdouble:
+ double real
+ double imag
+
+ ctypedef struct npy_clongdouble:
+ long double real
+ long double imag
+
+ ctypedef struct npy_complex64:
+ float real
+ float imag
+
+ ctypedef struct npy_complex128:
+ double real
+ double imag
+
+ ctypedef struct npy_complex160:
+ long double real
+ long double imag
+
+ ctypedef struct npy_complex192:
+ long double real
+ long double imag
+
+ ctypedef struct npy_complex256:
+ long double real
+ long double imag
+
+ ctypedef struct PyArray_Dims:
+ npy_intp *ptr
+ int len
+
+ int _import_array() except -1
+ # A second definition so _import_array isn't marked as used when we use it here.
+ # Do not use - subject to change any time.
+ int __pyx_import_array "_import_array"() except -1
+
+ #
+ # Macros from ndarrayobject.h
+ #
+ bint PyArray_CHKFLAGS(ndarray m, int flags) nogil
+ bint PyArray_IS_C_CONTIGUOUS(ndarray arr) nogil
+ bint PyArray_IS_F_CONTIGUOUS(ndarray arr) nogil
+ bint PyArray_ISCONTIGUOUS(ndarray m) nogil
+ bint PyArray_ISWRITEABLE(ndarray m) nogil
+ bint PyArray_ISALIGNED(ndarray m) nogil
+
+ int PyArray_NDIM(ndarray) nogil
+ bint PyArray_ISONESEGMENT(ndarray) nogil
+ bint PyArray_ISFORTRAN(ndarray) nogil
+ int PyArray_FORTRANIF(ndarray) nogil
+
+ void* PyArray_DATA(ndarray) nogil
+ char* PyArray_BYTES(ndarray) nogil
+
+ npy_intp* PyArray_DIMS(ndarray) nogil
+ npy_intp* PyArray_STRIDES(ndarray) nogil
+ npy_intp PyArray_DIM(ndarray, size_t) nogil
+ npy_intp PyArray_STRIDE(ndarray, size_t) nogil
+
+ PyObject *PyArray_BASE(ndarray) nogil # returns borrowed reference!
+ PyArray_Descr *PyArray_DESCR(ndarray) nogil # returns borrowed reference to dtype!
+ int PyArray_FLAGS(ndarray) nogil
+ npy_intp PyArray_ITEMSIZE(ndarray) nogil
+ int PyArray_TYPE(ndarray arr) nogil
+
+ object PyArray_GETITEM(ndarray arr, void *itemptr)
+ int PyArray_SETITEM(ndarray arr, void *itemptr, object obj)
+
+ bint PyTypeNum_ISBOOL(int) nogil
+ bint PyTypeNum_ISUNSIGNED(int) nogil
+ bint PyTypeNum_ISSIGNED(int) nogil
+ bint PyTypeNum_ISINTEGER(int) nogil
+ bint PyTypeNum_ISFLOAT(int) nogil
+ bint PyTypeNum_ISNUMBER(int) nogil
+ bint PyTypeNum_ISSTRING(int) nogil
+ bint PyTypeNum_ISCOMPLEX(int) nogil
+ bint PyTypeNum_ISPYTHON(int) nogil
+ bint PyTypeNum_ISFLEXIBLE(int) nogil
+ bint PyTypeNum_ISUSERDEF(int) nogil
+ bint PyTypeNum_ISEXTENDED(int) nogil
+ bint PyTypeNum_ISOBJECT(int) nogil
+
+ bint PyDataType_ISBOOL(dtype) nogil
+ bint PyDataType_ISUNSIGNED(dtype) nogil
+ bint PyDataType_ISSIGNED(dtype) nogil
+ bint PyDataType_ISINTEGER(dtype) nogil
+ bint PyDataType_ISFLOAT(dtype) nogil
+ bint PyDataType_ISNUMBER(dtype) nogil
+ bint PyDataType_ISSTRING(dtype) nogil
+ bint PyDataType_ISCOMPLEX(dtype) nogil
+ bint PyDataType_ISPYTHON(dtype) nogil
+ bint PyDataType_ISFLEXIBLE(dtype) nogil
+ bint PyDataType_ISUSERDEF(dtype) nogil
+ bint PyDataType_ISEXTENDED(dtype) nogil
+ bint PyDataType_ISOBJECT(dtype) nogil
+ bint PyDataType_HASFIELDS(dtype) nogil
+ bint PyDataType_HASSUBARRAY(dtype) nogil
+
+ bint PyArray_ISBOOL(ndarray) nogil
+ bint PyArray_ISUNSIGNED(ndarray) nogil
+ bint PyArray_ISSIGNED(ndarray) nogil
+ bint PyArray_ISINTEGER(ndarray) nogil
+ bint PyArray_ISFLOAT(ndarray) nogil
+ bint PyArray_ISNUMBER(ndarray) nogil
+ bint PyArray_ISSTRING(ndarray) nogil
+ bint PyArray_ISCOMPLEX(ndarray) nogil
+ bint PyArray_ISPYTHON(ndarray) nogil
+ bint PyArray_ISFLEXIBLE(ndarray) nogil
+ bint PyArray_ISUSERDEF(ndarray) nogil
+ bint PyArray_ISEXTENDED(ndarray) nogil
+ bint PyArray_ISOBJECT(ndarray) nogil
+ bint PyArray_HASFIELDS(ndarray) nogil
+
+ bint PyArray_ISVARIABLE(ndarray) nogil
+
+ bint PyArray_SAFEALIGNEDCOPY(ndarray) nogil
+ bint PyArray_ISNBO(char) nogil # works on ndarray.byteorder
+ bint PyArray_IsNativeByteOrder(char) nogil # works on ndarray.byteorder
+ bint PyArray_ISNOTSWAPPED(ndarray) nogil
+ bint PyArray_ISBYTESWAPPED(ndarray) nogil
+
+ bint PyArray_FLAGSWAP(ndarray, int) nogil
+
+ bint PyArray_ISCARRAY(ndarray) nogil
+ bint PyArray_ISCARRAY_RO(ndarray) nogil
+ bint PyArray_ISFARRAY(ndarray) nogil
+ bint PyArray_ISFARRAY_RO(ndarray) nogil
+ bint PyArray_ISBEHAVED(ndarray) nogil
+ bint PyArray_ISBEHAVED_RO(ndarray) nogil
+
+
+ bint PyDataType_ISNOTSWAPPED(dtype) nogil
+ bint PyDataType_ISBYTESWAPPED(dtype) nogil
+
+ bint PyArray_DescrCheck(object)
+
+ bint PyArray_Check(object)
+ bint PyArray_CheckExact(object)
+
+ # Cannot be supported due to out arg:
+ # bint PyArray_HasArrayInterfaceType(object, dtype, object, object&)
+ # bint PyArray_HasArrayInterface(op, out)
+
+
+ bint PyArray_IsZeroDim(object)
+ # Cannot be supported due to ## ## in macro:
+ # bint PyArray_IsScalar(object, verbatim work)
+ bint PyArray_CheckScalar(object)
+ bint PyArray_IsPythonNumber(object)
+ bint PyArray_IsPythonScalar(object)
+ bint PyArray_IsAnyScalar(object)
+ bint PyArray_CheckAnyScalar(object)
+
+ ndarray PyArray_GETCONTIGUOUS(ndarray)
+ bint PyArray_SAMESHAPE(ndarray, ndarray) nogil
+ npy_intp PyArray_SIZE(ndarray) nogil
+ npy_intp PyArray_NBYTES(ndarray) nogil
+
+ object PyArray_FROM_O(object)
+ object PyArray_FROM_OF(object m, int flags)
+ object PyArray_FROM_OT(object m, int type)
+ object PyArray_FROM_OTF(object m, int type, int flags)
+ object PyArray_FROMANY(object m, int type, int min, int max, int flags)
+ object PyArray_ZEROS(int nd, npy_intp* dims, int type, int fortran)
+ object PyArray_EMPTY(int nd, npy_intp* dims, int type, int fortran)
+ void PyArray_FILLWBYTE(object, int val)
+ npy_intp PyArray_REFCOUNT(object)
+ object PyArray_ContiguousFromAny(op, int, int min_depth, int max_depth)
+ unsigned char PyArray_EquivArrTypes(ndarray a1, ndarray a2)
+ bint PyArray_EquivByteorders(int b1, int b2) nogil
+ object PyArray_SimpleNew(int nd, npy_intp* dims, int typenum)
+ object PyArray_SimpleNewFromData(int nd, npy_intp* dims, int typenum, void* data)
+ #object PyArray_SimpleNewFromDescr(int nd, npy_intp* dims, dtype descr)
+ object PyArray_ToScalar(void* data, ndarray arr)
+
+ void* PyArray_GETPTR1(ndarray m, npy_intp i) nogil
+ void* PyArray_GETPTR2(ndarray m, npy_intp i, npy_intp j) nogil
+ void* PyArray_GETPTR3(ndarray m, npy_intp i, npy_intp j, npy_intp k) nogil
+ void* PyArray_GETPTR4(ndarray m, npy_intp i, npy_intp j, npy_intp k, npy_intp l) nogil
+
+ void PyArray_XDECREF_ERR(ndarray)
+ # Cannot be supported due to out arg
+ # void PyArray_DESCR_REPLACE(descr)
+
+
+ object PyArray_Copy(ndarray)
+ object PyArray_FromObject(object op, int type, int min_depth, int max_depth)
+ object PyArray_ContiguousFromObject(object op, int type, int min_depth, int max_depth)
+ object PyArray_CopyFromObject(object op, int type, int min_depth, int max_depth)
+
+ object PyArray_Cast(ndarray mp, int type_num)
+ object PyArray_Take(ndarray ap, object items, int axis)
+ object PyArray_Put(ndarray ap, object items, object values)
+
+ void PyArray_ITER_RESET(flatiter it) nogil
+ void PyArray_ITER_NEXT(flatiter it) nogil
+ void PyArray_ITER_GOTO(flatiter it, npy_intp* destination) nogil
+ void PyArray_ITER_GOTO1D(flatiter it, npy_intp ind) nogil
+ void* PyArray_ITER_DATA(flatiter it) nogil
+ bint PyArray_ITER_NOTDONE(flatiter it) nogil
+
+ void PyArray_MultiIter_RESET(broadcast multi) nogil
+ void PyArray_MultiIter_NEXT(broadcast multi) nogil
+ void PyArray_MultiIter_GOTO(broadcast multi, npy_intp dest) nogil
+ void PyArray_MultiIter_GOTO1D(broadcast multi, npy_intp ind) nogil
+ void* PyArray_MultiIter_DATA(broadcast multi, npy_intp i) nogil
+ void PyArray_MultiIter_NEXTi(broadcast multi, npy_intp i) nogil
+ bint PyArray_MultiIter_NOTDONE(broadcast multi) nogil
+
+ # Functions from __multiarray_api.h
+
+ # Functions taking dtype and returning object/ndarray are disabled
+ # for now as they steal dtype references. I'm conservative and disable
+ # more than is probably needed until it can be checked further.
+ int PyArray_SetNumericOps (object)
+ object PyArray_GetNumericOps ()
+ int PyArray_INCREF (ndarray)
+ int PyArray_XDECREF (ndarray)
+ void PyArray_SetStringFunction (object, int)
+ dtype PyArray_DescrFromType (int)
+ object PyArray_TypeObjectFromType (int)
+ char * PyArray_Zero (ndarray)
+ char * PyArray_One (ndarray)
+ #object PyArray_CastToType (ndarray, dtype, int)
+ int PyArray_CastTo (ndarray, ndarray)
+ int PyArray_CastAnyTo (ndarray, ndarray)
+ int PyArray_CanCastSafely (int, int)
+ npy_bool PyArray_CanCastTo (dtype, dtype)
+ int PyArray_ObjectType (object, int)
+ dtype PyArray_DescrFromObject (object, dtype)
+ #ndarray* PyArray_ConvertToCommonType (object, int *)
+ dtype PyArray_DescrFromScalar (object)
+ dtype PyArray_DescrFromTypeObject (object)
+ npy_intp PyArray_Size (object)
+ #object PyArray_Scalar (void *, dtype, object)
+ #object PyArray_FromScalar (object, dtype)
+ void PyArray_ScalarAsCtype (object, void *)
+ #int PyArray_CastScalarToCtype (object, void *, dtype)
+ #int PyArray_CastScalarDirect (object, dtype, void *, int)
+ object PyArray_ScalarFromObject (object)
+ #PyArray_VectorUnaryFunc * PyArray_GetCastFunc (dtype, int)
+ object PyArray_FromDims (int, int *, int)
+ #object PyArray_FromDimsAndDataAndDescr (int, int *, dtype, char *)
+ #object PyArray_FromAny (object, dtype, int, int, int, object)
+ object PyArray_EnsureArray (object)
+ object PyArray_EnsureAnyArray (object)
+ #object PyArray_FromFile (stdio.FILE *, dtype, npy_intp, char *)
+ #object PyArray_FromString (char *, npy_intp, dtype, npy_intp, char *)
+ #object PyArray_FromBuffer (object, dtype, npy_intp, npy_intp)
+ #object PyArray_FromIter (object, dtype, npy_intp)
+ object PyArray_Return (ndarray)
+ #object PyArray_GetField (ndarray, dtype, int)
+ #int PyArray_SetField (ndarray, dtype, int, object)
+ object PyArray_Byteswap (ndarray, npy_bool)
+ object PyArray_Resize (ndarray, PyArray_Dims *, int, NPY_ORDER)
+ int PyArray_MoveInto (ndarray, ndarray)
+ int PyArray_CopyInto (ndarray, ndarray)
+ int PyArray_CopyAnyInto (ndarray, ndarray)
+ int PyArray_CopyObject (ndarray, object)
+ object PyArray_NewCopy (ndarray, NPY_ORDER)
+ object PyArray_ToList (ndarray)
+ object PyArray_ToString (ndarray, NPY_ORDER)
+ int PyArray_ToFile (ndarray, stdio.FILE *, char *, char *)
+ int PyArray_Dump (object, object, int)
+ object PyArray_Dumps (object, int)
+ int PyArray_ValidType (int)
+ void PyArray_UpdateFlags (ndarray, int)
+ object PyArray_New (type, int, npy_intp *, int, npy_intp *, void *, int, int, object)
+ #object PyArray_NewFromDescr (type, dtype, int, npy_intp *, npy_intp *, void *, int, object)
+ #dtype PyArray_DescrNew (dtype)
+ dtype PyArray_DescrNewFromType (int)
+ double PyArray_GetPriority (object, double)
+ object PyArray_IterNew (object)
+ object PyArray_MultiIterNew (int, ...)
+
+ int PyArray_PyIntAsInt (object)
+ npy_intp PyArray_PyIntAsIntp (object)
+ int PyArray_Broadcast (broadcast)
+ void PyArray_FillObjectArray (ndarray, object)
+ int PyArray_FillWithScalar (ndarray, object)
+ npy_bool PyArray_CheckStrides (int, int, npy_intp, npy_intp, npy_intp *, npy_intp *)
+ dtype PyArray_DescrNewByteorder (dtype, char)
+ object PyArray_IterAllButAxis (object, int *)
+ #object PyArray_CheckFromAny (object, dtype, int, int, int, object)
+ #object PyArray_FromArray (ndarray, dtype, int)
+ object PyArray_FromInterface (object)
+ object PyArray_FromStructInterface (object)
+ #object PyArray_FromArrayAttr (object, dtype, object)
+ #NPY_SCALARKIND PyArray_ScalarKind (int, ndarray*)
+ int PyArray_CanCoerceScalar (int, int, NPY_SCALARKIND)
+ object PyArray_NewFlagsObject (object)
+ npy_bool PyArray_CanCastScalar (type, type)
+ #int PyArray_CompareUCS4 (npy_ucs4 *, npy_ucs4 *, register size_t)
+ int PyArray_RemoveSmallest (broadcast)
+ int PyArray_ElementStrides (object)
+ void PyArray_Item_INCREF (char *, dtype)
+ void PyArray_Item_XDECREF (char *, dtype)
+ object PyArray_FieldNames (object)
+ object PyArray_Transpose (ndarray, PyArray_Dims *)
+ object PyArray_TakeFrom (ndarray, object, int, ndarray, NPY_CLIPMODE)
+ object PyArray_PutTo (ndarray, object, object, NPY_CLIPMODE)
+ object PyArray_PutMask (ndarray, object, object)
+ object PyArray_Repeat (ndarray, object, int)
+ object PyArray_Choose (ndarray, object, ndarray, NPY_CLIPMODE)
+ int PyArray_Sort (ndarray, int, NPY_SORTKIND)
+ object PyArray_ArgSort (ndarray, int, NPY_SORTKIND)
+ object PyArray_SearchSorted (ndarray, object, NPY_SEARCHSIDE, PyObject *)
+ object PyArray_ArgMax (ndarray, int, ndarray)
+ object PyArray_ArgMin (ndarray, int, ndarray)
+ object PyArray_Reshape (ndarray, object)
+ object PyArray_Newshape (ndarray, PyArray_Dims *, NPY_ORDER)
+ object PyArray_Squeeze (ndarray)
+ #object PyArray_View (ndarray, dtype, type)
+ object PyArray_SwapAxes (ndarray, int, int)
+ object PyArray_Max (ndarray, int, ndarray)
+ object PyArray_Min (ndarray, int, ndarray)
+ object PyArray_Ptp (ndarray, int, ndarray)
+ object PyArray_Mean (ndarray, int, int, ndarray)
+ object PyArray_Trace (ndarray, int, int, int, int, ndarray)
+ object PyArray_Diagonal (ndarray, int, int, int)
+ object PyArray_Clip (ndarray, object, object, ndarray)
+ object PyArray_Conjugate (ndarray, ndarray)
+ object PyArray_Nonzero (ndarray)
+ object PyArray_Std (ndarray, int, int, ndarray, int)
+ object PyArray_Sum (ndarray, int, int, ndarray)
+ object PyArray_CumSum (ndarray, int, int, ndarray)
+ object PyArray_Prod (ndarray, int, int, ndarray)
+ object PyArray_CumProd (ndarray, int, int, ndarray)
+ object PyArray_All (ndarray, int, ndarray)
+ object PyArray_Any (ndarray, int, ndarray)
+ object PyArray_Compress (ndarray, object, int, ndarray)
+ object PyArray_Flatten (ndarray, NPY_ORDER)
+ object PyArray_Ravel (ndarray, NPY_ORDER)
+ npy_intp PyArray_MultiplyList (npy_intp *, int)
+ int PyArray_MultiplyIntList (int *, int)
+ void * PyArray_GetPtr (ndarray, npy_intp*)
+ int PyArray_CompareLists (npy_intp *, npy_intp *, int)
+ #int PyArray_AsCArray (object*, void *, npy_intp *, int, dtype)
+ #int PyArray_As1D (object*, char **, int *, int)
+ #int PyArray_As2D (object*, char ***, int *, int *, int)
+ int PyArray_Free (object, void *)
+ #int PyArray_Converter (object, object*)
+ int PyArray_IntpFromSequence (object, npy_intp *, int)
+ object PyArray_Concatenate (object, int)
+ object PyArray_InnerProduct (object, object)
+ object PyArray_MatrixProduct (object, object)
+ object PyArray_CopyAndTranspose (object)
+ object PyArray_Correlate (object, object, int)
+ int PyArray_TypestrConvert (int, int)
+ #int PyArray_DescrConverter (object, dtype*)
+ #int PyArray_DescrConverter2 (object, dtype*)
+ int PyArray_IntpConverter (object, PyArray_Dims *)
+ #int PyArray_BufferConverter (object, chunk)
+ int PyArray_AxisConverter (object, int *)
+ int PyArray_BoolConverter (object, npy_bool *)
+ int PyArray_ByteorderConverter (object, char *)
+ int PyArray_OrderConverter (object, NPY_ORDER *)
+ unsigned char PyArray_EquivTypes (dtype, dtype)
+ #object PyArray_Zeros (int, npy_intp *, dtype, int)
+ #object PyArray_Empty (int, npy_intp *, dtype, int)
+ object PyArray_Where (object, object, object)
+ object PyArray_Arange (double, double, double, int)
+ #object PyArray_ArangeObj (object, object, object, dtype)
+ int PyArray_SortkindConverter (object, NPY_SORTKIND *)
+ object PyArray_LexSort (object, int)
+ object PyArray_Round (ndarray, int, ndarray)
+ unsigned char PyArray_EquivTypenums (int, int)
+ int PyArray_RegisterDataType (dtype)
+ int PyArray_RegisterCastFunc (dtype, int, PyArray_VectorUnaryFunc *)
+ int PyArray_RegisterCanCast (dtype, int, NPY_SCALARKIND)
+ #void PyArray_InitArrFuncs (PyArray_ArrFuncs *)
+ object PyArray_IntTupleFromIntp (int, npy_intp *)
+ int PyArray_TypeNumFromName (char *)
+ int PyArray_ClipmodeConverter (object, NPY_CLIPMODE *)
+ #int PyArray_OutputConverter (object, ndarray*)
+ object PyArray_BroadcastToShape (object, npy_intp *, int)
+ void _PyArray_SigintHandler (int)
+ void* _PyArray_GetSigintBuf ()
+ #int PyArray_DescrAlignConverter (object, dtype*)
+ #int PyArray_DescrAlignConverter2 (object, dtype*)
+ int PyArray_SearchsideConverter (object, void *)
+ object PyArray_CheckAxis (ndarray, int *, int)
+ npy_intp PyArray_OverflowMultiplyList (npy_intp *, int)
+ int PyArray_CompareString (char *, char *, size_t)
+ int PyArray_SetBaseObject(ndarray, base) # NOTE: steals a reference to base! Use "set_array_base()" instead.
+
+
+# Typedefs that matches the runtime dtype objects in
+# the numpy module.
+
+# The ones that are commented out needs an IFDEF function
+# in Cython to enable them only on the right systems.
+
+ctypedef npy_int8 int8_t
+ctypedef npy_int16 int16_t
+ctypedef npy_int32 int32_t
+ctypedef npy_int64 int64_t
+#ctypedef npy_int96 int96_t
+#ctypedef npy_int128 int128_t
+
+ctypedef npy_uint8 uint8_t
+ctypedef npy_uint16 uint16_t
+ctypedef npy_uint32 uint32_t
+ctypedef npy_uint64 uint64_t
+#ctypedef npy_uint96 uint96_t
+#ctypedef npy_uint128 uint128_t
+
+ctypedef npy_float32 float32_t
+ctypedef npy_float64 float64_t
+#ctypedef npy_float80 float80_t
+#ctypedef npy_float128 float128_t
+
+ctypedef float complex complex64_t
+ctypedef double complex complex128_t
+
+# The int types are mapped a bit surprising --
+# numpy.int corresponds to 'l' and numpy.long to 'q'
+ctypedef npy_long int_t
+ctypedef npy_longlong long_t
+ctypedef npy_longlong longlong_t
+
+ctypedef npy_ulong uint_t
+ctypedef npy_ulonglong ulong_t
+ctypedef npy_ulonglong ulonglong_t
+
+ctypedef npy_intp intp_t
+ctypedef npy_uintp uintp_t
+
+ctypedef npy_double float_t
+ctypedef npy_double double_t
+ctypedef npy_longdouble longdouble_t
+
+ctypedef npy_cfloat cfloat_t
+ctypedef npy_cdouble cdouble_t
+ctypedef npy_clongdouble clongdouble_t
+
+ctypedef npy_cdouble complex_t
+
+cdef inline object PyArray_MultiIterNew1(a):
+ return PyArray_MultiIterNew(1, a)
+
+cdef inline object PyArray_MultiIterNew2(a, b):
+ return PyArray_MultiIterNew(2, a, b)
+
+cdef inline object PyArray_MultiIterNew3(a, b, c):
+ return PyArray_MultiIterNew(3, a, b, c)
+
+cdef inline object PyArray_MultiIterNew4(a, b, c, d):
+ return PyArray_MultiIterNew(4, a, b, c, d)
+
+cdef inline object PyArray_MultiIterNew5(a, b, c, d, e):
+ return PyArray_MultiIterNew(5, a, b, c, d, e)
+
+cdef inline tuple PyDataType_SHAPE(dtype d):
+ if PyDataType_HASSUBARRAY(d):
+ return d.subarray.shape
+ else:
+ return ()
+
+
+cdef extern from "numpy/ndarrayobject.h":
+ PyTypeObject PyTimedeltaArrType_Type
+ PyTypeObject PyDatetimeArrType_Type
+ ctypedef int64_t npy_timedelta
+ ctypedef int64_t npy_datetime
+
+cdef extern from "numpy/ndarraytypes.h":
+ ctypedef struct PyArray_DatetimeMetaData:
+ NPY_DATETIMEUNIT base
+ int64_t num
+
+cdef extern from "numpy/arrayscalars.h":
+
+ # abstract types
+ ctypedef class numpy.generic [object PyObject]:
+ pass
+ ctypedef class numpy.number [object PyObject]:
+ pass
+ ctypedef class numpy.integer [object PyObject]:
+ pass
+ ctypedef class numpy.signedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.unsignedinteger [object PyObject]:
+ pass
+ ctypedef class numpy.inexact [object PyObject]:
+ pass
+ ctypedef class numpy.floating [object PyObject]:
+ pass
+ ctypedef class numpy.complexfloating [object PyObject]:
+ pass
+ ctypedef class numpy.flexible [object PyObject]:
+ pass
+ ctypedef class numpy.character [object PyObject]:
+ pass
+
+ ctypedef struct PyDatetimeScalarObject:
+ # PyObject_HEAD
+ npy_datetime obval
+ PyArray_DatetimeMetaData obmeta
+
+ ctypedef struct PyTimedeltaScalarObject:
+ # PyObject_HEAD
+ npy_timedelta obval
+ PyArray_DatetimeMetaData obmeta
+
+ ctypedef enum NPY_DATETIMEUNIT:
+ NPY_FR_Y
+ NPY_FR_M
+ NPY_FR_W
+ NPY_FR_D
+ NPY_FR_B
+ NPY_FR_h
+ NPY_FR_m
+ NPY_FR_s
+ NPY_FR_ms
+ NPY_FR_us
+ NPY_FR_ns
+ NPY_FR_ps
+ NPY_FR_fs
+ NPY_FR_as
+
+
+#
+# ufunc API
+#
+
+cdef extern from "numpy/ufuncobject.h":
+
+ ctypedef void (*PyUFuncGenericFunction) (char **, npy_intp *, npy_intp *, void *)
+
+ ctypedef class numpy.ufunc [object PyUFuncObject, check_size ignore]:
+ cdef:
+ int nin, nout, nargs
+ int identity
+ PyUFuncGenericFunction *functions
+ void **data
+ int ntypes
+ int check_return
+ char *name
+ char *types
+ char *doc
+ void *ptr
+ PyObject *obj
+ PyObject *userloops
+
+ cdef enum:
+ PyUFunc_Zero
+ PyUFunc_One
+ PyUFunc_None
+ UFUNC_ERR_IGNORE
+ UFUNC_ERR_WARN
+ UFUNC_ERR_RAISE
+ UFUNC_ERR_CALL
+ UFUNC_ERR_PRINT
+ UFUNC_ERR_LOG
+ UFUNC_MASK_DIVIDEBYZERO
+ UFUNC_MASK_OVERFLOW
+ UFUNC_MASK_UNDERFLOW
+ UFUNC_MASK_INVALID
+ UFUNC_SHIFT_DIVIDEBYZERO
+ UFUNC_SHIFT_OVERFLOW
+ UFUNC_SHIFT_UNDERFLOW
+ UFUNC_SHIFT_INVALID
+ UFUNC_FPE_DIVIDEBYZERO
+ UFUNC_FPE_OVERFLOW
+ UFUNC_FPE_UNDERFLOW
+ UFUNC_FPE_INVALID
+ UFUNC_ERR_DEFAULT
+ UFUNC_ERR_DEFAULT2
+
+ object PyUFunc_FromFuncAndData(PyUFuncGenericFunction *,
+ void **, char *, int, int, int, int, char *, char *, int)
+ int PyUFunc_RegisterLoopForType(ufunc, int,
+ PyUFuncGenericFunction, int *, void *)
+ int PyUFunc_GenericFunction \
+ (ufunc, PyObject *, PyObject *, PyArrayObject **)
+ void PyUFunc_f_f_As_d_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_d_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_f_f \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_g_g \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_F_F_As_D_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_F_F \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_D_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_G_G \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_O_O \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_ff_f_As_dd_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_ff_f \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_dd_d \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_gg_g \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_FF_F_As_DD_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_DD_D \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_FF_F \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_GG_G \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_OO_O \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_O_O_method \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_OO_O_method \
+ (char **, npy_intp *, npy_intp *, void *)
+ void PyUFunc_On_Om \
+ (char **, npy_intp *, npy_intp *, void *)
+ int PyUFunc_GetPyValues \
+ (char *, int *, int *, PyObject **)
+ int PyUFunc_checkfperr \
+ (int, PyObject *, int *)
+ void PyUFunc_clearfperr()
+ int PyUFunc_getfperr()
+ int PyUFunc_handlefperr \
+ (int, PyObject *, int, int *)
+ int PyUFunc_ReplaceLoopBySignature \
+ (ufunc, PyUFuncGenericFunction, int *, PyUFuncGenericFunction *)
+ object PyUFunc_FromFuncAndDataAndSignature \
+ (PyUFuncGenericFunction *, void **, char *, int, int, int,
+ int, char *, char *, int, char *)
+
+ int _import_umath() except -1
+
+cdef inline void set_array_base(ndarray arr, object base):
+ Py_INCREF(base) # important to do this before stealing the reference below!
+ PyArray_SetBaseObject(arr, base)
+
+cdef inline object get_array_base(ndarray arr):
+ base = PyArray_BASE(arr)
+ if base is NULL:
+ return None
+ return base
+
+# Versions of the import_* functions which are more suitable for
+# Cython code.
+cdef inline int import_array() except -1:
+ try:
+ __pyx_import_array()
+ except Exception:
+ raise ImportError("numpy.core.multiarray failed to import")
+
+cdef inline int import_umath() except -1:
+ try:
+ _import_umath()
+ except Exception:
+ raise ImportError("numpy.core.umath failed to import")
+
+cdef inline int import_ufunc() except -1:
+ try:
+ _import_umath()
+ except Exception:
+ raise ImportError("numpy.core.umath failed to import")
+
+cdef extern from *:
+ # Leave a marker that the NumPy declarations came from this file
+ # See https://github.com/cython/cython/issues/3573
+ """
+ /* NumPy API declarations from "numpy/__init__.pxd" */
+ """
+
+
+cdef inline bint is_timedelta64_object(object obj):
+ """
+ Cython equivalent of `isinstance(obj, np.timedelta64)`
+
+ Parameters
+ ----------
+ obj : object
+
+ Returns
+ -------
+ bool
+ """
+ return PyObject_TypeCheck(obj, &PyTimedeltaArrType_Type)
+
+
+cdef inline bint is_datetime64_object(object obj):
+ """
+ Cython equivalent of `isinstance(obj, np.datetime64)`
+
+ Parameters
+ ----------
+ obj : object
+
+ Returns
+ -------
+ bool
+ """
+ return PyObject_TypeCheck(obj, &PyDatetimeArrType_Type)
+
+
+cdef inline npy_datetime get_datetime64_value(object obj) nogil:
+ """
+ returns the int64 value underlying scalar numpy datetime64 object
+
+ Note that to interpret this as a datetime, the corresponding unit is
+ also needed. That can be found using `get_datetime64_unit`.
+ """
+ return (obj).obval
+
+
+cdef inline npy_timedelta get_timedelta64_value(object obj) nogil:
+ """
+ returns the int64 value underlying scalar numpy timedelta64 object
+ """
+ return (obj).obval
+
+
+cdef inline NPY_DATETIMEUNIT get_datetime64_unit(object obj) nogil:
+ """
+ returns the unit part of the dtype for a numpy datetime64 object.
+ """
+ return (obj).obmeta.base
diff --git a/venv/Lib/site-packages/numpy/__init__.py b/venv/Lib/site-packages/numpy/__init__.py
new file mode 100644
index 0000000..2fabd0c
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/__init__.py
@@ -0,0 +1,410 @@
+"""
+NumPy
+=====
+
+Provides
+ 1. An array object of arbitrary homogeneous items
+ 2. Fast mathematical operations over arrays
+ 3. Linear Algebra, Fourier Transforms, Random Number Generation
+
+How to use the documentation
+----------------------------
+Documentation is available in two forms: docstrings provided
+with the code, and a loose standing reference guide, available from
+`the NumPy homepage `_.
+
+We recommend exploring the docstrings using
+`IPython `_, an advanced Python shell with
+TAB-completion and introspection capabilities. See below for further
+instructions.
+
+The docstring examples assume that `numpy` has been imported as `np`::
+
+ >>> import numpy as np
+
+Code snippets are indicated by three greater-than signs::
+
+ >>> x = 42
+ >>> x = x + 1
+
+Use the built-in ``help`` function to view a function's docstring::
+
+ >>> help(np.sort)
+ ... # doctest: +SKIP
+
+For some objects, ``np.info(obj)`` may provide additional help. This is
+particularly true if you see the line "Help on ufunc object:" at the top
+of the help() page. Ufuncs are implemented in C, not Python, for speed.
+The native Python help() does not know how to view their help, but our
+np.info() function does.
+
+To search for documents containing a keyword, do::
+
+ >>> np.lookfor('keyword')
+ ... # doctest: +SKIP
+
+General-purpose documents like a glossary and help on the basic concepts
+of numpy are available under the ``doc`` sub-module::
+
+ >>> from numpy import doc
+ >>> help(doc)
+ ... # doctest: +SKIP
+
+Available subpackages
+---------------------
+doc
+ Topical documentation on broadcasting, indexing, etc.
+lib
+ Basic functions used by several sub-packages.
+random
+ Core Random Tools
+linalg
+ Core Linear Algebra Tools
+fft
+ Core FFT routines
+polynomial
+ Polynomial tools
+testing
+ NumPy testing tools
+f2py
+ Fortran to Python Interface Generator.
+distutils
+ Enhancements to distutils with support for
+ Fortran compilers support and more.
+
+Utilities
+---------
+test
+ Run numpy unittests
+show_config
+ Show numpy build configuration
+dual
+ Overwrite certain functions with high-performance SciPy tools.
+ Note: `numpy.dual` is deprecated. Use the functions from NumPy or Scipy
+ directly instead of importing them from `numpy.dual`.
+matlib
+ Make everything matrices.
+__version__
+ NumPy version string
+
+Viewing documentation using IPython
+-----------------------------------
+Start IPython with the NumPy profile (``ipython -p numpy``), which will
+import `numpy` under the alias `np`. Then, use the ``cpaste`` command to
+paste examples into the shell. To see which functions are available in
+`numpy`, type ``np.`` (where ```` refers to the TAB key), or use
+``np.*cos*?`` (where ```` refers to the ENTER key) to narrow
+down the list. To view the docstring for a function, use
+``np.cos?`` (to view the docstring) and ``np.cos??`` (to view
+the source code).
+
+Copies vs. in-place operation
+-----------------------------
+Most of the functions in `numpy` return a copy of the array argument
+(e.g., `np.sort`). In-place versions of these functions are often
+available as array methods, i.e. ``x = np.array([1,2,3]); x.sort()``.
+Exceptions to this rule are documented.
+
+"""
+import sys
+import warnings
+
+from ._globals import ModuleDeprecationWarning, VisibleDeprecationWarning
+from ._globals import _NoValue
+
+# We first need to detect if we're being called as part of the numpy setup
+# procedure itself in a reliable manner.
+try:
+ __NUMPY_SETUP__
+except NameError:
+ __NUMPY_SETUP__ = False
+
+if __NUMPY_SETUP__:
+ sys.stderr.write('Running from numpy source directory.\n')
+else:
+ try:
+ from numpy.__config__ import show as show_config
+ except ImportError as e:
+ msg = """Error importing numpy: you should not try to import numpy from
+ its source directory; please exit the numpy source tree, and relaunch
+ your python interpreter from there."""
+ raise ImportError(msg) from e
+
+ from .version import git_revision as __git_revision__
+ from .version import version as __version__
+
+ __all__ = ['ModuleDeprecationWarning',
+ 'VisibleDeprecationWarning']
+
+ # mapping of {name: (value, deprecation_msg)}
+ __deprecated_attrs__ = {}
+
+ # Allow distributors to run custom init code
+ from . import _distributor_init
+
+ from . import core
+ from .core import *
+ from . import compat
+ from . import lib
+ # NOTE: to be revisited following future namespace cleanup.
+ # See gh-14454 and gh-15672 for discussion.
+ from .lib import *
+
+ from . import linalg
+ from . import fft
+ from . import polynomial
+ from . import random
+ from . import ctypeslib
+ from . import ma
+ from . import matrixlib as _mat
+ from .matrixlib import *
+
+ # Deprecations introduced in NumPy 1.20.0, 2020-06-06
+ import builtins as _builtins
+
+ _msg = (
+ "`np.{n}` is a deprecated alias for the builtin `{n}`. "
+ "To silence this warning, use `{n}` by itself. Doing this will not "
+ "modify any behavior and is safe. {extended_msg}\n"
+ "Deprecated in NumPy 1.20; for more details and guidance: "
+ "https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations")
+
+ _specific_msg = (
+ "If you specifically wanted the numpy scalar type, use `np.{}` here.")
+
+ _int_extended_msg = (
+ "When replacing `np.{}`, you may wish to use e.g. `np.int64` "
+ "or `np.int32` to specify the precision. If you wish to review "
+ "your current use, check the release note link for "
+ "additional information.")
+
+ _type_info = [
+ ("object", ""), # The NumPy scalar only exists by name.
+ ("bool", _specific_msg.format("bool_")),
+ ("float", _specific_msg.format("float64")),
+ ("complex", _specific_msg.format("complex128")),
+ ("str", _specific_msg.format("str_")),
+ ("int", _int_extended_msg.format("int"))]
+
+ __deprecated_attrs__.update({
+ n: (getattr(_builtins, n), _msg.format(n=n, extended_msg=extended_msg))
+ for n, extended_msg in _type_info
+ })
+
+ _msg = (
+ "`np.{n}` is a deprecated alias for `np.compat.{n}`. "
+ "To silence this warning, use `np.compat.{n}` by itself. "
+ "In the likely event your code does not need to work on Python 2 "
+ "you can use the builtin `{n2}` for which `np.compat.{n}` is itself "
+ "an alias. Doing this will not modify any behaviour and is safe. "
+ "{extended_msg}\n"
+ "Deprecated in NumPy 1.20; for more details and guidance: "
+ "https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations")
+
+ __deprecated_attrs__["long"] = (
+ getattr(compat, "long"),
+ _msg.format(n="long", n2="int",
+ extended_msg=_int_extended_msg.format("long")))
+
+ __deprecated_attrs__["unicode"] = (
+ getattr(compat, "unicode"),
+ _msg.format(n="unicode", n2="str",
+ extended_msg=_specific_msg.format("str_")))
+
+ del _msg, _specific_msg, _int_extended_msg, _type_info, _builtins
+
+ from .core import round, abs, max, min
+ # now that numpy modules are imported, can initialize limits
+ core.getlimits._register_known_types()
+
+ __all__.extend(['__version__', 'show_config'])
+ __all__.extend(core.__all__)
+ __all__.extend(_mat.__all__)
+ __all__.extend(lib.__all__)
+ __all__.extend(['linalg', 'fft', 'random', 'ctypeslib', 'ma'])
+
+ # These are exported by np.core, but are replaced by the builtins below
+ # remove them to ensure that we don't end up with `np.long == np.int_`,
+ # which would be a breaking change.
+ del long, unicode
+ __all__.remove('long')
+ __all__.remove('unicode')
+
+ # Remove things that are in the numpy.lib but not in the numpy namespace
+ # Note that there is a test (numpy/tests/test_public_api.py:test_numpy_namespace)
+ # that prevents adding more things to the main namespace by accident.
+ # The list below will grow until the `from .lib import *` fixme above is
+ # taken care of
+ __all__.remove('Arrayterator')
+ del Arrayterator
+
+ # These names were removed in NumPy 1.20. For at least one release,
+ # attempts to access these names in the numpy namespace will trigger
+ # a warning, and calling the function will raise an exception.
+ _financial_names = ['fv', 'ipmt', 'irr', 'mirr', 'nper', 'npv', 'pmt',
+ 'ppmt', 'pv', 'rate']
+ __expired_functions__ = {
+ name: (f'In accordance with NEP 32, the function {name} was removed '
+ 'from NumPy version 1.20. A replacement for this function '
+ 'is available in the numpy_financial library: '
+ 'https://pypi.org/project/numpy-financial')
+ for name in _financial_names}
+
+ # Filter out Cython harmless warnings
+ warnings.filterwarnings("ignore", message="numpy.dtype size changed")
+ warnings.filterwarnings("ignore", message="numpy.ufunc size changed")
+ warnings.filterwarnings("ignore", message="numpy.ndarray size changed")
+
+ # oldnumeric and numarray were removed in 1.9. In case some packages import
+ # but do not use them, we define them here for backward compatibility.
+ oldnumeric = 'removed'
+ numarray = 'removed'
+
+ if sys.version_info[:2] >= (3, 7):
+ # module level getattr is only supported in 3.7 onwards
+ # https://www.python.org/dev/peps/pep-0562/
+ def __getattr__(attr):
+ # Warn for expired attributes, and return a dummy function
+ # that always raises an exception.
+ try:
+ msg = __expired_functions__[attr]
+ except KeyError:
+ pass
+ else:
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
+
+ def _expired(*args, **kwds):
+ raise RuntimeError(msg)
+
+ return _expired
+
+ # Emit warnings for deprecated attributes
+ try:
+ val, msg = __deprecated_attrs__[attr]
+ except KeyError:
+ pass
+ else:
+ warnings.warn(msg, DeprecationWarning, stacklevel=2)
+ return val
+
+ # Importing Tester requires importing all of UnitTest which is not a
+ # cheap import Since it is mainly used in test suits, we lazy import it
+ # here to save on the order of 10 ms of import time for most users
+ #
+ # The previous way Tester was imported also had a side effect of adding
+ # the full `numpy.testing` namespace
+ if attr == 'testing':
+ import numpy.testing as testing
+ return testing
+ elif attr == 'Tester':
+ from .testing import Tester
+ return Tester
+
+ raise AttributeError("module {!r} has no attribute "
+ "{!r}".format(__name__, attr))
+
+ def __dir__():
+ return list(globals().keys() | {'Tester', 'testing'})
+
+ else:
+ # We don't actually use this ourselves anymore, but I'm not 100% sure that
+ # no-one else in the world is using it (though I hope not)
+ from .testing import Tester
+
+ # We weren't able to emit a warning about these, so keep them around
+ globals().update({
+ k: v
+ for k, (v, msg) in __deprecated_attrs__.items()
+ })
+
+
+ # Pytest testing
+ from numpy._pytesttester import PytestTester
+ test = PytestTester(__name__)
+ del PytestTester
+
+
+ def _sanity_check():
+ """
+ Quick sanity checks for common bugs caused by environment.
+ There are some cases e.g. with wrong BLAS ABI that cause wrong
+ results under specific runtime conditions that are not necessarily
+ achieved during test suite runs, and it is useful to catch those early.
+
+ See https://github.com/numpy/numpy/issues/8577 and other
+ similar bug reports.
+
+ """
+ try:
+ x = ones(2, dtype=float32)
+ if not abs(x.dot(x) - 2.0) < 1e-5:
+ raise AssertionError()
+ except AssertionError:
+ msg = ("The current Numpy installation ({!r}) fails to "
+ "pass simple sanity checks. This can be caused for example "
+ "by incorrect BLAS library being linked in, or by mixing "
+ "package managers (pip, conda, apt, ...). Search closed "
+ "numpy issues for similar problems.")
+ raise RuntimeError(msg.format(__file__)) from None
+
+ _sanity_check()
+ del _sanity_check
+
+ def _mac_os_check():
+ """
+ Quick Sanity check for Mac OS look for accelerate build bugs.
+ Testing numpy polyfit calls init_dgelsd(LAPACK)
+ """
+ try:
+ c = array([3., 2., 1.])
+ x = linspace(0, 2, 5)
+ y = polyval(c, x)
+ _ = polyfit(x, y, 2, cov=True)
+ except ValueError:
+ pass
+
+ import sys
+ if sys.platform == "darwin":
+ with warnings.catch_warnings(record=True) as w:
+ _mac_os_check()
+ # Throw runtime error, if the test failed Check for warning and error_message
+ error_message = ""
+ if len(w) > 0:
+ error_message = "{}: {}".format(w[-1].category.__name__, str(w[-1].message))
+ msg = (
+ "Polyfit sanity test emitted a warning, most likely due "
+ "to using a buggy Accelerate backend. If you compiled "
+ "yourself, more information is available at "
+ "https://numpy.org/doc/stable/user/building.html#accelerated-blas-lapack-libraries "
+ "Otherwise report this to the vendor "
+ "that provided NumPy.\n{}\n".format(error_message))
+ raise RuntimeError(msg)
+ del _mac_os_check
+
+ # We usually use madvise hugepages support, but on some old kernels it
+ # is slow and thus better avoided.
+ # Specifically kernel version 4.6 had a bug fix which probably fixed this:
+ # https://github.com/torvalds/linux/commit/7cf91a98e607c2f935dbcc177d70011e95b8faff
+ import os
+ use_hugepage = os.environ.get("NUMPY_MADVISE_HUGEPAGE", None)
+ if sys.platform == "linux" and use_hugepage is None:
+ # If there is an issue with parsing the kernel version,
+ # set use_hugepages to 0. Usage of LooseVersion will handle
+ # the kernel version parsing better, but avoided since it
+ # will increase the import time. See: #16679 for related discussion.
+ try:
+ use_hugepage = 1
+ kernel_version = os.uname().release.split(".")[:2]
+ kernel_version = tuple(int(v) for v in kernel_version)
+ if kernel_version < (4, 6):
+ use_hugepage = 0
+ except ValueError:
+ use_hugepages = 0
+ elif use_hugepage is None:
+ # This is not Linux, so it should not matter, just enable anyway
+ use_hugepage = 1
+ else:
+ use_hugepage = int(use_hugepage)
+
+ # Note that this will currently only make a difference on Linux
+ core.multiarray._set_madvise_hugepage(use_hugepage)
diff --git a/venv/Lib/site-packages/numpy/__init__.pyi b/venv/Lib/site-packages/numpy/__init__.pyi
new file mode 100644
index 0000000..d7fbcd4
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/__init__.pyi
@@ -0,0 +1,2257 @@
+import builtins
+import sys
+import datetime as dt
+from abc import abstractmethod
+from types import TracebackType
+from contextlib import ContextDecorator
+
+from numpy.core._internal import _ctypes
+from numpy.typing import (
+ ArrayLike,
+ DTypeLike,
+ _Shape,
+ _ShapeLike,
+ _CharLike,
+ _BoolLike,
+ _IntLike,
+ _FloatLike,
+ _ComplexLike,
+ _NumberLike,
+ _SupportsDType,
+ _VoidDTypeLike,
+ NBitBase,
+ _64Bit,
+ _32Bit,
+ _16Bit,
+ _8Bit,
+)
+from numpy.typing._callable import (
+ _BoolOp,
+ _BoolBitOp,
+ _BoolSub,
+ _BoolTrueDiv,
+ _BoolMod,
+ _BoolDivMod,
+ _TD64Div,
+ _IntTrueDiv,
+ _UnsignedIntOp,
+ _UnsignedIntBitOp,
+ _UnsignedIntMod,
+ _UnsignedIntDivMod,
+ _SignedIntOp,
+ _SignedIntBitOp,
+ _SignedIntMod,
+ _SignedIntDivMod,
+ _FloatOp,
+ _FloatMod,
+ _FloatDivMod,
+ _ComplexOp,
+ _NumberOp,
+)
+
+from typing import (
+ Any,
+ ByteString,
+ Callable,
+ Container,
+ Callable,
+ Dict,
+ Generic,
+ IO,
+ Iterable,
+ List,
+ Mapping,
+ Optional,
+ overload,
+ Sequence,
+ Sized,
+ SupportsComplex,
+ SupportsFloat,
+ SupportsInt,
+ Text,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+)
+
+if sys.version_info >= (3, 8):
+ from typing import Literal, Protocol, SupportsIndex, Final
+else:
+ from typing_extensions import Literal, Protocol, Final
+ class SupportsIndex(Protocol):
+ def __index__(self) -> int: ...
+
+# Ensures that the stubs are picked up
+from numpy import (
+ char,
+ ctypeslib,
+ emath,
+ fft,
+ lib,
+ linalg,
+ ma,
+ matrixlib,
+ polynomial,
+ random,
+ rec,
+ testing,
+ version,
+)
+
+from numpy.core.function_base import (
+ linspace,
+ logspace,
+ geomspace,
+)
+
+from numpy.core.fromnumeric import (
+ take,
+ reshape,
+ choose,
+ repeat,
+ put,
+ swapaxes,
+ transpose,
+ partition,
+ argpartition,
+ sort,
+ argsort,
+ argmax,
+ argmin,
+ searchsorted,
+ resize,
+ squeeze,
+ diagonal,
+ trace,
+ ravel,
+ nonzero,
+ shape,
+ compress,
+ clip,
+ sum,
+ all,
+ any,
+ cumsum,
+ ptp,
+ amax,
+ amin,
+ prod,
+ cumprod,
+ ndim,
+ size,
+ around,
+ mean,
+ std,
+ var,
+)
+
+from numpy.core._asarray import (
+ asarray as asarray,
+ asanyarray as asanyarray,
+ ascontiguousarray as ascontiguousarray,
+ asfortranarray as asfortranarray,
+ require as require,
+)
+
+from numpy.core._type_aliases import (
+ sctypes as sctypes,
+ sctypeDict as sctypeDict,
+)
+
+from numpy.core._ufunc_config import (
+ seterr as seterr,
+ geterr as geterr,
+ setbufsize as setbufsize,
+ getbufsize as getbufsize,
+ seterrcall as seterrcall,
+ geterrcall as geterrcall,
+ _SupportsWrite,
+ _ErrKind,
+ _ErrFunc,
+ _ErrDictOptional,
+)
+
+from numpy.core.numeric import (
+ zeros_like as zeros_like,
+ ones as ones,
+ ones_like as ones_like,
+ empty_like as empty_like,
+ full as full,
+ full_like as full_like,
+ count_nonzero as count_nonzero,
+ isfortran as isfortran,
+ argwhere as argwhere,
+ flatnonzero as flatnonzero,
+ correlate as correlate,
+ convolve as convolve,
+ outer as outer,
+ tensordot as tensordot,
+ roll as roll,
+ rollaxis as rollaxis,
+ moveaxis as moveaxis,
+ cross as cross,
+ indices as indices,
+ fromfunction as fromfunction,
+ isscalar as isscalar,
+ binary_repr as binary_repr,
+ base_repr as base_repr,
+ identity as identity,
+ allclose as allclose,
+ isclose as isclose,
+ array_equal as array_equal,
+ array_equiv as array_equiv,
+)
+
+from numpy.core.numerictypes import (
+ maximum_sctype as maximum_sctype,
+ issctype as issctype,
+ obj2sctype as obj2sctype,
+ issubclass_ as issubclass_,
+ issubsctype as issubsctype,
+ issubdtype as issubdtype,
+ sctype2char as sctype2char,
+ find_common_type as find_common_type,
+)
+
+from numpy.core.shape_base import (
+ atleast_1d as atleast_1d,
+ atleast_2d as atleast_2d,
+ atleast_3d as atleast_3d,
+ block as block,
+ hstack as hstack,
+ stack as stack,
+ vstack as vstack,
+)
+
+# Add an object to `__all__` if their stubs are defined in an external file;
+# their stubs will not be recognized otherwise.
+# NOTE: This is redundant for objects defined within this file.
+__all__ = [
+ "linspace",
+ "logspace",
+ "geomspace",
+ "take",
+ "reshape",
+ "choose",
+ "repeat",
+ "put",
+ "swapaxes",
+ "transpose",
+ "partition",
+ "argpartition",
+ "sort",
+ "argsort",
+ "argmax",
+ "argmin",
+ "searchsorted",
+ "resize",
+ "squeeze",
+ "diagonal",
+ "trace",
+ "ravel",
+ "nonzero",
+ "shape",
+ "compress",
+ "clip",
+ "sum",
+ "all",
+ "any",
+ "cumsum",
+ "ptp",
+ "amax",
+ "amin",
+ "prod",
+ "cumprod",
+ "ndim",
+ "size",
+ "around",
+ "mean",
+ "std",
+ "var",
+]
+
+__path__: List[str]
+__version__: str
+
+DataSource: Any
+MachAr: Any
+ScalarType: Any
+angle: Any
+append: Any
+apply_along_axis: Any
+apply_over_axes: Any
+arange: Any
+array2string: Any
+array_repr: Any
+array_split: Any
+array_str: Any
+asarray_chkfinite: Any
+asfarray: Any
+asmatrix: Any
+asscalar: Any
+average: Any
+bartlett: Any
+bincount: Any
+bitwise_not: Any
+blackman: Any
+bmat: Any
+bool8: Any
+broadcast: Any
+broadcast_arrays: Any
+broadcast_to: Any
+busday_count: Any
+busday_offset: Any
+busdaycalendar: Any
+byte: Any
+byte_bounds: Any
+bytes0: Any
+c_: Any
+can_cast: Any
+cast: Any
+cdouble: Any
+cfloat: Any
+chararray: Any
+clongdouble: Any
+clongfloat: Any
+column_stack: Any
+common_type: Any
+compare_chararrays: Any
+complex256: Any
+complex_: Any
+concatenate: Any
+conj: Any
+copy: Any
+copyto: Any
+corrcoef: Any
+cov: Any
+csingle: Any
+cumproduct: Any
+datetime_as_string: Any
+datetime_data: Any
+delete: Any
+deprecate: Any
+deprecate_with_doc: Any
+diag: Any
+diag_indices: Any
+diag_indices_from: Any
+diagflat: Any
+diff: Any
+digitize: Any
+disp: Any
+divide: Any
+dot: Any
+double: Any
+dsplit: Any
+dstack: Any
+ediff1d: Any
+einsum: Any
+einsum_path: Any
+expand_dims: Any
+extract: Any
+eye: Any
+fill_diagonal: Any
+finfo: Any
+fix: Any
+flip: Any
+fliplr: Any
+flipud: Any
+float128: Any
+float_: Any
+format_float_positional: Any
+format_float_scientific: Any
+format_parser: Any
+frombuffer: Any
+fromfile: Any
+fromiter: Any
+frompyfunc: Any
+fromregex: Any
+fromstring: Any
+genfromtxt: Any
+get_include: Any
+get_printoptions: Any
+geterrobj: Any
+gradient: Any
+half: Any
+hamming: Any
+hanning: Any
+histogram: Any
+histogram2d: Any
+histogram_bin_edges: Any
+histogramdd: Any
+hsplit: Any
+i0: Any
+iinfo: Any
+imag: Any
+in1d: Any
+index_exp: Any
+info: Any
+inner: Any
+insert: Any
+int0: Any
+int_: Any
+intc: Any
+interp: Any
+intersect1d: Any
+intp: Any
+is_busday: Any
+iscomplex: Any
+iscomplexobj: Any
+isin: Any
+isneginf: Any
+isposinf: Any
+isreal: Any
+isrealobj: Any
+iterable: Any
+ix_: Any
+kaiser: Any
+kron: Any
+lexsort: Any
+load: Any
+loads: Any
+loadtxt: Any
+longcomplex: Any
+longdouble: Any
+longfloat: Any
+longlong: Any
+lookfor: Any
+mafromtxt: Any
+mask_indices: Any
+mat: Any
+matrix: Any
+max: Any
+may_share_memory: Any
+median: Any
+memmap: Any
+meshgrid: Any
+mgrid: Any
+min: Any
+min_scalar_type: Any
+mintypecode: Any
+mod: Any
+msort: Any
+nan_to_num: Any
+nanargmax: Any
+nanargmin: Any
+nancumprod: Any
+nancumsum: Any
+nanmax: Any
+nanmean: Any
+nanmedian: Any
+nanmin: Any
+nanpercentile: Any
+nanprod: Any
+nanquantile: Any
+nanstd: Any
+nansum: Any
+nanvar: Any
+nbytes: Any
+ndenumerate: Any
+ndfromtxt: Any
+ndindex: Any
+nditer: Any
+nested_iters: Any
+newaxis: Any
+numarray: Any
+object0: Any
+ogrid: Any
+packbits: Any
+pad: Any
+percentile: Any
+piecewise: Any
+place: Any
+poly: Any
+poly1d: Any
+polyadd: Any
+polyder: Any
+polydiv: Any
+polyfit: Any
+polyint: Any
+polymul: Any
+polysub: Any
+polyval: Any
+printoptions: Any
+product: Any
+promote_types: Any
+put_along_axis: Any
+putmask: Any
+quantile: Any
+r_: Any
+ravel_multi_index: Any
+real: Any
+real_if_close: Any
+recarray: Any
+recfromcsv: Any
+recfromtxt: Any
+record: Any
+result_type: Any
+roots: Any
+rot90: Any
+round: Any
+round_: Any
+row_stack: Any
+s_: Any
+save: Any
+savetxt: Any
+savez: Any
+savez_compressed: Any
+select: Any
+set_printoptions: Any
+set_string_function: Any
+setdiff1d: Any
+seterrobj: Any
+setxor1d: Any
+shares_memory: Any
+short: Any
+show_config: Any
+sinc: Any
+single: Any
+singlecomplex: Any
+sort_complex: Any
+source: Any
+split: Any
+string_: Any
+take_along_axis: Any
+tile: Any
+trapz: Any
+tri: Any
+tril: Any
+tril_indices: Any
+tril_indices_from: Any
+trim_zeros: Any
+triu: Any
+triu_indices: Any
+triu_indices_from: Any
+typeDict: Any
+typecodes: Any
+typename: Any
+ubyte: Any
+uint: Any
+uint0: Any
+uintc: Any
+uintp: Any
+ulonglong: Any
+union1d: Any
+unique: Any
+unpackbits: Any
+unravel_index: Any
+unwrap: Any
+ushort: Any
+vander: Any
+vdot: Any
+vectorize: Any
+void0: Any
+vsplit: Any
+where: Any
+who: Any
+
+_NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray)
+_DTypeScalar = TypeVar("_DTypeScalar", bound=generic)
+_ByteOrder = Literal["S", "<", ">", "=", "|", "L", "B", "N", "I"]
+
+class dtype(Generic[_DTypeScalar]):
+ names: Optional[Tuple[str, ...]]
+ # Overload for subclass of generic
+ @overload
+ def __new__(
+ cls,
+ dtype: Type[_DTypeScalar],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[_DTypeScalar]: ...
+ # Overloads for string aliases, Python types, and some assorted
+ # other special cases. Order is sometimes important because of the
+ # subtype relationships
+ #
+ # bool < int < float < complex
+ #
+ # so we have to make sure the overloads for the narrowest type is
+ # first.
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[bool],
+ Literal[
+ "?",
+ "=?",
+ "",
+ ">?",
+ "bool",
+ "bool_",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[bool_]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint8",
+ "u1",
+ "=u1",
+ "u1",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint8]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint16",
+ "u2",
+ "=u2",
+ "u2",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint16]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint32",
+ "u4",
+ "=u4",
+ "u4",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint32]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "uint64",
+ "u8",
+ "=u8",
+ "u8",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[uint64]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int8",
+ "i1",
+ "=i1",
+ "i1",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int8]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int16",
+ "i2",
+ "=i2",
+ "i2",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int16]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int32",
+ "i4",
+ "=i4",
+ "i4",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int32]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "int64",
+ "i8",
+ "=i8",
+ "i8",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[int64]: ...
+ # "int"/int resolve to int_, which is system dependent and as of
+ # now untyped. Long-term we'll do something fancier here.
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[Type[int], Literal["int"]],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "float16",
+ "f4",
+ "=f4",
+ "f4",
+ "e",
+ "=e",
+ "e",
+ "half",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[float16]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "float32",
+ "f4",
+ "=f4",
+ "f4",
+ "f",
+ "=f",
+ "f",
+ "single",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[float32]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ None,
+ Type[float],
+ Literal[
+ "float64",
+ "f8",
+ "=f8",
+ "f8",
+ "d",
+ "d",
+ "float",
+ "double",
+ "float_",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[float64]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Literal[
+ "complex64",
+ "c8",
+ "=c8",
+ "c8",
+ "F",
+ "=F",
+ "F",
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[complex64]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[complex],
+ Literal[
+ "complex128",
+ "c16",
+ "=c16",
+ "c16",
+ "D",
+ "=D",
+ "D",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[complex128]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[bytes],
+ Literal[
+ "S",
+ "=S",
+ "S",
+ "bytes",
+ "bytes_",
+ "bytes0",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[bytes_]: ...
+ @overload
+ def __new__(
+ cls,
+ dtype: Union[
+ Type[str],
+ Literal[
+ "U",
+ "=U",
+ # U intentionally not included; they are not
+ # the same dtype and which one dtype("U") translates
+ # to is platform-dependent.
+ "str",
+ "str_",
+ "str0",
+ ],
+ ],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[str_]: ...
+ # dtype of a dtype is the same dtype
+ @overload
+ def __new__(
+ cls,
+ dtype: dtype[_DTypeScalar],
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[_DTypeScalar]: ...
+ # TODO: handle _SupportsDType better
+ @overload
+ def __new__(
+ cls,
+ dtype: _SupportsDType,
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[Any]: ...
+ # Handle strings that can't be expressed as literals; i.e. s1, s2, ...
+ @overload
+ def __new__(
+ cls,
+ dtype: str,
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[Any]: ...
+ # Catchall overload
+ @overload
+ def __new__(
+ cls,
+ dtype: _VoidDTypeLike,
+ align: bool = ...,
+ copy: bool = ...,
+ ) -> dtype[void]: ...
+ def __eq__(self, other: DTypeLike) -> bool: ...
+ def __ne__(self, other: DTypeLike) -> bool: ...
+ def __gt__(self, other: DTypeLike) -> bool: ...
+ def __ge__(self, other: DTypeLike) -> bool: ...
+ def __lt__(self, other: DTypeLike) -> bool: ...
+ def __le__(self, other: DTypeLike) -> bool: ...
+ @property
+ def alignment(self) -> int: ...
+ @property
+ def base(self) -> dtype: ...
+ @property
+ def byteorder(self) -> str: ...
+ @property
+ def char(self) -> str: ...
+ @property
+ def descr(self) -> List[Union[Tuple[str, str], Tuple[str, str, _Shape]]]: ...
+ @property
+ def fields(
+ self,
+ ) -> Optional[Mapping[str, Union[Tuple[dtype, int], Tuple[dtype, int, Any]]]]: ...
+ @property
+ def flags(self) -> int: ...
+ @property
+ def hasobject(self) -> bool: ...
+ @property
+ def isbuiltin(self) -> int: ...
+ @property
+ def isnative(self) -> bool: ...
+ @property
+ def isalignedstruct(self) -> bool: ...
+ @property
+ def itemsize(self) -> int: ...
+ @property
+ def kind(self) -> str: ...
+ @property
+ def metadata(self) -> Optional[Mapping[str, Any]]: ...
+ @property
+ def name(self) -> str: ...
+ @property
+ def num(self) -> int: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @property
+ def ndim(self) -> int: ...
+ @property
+ def subdtype(self) -> Optional[Tuple[dtype, _Shape]]: ...
+ def newbyteorder(self, __new_order: _ByteOrder = ...) -> dtype: ...
+ # Leave str and type for end to avoid having to use `builtins.str`
+ # everywhere. See https://github.com/python/mypy/issues/3775
+ @property
+ def str(self) -> builtins.str: ...
+ @property
+ def type(self) -> Type[generic]: ...
+
+_DType = dtype # to avoid name conflicts with ndarray.dtype
+
+class _flagsobj:
+ aligned: bool
+ updateifcopy: bool
+ writeable: bool
+ writebackifcopy: bool
+ @property
+ def behaved(self) -> bool: ...
+ @property
+ def c_contiguous(self) -> bool: ...
+ @property
+ def carray(self) -> bool: ...
+ @property
+ def contiguous(self) -> bool: ...
+ @property
+ def f_contiguous(self) -> bool: ...
+ @property
+ def farray(self) -> bool: ...
+ @property
+ def fnc(self) -> bool: ...
+ @property
+ def forc(self) -> bool: ...
+ @property
+ def fortran(self) -> bool: ...
+ @property
+ def num(self) -> int: ...
+ @property
+ def owndata(self) -> bool: ...
+ def __getitem__(self, key: str) -> bool: ...
+ def __setitem__(self, key: str, value: bool) -> None: ...
+
+_ArrayLikeInt = Union[
+ int,
+ integer,
+ Sequence[Union[int, integer]],
+ Sequence[Sequence[Any]], # TODO: wait for support for recursive types
+ ndarray
+]
+
+_FlatIterSelf = TypeVar("_FlatIterSelf", bound=flatiter)
+
+class flatiter(Generic[_ArraySelf]):
+ @property
+ def base(self) -> _ArraySelf: ...
+ @property
+ def coords(self) -> _Shape: ...
+ @property
+ def index(self) -> int: ...
+ def copy(self) -> _ArraySelf: ...
+ def __iter__(self: _FlatIterSelf) -> _FlatIterSelf: ...
+ def __next__(self) -> generic: ...
+ def __len__(self) -> int: ...
+ @overload
+ def __getitem__(self, key: Union[int, integer]) -> generic: ...
+ @overload
+ def __getitem__(
+ self, key: Union[_ArrayLikeInt, slice, ellipsis],
+ ) -> _ArraySelf: ...
+ def __array__(self, __dtype: DTypeLike = ...) -> ndarray: ...
+
+_OrderKACF = Optional[Literal["K", "A", "C", "F"]]
+_OrderACF = Optional[Literal["A", "C", "F"]]
+_OrderCF = Optional[Literal["C", "F"]]
+
+_ModeKind = Literal["raise", "wrap", "clip"]
+_PartitionKind = Literal["introselect"]
+_SortKind = Literal["quicksort", "mergesort", "heapsort", "stable"]
+_SortSide = Literal["left", "right"]
+
+_ArrayLikeBool = Union[_BoolLike, Sequence[_BoolLike], ndarray]
+_ArrayLikeIntOrBool = Union[
+ _IntLike,
+ _BoolLike,
+ ndarray,
+ Sequence[_IntLike],
+ Sequence[_BoolLike],
+ Sequence[Sequence[Any]], # TODO: wait for support for recursive types
+]
+
+_ArraySelf = TypeVar("_ArraySelf", bound=_ArrayOrScalarCommon)
+
+class _ArrayOrScalarCommon:
+ @property
+ def T(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def data(self) -> memoryview: ...
+ @property
+ def flags(self) -> _flagsobj: ...
+ @property
+ def itemsize(self) -> int: ...
+ @property
+ def nbytes(self) -> int: ...
+ def __array__(self, __dtype: DTypeLike = ...) -> ndarray: ...
+ def __bool__(self) -> bool: ...
+ def __bytes__(self) -> bytes: ...
+ def __str__(self) -> str: ...
+ def __repr__(self) -> str: ...
+ def __copy__(self: _ArraySelf) -> _ArraySelf: ...
+ def __deepcopy__(self: _ArraySelf, __memo: Optional[dict] = ...) -> _ArraySelf: ...
+ def __lt__(self, other): ...
+ def __le__(self, other): ...
+ def __eq__(self, other): ...
+ def __ne__(self, other): ...
+ def __gt__(self, other): ...
+ def __ge__(self, other): ...
+ def astype(
+ self: _ArraySelf,
+ dtype: DTypeLike,
+ order: _OrderKACF = ...,
+ casting: _Casting = ...,
+ subok: bool = ...,
+ copy: bool = ...,
+ ) -> _ArraySelf: ...
+ def copy(self: _ArraySelf, order: _OrderKACF = ...) -> _ArraySelf: ...
+ def dump(self, file: str) -> None: ...
+ def dumps(self) -> bytes: ...
+ def flatten(self, order: _OrderKACF = ...) -> ndarray: ...
+ def getfield(
+ self: _ArraySelf, dtype: DTypeLike, offset: int = ...
+ ) -> _ArraySelf: ...
+ def ravel(self, order: _OrderKACF = ...) -> ndarray: ...
+ @overload
+ def reshape(
+ self, __shape: Sequence[int], *, order: _OrderACF = ...
+ ) -> ndarray: ...
+ @overload
+ def reshape(
+ self, *shape: int, order: _OrderACF = ...
+ ) -> ndarray: ...
+ def tobytes(self, order: _OrderKACF = ...) -> bytes: ...
+ # NOTE: `tostring()` is deprecated and therefore excluded
+ # def tostring(self, order=...): ...
+ def tofile(
+ self, fid: Union[IO[bytes], str], sep: str = ..., format: str = ...
+ ) -> None: ...
+ # generics and 0d arrays return builtin scalars
+ def tolist(self) -> Any: ...
+ @overload
+ def view(self, type: Type[_NdArraySubClass]) -> _NdArraySubClass: ...
+ @overload
+ def view(self: _ArraySelf, dtype: DTypeLike = ...) -> _ArraySelf: ...
+ @overload
+ def view(
+ self, dtype: DTypeLike, type: Type[_NdArraySubClass]
+ ) -> _NdArraySubClass: ...
+
+ # TODO: Add proper signatures
+ def __getitem__(self, key) -> Any: ...
+ @property
+ def __array_interface__(self): ...
+ @property
+ def __array_priority__(self): ...
+ @property
+ def __array_struct__(self): ...
+ def __array_wrap__(array, context=...): ...
+ def __setstate__(self, __state): ...
+ # a `bool_` is returned when `keepdims=True` and `self` is a 0d array
+ @overload
+ def all(
+ self, axis: None = ..., out: None = ..., keepdims: Literal[False] = ...
+ ) -> bool_: ...
+ @overload
+ def all(
+ self, axis: Optional[_ShapeLike] = ..., out: None = ..., keepdims: bool = ...
+ ) -> Union[bool_, ndarray]: ...
+ @overload
+ def all(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def any(
+ self, axis: None = ..., out: None = ..., keepdims: Literal[False] = ...
+ ) -> bool_: ...
+ @overload
+ def any(
+ self, axis: Optional[_ShapeLike] = ..., out: None = ..., keepdims: bool = ...
+ ) -> Union[bool_, ndarray]: ...
+ @overload
+ def any(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def argmax(self, axis: None = ..., out: None = ...) -> signedinteger: ...
+ @overload
+ def argmax(
+ self, axis: _ShapeLike = ..., out: None = ...
+ ) -> Union[signedinteger, ndarray]: ...
+ @overload
+ def argmax(
+ self, axis: Optional[_ShapeLike] = ..., out: _NdArraySubClass = ...
+ ) -> _NdArraySubClass: ...
+ @overload
+ def argmin(self, axis: None = ..., out: None = ...) -> signedinteger: ...
+ @overload
+ def argmin(
+ self, axis: _ShapeLike = ..., out: None = ...
+ ) -> Union[signedinteger, ndarray]: ...
+ @overload
+ def argmin(
+ self, axis: Optional[_ShapeLike] = ..., out: _NdArraySubClass = ...
+ ) -> _NdArraySubClass: ...
+ def argsort(
+ self,
+ axis: Optional[int] = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> ndarray: ...
+ @overload
+ def choose(
+ self, choices: ArrayLike, out: None = ..., mode: _ModeKind = ...,
+ ) -> ndarray: ...
+ @overload
+ def choose(
+ self, choices: ArrayLike, out: _NdArraySubClass = ..., mode: _ModeKind = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def clip(
+ self,
+ min: ArrayLike = ...,
+ max: Optional[ArrayLike] = ...,
+ out: None = ...,
+ **kwargs: Any,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def clip(
+ self,
+ min: None = ...,
+ max: ArrayLike = ...,
+ out: None = ...,
+ **kwargs: Any,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def clip(
+ self,
+ min: ArrayLike = ...,
+ max: Optional[ArrayLike] = ...,
+ out: _NdArraySubClass = ...,
+ **kwargs: Any,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def clip(
+ self,
+ min: None = ...,
+ max: ArrayLike = ...,
+ out: _NdArraySubClass = ...,
+ **kwargs: Any,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def compress(
+ self, a: ArrayLike, axis: Optional[int] = ..., out: None = ...,
+ ) -> ndarray: ...
+ @overload
+ def compress(
+ self, a: ArrayLike, axis: Optional[int] = ..., out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ def conj(self: _ArraySelf) -> _ArraySelf: ...
+ def conjugate(self: _ArraySelf) -> _ArraySelf: ...
+ @overload
+ def cumprod(
+ self, axis: Optional[int] = ..., dtype: DTypeLike = ..., out: None = ...,
+ ) -> ndarray: ...
+ @overload
+ def cumprod(
+ self,
+ axis: Optional[int] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def cumsum(
+ self, axis: Optional[int] = ..., dtype: DTypeLike = ..., out: None = ...,
+ ) -> ndarray: ...
+ @overload
+ def cumsum(
+ self,
+ axis: Optional[int] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def max(
+ self,
+ axis: None = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def max(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def max(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def mean(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def mean(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def mean(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def min(
+ self,
+ axis: None = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def min(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def min(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ def newbyteorder(self: _ArraySelf, __new_order: _ByteOrder = ...) -> _ArraySelf: ...
+ @overload
+ def prod(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def prod(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def prod(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def ptp(
+ self, axis: None = ..., out: None = ..., keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def ptp(
+ self, axis: Optional[_ShapeLike] = ..., out: None = ..., keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def ptp(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ def repeat(
+ self, repeats: _ArrayLikeIntOrBool, axis: Optional[int] = ...
+ ) -> ndarray: ...
+ @overload
+ def round(self: _ArraySelf, decimals: int = ..., out: None = ...) -> _ArraySelf: ...
+ @overload
+ def round(
+ self, decimals: int = ..., out: _NdArraySubClass = ...
+ ) -> _NdArraySubClass: ...
+ @overload
+ def std(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def std(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def std(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def sum(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: Literal[False] = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> number: ...
+ @overload
+ def sum(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def sum(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ keepdims: bool = ...,
+ initial: _NumberLike = ...,
+ where: _ArrayLikeBool = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def take(
+ self,
+ indices: Union[_IntLike, _BoolLike],
+ axis: Optional[int] = ...,
+ out: None = ...,
+ mode: _ModeKind = ...,
+ ) -> generic: ...
+ @overload
+ def take(
+ self,
+ indices: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ out: None = ...,
+ mode: _ModeKind = ...,
+ ) -> ndarray: ...
+ @overload
+ def take(
+ self,
+ indices: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ out: _NdArraySubClass = ...,
+ mode: _ModeKind = ...,
+ ) -> _NdArraySubClass: ...
+ @overload
+ def var(
+ self,
+ axis: None = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: Literal[False] = ...,
+ ) -> number: ...
+ @overload
+ def var(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def var(
+ self,
+ axis: Optional[_ShapeLike] = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ddof: int = ...,
+ keepdims: bool = ...,
+ ) -> _NdArraySubClass: ...
+
+_BufferType = Union[ndarray, bytes, bytearray, memoryview]
+_Casting = Literal["no", "equiv", "safe", "same_kind", "unsafe"]
+
+class ndarray(_ArrayOrScalarCommon, Iterable, Sized, Container):
+ @property
+ def base(self) -> Optional[ndarray]: ...
+ @property
+ def ndim(self) -> int: ...
+ @property
+ def size(self) -> int: ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @real.setter
+ def real(self, value: ArrayLike) -> None: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ @imag.setter
+ def imag(self, value: ArrayLike) -> None: ...
+ def __new__(
+ cls: Type[_ArraySelf],
+ shape: Sequence[int],
+ dtype: DTypeLike = ...,
+ buffer: _BufferType = ...,
+ offset: int = ...,
+ strides: _ShapeLike = ...,
+ order: _OrderKACF = ...,
+ ) -> _ArraySelf: ...
+ @property
+ def dtype(self) -> _DType: ...
+ @property
+ def ctypes(self) -> _ctypes: ...
+ @property
+ def shape(self) -> _Shape: ...
+ @shape.setter
+ def shape(self, value: _ShapeLike): ...
+ @property
+ def strides(self) -> _Shape: ...
+ @strides.setter
+ def strides(self, value: _ShapeLike): ...
+ def byteswap(self: _ArraySelf, inplace: bool = ...) -> _ArraySelf: ...
+ def fill(self, value: Any) -> None: ...
+ @property
+ def flat(self: _ArraySelf) -> flatiter[_ArraySelf]: ...
+ @overload
+ def item(self, *args: int) -> Any: ...
+ @overload
+ def item(self, __args: Tuple[int, ...]) -> Any: ...
+ @overload
+ def itemset(self, __value: Any) -> None: ...
+ @overload
+ def itemset(self, __item: _ShapeLike, __value: Any) -> None: ...
+ @overload
+ def resize(self, __new_shape: Sequence[int], *, refcheck: bool = ...) -> None: ...
+ @overload
+ def resize(self, *new_shape: int, refcheck: bool = ...) -> None: ...
+ def setflags(
+ self, write: bool = ..., align: bool = ..., uic: bool = ...
+ ) -> None: ...
+ def squeeze(
+ self: _ArraySelf, axis: Union[int, Tuple[int, ...]] = ...
+ ) -> _ArraySelf: ...
+ def swapaxes(self: _ArraySelf, axis1: int, axis2: int) -> _ArraySelf: ...
+ @overload
+ def transpose(self: _ArraySelf, __axes: Sequence[int]) -> _ArraySelf: ...
+ @overload
+ def transpose(self: _ArraySelf, *axes: int) -> _ArraySelf: ...
+ def argpartition(
+ self,
+ kth: _ArrayLikeIntOrBool,
+ axis: Optional[int] = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> ndarray: ...
+ def diagonal(
+ self: _ArraySelf, offset: int = ..., axis1: int = ..., axis2: int = ...
+ ) -> _ArraySelf: ...
+ @overload
+ def dot(self, b: ArrayLike, out: None = ...) -> Union[number, ndarray]: ...
+ @overload
+ def dot(self, b: ArrayLike, out: _NdArraySubClass = ...) -> _NdArraySubClass: ...
+ # `nonzero()` is deprecated for 0d arrays/generics
+ def nonzero(self) -> Tuple[ndarray, ...]: ...
+ def partition(
+ self,
+ kth: _ArrayLikeIntOrBool,
+ axis: int = ...,
+ kind: _PartitionKind = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> None: ...
+ # `put` is technically available to `generic`,
+ # but is pointless as `generic`s are immutable
+ def put(
+ self, ind: _ArrayLikeIntOrBool, v: ArrayLike, mode: _ModeKind = ...
+ ) -> None: ...
+ def searchsorted(
+ self, # >= 1D array
+ v: ArrayLike,
+ side: _SortSide = ...,
+ sorter: Optional[_ArrayLikeIntOrBool] = ..., # 1D int array
+ ) -> ndarray: ...
+ def setfield(
+ self, val: ArrayLike, dtype: DTypeLike, offset: int = ...
+ ) -> None: ...
+ def sort(
+ self,
+ axis: int = ...,
+ kind: Optional[_SortKind] = ...,
+ order: Union[None, str, Sequence[str]] = ...,
+ ) -> None: ...
+ @overload
+ def trace(
+ self, # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+ dtype: DTypeLike = ...,
+ out: None = ...,
+ ) -> Union[number, ndarray]: ...
+ @overload
+ def trace(
+ self, # >= 2D array
+ offset: int = ...,
+ axis1: int = ...,
+ axis2: int = ...,
+ dtype: DTypeLike = ...,
+ out: _NdArraySubClass = ...,
+ ) -> _NdArraySubClass: ...
+ # Many of these special methods are irrelevant currently, since protocols
+ # aren't supported yet. That said, I'm adding them for completeness.
+ # https://docs.python.org/3/reference/datamodel.html
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __len__(self) -> int: ...
+ def __setitem__(self, key, value): ...
+ def __iter__(self) -> Any: ...
+ def __contains__(self, key) -> bool: ...
+ def __index__(self) -> int: ...
+ def __matmul__(self, other: ArrayLike) -> Any: ...
+ # NOTE: `ndarray` does not implement `__imatmul__`
+ def __rmatmul__(self, other: ArrayLike) -> Any: ...
+ def __neg__(self: _ArraySelf) -> Any: ...
+ def __pos__(self: _ArraySelf) -> Any: ...
+ def __abs__(self: _ArraySelf) -> Any: ...
+ def __mod__(self, other: ArrayLike) -> Any: ...
+ def __rmod__(self, other: ArrayLike) -> Any: ...
+ def __divmod__(self, other: ArrayLike) -> Tuple[Any, Any]: ...
+ def __rdivmod__(self, other: ArrayLike) -> Tuple[Any, Any]: ...
+ def __add__(self, other: ArrayLike) -> Any: ...
+ def __radd__(self, other: ArrayLike) -> Any: ...
+ def __sub__(self, other: ArrayLike) -> Any: ...
+ def __rsub__(self, other: ArrayLike) -> Any: ...
+ def __mul__(self, other: ArrayLike) -> Any: ...
+ def __rmul__(self, other: ArrayLike) -> Any: ...
+ def __floordiv__(self, other: ArrayLike) -> Any: ...
+ def __rfloordiv__(self, other: ArrayLike) -> Any: ...
+ def __pow__(self, other: ArrayLike) -> Any: ...
+ def __rpow__(self, other: ArrayLike) -> Any: ...
+ def __truediv__(self, other: ArrayLike) -> Any: ...
+ def __rtruediv__(self, other: ArrayLike) -> Any: ...
+ def __invert__(self: _ArraySelf) -> Any: ...
+ def __lshift__(self, other: ArrayLike) -> Any: ...
+ def __rlshift__(self, other: ArrayLike) -> Any: ...
+ def __rshift__(self, other: ArrayLike) -> Any: ...
+ def __rrshift__(self, other: ArrayLike) -> Any: ...
+ def __and__(self, other: ArrayLike) -> Any: ...
+ def __rand__(self, other: ArrayLike) -> Any: ...
+ def __xor__(self, other: ArrayLike) -> Any: ...
+ def __rxor__(self, other: ArrayLike) -> Any: ...
+ def __or__(self, other: ArrayLike) -> Any: ...
+ def __ror__(self, other: ArrayLike) -> Any: ...
+ # `np.generic` does not support inplace operations
+ def __iadd__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __isub__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __imul__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __itruediv__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ifloordiv__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ipow__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __imod__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ilshift__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __irshift__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __iand__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ixor__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+ def __ior__(self: _ArraySelf, other: ArrayLike) -> _ArraySelf: ...
+
+# NOTE: while `np.generic` is not technically an instance of `ABCMeta`,
+# the `@abstractmethod` decorator is herein used to (forcefully) deny
+# the creation of `np.generic` instances.
+# The `# type: ignore` comments are necessary to silence mypy errors regarding
+# the missing `ABCMeta` metaclass.
+
+# See https://github.com/numpy/numpy-stubs/pull/80 for more details.
+
+_ScalarType = TypeVar("_ScalarType", bound=generic)
+_NBit_co = TypeVar("_NBit_co", covariant=True, bound=NBitBase)
+_NBit_co2 = TypeVar("_NBit_co2", covariant=True, bound=NBitBase)
+
+class generic(_ArrayOrScalarCommon):
+ @abstractmethod
+ def __init__(self, *args: Any, **kwargs: Any) -> None: ...
+ @property
+ def base(self) -> None: ...
+ @property
+ def dtype(self: _ScalarType) -> _DType[_ScalarType]: ...
+ @property
+ def ndim(self) -> Literal[0]: ...
+ @property
+ def size(self) -> Literal[1]: ...
+ @property
+ def shape(self) -> Tuple[()]: ...
+ @property
+ def strides(self) -> Tuple[()]: ...
+ def byteswap(self: _ScalarType, inplace: Literal[False] = ...) -> _ScalarType: ...
+ @property
+ def flat(self) -> flatiter[ndarray]: ...
+ def item(
+ self: _ScalarType,
+ __args: Union[Literal[0], Tuple[()], Tuple[Literal[0]]] = ...,
+ ) -> Any: ...
+ def squeeze(
+ self: _ScalarType, axis: Union[Literal[0], Tuple[()]] = ...
+ ) -> _ScalarType: ...
+ def transpose(self: _ScalarType, __axes: Tuple[()] = ...) -> _ScalarType: ...
+
+class number(generic, Generic[_NBit_co]): # type: ignore
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __neg__(self: _ArraySelf) -> _ArraySelf: ...
+ def __pos__(self: _ArraySelf) -> _ArraySelf: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ # Ensure that objects annotated as `number` support arithmetic operations
+ __add__: _NumberOp
+ __radd__: _NumberOp
+ __sub__: _NumberOp
+ __rsub__: _NumberOp
+ __mul__: _NumberOp
+ __rmul__: _NumberOp
+ __floordiv__: _NumberOp
+ __rfloordiv__: _NumberOp
+ __pow__: _NumberOp
+ __rpow__: _NumberOp
+ __truediv__: _NumberOp
+ __rtruediv__: _NumberOp
+
+class bool_(generic):
+ def __init__(self, __value: object = ...) -> None: ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ __add__: _BoolOp[bool_]
+ __radd__: _BoolOp[bool_]
+ __sub__: _BoolSub
+ __rsub__: _BoolSub
+ __mul__: _BoolOp[bool_]
+ __rmul__: _BoolOp[bool_]
+ __floordiv__: _BoolOp[int8]
+ __rfloordiv__: _BoolOp[int8]
+ __pow__: _BoolOp[int8]
+ __rpow__: _BoolOp[int8]
+ __truediv__: _BoolTrueDiv
+ __rtruediv__: _BoolTrueDiv
+ def __invert__(self) -> bool_: ...
+ __lshift__: _BoolBitOp[int8]
+ __rlshift__: _BoolBitOp[int8]
+ __rshift__: _BoolBitOp[int8]
+ __rrshift__: _BoolBitOp[int8]
+ __and__: _BoolBitOp[bool_]
+ __rand__: _BoolBitOp[bool_]
+ __xor__: _BoolBitOp[bool_]
+ __rxor__: _BoolBitOp[bool_]
+ __or__: _BoolBitOp[bool_]
+ __ror__: _BoolBitOp[bool_]
+ __mod__: _BoolMod
+ __rmod__: _BoolMod
+ __divmod__: _BoolDivMod
+ __rdivmod__: _BoolDivMod
+
+class object_(generic):
+ def __init__(self, __value: object = ...) -> None: ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+
+class datetime64(generic):
+ @overload
+ def __init__(
+ self,
+ __value: Union[None, datetime64, _CharLike, dt.datetime] = ...,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]] = ...,
+ ) -> None: ...
+ @overload
+ def __init__(
+ self,
+ __value: int,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]]
+ ) -> None: ...
+ def __add__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ def __radd__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ @overload
+ def __sub__(self, other: datetime64) -> timedelta64: ...
+ @overload
+ def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> datetime64: ...
+ def __rsub__(self, other: datetime64) -> timedelta64: ...
+
+# Support for `__index__` was added in python 3.8 (bpo-20092)
+if sys.version_info >= (3, 8):
+ _IntValue = Union[SupportsInt, _CharLike, SupportsIndex]
+ _FloatValue = Union[None, _CharLike, SupportsFloat, SupportsIndex]
+ _ComplexValue = Union[None, _CharLike, SupportsFloat, SupportsComplex, SupportsIndex]
+else:
+ _IntValue = Union[SupportsInt, _CharLike]
+ _FloatValue = Union[None, _CharLike, SupportsFloat]
+ _ComplexValue = Union[None, _CharLike, SupportsFloat, SupportsComplex]
+
+class integer(number[_NBit_co]): # type: ignore
+ # NOTE: `__index__` is technically defined in the bottom-most
+ # sub-classes (`int64`, `uint32`, etc)
+ def __index__(self) -> int: ...
+ __truediv__: _IntTrueDiv[_NBit_co]
+ __rtruediv__: _IntTrueDiv[_NBit_co]
+ def __mod__(self, value: Union[_IntLike, integer]) -> integer: ...
+ def __rmod__(self, value: Union[_IntLike, integer]) -> integer: ...
+ def __invert__(self: _IntType) -> _IntType: ...
+ # Ensure that objects annotated as `integer` support bit-wise operations
+ def __lshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rlshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rrshift__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __and__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rand__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __or__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __ror__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __xor__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+ def __rxor__(self, other: Union[_IntLike, _BoolLike]) -> integer: ...
+
+class signedinteger(integer[_NBit_co]):
+ def __init__(self, __value: _IntValue = ...) -> None: ...
+ __add__: _SignedIntOp[_NBit_co]
+ __radd__: _SignedIntOp[_NBit_co]
+ __sub__: _SignedIntOp[_NBit_co]
+ __rsub__: _SignedIntOp[_NBit_co]
+ __mul__: _SignedIntOp[_NBit_co]
+ __rmul__: _SignedIntOp[_NBit_co]
+ __floordiv__: _SignedIntOp[_NBit_co]
+ __rfloordiv__: _SignedIntOp[_NBit_co]
+ __pow__: _SignedIntOp[_NBit_co]
+ __rpow__: _SignedIntOp[_NBit_co]
+ __lshift__: _SignedIntBitOp[_NBit_co]
+ __rlshift__: _SignedIntBitOp[_NBit_co]
+ __rshift__: _SignedIntBitOp[_NBit_co]
+ __rrshift__: _SignedIntBitOp[_NBit_co]
+ __and__: _SignedIntBitOp[_NBit_co]
+ __rand__: _SignedIntBitOp[_NBit_co]
+ __xor__: _SignedIntBitOp[_NBit_co]
+ __rxor__: _SignedIntBitOp[_NBit_co]
+ __or__: _SignedIntBitOp[_NBit_co]
+ __ror__: _SignedIntBitOp[_NBit_co]
+ __mod__: _SignedIntMod[_NBit_co]
+ __rmod__: _SignedIntMod[_NBit_co]
+ __divmod__: _SignedIntDivMod[_NBit_co]
+ __rdivmod__: _SignedIntDivMod[_NBit_co]
+
+int8 = signedinteger[_8Bit]
+int16 = signedinteger[_16Bit]
+int32 = signedinteger[_32Bit]
+int64 = signedinteger[_64Bit]
+
+class timedelta64(generic):
+ def __init__(
+ self,
+ __value: Union[None, int, _CharLike, dt.timedelta, timedelta64] = ...,
+ __format: Union[_CharLike, Tuple[_CharLike, _IntLike]] = ...,
+ ) -> None: ...
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+ def __complex__(self) -> complex: ...
+ def __neg__(self: _ArraySelf) -> _ArraySelf: ...
+ def __pos__(self: _ArraySelf) -> _ArraySelf: ...
+ def __abs__(self: _ArraySelf) -> _ArraySelf: ...
+ def __add__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __radd__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __sub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __rsub__(self, other: Union[timedelta64, _IntLike, _BoolLike]) -> timedelta64: ...
+ def __mul__(self, other: Union[_FloatLike, _BoolLike]) -> timedelta64: ...
+ def __rmul__(self, other: Union[_FloatLike, _BoolLike]) -> timedelta64: ...
+ __truediv__: _TD64Div[float64]
+ __floordiv__: _TD64Div[int64]
+ def __rtruediv__(self, other: timedelta64) -> float64: ...
+ def __rfloordiv__(self, other: timedelta64) -> int64: ...
+ def __mod__(self, other: timedelta64) -> timedelta64: ...
+ def __rmod__(self, other: timedelta64) -> timedelta64: ...
+ def __divmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ...
+ def __rdivmod__(self, other: timedelta64) -> Tuple[int64, timedelta64]: ...
+
+class unsignedinteger(integer[_NBit_co]):
+ # NOTE: `uint64 + signedinteger -> float64`
+ def __init__(self, __value: _IntValue = ...) -> None: ...
+ __add__: _UnsignedIntOp[_NBit_co]
+ __radd__: _UnsignedIntOp[_NBit_co]
+ __sub__: _UnsignedIntOp[_NBit_co]
+ __rsub__: _UnsignedIntOp[_NBit_co]
+ __mul__: _UnsignedIntOp[_NBit_co]
+ __rmul__: _UnsignedIntOp[_NBit_co]
+ __floordiv__: _UnsignedIntOp[_NBit_co]
+ __rfloordiv__: _UnsignedIntOp[_NBit_co]
+ __pow__: _UnsignedIntOp[_NBit_co]
+ __rpow__: _UnsignedIntOp[_NBit_co]
+ __lshift__: _UnsignedIntBitOp[_NBit_co]
+ __rlshift__: _UnsignedIntBitOp[_NBit_co]
+ __rshift__: _UnsignedIntBitOp[_NBit_co]
+ __rrshift__: _UnsignedIntBitOp[_NBit_co]
+ __and__: _UnsignedIntBitOp[_NBit_co]
+ __rand__: _UnsignedIntBitOp[_NBit_co]
+ __xor__: _UnsignedIntBitOp[_NBit_co]
+ __rxor__: _UnsignedIntBitOp[_NBit_co]
+ __or__: _UnsignedIntBitOp[_NBit_co]
+ __ror__: _UnsignedIntBitOp[_NBit_co]
+ __mod__: _UnsignedIntMod[_NBit_co]
+ __rmod__: _UnsignedIntMod[_NBit_co]
+ __divmod__: _UnsignedIntDivMod[_NBit_co]
+ __rdivmod__: _UnsignedIntDivMod[_NBit_co]
+
+uint8 = unsignedinteger[_8Bit]
+uint16 = unsignedinteger[_16Bit]
+uint32 = unsignedinteger[_32Bit]
+uint64 = unsignedinteger[_64Bit]
+
+class inexact(number[_NBit_co]): ... # type: ignore
+
+_IntType = TypeVar("_IntType", bound=integer)
+_FloatType = TypeVar('_FloatType', bound=floating)
+
+class floating(inexact[_NBit_co]):
+ def __init__(self, __value: _FloatValue = ...) -> None: ...
+ __add__: _FloatOp[_NBit_co]
+ __radd__: _FloatOp[_NBit_co]
+ __sub__: _FloatOp[_NBit_co]
+ __rsub__: _FloatOp[_NBit_co]
+ __mul__: _FloatOp[_NBit_co]
+ __rmul__: _FloatOp[_NBit_co]
+ __truediv__: _FloatOp[_NBit_co]
+ __rtruediv__: _FloatOp[_NBit_co]
+ __floordiv__: _FloatOp[_NBit_co]
+ __rfloordiv__: _FloatOp[_NBit_co]
+ __pow__: _FloatOp[_NBit_co]
+ __rpow__: _FloatOp[_NBit_co]
+ __mod__: _FloatMod[_NBit_co]
+ __rmod__: _FloatMod[_NBit_co]
+ __divmod__: _FloatDivMod[_NBit_co]
+ __rdivmod__: _FloatDivMod[_NBit_co]
+
+float16 = floating[_16Bit]
+float32 = floating[_32Bit]
+float64 = floating[_64Bit]
+
+# The main reason for `complexfloating` having two typevars is cosmetic.
+# It is used to clarify why `complex128`s precision is `_64Bit`, the latter
+# describing the two 64 bit floats representing its real and imaginary component
+
+class complexfloating(inexact[_NBit_co], Generic[_NBit_co, _NBit_co2]):
+ def __init__(self, __value: _ComplexValue = ...) -> None: ...
+ @property
+ def real(self) -> floating[_NBit_co]: ... # type: ignore[override]
+ @property
+ def imag(self) -> floating[_NBit_co2]: ... # type: ignore[override]
+ def __abs__(self) -> floating[_NBit_co]: ... # type: ignore[override]
+ __add__: _ComplexOp[_NBit_co]
+ __radd__: _ComplexOp[_NBit_co]
+ __sub__: _ComplexOp[_NBit_co]
+ __rsub__: _ComplexOp[_NBit_co]
+ __mul__: _ComplexOp[_NBit_co]
+ __rmul__: _ComplexOp[_NBit_co]
+ __truediv__: _ComplexOp[_NBit_co]
+ __rtruediv__: _ComplexOp[_NBit_co]
+ __floordiv__: _ComplexOp[_NBit_co]
+ __rfloordiv__: _ComplexOp[_NBit_co]
+ __pow__: _ComplexOp[_NBit_co]
+ __rpow__: _ComplexOp[_NBit_co]
+
+complex64 = complexfloating[_32Bit, _32Bit]
+complex128 = complexfloating[_64Bit, _64Bit]
+
+class flexible(generic): ... # type: ignore
+
+class void(flexible):
+ def __init__(self, __value: Union[_IntLike, _BoolLike, bytes]): ...
+ @property
+ def real(self: _ArraySelf) -> _ArraySelf: ...
+ @property
+ def imag(self: _ArraySelf) -> _ArraySelf: ...
+ def setfield(
+ self, val: ArrayLike, dtype: DTypeLike, offset: int = ...
+ ) -> None: ...
+
+class character(flexible): # type: ignore
+ def __int__(self) -> int: ...
+ def __float__(self) -> float: ...
+
+# NOTE: Most `np.bytes_` / `np.str_` methods return their
+# builtin `bytes` / `str` counterpart
+
+class bytes_(character, bytes):
+ @overload
+ def __init__(self, __value: object = ...) -> None: ...
+ @overload
+ def __init__(
+ self, __value: str, encoding: str = ..., errors: str = ...
+ ) -> None: ...
+
+class str_(character, str):
+ @overload
+ def __init__(self, __value: object = ...) -> None: ...
+ @overload
+ def __init__(
+ self, __value: bytes, encoding: str = ..., errors: str = ...
+ ) -> None: ...
+
+unicode_ = str0 = str_
+
+# TODO(alan): Platform dependent types
+# longcomplex, longdouble, longfloat
+# bytes, short, intc, intp, longlong
+# half, single, double, longdouble
+# uint_, int_, float_, complex_
+# float128, complex256
+# float96
+
+def array(
+ object: object,
+ dtype: DTypeLike = ...,
+ *,
+ copy: bool = ...,
+ order: _OrderKACF = ...,
+ subok: bool = ...,
+ ndmin: int = ...,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+def zeros(
+ shape: _ShapeLike,
+ dtype: DTypeLike = ...,
+ order: _OrderCF = ...,
+ *,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+def empty(
+ shape: _ShapeLike,
+ dtype: DTypeLike = ...,
+ order: _OrderCF = ...,
+ *,
+ like: ArrayLike = ...,
+) -> ndarray: ...
+
+def broadcast_shapes(*args: _ShapeLike) -> _Shape: ...
+
+#
+# Constants
+#
+
+Inf: Final[float]
+Infinity: Final[float]
+NAN: Final[float]
+NINF: Final[float]
+NZERO: Final[float]
+NaN: Final[float]
+PINF: Final[float]
+PZERO: Final[float]
+e: Final[float]
+euler_gamma: Final[float]
+inf: Final[float]
+infty: Final[float]
+nan: Final[float]
+pi: Final[float]
+ALLOW_THREADS: Final[int]
+BUFSIZE: Final[int]
+CLIP: Final[int]
+ERR_CALL: Final[int]
+ERR_DEFAULT: Final[int]
+ERR_IGNORE: Final[int]
+ERR_LOG: Final[int]
+ERR_PRINT: Final[int]
+ERR_RAISE: Final[int]
+ERR_WARN: Final[int]
+FLOATING_POINT_SUPPORT: Final[int]
+FPE_DIVIDEBYZERO: Final[int]
+FPE_INVALID: Final[int]
+FPE_OVERFLOW: Final[int]
+FPE_UNDERFLOW: Final[int]
+MAXDIMS: Final[int]
+MAY_SHARE_BOUNDS: Final[int]
+MAY_SHARE_EXACT: Final[int]
+RAISE: Final[int]
+SHIFT_DIVIDEBYZERO: Final[int]
+SHIFT_INVALID: Final[int]
+SHIFT_OVERFLOW: Final[int]
+SHIFT_UNDERFLOW: Final[int]
+UFUNC_BUFSIZE_DEFAULT: Final[int]
+WRAP: Final[int]
+tracemalloc_domain: Final[int]
+
+little_endian: Final[bool]
+True_: Final[bool_]
+False_: Final[bool_]
+
+UFUNC_PYVALS_NAME: Final[str]
+
+class ufunc:
+ @property
+ def __name__(self) -> str: ...
+ def __call__(
+ self,
+ *args: ArrayLike,
+ out: Optional[Union[ndarray, Tuple[ndarray, ...]]] = ...,
+ where: Optional[ndarray] = ...,
+ # The list should be a list of tuples of ints, but since we
+ # don't know the signature it would need to be
+ # Tuple[int, ...]. But, since List is invariant something like
+ # e.g. List[Tuple[int, int]] isn't a subtype of
+ # List[Tuple[int, ...]], so we can't type precisely here.
+ axes: List[Any] = ...,
+ axis: int = ...,
+ keepdims: bool = ...,
+ casting: _Casting = ...,
+ order: _OrderKACF = ...,
+ dtype: DTypeLike = ...,
+ subok: bool = ...,
+ signature: Union[str, Tuple[str]] = ...,
+ # In reality this should be a length of list 3 containing an
+ # int, an int, and a callable, but there's no way to express
+ # that.
+ extobj: List[Union[int, Callable]] = ...,
+ ) -> Any: ...
+ @property
+ def nin(self) -> int: ...
+ @property
+ def nout(self) -> int: ...
+ @property
+ def nargs(self) -> int: ...
+ @property
+ def ntypes(self) -> int: ...
+ @property
+ def types(self) -> List[str]: ...
+ # Broad return type because it has to encompass things like
+ #
+ # >>> np.logical_and.identity is True
+ # True
+ # >>> np.add.identity is 0
+ # True
+ # >>> np.sin.identity is None
+ # True
+ #
+ # and any user-defined ufuncs.
+ @property
+ def identity(self) -> Any: ...
+ # This is None for ufuncs and a string for gufuncs.
+ @property
+ def signature(self) -> Optional[str]: ...
+ # The next four methods will always exist, but they will just
+ # raise a ValueError ufuncs with that don't accept two input
+ # arguments and return one output argument. Because of that we
+ # can't type them very precisely.
+ @property
+ def reduce(self) -> Any: ...
+ @property
+ def accumulate(self) -> Any: ...
+ @property
+ def reduceat(self) -> Any: ...
+ @property
+ def outer(self) -> Any: ...
+ # Similarly at won't be defined for ufuncs that return multiple
+ # outputs, so we can't type it very precisely.
+ @property
+ def at(self) -> Any: ...
+
+absolute: ufunc
+add: ufunc
+arccos: ufunc
+arccosh: ufunc
+arcsin: ufunc
+arcsinh: ufunc
+arctan2: ufunc
+arctan: ufunc
+arctanh: ufunc
+bitwise_and: ufunc
+bitwise_or: ufunc
+bitwise_xor: ufunc
+cbrt: ufunc
+ceil: ufunc
+conjugate: ufunc
+copysign: ufunc
+cos: ufunc
+cosh: ufunc
+deg2rad: ufunc
+degrees: ufunc
+divmod: ufunc
+equal: ufunc
+exp2: ufunc
+exp: ufunc
+expm1: ufunc
+fabs: ufunc
+float_power: ufunc
+floor: ufunc
+floor_divide: ufunc
+fmax: ufunc
+fmin: ufunc
+fmod: ufunc
+frexp: ufunc
+gcd: ufunc
+greater: ufunc
+greater_equal: ufunc
+heaviside: ufunc
+hypot: ufunc
+invert: ufunc
+isfinite: ufunc
+isinf: ufunc
+isnan: ufunc
+isnat: ufunc
+lcm: ufunc
+ldexp: ufunc
+left_shift: ufunc
+less: ufunc
+less_equal: ufunc
+log10: ufunc
+log1p: ufunc
+log2: ufunc
+log: ufunc
+logaddexp2: ufunc
+logaddexp: ufunc
+logical_and: ufunc
+logical_not: ufunc
+logical_or: ufunc
+logical_xor: ufunc
+matmul: ufunc
+maximum: ufunc
+minimum: ufunc
+modf: ufunc
+multiply: ufunc
+negative: ufunc
+nextafter: ufunc
+not_equal: ufunc
+positive: ufunc
+power: ufunc
+rad2deg: ufunc
+radians: ufunc
+reciprocal: ufunc
+remainder: ufunc
+right_shift: ufunc
+rint: ufunc
+sign: ufunc
+signbit: ufunc
+sin: ufunc
+sinh: ufunc
+spacing: ufunc
+sqrt: ufunc
+square: ufunc
+subtract: ufunc
+tan: ufunc
+tanh: ufunc
+true_divide: ufunc
+trunc: ufunc
+
+abs = absolute
+
+# Warnings
+class ModuleDeprecationWarning(DeprecationWarning): ...
+class VisibleDeprecationWarning(UserWarning): ...
+class ComplexWarning(RuntimeWarning): ...
+class RankWarning(UserWarning): ...
+
+# Errors
+class TooHardError(RuntimeError): ...
+
+class AxisError(ValueError, IndexError):
+ def __init__(
+ self, axis: int, ndim: Optional[int] = ..., msg_prefix: Optional[str] = ...
+ ) -> None: ...
+
+_CallType = TypeVar("_CallType", bound=Union[_ErrFunc, _SupportsWrite])
+
+class errstate(Generic[_CallType], ContextDecorator):
+ call: _CallType
+ kwargs: _ErrDictOptional
+
+ # Expand `**kwargs` into explicit keyword-only arguments
+ def __init__(
+ self,
+ *,
+ call: _CallType = ...,
+ all: Optional[_ErrKind] = ...,
+ divide: Optional[_ErrKind] = ...,
+ over: Optional[_ErrKind] = ...,
+ under: Optional[_ErrKind] = ...,
+ invalid: Optional[_ErrKind] = ...,
+ ) -> None: ...
+ def __enter__(self) -> None: ...
+ def __exit__(
+ self,
+ __exc_type: Optional[Type[BaseException]],
+ __exc_value: Optional[BaseException],
+ __traceback: Optional[TracebackType],
+ ) -> None: ...
diff --git a/venv/Lib/site-packages/numpy/__pycache__/__config__.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/__config__.cpython-39.pyc
new file mode 100644
index 0000000..dd56cf3
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/__config__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..55f9f11
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/__init__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/_distributor_init.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/_distributor_init.cpython-39.pyc
new file mode 100644
index 0000000..88ff089
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/_distributor_init.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/_globals.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/_globals.cpython-39.pyc
new file mode 100644
index 0000000..fa3853c
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/_globals.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/_pytesttester.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/_pytesttester.cpython-39.pyc
new file mode 100644
index 0000000..a42a5a3
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/_pytesttester.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/conftest.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/conftest.cpython-39.pyc
new file mode 100644
index 0000000..4dee379
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/conftest.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/ctypeslib.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/ctypeslib.cpython-39.pyc
new file mode 100644
index 0000000..09514a5
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/ctypeslib.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/dual.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/dual.cpython-39.pyc
new file mode 100644
index 0000000..bd6a1b2
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/dual.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/matlib.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/matlib.cpython-39.pyc
new file mode 100644
index 0000000..d20fa2a
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/matlib.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/setup.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/setup.cpython-39.pyc
new file mode 100644
index 0000000..cb270cd
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/setup.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/__pycache__/version.cpython-39.pyc b/venv/Lib/site-packages/numpy/__pycache__/version.cpython-39.pyc
new file mode 100644
index 0000000..0b51ef5
Binary files /dev/null and b/venv/Lib/site-packages/numpy/__pycache__/version.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/_distributor_init.py b/venv/Lib/site-packages/numpy/_distributor_init.py
new file mode 100644
index 0000000..9b51979
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/_distributor_init.py
@@ -0,0 +1,32 @@
+
+'''
+Helper to preload windows dlls to prevent dll not found errors.
+Once a DLL is preloaded, its namespace is made available to any
+subsequent DLL. This file originated in the numpy-wheels repo,
+and is created as part of the scripts that build the wheel.
+'''
+import os
+import glob
+if os.name == 'nt':
+ # convention for storing / loading the DLL from
+ # numpy/.libs/, if present
+ try:
+ from ctypes import WinDLL
+ basedir = os.path.dirname(__file__)
+ except:
+ pass
+ else:
+ libs_dir = os.path.abspath(os.path.join(basedir, '.libs'))
+ DLL_filenames = []
+ if os.path.isdir(libs_dir):
+ for filename in glob.glob(os.path.join(libs_dir,
+ '*openblas*dll')):
+ # NOTE: would it change behavior to load ALL
+ # DLLs at this path vs. the name restriction?
+ WinDLL(os.path.abspath(filename))
+ DLL_filenames.append(filename)
+ if len(DLL_filenames) > 1:
+ import warnings
+ warnings.warn("loaded more than 1 DLL from .libs:"
+ "\n%s" % "\n".join(DLL_filenames),
+ stacklevel=1)
diff --git a/venv/Lib/site-packages/numpy/_globals.py b/venv/Lib/site-packages/numpy/_globals.py
new file mode 100644
index 0000000..b8f579a
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/_globals.py
@@ -0,0 +1,79 @@
+"""
+Module defining global singleton classes.
+
+This module raises a RuntimeError if an attempt to reload it is made. In that
+way the identities of the classes defined here are fixed and will remain so
+even if numpy itself is reloaded. In particular, a function like the following
+will still work correctly after numpy is reloaded::
+
+ def foo(arg=np._NoValue):
+ if arg is np._NoValue:
+ ...
+
+That was not the case when the singleton classes were defined in the numpy
+``__init__.py`` file. See gh-7844 for a discussion of the reload problem that
+motivated this module.
+
+"""
+__ALL__ = [
+ 'ModuleDeprecationWarning', 'VisibleDeprecationWarning', '_NoValue'
+ ]
+
+
+# Disallow reloading this module so as to preserve the identities of the
+# classes defined here.
+if '_is_loaded' in globals():
+ raise RuntimeError('Reloading numpy._globals is not allowed')
+_is_loaded = True
+
+
+class ModuleDeprecationWarning(DeprecationWarning):
+ """Module deprecation warning.
+
+ The nose tester turns ordinary Deprecation warnings into test failures.
+ That makes it hard to deprecate whole modules, because they get
+ imported by default. So this is a special Deprecation warning that the
+ nose tester will let pass without making tests fail.
+
+ """
+
+
+ModuleDeprecationWarning.__module__ = 'numpy'
+
+
+class VisibleDeprecationWarning(UserWarning):
+ """Visible deprecation warning.
+
+ By default, python will not show deprecation warnings, so this class
+ can be used when a very visible warning is helpful, for example because
+ the usage is most likely a user bug.
+
+ """
+
+
+VisibleDeprecationWarning.__module__ = 'numpy'
+
+
+class _NoValueType:
+ """Special keyword value.
+
+ The instance of this class may be used as the default value assigned to a
+ deprecated keyword in order to check if it has been given a user defined
+ value.
+ """
+ __instance = None
+ def __new__(cls):
+ # ensure that only one instance exists
+ if not cls.__instance:
+ cls.__instance = super(_NoValueType, cls).__new__(cls)
+ return cls.__instance
+
+ # needed for python 2 to preserve identity through a pickle
+ def __reduce__(self):
+ return (self.__class__, ())
+
+ def __repr__(self):
+ return ""
+
+
+_NoValue = _NoValueType()
diff --git a/venv/Lib/site-packages/numpy/_pytesttester.py b/venv/Lib/site-packages/numpy/_pytesttester.py
new file mode 100644
index 0000000..daa75e0
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/_pytesttester.py
@@ -0,0 +1,213 @@
+"""
+Pytest test running.
+
+This module implements the ``test()`` function for NumPy modules. The usual
+boiler plate for doing that is to put the following in the module
+``__init__.py`` file::
+
+ from numpy._pytesttester import PytestTester
+ test = PytestTester(__name__)
+ del PytestTester
+
+
+Warnings filtering and other runtime settings should be dealt with in the
+``pytest.ini`` file in the numpy repo root. The behavior of the test depends on
+whether or not that file is found as follows:
+
+* ``pytest.ini`` is present (develop mode)
+ All warnings except those explicitly filtered out are raised as error.
+* ``pytest.ini`` is absent (release mode)
+ DeprecationWarnings and PendingDeprecationWarnings are ignored, other
+ warnings are passed through.
+
+In practice, tests run from the numpy repo are run in develop mode. That
+includes the standard ``python runtests.py`` invocation.
+
+This module is imported by every numpy subpackage, so lies at the top level to
+simplify circular import issues. For the same reason, it contains no numpy
+imports at module scope, instead importing numpy within function calls.
+"""
+import sys
+import os
+
+__all__ = ['PytestTester']
+
+
+
+def _show_numpy_info():
+ from numpy.core._multiarray_umath import (
+ __cpu_features__, __cpu_baseline__, __cpu_dispatch__
+ )
+ import numpy as np
+
+ print("NumPy version %s" % np.__version__)
+ relaxed_strides = np.ones((10, 1), order="C").flags.f_contiguous
+ print("NumPy relaxed strides checking option:", relaxed_strides)
+
+ if len(__cpu_baseline__) == 0 and len(__cpu_dispatch__) == 0:
+ enabled_features = "nothing enabled"
+ else:
+ enabled_features = ' '.join(__cpu_baseline__)
+ for feature in __cpu_dispatch__:
+ if __cpu_features__[feature]:
+ enabled_features += " %s*" % feature
+ else:
+ enabled_features += " %s?" % feature
+ print("NumPy CPU features:", enabled_features)
+
+
+
+class PytestTester:
+ """
+ Pytest test runner.
+
+ A test function is typically added to a package's __init__.py like so::
+
+ from numpy._pytesttester import PytestTester
+ test = PytestTester(__name__).test
+ del PytestTester
+
+ Calling this test function finds and runs all tests associated with the
+ module and all its sub-modules.
+
+ Attributes
+ ----------
+ module_name : str
+ Full path to the package to test.
+
+ Parameters
+ ----------
+ module_name : module name
+ The name of the module to test.
+
+ Notes
+ -----
+ Unlike the previous ``nose``-based implementation, this class is not
+ publicly exposed as it performs some ``numpy``-specific warning
+ suppression.
+
+ """
+ def __init__(self, module_name):
+ self.module_name = module_name
+
+ def __call__(self, label='fast', verbose=1, extra_argv=None,
+ doctests=False, coverage=False, durations=-1, tests=None):
+ """
+ Run tests for module using pytest.
+
+ Parameters
+ ----------
+ label : {'fast', 'full'}, optional
+ Identifies the tests to run. When set to 'fast', tests decorated
+ with `pytest.mark.slow` are skipped, when 'full', the slow marker
+ is ignored.
+ verbose : int, optional
+ Verbosity value for test outputs, in the range 1-3. Default is 1.
+ extra_argv : list, optional
+ List with any extra arguments to pass to pytests.
+ doctests : bool, optional
+ .. note:: Not supported
+ coverage : bool, optional
+ If True, report coverage of NumPy code. Default is False.
+ Requires installation of (pip) pytest-cov.
+ durations : int, optional
+ If < 0, do nothing, If 0, report time of all tests, if > 0,
+ report the time of the slowest `timer` tests. Default is -1.
+ tests : test or list of tests
+ Tests to be executed with pytest '--pyargs'
+
+ Returns
+ -------
+ result : bool
+ Return True on success, false otherwise.
+
+ Notes
+ -----
+ Each NumPy module exposes `test` in its namespace to run all tests for
+ it. For example, to run all tests for numpy.lib:
+
+ >>> np.lib.test() #doctest: +SKIP
+
+ Examples
+ --------
+ >>> result = np.lib.test() #doctest: +SKIP
+ ...
+ 1023 passed, 2 skipped, 6 deselected, 1 xfailed in 10.39 seconds
+ >>> result
+ True
+
+ """
+ import pytest
+ import warnings
+
+ module = sys.modules[self.module_name]
+ module_path = os.path.abspath(module.__path__[0])
+
+ # setup the pytest arguments
+ pytest_args = ["-l"]
+
+ # offset verbosity. The "-q" cancels a "-v".
+ pytest_args += ["-q"]
+
+ # Filter out distutils cpu warnings (could be localized to
+ # distutils tests). ASV has problems with top level import,
+ # so fetch module for suppression here.
+ with warnings.catch_warnings():
+ warnings.simplefilter("always")
+ from numpy.distutils import cpuinfo
+
+ # Filter out annoying import messages. Want these in both develop and
+ # release mode.
+ pytest_args += [
+ "-W ignore:Not importing directory",
+ "-W ignore:numpy.dtype size changed",
+ "-W ignore:numpy.ufunc size changed",
+ "-W ignore::UserWarning:cpuinfo",
+ ]
+
+ # When testing matrices, ignore their PendingDeprecationWarnings
+ pytest_args += [
+ "-W ignore:the matrix subclass is not",
+ "-W ignore:Importing from numpy.matlib is",
+ ]
+
+ if doctests:
+ raise ValueError("Doctests not supported")
+
+ if extra_argv:
+ pytest_args += list(extra_argv)
+
+ if verbose > 1:
+ pytest_args += ["-" + "v"*(verbose - 1)]
+
+ if coverage:
+ pytest_args += ["--cov=" + module_path]
+
+ if label == "fast":
+ # not importing at the top level to avoid circular import of module
+ from numpy.testing import IS_PYPY
+ if IS_PYPY:
+ pytest_args += ["-m", "not slow and not slow_pypy"]
+ else:
+ pytest_args += ["-m", "not slow"]
+
+ elif label != "full":
+ pytest_args += ["-m", label]
+
+ if durations >= 0:
+ pytest_args += ["--durations=%s" % durations]
+
+ if tests is None:
+ tests = [self.module_name]
+
+ pytest_args += ["--pyargs"] + list(tests)
+
+ # run tests.
+ _show_numpy_info()
+
+ try:
+ code = pytest.main(pytest_args)
+ except SystemExit as exc:
+ code = exc.code
+
+ return code == 0
diff --git a/venv/Lib/site-packages/numpy/char.pyi b/venv/Lib/site-packages/numpy/char.pyi
new file mode 100644
index 0000000..52f2f7c
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/char.pyi
@@ -0,0 +1,56 @@
+from typing import Any, List
+
+__all__: List[str]
+
+equal: Any
+not_equal: Any
+greater_equal: Any
+less_equal: Any
+greater: Any
+less: Any
+str_len: Any
+add: Any
+multiply: Any
+mod: Any
+capitalize: Any
+center: Any
+count: Any
+decode: Any
+encode: Any
+endswith: Any
+expandtabs: Any
+find: Any
+index: Any
+isalnum: Any
+isalpha: Any
+isdigit: Any
+islower: Any
+isspace: Any
+istitle: Any
+isupper: Any
+join: Any
+ljust: Any
+lower: Any
+lstrip: Any
+partition: Any
+replace: Any
+rfind: Any
+rindex: Any
+rjust: Any
+rpartition: Any
+rsplit: Any
+rstrip: Any
+split: Any
+splitlines: Any
+startswith: Any
+strip: Any
+swapcase: Any
+title: Any
+translate: Any
+upper: Any
+zfill: Any
+isnumeric: Any
+isdecimal: Any
+array: Any
+asarray: Any
+chararray: Any
diff --git a/venv/Lib/site-packages/numpy/compat/__init__.py b/venv/Lib/site-packages/numpy/compat/__init__.py
new file mode 100644
index 0000000..0f02af4
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/compat/__init__.py
@@ -0,0 +1,18 @@
+"""
+Compatibility module.
+
+This module contains duplicated code from Python itself or 3rd party
+extensions, which may be included for the following reasons:
+
+ * compatibility
+ * we may only need a small subset of the copied library/module
+
+"""
+from . import _inspect
+from . import py3k
+from ._inspect import getargspec, formatargspec
+from .py3k import *
+
+__all__ = []
+__all__.extend(_inspect.__all__)
+__all__.extend(py3k.__all__)
diff --git a/venv/Lib/site-packages/numpy/compat/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/numpy/compat/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..104a776
Binary files /dev/null and b/venv/Lib/site-packages/numpy/compat/__pycache__/__init__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/compat/__pycache__/_inspect.cpython-39.pyc b/venv/Lib/site-packages/numpy/compat/__pycache__/_inspect.cpython-39.pyc
new file mode 100644
index 0000000..85de9ee
Binary files /dev/null and b/venv/Lib/site-packages/numpy/compat/__pycache__/_inspect.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/compat/__pycache__/py3k.cpython-39.pyc b/venv/Lib/site-packages/numpy/compat/__pycache__/py3k.cpython-39.pyc
new file mode 100644
index 0000000..26239c1
Binary files /dev/null and b/venv/Lib/site-packages/numpy/compat/__pycache__/py3k.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/compat/__pycache__/setup.cpython-39.pyc b/venv/Lib/site-packages/numpy/compat/__pycache__/setup.cpython-39.pyc
new file mode 100644
index 0000000..e7fc547
Binary files /dev/null and b/venv/Lib/site-packages/numpy/compat/__pycache__/setup.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/compat/_inspect.py b/venv/Lib/site-packages/numpy/compat/_inspect.py
new file mode 100644
index 0000000..f8f68a6
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/compat/_inspect.py
@@ -0,0 +1,191 @@
+"""Subset of inspect module from upstream python
+
+We use this instead of upstream because upstream inspect is slow to import, and
+significantly contributes to numpy import times. Importing this copy has almost
+no overhead.
+
+"""
+import types
+
+__all__ = ['getargspec', 'formatargspec']
+
+# ----------------------------------------------------------- type-checking
+def ismethod(object):
+ """Return true if the object is an instance method.
+
+ Instance method objects provide these attributes:
+ __doc__ documentation string
+ __name__ name with which this method was defined
+ im_class class object in which this method belongs
+ im_func function object containing implementation of method
+ im_self instance to which this method is bound, or None
+
+ """
+ return isinstance(object, types.MethodType)
+
+def isfunction(object):
+ """Return true if the object is a user-defined function.
+
+ Function objects provide these attributes:
+ __doc__ documentation string
+ __name__ name with which this function was defined
+ func_code code object containing compiled function bytecode
+ func_defaults tuple of any default values for arguments
+ func_doc (same as __doc__)
+ func_globals global namespace in which this function was defined
+ func_name (same as __name__)
+
+ """
+ return isinstance(object, types.FunctionType)
+
+def iscode(object):
+ """Return true if the object is a code object.
+
+ Code objects provide these attributes:
+ co_argcount number of arguments (not including * or ** args)
+ co_code string of raw compiled bytecode
+ co_consts tuple of constants used in the bytecode
+ co_filename name of file in which this code object was created
+ co_firstlineno number of first line in Python source code
+ co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
+ co_lnotab encoded mapping of line numbers to bytecode indices
+ co_name name with which this code object was defined
+ co_names tuple of names of local variables
+ co_nlocals number of local variables
+ co_stacksize virtual machine stack space required
+ co_varnames tuple of names of arguments and local variables
+
+ """
+ return isinstance(object, types.CodeType)
+
+# ------------------------------------------------ argument list extraction
+# These constants are from Python's compile.h.
+CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
+
+def getargs(co):
+ """Get information about the arguments accepted by a code object.
+
+ Three things are returned: (args, varargs, varkw), where 'args' is
+ a list of argument names (possibly containing nested lists), and
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+
+ """
+
+ if not iscode(co):
+ raise TypeError('arg is not a code object')
+
+ nargs = co.co_argcount
+ names = co.co_varnames
+ args = list(names[:nargs])
+
+ # The following acrobatics are for anonymous (tuple) arguments.
+ # Which we do not need to support, so remove to avoid importing
+ # the dis module.
+ for i in range(nargs):
+ if args[i][:1] in ['', '.']:
+ raise TypeError("tuple function arguments are not supported")
+ varargs = None
+ if co.co_flags & CO_VARARGS:
+ varargs = co.co_varnames[nargs]
+ nargs = nargs + 1
+ varkw = None
+ if co.co_flags & CO_VARKEYWORDS:
+ varkw = co.co_varnames[nargs]
+ return args, varargs, varkw
+
+def getargspec(func):
+ """Get the names and default values of a function's arguments.
+
+ A tuple of four things is returned: (args, varargs, varkw, defaults).
+ 'args' is a list of the argument names (it may contain nested lists).
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'defaults' is an n-tuple of the default values of the last n arguments.
+
+ """
+
+ if ismethod(func):
+ func = func.__func__
+ if not isfunction(func):
+ raise TypeError('arg is not a Python function')
+ args, varargs, varkw = getargs(func.__code__)
+ return args, varargs, varkw, func.__defaults__
+
+def getargvalues(frame):
+ """Get information about arguments passed into a particular frame.
+
+ A tuple of four things is returned: (args, varargs, varkw, locals).
+ 'args' is a list of the argument names (it may contain nested lists).
+ 'varargs' and 'varkw' are the names of the * and ** arguments or None.
+ 'locals' is the locals dictionary of the given frame.
+
+ """
+ args, varargs, varkw = getargs(frame.f_code)
+ return args, varargs, varkw, frame.f_locals
+
+def joinseq(seq):
+ if len(seq) == 1:
+ return '(' + seq[0] + ',)'
+ else:
+ return '(' + ', '.join(seq) + ')'
+
+def strseq(object, convert, join=joinseq):
+ """Recursively walk a sequence, stringifying each element.
+
+ """
+ if type(object) in [list, tuple]:
+ return join([strseq(_o, convert, join) for _o in object])
+ else:
+ return convert(object)
+
+def formatargspec(args, varargs=None, varkw=None, defaults=None,
+ formatarg=str,
+ formatvarargs=lambda name: '*' + name,
+ formatvarkw=lambda name: '**' + name,
+ formatvalue=lambda value: '=' + repr(value),
+ join=joinseq):
+ """Format an argument spec from the 4 values returned by getargspec.
+
+ The first four arguments are (args, varargs, varkw, defaults). The
+ other four arguments are the corresponding optional formatting functions
+ that are called to turn names and values into strings. The ninth
+ argument is an optional function to format the sequence of arguments.
+
+ """
+ specs = []
+ if defaults:
+ firstdefault = len(args) - len(defaults)
+ for i in range(len(args)):
+ spec = strseq(args[i], formatarg, join)
+ if defaults and i >= firstdefault:
+ spec = spec + formatvalue(defaults[i - firstdefault])
+ specs.append(spec)
+ if varargs is not None:
+ specs.append(formatvarargs(varargs))
+ if varkw is not None:
+ specs.append(formatvarkw(varkw))
+ return '(' + ', '.join(specs) + ')'
+
+def formatargvalues(args, varargs, varkw, locals,
+ formatarg=str,
+ formatvarargs=lambda name: '*' + name,
+ formatvarkw=lambda name: '**' + name,
+ formatvalue=lambda value: '=' + repr(value),
+ join=joinseq):
+ """Format an argument spec from the 4 values returned by getargvalues.
+
+ The first four arguments are (args, varargs, varkw, locals). The
+ next four arguments are the corresponding optional formatting functions
+ that are called to turn names and values into strings. The ninth
+ argument is an optional function to format the sequence of arguments.
+
+ """
+ def convert(name, locals=locals,
+ formatarg=formatarg, formatvalue=formatvalue):
+ return formatarg(name) + formatvalue(locals[name])
+ specs = [strseq(arg, convert, join) for arg in args]
+
+ if varargs:
+ specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
+ if varkw:
+ specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
+ return '(' + ', '.join(specs) + ')'
diff --git a/venv/Lib/site-packages/numpy/compat/py3k.py b/venv/Lib/site-packages/numpy/compat/py3k.py
new file mode 100644
index 0000000..9768970
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/compat/py3k.py
@@ -0,0 +1,136 @@
+"""
+Python 3.X compatibility tools.
+
+While this file was originally intended for Python 2 -> 3 transition,
+it is now used to create a compatibility layer between different
+minor versions of Python 3.
+
+While the active version of numpy may not support a given version of python, we
+allow downstream libraries to continue to use these shims for forward
+compatibility with numpy while they transition their code to newer versions of
+Python.
+"""
+__all__ = ['bytes', 'asbytes', 'isfileobj', 'getexception', 'strchar',
+ 'unicode', 'asunicode', 'asbytes_nested', 'asunicode_nested',
+ 'asstr', 'open_latin1', 'long', 'basestring', 'sixu',
+ 'integer_types', 'is_pathlib_path', 'npy_load_module', 'Path',
+ 'pickle', 'contextlib_nullcontext', 'os_fspath', 'os_PathLike']
+
+import sys
+import os
+from pathlib import Path
+import io
+
+import abc
+from abc import ABC as abc_ABC
+
+try:
+ import pickle5 as pickle
+except ImportError:
+ import pickle
+
+long = int
+integer_types = (int,)
+basestring = str
+unicode = str
+bytes = bytes
+
+def asunicode(s):
+ if isinstance(s, bytes):
+ return s.decode('latin1')
+ return str(s)
+
+def asbytes(s):
+ if isinstance(s, bytes):
+ return s
+ return str(s).encode('latin1')
+
+def asstr(s):
+ if isinstance(s, bytes):
+ return s.decode('latin1')
+ return str(s)
+
+def isfileobj(f):
+ return isinstance(f, (io.FileIO, io.BufferedReader, io.BufferedWriter))
+
+def open_latin1(filename, mode='r'):
+ return open(filename, mode=mode, encoding='iso-8859-1')
+
+def sixu(s):
+ return s
+
+strchar = 'U'
+
+def getexception():
+ return sys.exc_info()[1]
+
+def asbytes_nested(x):
+ if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)):
+ return [asbytes_nested(y) for y in x]
+ else:
+ return asbytes(x)
+
+def asunicode_nested(x):
+ if hasattr(x, '__iter__') and not isinstance(x, (bytes, unicode)):
+ return [asunicode_nested(y) for y in x]
+ else:
+ return asunicode(x)
+
+def is_pathlib_path(obj):
+ """
+ Check whether obj is a `pathlib.Path` object.
+
+ Prefer using ``isinstance(obj, os.PathLike)`` instead of this function.
+ """
+ return isinstance(obj, Path)
+
+# from Python 3.7
+class contextlib_nullcontext:
+ """Context manager that does no additional processing.
+
+ Used as a stand-in for a normal context manager, when a particular
+ block of code is only sometimes used with a normal context manager:
+
+ cm = optional_cm if condition else nullcontext()
+ with cm:
+ # Perform operation, using optional_cm if condition is True
+ """
+
+ def __init__(self, enter_result=None):
+ self.enter_result = enter_result
+
+ def __enter__(self):
+ return self.enter_result
+
+ def __exit__(self, *excinfo):
+ pass
+
+
+def npy_load_module(name, fn, info=None):
+ """
+ Load a module.
+
+ .. versionadded:: 1.11.2
+
+ Parameters
+ ----------
+ name : str
+ Full module name.
+ fn : str
+ Path to module file.
+ info : tuple, optional
+ Only here for backward compatibility with Python 2.*.
+
+ Returns
+ -------
+ mod : module
+
+ """
+ # Explicitly lazy import this to avoid paying the cost
+ # of importing importlib at startup
+ from importlib.machinery import SourceFileLoader
+ return SourceFileLoader(name, fn).load_module()
+
+
+os_fspath = os.fspath
+os_PathLike = os.PathLike
diff --git a/venv/Lib/site-packages/numpy/compat/setup.py b/venv/Lib/site-packages/numpy/compat/setup.py
new file mode 100644
index 0000000..4c28518
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/compat/setup.py
@@ -0,0 +1,10 @@
+def configuration(parent_package='',top_path=None):
+ from numpy.distutils.misc_util import Configuration
+
+ config = Configuration('compat', parent_package, top_path)
+ config.add_subpackage('tests')
+ return config
+
+if __name__ == '__main__':
+ from numpy.distutils.core import setup
+ setup(configuration=configuration)
diff --git a/venv/Lib/site-packages/numpy/compat/tests/__init__.py b/venv/Lib/site-packages/numpy/compat/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/venv/Lib/site-packages/numpy/compat/tests/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/numpy/compat/tests/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..ad2c12f
Binary files /dev/null and b/venv/Lib/site-packages/numpy/compat/tests/__pycache__/__init__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/compat/tests/__pycache__/test_compat.cpython-39.pyc b/venv/Lib/site-packages/numpy/compat/tests/__pycache__/test_compat.cpython-39.pyc
new file mode 100644
index 0000000..761af37
Binary files /dev/null and b/venv/Lib/site-packages/numpy/compat/tests/__pycache__/test_compat.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/compat/tests/test_compat.py b/venv/Lib/site-packages/numpy/compat/tests/test_compat.py
new file mode 100644
index 0000000..33c9dda
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/compat/tests/test_compat.py
@@ -0,0 +1,19 @@
+from os.path import join
+
+from numpy.compat import isfileobj
+from numpy.testing import assert_
+from numpy.testing import tempdir
+
+
+def test_isfileobj():
+ with tempdir(prefix="numpy_test_compat_") as folder:
+ filename = join(folder, 'a.bin')
+
+ with open(filename, 'wb') as f:
+ assert_(isfileobj(f))
+
+ with open(filename, 'ab') as f:
+ assert_(isfileobj(f))
+
+ with open(filename, 'rb') as f:
+ assert_(isfileobj(f))
diff --git a/venv/Lib/site-packages/numpy/conftest.py b/venv/Lib/site-packages/numpy/conftest.py
new file mode 100644
index 0000000..7ce6a9f
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/conftest.py
@@ -0,0 +1,119 @@
+"""
+Pytest configuration and fixtures for the Numpy test suite.
+"""
+import os
+import tempfile
+
+import hypothesis
+import pytest
+import numpy
+
+from numpy.core._multiarray_tests import get_fpu_mode
+
+
+_old_fpu_mode = None
+_collect_results = {}
+
+# Use a known and persistent tmpdir for hypothesis' caches, which
+# can be automatically cleared by the OS or user.
+hypothesis.configuration.set_hypothesis_home_dir(
+ os.path.join(tempfile.gettempdir(), ".hypothesis")
+)
+
+# We register two custom profiles for Numpy - for details see
+# https://hypothesis.readthedocs.io/en/latest/settings.html
+# The first is designed for our own CI runs; the latter also
+# forces determinism and is designed for use via np.test()
+hypothesis.settings.register_profile(
+ name="numpy-profile", deadline=None, print_blob=True,
+)
+hypothesis.settings.register_profile(
+ name="np.test() profile",
+ deadline=None, print_blob=True, database=None, derandomize=True,
+ suppress_health_check=hypothesis.HealthCheck.all(),
+)
+# Note that the default profile is chosen based on the presence
+# of pytest.ini, but can be overriden by passing the
+# --hypothesis-profile=NAME argument to pytest.
+_pytest_ini = os.path.join(os.path.dirname(__file__), "..", "pytest.ini")
+hypothesis.settings.load_profile(
+ "numpy-profile" if os.path.isfile(_pytest_ini) else "np.test() profile"
+)
+
+
+def pytest_configure(config):
+ config.addinivalue_line("markers",
+ "valgrind_error: Tests that are known to error under valgrind.")
+ config.addinivalue_line("markers",
+ "leaks_references: Tests that are known to leak references.")
+ config.addinivalue_line("markers",
+ "slow: Tests that are very slow.")
+ config.addinivalue_line("markers",
+ "slow_pypy: Tests that are very slow on pypy.")
+
+
+def pytest_addoption(parser):
+ parser.addoption("--available-memory", action="store", default=None,
+ help=("Set amount of memory available for running the "
+ "test suite. This can result to tests requiring "
+ "especially large amounts of memory to be skipped. "
+ "Equivalent to setting environment variable "
+ "NPY_AVAILABLE_MEM. Default: determined"
+ "automatically."))
+
+
+def pytest_sessionstart(session):
+ available_mem = session.config.getoption('available_memory')
+ if available_mem is not None:
+ os.environ['NPY_AVAILABLE_MEM'] = available_mem
+
+
+#FIXME when yield tests are gone.
+@pytest.hookimpl()
+def pytest_itemcollected(item):
+ """
+ Check FPU precision mode was not changed during test collection.
+
+ The clumsy way we do it here is mainly necessary because numpy
+ still uses yield tests, which can execute code at test collection
+ time.
+ """
+ global _old_fpu_mode
+
+ mode = get_fpu_mode()
+
+ if _old_fpu_mode is None:
+ _old_fpu_mode = mode
+ elif mode != _old_fpu_mode:
+ _collect_results[item] = (_old_fpu_mode, mode)
+ _old_fpu_mode = mode
+
+
+@pytest.fixture(scope="function", autouse=True)
+def check_fpu_mode(request):
+ """
+ Check FPU precision mode was not changed during the test.
+ """
+ old_mode = get_fpu_mode()
+ yield
+ new_mode = get_fpu_mode()
+
+ if old_mode != new_mode:
+ raise AssertionError("FPU precision mode changed from {0:#x} to {1:#x}"
+ " during the test".format(old_mode, new_mode))
+
+ collect_result = _collect_results.get(request.node)
+ if collect_result is not None:
+ old_mode, new_mode = collect_result
+ raise AssertionError("FPU precision mode changed from {0:#x} to {1:#x}"
+ " when collecting the test".format(old_mode,
+ new_mode))
+
+
+@pytest.fixture(autouse=True)
+def add_np(doctest_namespace):
+ doctest_namespace['np'] = numpy
+
+@pytest.fixture(autouse=True)
+def env_setup(monkeypatch):
+ monkeypatch.setenv('PYTHONHASHSEED', '0')
diff --git a/venv/Lib/site-packages/numpy/core/__init__.py b/venv/Lib/site-packages/numpy/core/__init__.py
new file mode 100644
index 0000000..692e999
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/core/__init__.py
@@ -0,0 +1,166 @@
+"""
+Contains the core of NumPy: ndarray, ufuncs, dtypes, etc.
+
+Please note that this module is private. All functions and objects
+are available in the main ``numpy`` namespace - use that instead.
+
+"""
+
+from numpy.version import version as __version__
+
+import os
+
+# disables OpenBLAS affinity setting of the main thread that limits
+# python threads or processes to one core
+env_added = []
+for envkey in ['OPENBLAS_MAIN_FREE', 'GOTOBLAS_MAIN_FREE']:
+ if envkey not in os.environ:
+ os.environ[envkey] = '1'
+ env_added.append(envkey)
+
+try:
+ from . import multiarray
+except ImportError as exc:
+ import sys
+ msg = """
+
+IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!
+
+Importing the numpy C-extensions failed. This error can happen for
+many reasons, often due to issues with your setup or how NumPy was
+installed.
+
+We have compiled some common reasons and troubleshooting tips at:
+
+ https://numpy.org/devdocs/user/troubleshooting-importerror.html
+
+Please note and check the following:
+
+ * The Python version is: Python%d.%d from "%s"
+ * The NumPy version is: "%s"
+
+and make sure that they are the versions you expect.
+Please carefully study the documentation linked above for further help.
+
+Original error was: %s
+""" % (sys.version_info[0], sys.version_info[1], sys.executable,
+ __version__, exc)
+ raise ImportError(msg)
+finally:
+ for envkey in env_added:
+ del os.environ[envkey]
+del envkey
+del env_added
+del os
+
+from . import umath
+
+# Check that multiarray,umath are pure python modules wrapping
+# _multiarray_umath and not either of the old c-extension modules
+if not (hasattr(multiarray, '_multiarray_umath') and
+ hasattr(umath, '_multiarray_umath')):
+ import sys
+ path = sys.modules['numpy'].__path__
+ msg = ("Something is wrong with the numpy installation. "
+ "While importing we detected an older version of "
+ "numpy in {}. One method of fixing this is to repeatedly uninstall "
+ "numpy until none is found, then reinstall this version.")
+ raise ImportError(msg.format(path))
+
+from . import numerictypes as nt
+multiarray.set_typeDict(nt.sctypeDict)
+from . import numeric
+from .numeric import *
+from . import fromnumeric
+from .fromnumeric import *
+from . import defchararray as char
+from . import records as rec
+from .records import *
+from .memmap import *
+from .defchararray import chararray
+from . import function_base
+from .function_base import *
+from . import machar
+from .machar import *
+from . import getlimits
+from .getlimits import *
+from . import shape_base
+from .shape_base import *
+from . import einsumfunc
+from .einsumfunc import *
+del nt
+
+from .fromnumeric import amax as max, amin as min, round_ as round
+from .numeric import absolute as abs
+
+# do this after everything else, to minimize the chance of this misleadingly
+# appearing in an import-time traceback
+from . import _add_newdocs
+from . import _add_newdocs_scalars
+# add these for module-freeze analysis (like PyInstaller)
+from . import _dtype_ctypes
+from . import _internal
+from . import _dtype
+from . import _methods
+
+__all__ = ['char', 'rec', 'memmap']
+__all__ += numeric.__all__
+__all__ += fromnumeric.__all__
+__all__ += rec.__all__
+__all__ += ['chararray']
+__all__ += function_base.__all__
+__all__ += machar.__all__
+__all__ += getlimits.__all__
+__all__ += shape_base.__all__
+__all__ += einsumfunc.__all__
+
+# We used to use `np.core._ufunc_reconstruct` to unpickle. This is unnecessary,
+# but old pickles saved before 1.20 will be using it, and there is no reason
+# to break loading them.
+def _ufunc_reconstruct(module, name):
+ # The `fromlist` kwarg is required to ensure that `mod` points to the
+ # inner-most module rather than the parent package when module name is
+ # nested. This makes it possible to pickle non-toplevel ufuncs such as
+ # scipy.special.expit for instance.
+ mod = __import__(module, fromlist=[name])
+ return getattr(mod, name)
+
+
+def _ufunc_reduce(func):
+ # Report the `__name__`. pickle will try to find the module. Note that
+ # pickle supports for this `__name__` to be a `__qualname__`. It may
+ # make sense to add a `__qualname__` to ufuncs, to allow this more
+ # explicitly (Numba has ufuncs as attributes).
+ # See also: https://github.com/dask/distributed/issues/3450
+ return func.__name__
+
+
+def _DType_reconstruct(scalar_type):
+ # This is a work-around to pickle type(np.dtype(np.float64)), etc.
+ # and it should eventually be replaced with a better solution, e.g. when
+ # DTypes become HeapTypes.
+ return type(dtype(scalar_type))
+
+
+def _DType_reduce(DType):
+ # To pickle a DType without having to add top-level names, pickle the
+ # scalar type for now (and assume that reconstruction will be possible).
+ if DType is dtype:
+ return "dtype" # must pickle `np.dtype` as a singleton.
+ scalar_type = DType.type # pickle the scalar type for reconstruction
+ return _DType_reconstruct, (scalar_type,)
+
+
+import copyreg
+
+copyreg.pickle(ufunc, _ufunc_reduce)
+copyreg.pickle(type(dtype), _DType_reduce, _DType_reconstruct)
+
+# Unclutter namespace (must keep _*_reconstruct for unpickling)
+del copyreg
+del _ufunc_reduce
+del _DType_reduce
+
+from numpy._pytesttester import PytestTester
+test = PytestTester(__name__)
+del PytestTester
diff --git a/venv/Lib/site-packages/numpy/core/__init__.pyi b/venv/Lib/site-packages/numpy/core/__init__.pyi
new file mode 100644
index 0000000..e69de29
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/__init__.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/__init__.cpython-39.pyc
new file mode 100644
index 0000000..299b0b0
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/__init__.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_add_newdocs.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_add_newdocs.cpython-39.pyc
new file mode 100644
index 0000000..ce7bdc7
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_add_newdocs.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_add_newdocs_scalars.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_add_newdocs_scalars.cpython-39.pyc
new file mode 100644
index 0000000..75478ec
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_add_newdocs_scalars.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_asarray.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_asarray.cpython-39.pyc
new file mode 100644
index 0000000..5233115
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_asarray.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_dtype.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_dtype.cpython-39.pyc
new file mode 100644
index 0000000..c99450f
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_dtype.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_dtype_ctypes.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_dtype_ctypes.cpython-39.pyc
new file mode 100644
index 0000000..f4a5a89
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_dtype_ctypes.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_exceptions.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_exceptions.cpython-39.pyc
new file mode 100644
index 0000000..16bad5f
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_exceptions.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_internal.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_internal.cpython-39.pyc
new file mode 100644
index 0000000..a23eace
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_internal.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_methods.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_methods.cpython-39.pyc
new file mode 100644
index 0000000..1c7cc04
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_methods.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_string_helpers.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_string_helpers.cpython-39.pyc
new file mode 100644
index 0000000..3c4b5a9
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_string_helpers.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_type_aliases.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_type_aliases.cpython-39.pyc
new file mode 100644
index 0000000..2c94b26
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_type_aliases.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/_ufunc_config.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/_ufunc_config.cpython-39.pyc
new file mode 100644
index 0000000..601559c
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/_ufunc_config.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/arrayprint.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/arrayprint.cpython-39.pyc
new file mode 100644
index 0000000..cea67b4
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/arrayprint.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/cversions.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/cversions.cpython-39.pyc
new file mode 100644
index 0000000..50dff39
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/cversions.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/defchararray.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/defchararray.cpython-39.pyc
new file mode 100644
index 0000000..c8808d5
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/defchararray.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/einsumfunc.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/einsumfunc.cpython-39.pyc
new file mode 100644
index 0000000..61e87eb
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/einsumfunc.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/fromnumeric.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/fromnumeric.cpython-39.pyc
new file mode 100644
index 0000000..9e88f70
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/fromnumeric.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/function_base.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/function_base.cpython-39.pyc
new file mode 100644
index 0000000..e9263cf
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/function_base.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/generate_numpy_api.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/generate_numpy_api.cpython-39.pyc
new file mode 100644
index 0000000..4a1ee5f
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/generate_numpy_api.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/getlimits.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/getlimits.cpython-39.pyc
new file mode 100644
index 0000000..2eab653
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/getlimits.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/machar.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/machar.cpython-39.pyc
new file mode 100644
index 0000000..7745521
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/machar.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/memmap.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/memmap.cpython-39.pyc
new file mode 100644
index 0000000..99cc179
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/memmap.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/multiarray.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/multiarray.cpython-39.pyc
new file mode 100644
index 0000000..9dc7af5
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/multiarray.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/numeric.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/numeric.cpython-39.pyc
new file mode 100644
index 0000000..f4f1398
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/numeric.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/numerictypes.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/numerictypes.cpython-39.pyc
new file mode 100644
index 0000000..a7840d2
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/numerictypes.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/overrides.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/overrides.cpython-39.pyc
new file mode 100644
index 0000000..fd61f25
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/overrides.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/records.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/records.cpython-39.pyc
new file mode 100644
index 0000000..3ea93b8
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/records.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/setup.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/setup.cpython-39.pyc
new file mode 100644
index 0000000..7d0aba6
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/setup.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/setup_common.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/setup_common.cpython-39.pyc
new file mode 100644
index 0000000..a4ed920
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/setup_common.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/shape_base.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/shape_base.cpython-39.pyc
new file mode 100644
index 0000000..74c0251
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/shape_base.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/umath.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/umath.cpython-39.pyc
new file mode 100644
index 0000000..ee2fc90
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/umath.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/__pycache__/umath_tests.cpython-39.pyc b/venv/Lib/site-packages/numpy/core/__pycache__/umath_tests.cpython-39.pyc
new file mode 100644
index 0000000..ed6bb65
Binary files /dev/null and b/venv/Lib/site-packages/numpy/core/__pycache__/umath_tests.cpython-39.pyc differ
diff --git a/venv/Lib/site-packages/numpy/core/_add_newdocs.py b/venv/Lib/site-packages/numpy/core/_add_newdocs.py
new file mode 100644
index 0000000..3c55c6c
--- /dev/null
+++ b/venv/Lib/site-packages/numpy/core/_add_newdocs.py
@@ -0,0 +1,6284 @@
+"""
+This is only meant to add docs to objects defined in C-extension modules.
+The purpose is to allow easier editing of the docstrings without
+requiring a re-compile.
+
+NOTE: Many of the methods of ndarray have corresponding functions.
+ If you update these docstrings, please keep also the ones in
+ core/fromnumeric.py, core/defmatrix.py up-to-date.
+
+"""
+
+from numpy.core.function_base import add_newdoc
+from numpy.core.overrides import array_function_like_doc
+
+###############################################################################
+#
+# flatiter
+#
+# flatiter needs a toplevel description
+#
+###############################################################################
+
+add_newdoc('numpy.core', 'flatiter',
+ """
+ Flat iterator object to iterate over arrays.
+
+ A `flatiter` iterator is returned by ``x.flat`` for any array `x`.
+ It allows iterating over the array as if it were a 1-D array,
+ either in a for-loop or by calling its `next` method.
+
+ Iteration is done in row-major, C-style order (the last
+ index varying the fastest). The iterator can also be indexed using
+ basic slicing or advanced indexing.
+
+ See Also
+ --------
+ ndarray.flat : Return a flat iterator over an array.
+ ndarray.flatten : Returns a flattened copy of an array.
+
+ Notes
+ -----
+ A `flatiter` iterator can not be constructed directly from Python code
+ by calling the `flatiter` constructor.
+
+ Examples
+ --------
+ >>> x = np.arange(6).reshape(2, 3)
+ >>> fl = x.flat
+ >>> type(fl)
+
+ >>> for item in fl:
+ ... print(item)
+ ...
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+
+ >>> fl[2:4]
+ array([2, 3])
+
+ """)
+
+# flatiter attributes
+
+add_newdoc('numpy.core', 'flatiter', ('base',
+ """
+ A reference to the array that is iterated over.
+
+ Examples
+ --------
+ >>> x = np.arange(5)
+ >>> fl = x.flat
+ >>> fl.base is x
+ True
+
+ """))
+
+
+
+add_newdoc('numpy.core', 'flatiter', ('coords',
+ """
+ An N-dimensional tuple of current coordinates.
+
+ Examples
+ --------
+ >>> x = np.arange(6).reshape(2, 3)
+ >>> fl = x.flat
+ >>> fl.coords
+ (0, 0)
+ >>> next(fl)
+ 0
+ >>> fl.coords
+ (0, 1)
+
+ """))
+
+
+
+add_newdoc('numpy.core', 'flatiter', ('index',
+ """
+ Current flat index into the array.
+
+ Examples
+ --------
+ >>> x = np.arange(6).reshape(2, 3)
+ >>> fl = x.flat
+ >>> fl.index
+ 0
+ >>> next(fl)
+ 0
+ >>> fl.index
+ 1
+
+ """))
+
+# flatiter functions
+
+add_newdoc('numpy.core', 'flatiter', ('__array__',
+ """__array__(type=None) Get array from iterator
+
+ """))
+
+
+add_newdoc('numpy.core', 'flatiter', ('copy',
+ """
+ copy()
+
+ Get a copy of the iterator as a 1-D array.
+
+ Examples
+ --------
+ >>> x = np.arange(6).reshape(2, 3)
+ >>> x
+ array([[0, 1, 2],
+ [3, 4, 5]])
+ >>> fl = x.flat
+ >>> fl.copy()
+ array([0, 1, 2, 3, 4, 5])
+
+ """))
+
+
+###############################################################################
+#
+# nditer
+#
+###############################################################################
+
+add_newdoc('numpy.core', 'nditer',
+ """
+ nditer(op, flags=None, op_flags=None, op_dtypes=None, order='K', casting='safe', op_axes=None, itershape=None, buffersize=0)
+
+ Efficient multi-dimensional iterator object to iterate over arrays.
+ To get started using this object, see the
+ :ref:`introductory guide to array iteration `.
+
+ Parameters
+ ----------
+ op : ndarray or sequence of array_like
+ The array(s) to iterate over.
+
+ flags : sequence of str, optional
+ Flags to control the behavior of the iterator.
+
+ * ``buffered`` enables buffering when required.
+ * ``c_index`` causes a C-order index to be tracked.
+ * ``f_index`` causes a Fortran-order index to be tracked.
+ * ``multi_index`` causes a multi-index, or a tuple of indices
+ with one per iteration dimension, to be tracked.
+ * ``common_dtype`` causes all the operands to be converted to
+ a common data type, with copying or buffering as necessary.
+ * ``copy_if_overlap`` causes the iterator to determine if read
+ operands have overlap with write operands, and make temporary
+ copies as necessary to avoid overlap. False positives (needless
+ copying) are possible in some cases.
+ * ``delay_bufalloc`` delays allocation of the buffers until
+ a reset() call is made. Allows ``allocate`` operands to
+ be initialized before their values are copied into the buffers.
+ * ``external_loop`` causes the ``values`` given to be
+ one-dimensional arrays with multiple values instead of
+ zero-dimensional arrays.
+ * ``grow_inner`` allows the ``value`` array sizes to be made
+ larger than the buffer size when both ``buffered`` and
+ ``external_loop`` is used.
+ * ``ranged`` allows the iterator to be restricted to a sub-range
+ of the iterindex values.
+ * ``refs_ok`` enables iteration of reference types, such as
+ object arrays.
+ * ``reduce_ok`` enables iteration of ``readwrite`` operands
+ which are broadcasted, also known as reduction operands.
+ * ``zerosize_ok`` allows `itersize` to be zero.
+ op_flags : list of list of str, optional
+ This is a list of flags for each operand. At minimum, one of
+ ``readonly``, ``readwrite``, or ``writeonly`` must be specified.
+
+ * ``readonly`` indicates the operand will only be read from.
+ * ``readwrite`` indicates the operand will be read from and written to.
+ * ``writeonly`` indicates the operand will only be written to.
+ * ``no_broadcast`` prevents the operand from being broadcasted.
+ * ``contig`` forces the operand data to be contiguous.
+ * ``aligned`` forces the operand data to be aligned.
+ * ``nbo`` forces the operand data to be in native byte order.
+ * ``copy`` allows a temporary read-only copy if required.
+ * ``updateifcopy`` allows a temporary read-write copy if required.
+ * ``allocate`` causes the array to be allocated if it is None
+ in the ``op`` parameter.
+ * ``no_subtype`` prevents an ``allocate`` operand from using a subtype.
+ * ``arraymask`` indicates that this operand is the mask to use
+ for selecting elements when writing to operands with the
+ 'writemasked' flag set. The iterator does not enforce this,
+ but when writing from a buffer back to the array, it only
+ copies those elements indicated by this mask.
+ * ``writemasked`` indicates that only elements where the chosen
+ ``arraymask`` operand is True will be written to.
+ * ``overlap_assume_elementwise`` can be used to mark operands that are
+ accessed only in the iterator order, to allow less conservative
+ copying when ``copy_if_overlap`` is present.
+ op_dtypes : dtype or tuple of dtype(s), optional
+ The required data type(s) of the operands. If copying or buffering
+ is enabled, the data will be converted to/from their original types.
+ order : {'C', 'F', 'A', 'K'}, optional
+ Controls the iteration order. 'C' means C order, 'F' means
+ Fortran order, 'A' means 'F' order if all the arrays are Fortran
+ contiguous, 'C' order otherwise, and 'K' means as close to the
+ order the array elements appear in memory as possible. This also
+ affects the element memory order of ``allocate`` operands, as they
+ are allocated to be compatible with iteration order.
+ Default is 'K'.
+ casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
+ Controls what kind of data casting may occur when making a copy
+ or buffering. Setting this to 'unsafe' is not recommended,
+ as it can adversely affect accumulations.
+
+ * 'no' means the data types should not be cast at all.
+ * 'equiv' means only byte-order changes are allowed.
+ * 'safe' means only casts which can preserve values are allowed.
+ * 'same_kind' means only safe casts or casts within a kind,
+ like float64 to float32, are allowed.
+ * 'unsafe' means any data conversions may be done.
+ op_axes : list of list of ints, optional
+ If provided, is a list of ints or None for each operands.
+ The list of axes for an operand is a mapping from the dimensions
+ of the iterator to the dimensions of the operand. A value of
+ -1 can be placed for entries, causing that dimension to be
+ treated as `newaxis`.
+ itershape : tuple of ints, optional
+ The desired shape of the iterator. This allows ``allocate`` operands
+ with a dimension mapped by op_axes not corresponding to a dimension
+ of a different operand to get a value not equal to 1 for that
+ dimension.
+ buffersize : int, optional
+ When buffering is enabled, controls the size of the temporary
+ buffers. Set to 0 for the default value.
+
+ Attributes
+ ----------
+ dtypes : tuple of dtype(s)
+ The data types of the values provided in `value`. This may be
+ different from the operand data types if buffering is enabled.
+ Valid only before the iterator is closed.
+ finished : bool
+ Whether the iteration over the operands is finished or not.
+ has_delayed_bufalloc : bool
+ If True, the iterator was created with the ``delay_bufalloc`` flag,
+ and no reset() function was called on it yet.
+ has_index : bool
+ If True, the iterator was created with either the ``c_index`` or
+ the ``f_index`` flag, and the property `index` can be used to
+ retrieve it.
+ has_multi_index : bool
+ If True, the iterator was created with the ``multi_index`` flag,
+ and the property `multi_index` can be used to retrieve it.
+ index
+ When the ``c_index`` or ``f_index`` flag was used, this property
+ provides access to the index. Raises a ValueError if accessed
+ and ``has_index`` is False.
+ iterationneedsapi : bool
+ Whether iteration requires access to the Python API, for example
+ if one of the operands is an object array.
+ iterindex : int
+ An index which matches the order of iteration.
+ itersize : int
+ Size of the iterator.
+ itviews
+ Structured view(s) of `operands` in memory, matching the reordered
+ and optimized iterator access pattern. Valid only before the iterator
+ is closed.
+ multi_index
+ When the ``multi_index`` flag was used, this property
+ provides access to the index. Raises a ValueError if accessed
+ accessed and ``has_multi_index`` is False.
+ ndim : int
+ The dimensions of the iterator.
+ nop : int
+ The number of iterator operands.
+ operands : tuple of operand(s)
+ The array(s) to be iterated over. Valid only before the iterator is
+ closed.
+ shape : tuple of ints
+ Shape tuple, the shape of the iterator.
+ value
+ Value of ``operands`` at current iteration. Normally, this is a
+ tuple of array scalars, but if the flag ``external_loop`` is used,
+ it is a tuple of one dimensional arrays.
+
+ Notes
+ -----
+ `nditer` supersedes `flatiter`. The iterator implementation behind
+ `nditer` is also exposed by the NumPy C API.
+
+ The Python exposure supplies two iteration interfaces, one which follows
+ the Python iterator protocol, and another which mirrors the C-style
+ do-while pattern. The native Python approach is better in most cases, but
+ if you need the coordinates or index of an iterator, use the C-style pattern.
+
+ Examples
+ --------
+ Here is how we might write an ``iter_add`` function, using the
+ Python iterator protocol:
+
+ >>> def iter_add_py(x, y, out=None):
+ ... addop = np.add
+ ... it = np.nditer([x, y, out], [],
+ ... [['readonly'], ['readonly'], ['writeonly','allocate']])
+ ... with it:
+ ... for (a, b, c) in it:
+ ... addop(a, b, out=c)
+ ... return it.operands[2]
+
+ Here is the same function, but following the C-style pattern:
+
+ >>> def iter_add(x, y, out=None):
+ ... addop = np.add
+ ... it = np.nditer([x, y, out], [],
+ ... [['readonly'], ['readonly'], ['writeonly','allocate']])
+ ... with it:
+ ... while not it.finished:
+ ... addop(it[0], it[1], out=it[2])
+ ... it.iternext()
+ ... return it.operands[2]
+
+ Here is an example outer product function:
+
+ >>> def outer_it(x, y, out=None):
+ ... mulop = np.multiply
+ ... it = np.nditer([x, y, out], ['external_loop'],
+ ... [['readonly'], ['readonly'], ['writeonly', 'allocate']],
+ ... op_axes=[list(range(x.ndim)) + [-1] * y.ndim,
+ ... [-1] * x.ndim + list(range(y.ndim)),
+ ... None])
+ ... with it:
+ ... for (a, b, c) in it:
+ ... mulop(a, b, out=c)
+ ... return it.operands[2]
+
+ >>> a = np.arange(2)+1
+ >>> b = np.arange(3)+1
+ >>> outer_it(a,b)
+ array([[1, 2, 3],
+ [2, 4, 6]])
+
+ Here is an example function which operates like a "lambda" ufunc:
+
+ >>> def luf(lamdaexpr, *args, **kwargs):
+ ... '''luf(lambdaexpr, op1, ..., opn, out=None, order='K', casting='safe', buffersize=0)'''
+ ... nargs = len(args)
+ ... op = (kwargs.get('out',None),) + args
+ ... it = np.nditer(op, ['buffered','external_loop'],
+ ... [['writeonly','allocate','no_broadcast']] +
+ ... [['readonly','nbo','aligned']]*nargs,
+ ... order=kwargs.get('order','K'),
+ ... casting=kwargs.get('casting','safe'),
+ ... buffersize=kwargs.get('buffersize',0))
+ ... while not it.finished:
+ ... it[0] = lamdaexpr(*it[1:])
+ ... it.iternext()
+ ... return it.operands[0]
+
+ >>> a = np.arange(5)
+ >>> b = np.ones(5)
+ >>> luf(lambda i,j:i*i + j/2, a, b)
+ array([ 0.5, 1.5, 4.5, 9.5, 16.5])
+
+ If operand flags `"writeonly"` or `"readwrite"` are used the
+ operands may be views into the original data with the
+ `WRITEBACKIFCOPY` flag. In this case `nditer` must be used as a
+ context manager or the `nditer.close` method must be called before
+ using the result. The temporary data will be written back to the
+ original data when the `__exit__` function is called but not before:
+
+ >>> a = np.arange(6, dtype='i4')[::-2]
+ >>> with np.nditer(a, [],
+ ... [['writeonly', 'updateifcopy']],
+ ... casting='unsafe',
+ ... op_dtypes=[np.dtype('f4')]) as i:
+ ... x = i.operands[0]
+ ... x[:] = [-1, -2, -3]
+ ... # a still unchanged here
+ >>> a, x
+ (array([-1, -2, -3], dtype=int32), array([-1., -2., -3.], dtype=float32))
+
+ It is important to note that once the iterator is exited, dangling
+ references (like `x` in the example) may or may not share data with
+ the original data `a`. If writeback semantics were active, i.e. if
+ `x.base.flags.writebackifcopy` is `True`, then exiting the iterator
+ will sever the connection between `x` and `a`, writing to `x` will
+ no longer write to `a`. If writeback semantics are not active, then
+ `x.data` will still point at some part of `a.data`, and writing to
+ one will affect the other.
+
+ Context management and the `close` method appeared in version 1.15.0.
+
+ """)
+
+# nditer methods
+
+add_newdoc('numpy.core', 'nditer', ('copy',
+ """
+ copy()
+
+ Get a copy of the iterator in its current state.
+
+ Examples
+ --------
+ >>> x = np.arange(10)
+ >>> y = x + 1
+ >>> it = np.nditer([x, y])
+ >>> next(it)
+ (array(0), array(1))
+ >>> it2 = it.copy()
+ >>> next(it2)
+ (array(1), array(2))
+
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('operands',
+ """
+ operands[`Slice`]
+
+ The array(s) to be iterated over. Valid only before the iterator is closed.
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('debug_print',
+ """
+ debug_print()
+
+ Print the current state of the `nditer` instance and debug info to stdout.
+
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('enable_external_loop',
+ """
+ enable_external_loop()
+
+ When the "external_loop" was not used during construction, but
+ is desired, this modifies the iterator to behave as if the flag
+ was specified.
+
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('iternext',
+ """
+ iternext()
+
+ Check whether iterations are left, and perform a single internal iteration
+ without returning the result. Used in the C-style pattern do-while
+ pattern. For an example, see `nditer`.
+
+ Returns
+ -------
+ iternext : bool
+ Whether or not there are iterations left.
+
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('remove_axis',
+ """
+ remove_axis(i)
+
+ Removes axis `i` from the iterator. Requires that the flag "multi_index"
+ be enabled.
+
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('remove_multi_index',
+ """
+ remove_multi_index()
+
+ When the "multi_index" flag was specified, this removes it, allowing
+ the internal iteration structure to be optimized further.
+
+ """))
+
+add_newdoc('numpy.core', 'nditer', ('reset',
+ """
+ reset()
+
+ Reset the iterator to its initial state.
+
+ """))
+
+add_newdoc('numpy.core', 'nested_iters',
+ """
+ Create nditers for use in nested loops
+
+ Create a tuple of `nditer` objects which iterate in nested loops over
+ different axes of the op argument. The first iterator is used in the
+ outermost loop, the last in the innermost loop. Advancing one will change
+ the subsequent iterators to point at its new element.
+
+ Parameters
+ ----------
+ op : ndarray or sequence of array_like
+ The array(s) to iterate over.
+
+ axes : list of list of int
+ Each item is used as an "op_axes" argument to an nditer
+
+ flags, op_flags, op_dtypes, order, casting, buffersize (optional)
+ See `nditer` parameters of the same name
+
+ Returns
+ -------
+ iters : tuple of nditer
+ An nditer for each item in `axes`, outermost first
+
+ See Also
+ --------
+ nditer
+
+ Examples
+ --------
+
+ Basic usage. Note how y is the "flattened" version of
+ [a[:, 0, :], a[:, 1, 0], a[:, 2, :]] since we specified
+ the first iter's axes as [1]
+
+ >>> a = np.arange(12).reshape(2, 3, 2)
+ >>> i, j = np.nested_iters(a, [[1], [0, 2]], flags=["multi_index"])
+ >>> for x in i:
+ ... print(i.multi_index)
+ ... for y in j:
+ ... print('', j.multi_index, y)
+ (0,)
+ (0, 0) 0
+ (0, 1) 1
+ (1, 0) 6
+ (1, 1) 7
+ (1,)
+ (0, 0) 2
+ (0, 1) 3
+ (1, 0) 8
+ (1, 1) 9
+ (2,)
+ (0, 0) 4
+ (0, 1) 5
+ (1, 0) 10
+ (1, 1) 11
+
+ """)
+
+add_newdoc('numpy.core', 'nditer', ('close',
+ """
+ close()
+
+ Resolve all writeback semantics in writeable operands.
+
+ .. versionadded:: 1.15.0
+
+ See Also
+ --------
+
+ :ref:`nditer-context-manager`
+
+ """))
+
+
+###############################################################################
+#
+# broadcast
+#
+###############################################################################
+
+add_newdoc('numpy.core', 'broadcast',
+ """
+ Produce an object that mimics broadcasting.
+
+ Parameters
+ ----------
+ in1, in2, ... : array_like
+ Input parameters.
+
+ Returns
+ -------
+ b : broadcast object
+ Broadcast the input parameters against one another, and
+ return an object that encapsulates the result.
+ Amongst others, it has ``shape`` and ``nd`` properties, and
+ may be used as an iterator.
+
+ See Also
+ --------
+ broadcast_arrays
+ broadcast_to
+ broadcast_shapes
+
+ Examples
+ --------
+
+ Manually adding two vectors, using broadcasting:
+
+ >>> x = np.array([[1], [2], [3]])
+ >>> y = np.array([4, 5, 6])
+ >>> b = np.broadcast(x, y)
+
+ >>> out = np.empty(b.shape)
+ >>> out.flat = [u+v for (u,v) in b]
+ >>> out
+ array([[5., 6., 7.],
+ [6., 7., 8.],
+ [7., 8., 9.]])
+
+ Compare against built-in broadcasting:
+
+ >>> x + y
+ array([[5, 6, 7],
+ [6, 7, 8],
+ [7, 8, 9]])
+
+ """)
+
+# attributes
+
+add_newdoc('numpy.core', 'broadcast', ('index',
+ """
+ current index in broadcasted result
+
+ Examples
+ --------
+ >>> x = np.array([[1], [2], [3]])
+ >>> y = np.array([4, 5, 6])
+ >>> b = np.broadcast(x, y)
+ >>> b.index
+ 0
+ >>> next(b), next(b), next(b)
+ ((1, 4), (1, 5), (1, 6))
+ >>> b.index
+ 3
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('iters',
+ """
+ tuple of iterators along ``self``'s "components."
+
+ Returns a tuple of `numpy.flatiter` objects, one for each "component"
+ of ``self``.
+
+ See Also
+ --------
+ numpy.flatiter
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> row, col = b.iters
+ >>> next(row), next(col)
+ (1, 4)
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('ndim',
+ """
+ Number of dimensions of broadcasted result. Alias for `nd`.
+
+ .. versionadded:: 1.12.0
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> b.ndim
+ 2
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('nd',
+ """
+ Number of dimensions of broadcasted result. For code intended for NumPy
+ 1.12.0 and later the more consistent `ndim` is preferred.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> b.nd
+ 2
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('numiter',
+ """
+ Number of iterators possessed by the broadcasted result.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> b.numiter
+ 2
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('shape',
+ """
+ Shape of broadcasted result.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> b.shape
+ (3, 3)
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('size',
+ """
+ Total size of broadcasted result.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> b.size
+ 9
+
+ """))
+
+add_newdoc('numpy.core', 'broadcast', ('reset',
+ """
+ reset()
+
+ Reset the broadcasted result's iterator(s).
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ None
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> y = np.array([[4], [5], [6]])
+ >>> b = np.broadcast(x, y)
+ >>> b.index
+ 0
+ >>> next(b), next(b), next(b)
+ ((1, 4), (2, 4), (3, 4))
+ >>> b.index
+ 3
+ >>> b.reset()
+ >>> b.index
+ 0
+
+ """))
+
+###############################################################################
+#
+# numpy functions
+#
+###############################################################################
+
+add_newdoc('numpy.core.multiarray', 'array',
+ """
+ array(object, dtype=None, *, copy=True, order='K', subok=False, ndmin=0,
+ like=None)
+
+ Create an array.
+
+ Parameters
+ ----------
+ object : array_like
+ An array, any object exposing the array interface, an object whose
+ __array__ method returns an array, or any (nested) sequence.
+ dtype : data-type, optional
+ The desired data-type for the array. If not given, then the type will
+ be determined as the minimum type required to hold the objects in the
+ sequence.
+ copy : bool, optional
+ If true (default), then the object is copied. Otherwise, a copy will
+ only be made if __array__ returns a copy, if obj is a nested sequence,
+ or if a copy is needed to satisfy any of the other requirements
+ (`dtype`, `order`, etc.).
+ order : {'K', 'A', 'C', 'F'}, optional
+ Specify the memory layout of the array. If object is not an array, the
+ newly created array will be in C order (row major) unless 'F' is
+ specified, in which case it will be in Fortran order (column major).
+ If object is an array the following holds.
+
+ ===== ========= ===================================================
+ order no copy copy=True
+ ===== ========= ===================================================
+ 'K' unchanged F & C order preserved, otherwise most similar order
+ 'A' unchanged F order if input is F and not C, otherwise C order
+ 'C' C order C order
+ 'F' F order F order
+ ===== ========= ===================================================
+
+ When ``copy=False`` and a copy is made for other reasons, the result is
+ the same as if ``copy=True``, with some exceptions for `A`, see the
+ Notes section. The default order is 'K'.
+ subok : bool, optional
+ If True, then sub-classes will be passed-through, otherwise
+ the returned array will be forced to be a base-class array (default).
+ ndmin : int, optional
+ Specifies the minimum number of dimensions that the resulting
+ array should have. Ones will be pre-pended to the shape as
+ needed to meet this requirement.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
+
+ Returns
+ -------
+ out : ndarray
+ An array object satisfying the specified requirements.
+
+ See Also
+ --------
+ empty_like : Return an empty array with shape and type of input.
+ ones_like : Return an array of ones with shape and type of input.
+ zeros_like : Return an array of zeros with shape and type of input.
+ full_like : Return a new array with shape of input filled with value.
+ empty : Return a new uninitialized array.
+ ones : Return a new array setting values to one.
+ zeros : Return a new array setting values to zero.
+ full : Return a new array of given shape filled with value.
+
+
+ Notes
+ -----
+ When order is 'A' and `object` is an array in neither 'C' nor 'F' order,
+ and a copy is forced by a change in dtype, then the order of the result is
+ not necessarily 'C' as expected. This is likely a bug.
+
+ Examples
+ --------
+ >>> np.array([1, 2, 3])
+ array([1, 2, 3])
+
+ Upcasting:
+
+ >>> np.array([1, 2, 3.0])
+ array([ 1., 2., 3.])
+
+ More than one dimension:
+
+ >>> np.array([[1, 2], [3, 4]])
+ array([[1, 2],
+ [3, 4]])
+
+ Minimum dimensions 2:
+
+ >>> np.array([1, 2, 3], ndmin=2)
+ array([[1, 2, 3]])
+
+ Type provided:
+
+ >>> np.array([1, 2, 3], dtype=complex)
+ array([ 1.+0.j, 2.+0.j, 3.+0.j])
+
+ Data-type consisting of more than one element:
+
+ >>> x = np.array([(1,2),(3,4)],dtype=[('a','>> x['a']
+ array([1, 3])
+
+ Creating an array from sub-classes:
+
+ >>> np.array(np.mat('1 2; 3 4'))
+ array([[1, 2],
+ [3, 4]])
+
+ >>> np.array(np.mat('1 2; 3 4'), subok=True)
+ matrix([[1, 2],
+ [3, 4]])
+
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
+
+add_newdoc('numpy.core.multiarray', 'empty',
+ """
+ empty(shape, dtype=float, order='C', *, like=None)
+
+ Return a new array of given shape and type, without initializing entries.
+
+ Parameters
+ ----------
+ shape : int or tuple of int
+ Shape of the empty array, e.g., ``(2, 3)`` or ``2``.
+ dtype : data-type, optional
+ Desired output data-type for the array, e.g, `numpy.int8`. Default is
+ `numpy.float64`.
+ order : {'C', 'F'}, optional, default: 'C'
+ Whether to store multi-dimensional data in row-major
+ (C-style) or column-major (Fortran-style) order in
+ memory.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
+
+ Returns
+ -------
+ out : ndarray
+ Array of uninitialized (arbitrary) data of the given shape, dtype, and
+ order. Object arrays will be initialized to None.
+
+ See Also
+ --------
+ empty_like : Return an empty array with shape and type of input.
+ ones : Return a new array setting values to one.
+ zeros : Return a new array setting values to zero.
+ full : Return a new array of given shape filled with value.
+
+
+ Notes
+ -----
+ `empty`, unlike `zeros`, does not set the array values to zero,
+ and may therefore be marginally faster. On the other hand, it requires
+ the user to manually set all the values in the array, and should be
+ used with caution.
+
+ Examples
+ --------
+ >>> np.empty([2, 2])
+ array([[ -9.74499359e+001, 6.69583040e-309],
+ [ 2.13182611e-314, 3.06959433e-309]]) #uninitialized
+
+ >>> np.empty([2, 2], dtype=int)
+ array([[-1073741821, -1067949133],
+ [ 496041986, 19249760]]) #uninitialized
+
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
+
+add_newdoc('numpy.core.multiarray', 'scalar',
+ """
+ scalar(dtype, obj)
+
+ Return a new scalar array of the given type initialized with obj.
+
+ This function is meant mainly for pickle support. `dtype` must be a
+ valid data-type descriptor. If `dtype` corresponds to an object
+ descriptor, then `obj` can be any object, otherwise `obj` must be a
+ string. If `obj` is not given, it will be interpreted as None for object
+ type and as zeros for all other types.
+
+ """)
+
+add_newdoc('numpy.core.multiarray', 'zeros',
+ """
+ zeros(shape, dtype=float, order='C', *, like=None)
+
+ Return a new array of given shape and type, filled with zeros.
+
+ Parameters
+ ----------
+ shape : int or tuple of ints
+ Shape of the new array, e.g., ``(2, 3)`` or ``2``.
+ dtype : data-type, optional
+ The desired data-type for the array, e.g., `numpy.int8`. Default is
+ `numpy.float64`.
+ order : {'C', 'F'}, optional, default: 'C'
+ Whether to store multi-dimensional data in row-major
+ (C-style) or column-major (Fortran-style) order in
+ memory.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
+
+ Returns
+ -------
+ out : ndarray
+ Array of zeros with the given shape, dtype, and order.
+
+ See Also
+ --------
+ zeros_like : Return an array of zeros with shape and type of input.
+ empty : Return a new uninitialized array.
+ ones : Return a new array setting values to one.
+ full : Return a new array of given shape filled with value.
+
+ Examples
+ --------
+ >>> np.zeros(5)
+ array([ 0., 0., 0., 0., 0.])
+
+ >>> np.zeros((5,), dtype=int)
+ array([0, 0, 0, 0, 0])
+
+ >>> np.zeros((2, 1))
+ array([[ 0.],
+ [ 0.]])
+
+ >>> s = (2,2)
+ >>> np.zeros(s)
+ array([[ 0., 0.],
+ [ 0., 0.]])
+
+ >>> np.zeros((2,), dtype=[('x', 'i4'), ('y', 'i4')]) # custom dtype
+ array([(0, 0), (0, 0)],
+ dtype=[('x', '>> np.fromstring('1 2', dtype=int, sep=' ')
+ array([1, 2])
+ >>> np.fromstring('1, 2', dtype=int, sep=',')
+ array([1, 2])
+
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
+
+add_newdoc('numpy.core.multiarray', 'compare_chararrays',
+ """
+ compare_chararrays(a, b, cmp_op, rstrip)
+
+ Performs element-wise comparison of two string arrays using the
+ comparison operator specified by `cmp_op`.
+
+ Parameters
+ ----------
+ a, b : array_like
+ Arrays to be compared.
+ cmp_op : {"<", "<=", "==", ">=", ">", "!="}
+ Type of comparison.
+ rstrip : Boolean
+ If True, the spaces at the end of Strings are removed before the comparison.
+
+ Returns
+ -------
+ out : ndarray
+ The output array of type Boolean with the same shape as a and b.
+
+ Raises
+ ------
+ ValueError
+ If `cmp_op` is not valid.
+ TypeError
+ If at least one of `a` or `b` is a non-string array
+
+ Examples
+ --------
+ >>> a = np.array(["a", "b", "cde"])
+ >>> b = np.array(["a", "a", "dec"])
+ >>> np.compare_chararrays(a, b, ">", True)
+ array([False, True, False])
+
+ """)
+
+add_newdoc('numpy.core.multiarray', 'fromiter',
+ """
+ fromiter(iterable, dtype, count=-1, *, like=None)
+
+ Create a new 1-dimensional array from an iterable object.
+
+ Parameters
+ ----------
+ iterable : iterable object
+ An iterable object providing data for the array.
+ dtype : data-type
+ The data-type of the returned array.
+ count : int, optional
+ The number of items to read from *iterable*. The default is -1,
+ which means all data is read.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
+
+ Returns
+ -------
+ out : ndarray
+ The output array.
+
+ Notes
+ -----
+ Specify `count` to improve performance. It allows ``fromiter`` to
+ pre-allocate the output array, instead of resizing it on demand.
+
+ Examples
+ --------
+ >>> iterable = (x*x for x in range(5))
+ >>> np.fromiter(iterable, float)
+ array([ 0., 1., 4., 9., 16.])
+
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
+
+add_newdoc('numpy.core.multiarray', 'fromfile',
+ """
+ fromfile(file, dtype=float, count=-1, sep='', offset=0, *, like=None)
+
+ Construct an array from data in a text or binary file.
+
+ A highly efficient way of reading binary data with a known data-type,
+ as well as parsing simply formatted text files. Data written using the
+ `tofile` method can be read using this function.
+
+ Parameters
+ ----------
+ file : file or str or Path
+ Open file object or filename.
+
+ .. versionchanged:: 1.17.0
+ `pathlib.Path` objects are now accepted.
+
+ dtype : data-type
+ Data type of the returned array.
+ For binary files, it is used to determine the size and byte-order
+ of the items in the file.
+ Most builtin numeric types are supported and extension types may be supported.
+
+ .. versionadded:: 1.18.0
+ Complex dtypes.
+
+ count : int
+ Number of items to read. ``-1`` means all items (i.e., the complete
+ file).
+ sep : str
+ Separator between items if file is a text file.
+ Empty ("") separator means the file should be treated as binary.
+ Spaces (" ") in the separator match zero or more whitespace characters.
+ A separator consisting only of spaces must match at least one
+ whitespace.
+ offset : int
+ The offset (in bytes) from the file's current position. Defaults to 0.
+ Only permitted for binary files.
+
+ .. versionadded:: 1.17.0
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
+
+ See also
+ --------
+ load, save
+ ndarray.tofile
+ loadtxt : More flexible way of loading data from a text file.
+
+ Notes
+ -----
+ Do not rely on the combination of `tofile` and `fromfile` for
+ data storage, as the binary files generated are not platform
+ independent. In particular, no byte-order or data-type information is
+ saved. Data can be stored in the platform independent ``.npy`` format
+ using `save` and `load` instead.
+
+ Examples
+ --------
+ Construct an ndarray:
+
+ >>> dt = np.dtype([('time', [('min', np.int64), ('sec', np.int64)]),
+ ... ('temp', float)])
+ >>> x = np.zeros((1,), dtype=dt)
+ >>> x['time']['min'] = 10; x['temp'] = 98.25
+ >>> x
+ array([((10, 0), 98.25)],
+ dtype=[('time', [('min', '>> import tempfile
+ >>> fname = tempfile.mkstemp()[1]
+ >>> x.tofile(fname)
+
+ Read the raw data from disk:
+
+ >>> np.fromfile(fname, dtype=dt)
+ array([((10, 0), 98.25)],
+ dtype=[('time', [('min', '>> np.save(fname, x)
+ >>> np.load(fname + '.npy')
+ array([((10, 0), 98.25)],
+ dtype=[('time', [('min', '>> dt = np.dtype(int)
+ >>> dt = dt.newbyteorder('>')
+ >>> np.frombuffer(buf, dtype=dt) # doctest: +SKIP
+
+ The data of the resulting array will not be byteswapped, but will be
+ interpreted correctly.
+
+ Examples
+ --------
+ >>> s = b'hello world'
+ >>> np.frombuffer(s, dtype='S1', count=5, offset=6)
+ array([b'w', b'o', b'r', b'l', b'd'], dtype='|S1')
+
+ >>> np.frombuffer(b'\\x01\\x02', dtype=np.uint8)
+ array([1, 2], dtype=uint8)
+ >>> np.frombuffer(b'\\x01\\x02\\x03\\x04\\x05', dtype=np.uint8, count=3)
+ array([1, 2, 3], dtype=uint8)
+
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
+
+add_newdoc('numpy.core', 'fastCopyAndTranspose',
+ """_fastCopyAndTranspose(a)""")
+
+add_newdoc('numpy.core.multiarray', 'correlate',
+ """cross_correlate(a,v, mode=0)""")
+
+add_newdoc('numpy.core.multiarray', 'arange',
+ """
+ arange([start,] stop[, step,], dtype=None, *, like=None)
+
+ Return evenly spaced values within a given interval.
+
+ Values are generated within the half-open interval ``[start, stop)``
+ (in other words, the interval including `start` but excluding `stop`).
+ For integer arguments the function is equivalent to the Python built-in
+ `range` function, but returns an ndarray rather than a list.
+
+ When using a non-integer step, such as 0.1, the results will often not
+ be consistent. It is better to use `numpy.linspace` for these cases.
+
+ Parameters
+ ----------
+ start : integer or real, optional
+ Start of interval. The interval includes this value. The default
+ start value is 0.
+ stop : integer or real
+ End of interval. The interval does not include this value, except
+ in some cases where `step` is not an integer and floating point
+ round-off affects the length of `out`.
+ step : integer or real, optional
+ Spacing between values. For any output `out`, this is the distance
+ between two adjacent values, ``out[i+1] - out[i]``. The default
+ step size is 1. If `step` is specified as a position argument,
+ `start` must also be given.
+ dtype : dtype
+ The type of the output array. If `dtype` is not given, infer the data
+ type from the other input arguments.
+ ${ARRAY_FUNCTION_LIKE}
+
+ .. versionadded:: 1.20.0
+
+ Returns
+ -------
+ arange : ndarray
+ Array of evenly spaced values.
+
+ For floating point arguments, the length of the result is
+ ``ceil((stop - start)/step)``. Because of floating point overflow,
+ this rule may result in the last element of `out` being greater
+ than `stop`.
+
+ See Also
+ --------
+ numpy.linspace : Evenly spaced numbers with careful handling of endpoints.
+ numpy.ogrid: Arrays of evenly spaced numbers in N-dimensions.
+ numpy.mgrid: Grid-shaped arrays of evenly spaced numbers in N-dimensions.
+
+ Examples
+ --------
+ >>> np.arange(3)
+ array([0, 1, 2])
+ >>> np.arange(3.0)
+ array([ 0., 1., 2.])
+ >>> np.arange(3,7)
+ array([3, 4, 5, 6])
+ >>> np.arange(3,7,2)
+ array([3, 5])
+
+ """.replace(
+ "${ARRAY_FUNCTION_LIKE}",
+ array_function_like_doc,
+ ))
+
+add_newdoc('numpy.core.multiarray', '_get_ndarray_c_version',
+ """_get_ndarray_c_version()
+
+ Return the compile time NPY_VERSION (formerly called NDARRAY_VERSION) number.
+
+ """)
+
+add_newdoc('numpy.core.multiarray', '_reconstruct',
+ """_reconstruct(subtype, shape, dtype)
+
+ Construct an empty array. Used by Pickles.
+
+ """)
+
+
+add_newdoc('numpy.core.multiarray', 'set_string_function',
+ """
+ set_string_function(f, repr=1)
+
+ Internal method to set a function to be used when pretty printing arrays.
+
+ """)
+
+add_newdoc('numpy.core.multiarray', 'set_numeric_ops',
+ """
+ set_numeric_ops(op1=func1, op2=func2, ...)
+
+ Set numerical operators for array objects.
+
+ .. deprecated:: 1.16
+
+ For the general case, use :c:func:`PyUFunc_ReplaceLoopBySignature`.
+ For ndarray subclasses, define the ``__array_ufunc__`` method and
+ override the relevant ufunc.
+
+ Parameters
+ ----------
+ op1, op2, ... : callable
+ Each ``op = func`` pair describes an operator to be replaced.
+ For example, ``add = lambda x, y: np.add(x, y) % 5`` would replace
+ addition by modulus 5 addition.
+
+ Returns
+ -------
+ saved_ops : list of callables
+ A list of all operators, stored before making replacements.
+
+ Notes
+ -----
+ .. WARNING::
+ Use with care! Incorrect usage may lead to memory errors.
+
+ A function replacing an operator cannot make use of that operator.
+ For example, when replacing add, you may not use ``+``. Instead,
+ directly call ufuncs.
+
+ Examples
+ --------
+ >>> def add_mod5(x, y):
+ ... return np.add(x, y) % 5
+ ...
+ >>> old_funcs = np.set_numeric_ops(add=add_mod5)
+
+ >>> x = np.arange(12).reshape((3, 4))
+ >>> x + x
+ array([[0, 2, 4, 1],
+ [3, 0, 2, 4],
+ [1, 3, 0, 2]])
+
+ >>> ignore = np.set_numeric_ops(**old_funcs) # restore operators
+
+ """)
+
+add_newdoc('numpy.core.multiarray', 'promote_types',
+ """
+ promote_types(type1, type2)
+
+ Returns the data type with the smallest size and smallest scalar
+ kind to which both ``type1`` and ``type2`` may be safely cast.
+ The returned data type is always in native byte order.
+
+ This function is symmetric, but rarely associative.
+
+ Parameters
+ ----------
+ type1 : dtype or dtype specifier
+ First data type.
+ type2 : dtype or dtype specifier
+ Second data type.
+
+ Returns
+ -------
+ out : dtype
+ The promoted data type.
+
+ Notes
+ -----
+ .. versionadded:: 1.6.0
+
+ Starting in NumPy 1.9, promote_types function now returns a valid string
+ length when given an integer or float dtype as one argument and a string
+ dtype as another argument. Previously it always returned the input string
+ dtype, even if it wasn't long enough to store the max integer/float value
+ converted to a string.
+
+ See Also
+ --------
+ result_type, dtype, can_cast
+
+ Examples
+ --------
+ >>> np.promote_types('f4', 'f8')
+ dtype('float64')
+
+ >>> np.promote_types('i8', 'f4')
+ dtype('float64')
+
+ >>> np.promote_types('>i8', '>> np.promote_types('i4', 'S8')
+ dtype('S11')
+
+ An example of a non-associative case:
+
+ >>> p = np.promote_types
+ >>> p('S', p('i1', 'u1'))
+ dtype('S6')
+ >>> p(p('S', 'i1'), 'u1')
+ dtype('S4')
+
+ """)
+
+add_newdoc('numpy.core.multiarray', 'c_einsum',
+ """
+ c_einsum(subscripts, *operands, out=None, dtype=None, order='K',
+ casting='safe')
+
+ *This documentation shadows that of the native python implementation of the `einsum` function,
+ except all references and examples related to the `optimize` argument (v 0.12.0) have been removed.*
+
+ Evaluates the Einstein summation convention on the operands.
+
+ Using the Einstein summation convention, many common multi-dimensional,
+ linear algebraic array operations can be represented in a simple fashion.
+ In *implicit* mode `einsum` computes these values.
+
+ In *explicit* mode, `einsum` provides further flexibility to compute
+ other array operations that might not be considered classical Einstein
+ summation operations, by disabling, or forcing summation over specified
+ subscript labels.
+
+ See the notes and examples for clarification.
+
+ Parameters
+ ----------
+ subscripts : str
+ Specifies the subscripts for summation as comma separated list of
+ subscript labels. An implicit (classical Einstein summation)
+ calculation is performed unless the explicit indicator '->' is
+ included as well as subscript labels of the precise output form.
+ operands : list of array_like
+ These are the arrays for the operation.
+ out : ndarray, optional
+ If provided, the calculation is done into this array.
+ dtype : {data-type, None}, optional
+ If provided, forces the calculation to use the data type specified.
+ Note that you may have to also give a more liberal `casting`
+ parameter to allow the conversions. Default is None.
+ order : {'C', 'F', 'A', 'K'}, optional
+ Controls the memory layout of the output. 'C' means it should
+ be C contiguous. 'F' means it should be Fortran contiguous,
+ 'A' means it should be 'F' if the inputs are all 'F', 'C' otherwise.
+ 'K' means it should be as close to the layout of the inputs as
+ is possible, including arbitrarily permuted axes.
+ Default is 'K'.
+ casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
+ Controls what kind of data casting may occur. Setting this to
+ 'unsafe' is not recommended, as it can adversely affect accumulations.
+
+ * 'no' means the data types should not be cast at all.
+ * 'equiv' means only byte-order changes are allowed.
+ * 'safe' means only casts which can preserve values are allowed.
+ * 'same_kind' means only safe casts or casts within a kind,
+ like float64 to float32, are allowed.
+ * 'unsafe' means any data conversions may be done.
+
+ Default is 'safe'.
+ optimize : {False, True, 'greedy', 'optimal'}, optional
+ Controls if intermediate optimization should occur. No optimization
+ will occur if False and True will default to the 'greedy' algorithm.
+ Also accepts an explicit contraction list from the ``np.einsum_path``
+ function. See ``np.einsum_path`` for more details. Defaults to False.
+
+ Returns
+ -------
+ output : ndarray
+ The calculation based on the Einstein summation convention.
+
+ See Also
+ --------
+ einsum_path, dot, inner, outer, tensordot, linalg.multi_dot
+
+ Notes
+ -----
+ .. versionadded:: 1.6.0
+
+ The Einstein summation convention can be used to compute
+ many multi-dimensional, linear algebraic array operations. `einsum`
+ provides a succinct way of representing these.
+
+ A non-exhaustive list of these operations,
+ which can be computed by `einsum`, is shown below along with examples:
+
+ * Trace of an array, :py:func:`numpy.trace`.
+ * Return a diagonal, :py:func:`numpy.diag`.
+ * Array axis summations, :py:func:`numpy.sum`.
+ * Transpositions and permutations, :py:func:`numpy.transpose`.
+ * Matrix multiplication and dot product, :py:func:`numpy.matmul` :py:func:`numpy.dot`.
+ * Vector inner and outer products, :py:func:`numpy.inner` :py:func:`numpy.outer`.
+ * Broadcasting, element-wise and scalar multiplication, :py:func:`numpy.multiply`.
+ * Tensor contractions, :py:func:`numpy.tensordot`.
+ * Chained array operations, in efficient calculation order, :py:func:`numpy.einsum_path`.
+
+ The subscripts string is a comma-separated list of subscript labels,
+ where each label refers to a dimension of the corresponding operand.
+ Whenever a label is repeated it is summed, so ``np.einsum('i,i', a, b)``
+ is equivalent to :py:func:`np.inner(a,b) `. If a label
+ appears only once, it is not summed, so ``np.einsum('i', a)`` produces a
+ view of ``a`` with no changes. A further example ``np.einsum('ij,jk', a, b)``
+ describes traditional matrix multiplication and is equivalent to
+ :py:func:`np.matmul(a,b) `. Repeated subscript labels in one
+ operand take the diagonal. For example, ``np.einsum('ii', a)`` is equivalent
+ to :py:func:`np.trace(a) `.
+
+ In *implicit mode*, the chosen subscripts are important
+ since the axes of the output are reordered alphabetically. This
+ means that ``np.einsum('ij', a)`` doesn't affect a 2D array, while
+ ``np.einsum('ji', a)`` takes its transpose. Additionally,
+ ``np.einsum('ij,jk', a, b)`` returns a matrix multiplication, while,
+ ``np.einsum('ij,jh', a, b)`` returns the transpose of the
+ multiplication since subscript 'h' precedes subscript 'i'.
+
+ In *explicit mode* the output can be directly controlled by
+ specifying output subscript labels. This requires the
+ identifier '->' as well as the list of output subscript labels.
+ This feature increases the flexibility of the function since
+ summing can be disabled or forced when required. The call
+ ``np.einsum('i->', a)`` is like :py:func:`np.sum(a, axis=-1) `,
+ and ``np.einsum('ii->i', a)`` is like :py:func:`np.diag(a) `.
+ The difference is that `einsum` does not allow broadcasting by default.
+ Additionally ``np.einsum('ij,jh->ih', a, b)`` directly specifies the
+ order of the output subscript labels and therefore returns matrix
+ multiplication, unlike the example above in implicit mode.
+
+ To enable and control broadcasting, use an ellipsis. Default
+ NumPy-style broadcasting is done by adding an ellipsis
+ to the left of each term, like ``np.einsum('...ii->...i', a)``.
+ To take the trace along the first and last axes,
+ you can do ``np.einsum('i...i', a)``, or to do a matrix-matrix
+ product with the left-most indices instead of rightmost, one can do
+ ``np.einsum('ij...,jk...->ik...', a, b)``.
+
+ When there is only one operand, no axes are summed, and no output
+ parameter is provided, a view into the operand is returned instead
+ of a new array. Thus, taking the diagonal as ``np.einsum('ii->i', a)``
+ produces a view (changed in version 1.10.0).
+
+ `einsum` also provides an alternative way to provide the subscripts
+ and operands as ``einsum(op0, sublist0, op1, sublist1, ..., [sublistout])``.
+ If the output shape is not provided in this format `einsum` will be
+ calculated in implicit mode, otherwise it will be performed explicitly.
+ The examples below have corresponding `einsum` calls with the two
+ parameter methods.
+
+ .. versionadded:: 1.10.0
+
+ Views returned from einsum are now writeable whenever the input array
+ is writeable. For example, ``np.einsum('ijk...->kji...', a)`` will now
+ have the same effect as :py:func:`np.swapaxes(a, 0, 2) `
+ and ``np.einsum('ii->i', a)`` will return a writeable view of the diagonal
+ of a 2D array.
+
+ Examples
+ --------
+ >>> a = np.arange(25).reshape(5,5)
+ >>> b = np.arange(5)
+ >>> c = np.arange(6).reshape(2,3)
+
+ Trace of a matrix:
+
+ >>> np.einsum('ii', a)
+ 60
+ >>> np.einsum(a, [0,0])
+ 60
+ >>> np.trace(a)
+ 60
+
+ Extract the diagonal (requires explicit form):
+
+ >>> np.einsum('ii->i', a)
+ array([ 0, 6, 12, 18, 24])
+ >>> np.einsum(a, [0,0], [0])
+ array([ 0, 6, 12, 18, 24])
+ >>> np.diag(a)
+ array([ 0, 6, 12, 18, 24])
+
+ Sum over an axis (requires explicit form):
+
+ >>> np.einsum('ij->i', a)
+ array([ 10, 35, 60, 85, 110])
+ >>> np.einsum(a, [0,1], [0])
+ array([ 10, 35, 60, 85, 110])
+ >>> np.sum(a, axis=1)
+ array([ 10, 35, 60, 85, 110])
+
+ For higher dimensional arrays summing a single axis can be done with ellipsis:
+
+ >>> np.einsum('...j->...', a)
+ array([ 10, 35, 60, 85, 110])
+ >>> np.einsum(a, [Ellipsis,1], [Ellipsis])
+ array([ 10, 35, 60, 85, 110])
+
+ Compute a matrix transpose, or reorder any number of axes:
+
+ >>> np.einsum('ji', c)
+ array([[0, 3],
+ [1, 4],
+ [2, 5]])
+ >>> np.einsum('ij->ji', c)
+ array([[0, 3],
+ [1, 4],
+ [2, 5]])
+ >>> np.einsum(c, [1,0])
+ array([[0, 3],
+ [1, 4],
+ [2, 5]])
+ >>> np.transpose(c)
+ array([[0, 3],
+ [1, 4],
+ [2, 5]])
+
+ Vector inner products:
+
+ >>> np.einsum('i,i', b, b)
+ 30
+ >>> np.einsum(b, [0], b, [0])
+ 30
+ >>> np.inner(b,b)
+ 30
+
+ Matrix vector multiplication:
+
+ >>> np.einsum('ij,j', a, b)
+ array([ 30, 80, 130, 180, 230])
+ >>> np.einsum(a, [0,1], b, [1])
+ array([ 30, 80, 130, 180, 230])
+ >>> np.dot(a, b)
+ array([ 30, 80, 130, 180, 230])
+ >>> np.einsum('...j,j', a, b)
+ array([ 30, 80, 130, 180, 230])
+
+ Broadcasting and scalar multiplication:
+
+ >>> np.einsum('..., ...', 3, c)
+ array([[ 0, 3, 6],
+ [ 9, 12, 15]])
+ >>> np.einsum(',ij', 3, c)
+ array([[ 0, 3, 6],
+ [ 9, 12, 15]])
+ >>> np.einsum(3, [Ellipsis], c, [Ellipsis])
+ array([[ 0, 3, 6],
+ [ 9, 12, 15]])
+ >>> np.multiply(3, c)
+ array([[ 0, 3, 6],
+ [ 9, 12, 15]])
+
+ Vector outer product:
+
+ >>> np.einsum('i,j', np.arange(2)+1, b)
+ array([[0, 1, 2, 3, 4],
+ [0, 2, 4, 6, 8]])
+ >>> np.einsum(np.arange(2)+1, [0], b, [1])
+ array([[0, 1, 2, 3, 4],
+ [0, 2, 4, 6, 8]])
+ >>> np.outer(np.arange(2)+1, b)
+ array([[0, 1, 2, 3, 4],
+ [0, 2, 4, 6, 8]])
+
+ Tensor contraction:
+
+ >>> a = np.arange(60.).reshape(3,4,5)
+ >>> b = np.arange(24.).reshape(4,3,2)
+ >>> np.einsum('ijk,jil->kl', a, b)
+ array([[ 4400., 4730.],
+ [ 4532., 4874.],
+ [ 4664., 5018.],
+ [ 4796., 5162.],
+ [ 4928., 5306.]])
+ >>> np.einsum(a, [0,1,2], b, [1,0,3], [2,3])
+ array([[ 4400., 4730.],
+ [ 4532., 4874.],
+ [ 4664., 5018.],
+ [ 4796., 5162.],
+ [ 4928., 5306.]])
+ >>> np.tensordot(a,b, axes=([1,0],[0,1]))
+ array([[ 4400., 4730.],
+ [ 4532., 4874.],
+ [ 4664., 5018.],
+ [ 4796., 5162.],
+ [ 4928., 5306.]])
+
+ Writeable returned arrays (since version 1.10.0):
+
+ >>> a = np.zeros((3, 3))
+ >>> np.einsum('ii->i', a)[:] = 1
+ >>> a
+ array([[ 1., 0., 0.],
+ [ 0., 1., 0.],
+ [ 0., 0., 1.]])
+
+ Example of ellipsis use:
+
+ >>> a = np.arange(6).reshape((3,2))
+ >>> b = np.arange(12).reshape((4,3))
+ >>> np.einsum('ki,jk->ij', a, b)
+ array([[10, 28, 46, 64],
+ [13, 40, 67, 94]])
+ >>> np.einsum('ki,...k->i...', a, b)
+ array([[10, 28, 46, 64],
+ [13, 40, 67, 94]])
+ >>> np.einsum('k...,jk', a, b)
+ array([[10, 28, 46, 64],
+ [13, 40, 67, 94]])
+
+ """)
+
+
+##############################################################################
+#
+# Documentation for ndarray attributes and methods
+#
+##############################################################################
+
+
+##############################################################################
+#
+# ndarray object
+#
+##############################################################################
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray',
+ """
+ ndarray(shape, dtype=float, buffer=None, offset=0,
+ strides=None, order=None)
+
+ An array object represents a multidimensional, homogeneous array
+ of fixed-size items. An associated data-type object describes the
+ format of each element in the array (its byte-order, how many bytes it
+ occupies in memory, whether it is an integer, a floating point number,
+ or something else, etc.)
+
+ Arrays should be constructed using `array`, `zeros` or `empty` (refer
+ to the See Also section below). The parameters given here refer to
+ a low-level method (`ndarray(...)`) for instantiating an array.
+
+ For more information, refer to the `numpy` module and examine the
+ methods and attributes of an array.
+
+ Parameters
+ ----------
+ (for the __new__ method; see Notes below)
+
+ shape : tuple of ints
+ Shape of created array.
+ dtype : data-type, optional
+ Any object that can be interpreted as a numpy data type.
+ buffer : object exposing buffer interface, optional
+ Used to fill the array with data.
+ offset : int, optional
+ Offset of array data in buffer.
+ strides : tuple of ints, optional
+ Strides of data in memory.
+ order : {'C', 'F'}, optional
+ Row-major (C-style) or column-major (Fortran-style) order.
+
+ Attributes
+ ----------
+ T : ndarray
+ Transpose of the array.
+ data : buffer
+ The array's elements, in memory.
+ dtype : dtype object
+ Describes the format of the elements in the array.
+ flags : dict
+ Dictionary containing information related to memory use, e.g.,
+ 'C_CONTIGUOUS', 'OWNDATA', 'WRITEABLE', etc.
+ flat : numpy.flatiter object
+ Flattened version of the array as an iterator. The iterator
+ allows assignments, e.g., ``x.flat = 3`` (See `ndarray.flat` for
+ assignment examples; TODO).
+ imag : ndarray
+ Imaginary part of the array.
+ real : ndarray
+ Real part of the array.
+ size : int
+ Number of elements in the array.
+ itemsize : int
+ The memory use of each array element in bytes.
+ nbytes : int
+ The total number of bytes required to store the array data,
+ i.e., ``itemsize * size``.
+ ndim : int
+ The array's number of dimensions.
+ shape : tuple of ints
+ Shape of the array.
+ strides : tuple of ints
+ The step-size required to move from one element to the next in
+ memory. For example, a contiguous ``(3, 4)`` array of type
+ ``int16`` in C-order has strides ``(8, 2)``. This implies that
+ to move from element to element in memory requires jumps of 2 bytes.
+ To move from row-to-row, one needs to jump 8 bytes at a time
+ (``2 * 4``).
+ ctypes : ctypes object
+ Class containing properties of the array needed for interaction
+ with ctypes.
+ base : ndarray
+ If the array is a view into another array, that array is its `base`
+ (unless that array is also a view). The `base` array is where the
+ array data is actually stored.
+
+ See Also
+ --------
+ array : Construct an array.
+ zeros : Create an array, each element of which is zero.
+ empty : Create an array, but leave its allocated memory unchanged (i.e.,
+ it contains "garbage").
+ dtype : Create a data-type.
+
+ Notes
+ -----
+ There are two modes of creating an array using ``__new__``:
+
+ 1. If `buffer` is None, then only `shape`, `dtype`, and `order`
+ are used.
+ 2. If `buffer` is an object exposing the buffer interface, then
+ all keywords are interpreted.
+
+ No ``__init__`` method is needed because the array is fully initialized
+ after the ``__new__`` method.
+
+ Examples
+ --------
+ These examples illustrate the low-level `ndarray` constructor. Refer
+ to the `See Also` section above for easier ways of constructing an
+ ndarray.
+
+ First mode, `buffer` is None:
+
+ >>> np.ndarray(shape=(2,2), dtype=float, order='F')
+ array([[0.0e+000, 0.0e+000], # random
+ [ nan, 2.5e-323]])
+
+ Second mode:
+
+ >>> np.ndarray((2,), buffer=np.array([1,2,3]),
+ ... offset=np.int_().itemsize,
+ ... dtype=int) # offset = 1*itemsize, i.e. skip first element
+ array([2, 3])
+
+ """)
+
+
+##############################################################################
+#
+# ndarray attributes
+#
+##############################################################################
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_interface__',
+ """Array protocol: Python side."""))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_finalize__',
+ """None."""))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_priority__',
+ """Array priority."""))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_struct__',
+ """Array protocol: C-struct side."""))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('base',
+ """
+ Base object if memory is from some other object.
+
+ Examples
+ --------
+ The base of an array that owns its memory is None:
+
+ >>> x = np.array([1,2,3,4])
+ >>> x.base is None
+ True
+
+ Slicing creates a view, whose memory is shared with x:
+
+ >>> y = x[2:]
+ >>> y.base is x
+ True
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('ctypes',
+ """
+ An object to simplify the interaction of the array with the ctypes
+ module.
+
+ This attribute creates an object that makes it easier to use arrays
+ when calling shared libraries with the ctypes module. The returned
+ object has, among others, data, shape, and strides attributes (see
+ Notes below) which themselves return ctypes objects that can be used
+ as arguments to a shared library.
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ c : Python object
+ Possessing attributes data, shape, strides, etc.
+
+ See Also
+ --------
+ numpy.ctypeslib
+
+ Notes
+ -----
+ Below are the public attributes of this object which were documented
+ in "Guide to NumPy" (we have omitted undocumented public attributes,
+ as well as documented private attributes):
+
+ .. autoattribute:: numpy.core._internal._ctypes.data
+ :noindex:
+
+ .. autoattribute:: numpy.core._internal._ctypes.shape
+ :noindex:
+
+ .. autoattribute:: numpy.core._internal._ctypes.strides
+ :noindex:
+
+ .. automethod:: numpy.core._internal._ctypes.data_as
+ :noindex:
+
+ .. automethod:: numpy.core._internal._ctypes.shape_as
+ :noindex:
+
+ .. automethod:: numpy.core._internal._ctypes.strides_as
+ :noindex:
+
+ If the ctypes module is not available, then the ctypes attribute
+ of array objects still returns something useful, but ctypes objects
+ are not returned and errors may be raised instead. In particular,
+ the object will still have the ``as_parameter`` attribute which will
+ return an integer equal to the data attribute.
+
+ Examples
+ --------
+ >>> import ctypes
+ >>> x = np.array([[0, 1], [2, 3]], dtype=np.int32)
+ >>> x
+ array([[0, 1],
+ [2, 3]], dtype=int32)
+ >>> x.ctypes.data
+ 31962608 # may vary
+ >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_uint32))
+ <__main__.LP_c_uint object at 0x7ff2fc1fc200> # may vary
+ >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_uint32)).contents
+ c_uint(0)
+ >>> x.ctypes.data_as(ctypes.POINTER(ctypes.c_uint64)).contents
+ c_ulong(4294967296)
+ >>> x.ctypes.shape
+ # may vary
+ >>> x.ctypes.strides
+ # may vary
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('data',
+ """Python buffer object pointing to the start of the array's data."""))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('dtype',
+ """
+ Data-type of the array's elements.
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ d : numpy dtype object
+
+ See Also
+ --------
+ numpy.dtype
+
+ Examples
+ --------
+ >>> x
+ array([[0, 1],
+ [2, 3]])
+ >>> x.dtype
+ dtype('int32')
+ >>> type(x.dtype)
+
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('imag',
+ """
+ The imaginary part of the array.
+
+ Examples
+ --------
+ >>> x = np.sqrt([1+0j, 0+1j])
+ >>> x.imag
+ array([ 0. , 0.70710678])
+ >>> x.imag.dtype
+ dtype('float64')
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('itemsize',
+ """
+ Length of one array element in bytes.
+
+ Examples
+ --------
+ >>> x = np.array([1,2,3], dtype=np.float64)
+ >>> x.itemsize
+ 8
+ >>> x = np.array([1,2,3], dtype=np.complex128)
+ >>> x.itemsize
+ 16
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('flags',
+ """
+ Information about the memory layout of the array.
+
+ Attributes
+ ----------
+ C_CONTIGUOUS (C)
+ The data is in a single, C-style contiguous segment.
+ F_CONTIGUOUS (F)
+ The data is in a single, Fortran-style contiguous segment.
+ OWNDATA (O)
+ The array owns the memory it uses or borrows it from another object.
+ WRITEABLE (W)
+ The data area can be written to. Setting this to False locks
+ the data, making it read-only. A view (slice, etc.) inherits WRITEABLE
+ from its base array at creation time, but a view of a writeable
+ array may be subsequently locked while the base array remains writeable.
+ (The opposite is not true, in that a view of a locked array may not
+ be made writeable. However, currently, locking a base object does not
+ lock any views that already reference it, so under that circumstance it
+ is possible to alter the contents of a locked array via a previously
+ created writeable view onto it.) Attempting to change a non-writeable
+ array raises a RuntimeError exception.
+ ALIGNED (A)
+ The data and all elements are aligned appropriately for the hardware.
+ WRITEBACKIFCOPY (X)
+ This array is a copy of some other array. The C-API function
+ PyArray_ResolveWritebackIfCopy must be called before deallocating
+ to the base array will be updated with the contents of this array.
+ UPDATEIFCOPY (U)
+ (Deprecated, use WRITEBACKIFCOPY) This array is a copy of some other array.
+ When this array is
+ deallocated, the base array will be updated with the contents of
+ this array.
+ FNC
+ F_CONTIGUOUS and not C_CONTIGUOUS.
+ FORC
+ F_CONTIGUOUS or C_CONTIGUOUS (one-segment test).
+ BEHAVED (B)
+ ALIGNED and WRITEABLE.
+ CARRAY (CA)
+ BEHAVED and C_CONTIGUOUS.
+ FARRAY (FA)
+ BEHAVED and F_CONTIGUOUS and not C_CONTIGUOUS.
+
+ Notes
+ -----
+ The `flags` object can be accessed dictionary-like (as in ``a.flags['WRITEABLE']``),
+ or by using lowercased attribute names (as in ``a.flags.writeable``). Short flag
+ names are only supported in dictionary access.
+
+ Only the WRITEBACKIFCOPY, UPDATEIFCOPY, WRITEABLE, and ALIGNED flags can be
+ changed by the user, via direct assignment to the attribute or dictionary
+ entry, or by calling `ndarray.setflags`.
+
+ The array flags cannot be set arbitrarily:
+
+ - UPDATEIFCOPY can only be set ``False``.
+ - WRITEBACKIFCOPY can only be set ``False``.
+ - ALIGNED can only be set ``True`` if the data is truly aligned.
+ - WRITEABLE can only be set ``True`` if the array owns its own memory
+ or the ultimate owner of the memory exposes a writeable buffer
+ interface or is a string.
+
+ Arrays can be both C-style and Fortran-style contiguous simultaneously.
+ This is clear for 1-dimensional arrays, but can also be true for higher
+ dimensional arrays.
+
+ Even for contiguous arrays a stride for a given dimension
+ ``arr.strides[dim]`` may be *arbitrary* if ``arr.shape[dim] == 1``
+ or the array has no elements.
+ It does *not* generally hold that ``self.strides[-1] == self.itemsize``
+ for C-style contiguous arrays or ``self.strides[0] == self.itemsize`` for
+ Fortran-style contiguous arrays is true.
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('flat',
+ """
+ A 1-D iterator over the array.
+
+ This is a `numpy.flatiter` instance, which acts similarly to, but is not
+ a subclass of, Python's built-in iterator object.
+
+ See Also
+ --------
+ flatten : Return a copy of the array collapsed into one dimension.
+
+ flatiter
+
+ Examples
+ --------
+ >>> x = np.arange(1, 7).reshape(2, 3)
+ >>> x
+ array([[1, 2, 3],
+ [4, 5, 6]])
+ >>> x.flat[3]
+ 4
+ >>> x.T
+ array([[1, 4],
+ [2, 5],
+ [3, 6]])
+ >>> x.T.flat[3]
+ 5
+ >>> type(x.flat)
+
+
+ An assignment example:
+
+ >>> x.flat = 3; x
+ array([[3, 3, 3],
+ [3, 3, 3]])
+ >>> x.flat[[1,4]] = 1; x
+ array([[3, 1, 3],
+ [3, 1, 3]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('nbytes',
+ """
+ Total bytes consumed by the elements of the array.
+
+ Notes
+ -----
+ Does not include memory consumed by non-element attributes of the
+ array object.
+
+ Examples
+ --------
+ >>> x = np.zeros((3,5,2), dtype=np.complex128)
+ >>> x.nbytes
+ 480
+ >>> np.prod(x.shape) * x.itemsize
+ 480
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('ndim',
+ """
+ Number of array dimensions.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3])
+ >>> x.ndim
+ 1
+ >>> y = np.zeros((2, 3, 4))
+ >>> y.ndim
+ 3
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('real',
+ """
+ The real part of the array.
+
+ Examples
+ --------
+ >>> x = np.sqrt([1+0j, 0+1j])
+ >>> x.real
+ array([ 1. , 0.70710678])
+ >>> x.real.dtype
+ dtype('float64')
+
+ See Also
+ --------
+ numpy.real : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('shape',
+ """
+ Tuple of array dimensions.
+
+ The shape property is usually used to get the current shape of an array,
+ but may also be used to reshape the array in-place by assigning a tuple of
+ array dimensions to it. As with `numpy.reshape`, one of the new shape
+ dimensions can be -1, in which case its value is inferred from the size of
+ the array and the remaining dimensions. Reshaping an array in-place will
+ fail if a copy is required.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 3, 4])
+ >>> x.shape
+ (4,)
+ >>> y = np.zeros((2, 3, 4))
+ >>> y.shape
+ (2, 3, 4)
+ >>> y.shape = (3, 8)
+ >>> y
+ array([[ 0., 0., 0., 0., 0., 0., 0., 0.],
+ [ 0., 0., 0., 0., 0., 0., 0., 0.],
+ [ 0., 0., 0., 0., 0., 0., 0., 0.]])
+ >>> y.shape = (3, 6)
+ Traceback (most recent call last):
+ File "", line 1, in
+ ValueError: total size of new array must be unchanged
+ >>> np.zeros((4,2))[::2].shape = (-1,)
+ Traceback (most recent call last):
+ File "", line 1, in
+ AttributeError: Incompatible shape for in-place modification. Use
+ `.reshape()` to make a copy with the desired shape.
+
+ See Also
+ --------
+ numpy.reshape : similar function
+ ndarray.reshape : similar method
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('size',
+ """
+ Number of elements in the array.
+
+ Equal to ``np.prod(a.shape)``, i.e., the product of the array's
+ dimensions.
+
+ Notes
+ -----
+ `a.size` returns a standard arbitrary precision Python integer. This
+ may not be the case with other methods of obtaining the same value
+ (like the suggested ``np.prod(a.shape)``, which returns an instance
+ of ``np.int_``), and may be relevant if the value is used further in
+ calculations that may overflow a fixed size integer type.
+
+ Examples
+ --------
+ >>> x = np.zeros((3, 5, 2), dtype=np.complex128)
+ >>> x.size
+ 30
+ >>> np.prod(x.shape)
+ 30
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('strides',
+ """
+ Tuple of bytes to step in each dimension when traversing an array.
+
+ The byte offset of element ``(i[0], i[1], ..., i[n])`` in an array `a`
+ is::
+
+ offset = sum(np.array(i) * a.strides)
+
+ A more detailed explanation of strides can be found in the
+ "ndarray.rst" file in the NumPy reference guide.
+
+ Notes
+ -----
+ Imagine an array of 32-bit integers (each 4 bytes)::
+
+ x = np.array([[0, 1, 2, 3, 4],
+ [5, 6, 7, 8, 9]], dtype=np.int32)
+
+ This array is stored in memory as 40 bytes, one after the other
+ (known as a contiguous block of memory). The strides of an array tell
+ us how many bytes we have to skip in memory to move to the next position
+ along a certain axis. For example, we have to skip 4 bytes (1 value) to
+ move to the next column, but 20 bytes (5 values) to get to the same
+ position in the next row. As such, the strides for the array `x` will be
+ ``(20, 4)``.
+
+ See Also
+ --------
+ numpy.lib.stride_tricks.as_strided
+
+ Examples
+ --------
+ >>> y = np.reshape(np.arange(2*3*4), (2,3,4))
+ >>> y
+ array([[[ 0, 1, 2, 3],
+ [ 4, 5, 6, 7],
+ [ 8, 9, 10, 11]],
+ [[12, 13, 14, 15],
+ [16, 17, 18, 19],
+ [20, 21, 22, 23]]])
+ >>> y.strides
+ (48, 16, 4)
+ >>> y[1,1,1]
+ 17
+ >>> offset=sum(y.strides * np.array((1,1,1)))
+ >>> offset/y.itemsize
+ 17
+
+ >>> x = np.reshape(np.arange(5*6*7*8), (5,6,7,8)).transpose(2,3,1,0)
+ >>> x.strides
+ (32, 4, 224, 1344)
+ >>> i = np.array([3,5,2,2])
+ >>> offset = sum(i * x.strides)
+ >>> x[3,5,2,2]
+ 813
+ >>> offset / x.itemsize
+ 813
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('T',
+ """
+ The transposed array.
+
+ Same as ``self.transpose()``.
+
+ Examples
+ --------
+ >>> x = np.array([[1.,2.],[3.,4.]])
+ >>> x
+ array([[ 1., 2.],
+ [ 3., 4.]])
+ >>> x.T
+ array([[ 1., 3.],
+ [ 2., 4.]])
+ >>> x = np.array([1.,2.,3.,4.])
+ >>> x
+ array([ 1., 2., 3., 4.])
+ >>> x.T
+ array([ 1., 2., 3., 4.])
+
+ See Also
+ --------
+ transpose
+
+ """))
+
+
+##############################################################################
+#
+# ndarray methods
+#
+##############################################################################
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array__',
+ """ a.__array__([dtype], /) -> reference if type unchanged, copy otherwise.
+
+ Returns either a new reference to self if dtype is not given or a new array
+ of provided data type if dtype is different from the current dtype of the
+ array.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_prepare__',
+ """a.__array_prepare__(obj) -> Object of same type as ndarray object obj.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__array_wrap__',
+ """a.__array_wrap__(obj) -> Object of same type as ndarray object a.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__copy__',
+ """a.__copy__()
+
+ Used if :func:`copy.copy` is called on an array. Returns a copy of the array.
+
+ Equivalent to ``a.copy(order='K')``.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__deepcopy__',
+ """a.__deepcopy__(memo, /) -> Deep copy of array.
+
+ Used if :func:`copy.deepcopy` is called on an array.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__reduce__',
+ """a.__reduce__()
+
+ For pickling.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('__setstate__',
+ """a.__setstate__(state, /)
+
+ For unpickling.
+
+ The `state` argument must be a sequence that contains the following
+ elements:
+
+ Parameters
+ ----------
+ version : int
+ optional pickle version. If omitted defaults to 0.
+ shape : tuple
+ dtype : data-type
+ isFortran : bool
+ rawdata : string or list
+ a binary string with the data (or a list if 'a' is an object array)
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('all',
+ """
+ a.all(axis=None, out=None, keepdims=False, *, where=True)
+
+ Returns True if all elements evaluate to True.
+
+ Refer to `numpy.all` for full documentation.
+
+ See Also
+ --------
+ numpy.all : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('any',
+ """
+ a.any(axis=None, out=None, keepdims=False, *, where=True)
+
+ Returns True if any of the elements of `a` evaluate to True.
+
+ Refer to `numpy.any` for full documentation.
+
+ See Also
+ --------
+ numpy.any : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('argmax',
+ """
+ a.argmax(axis=None, out=None)
+
+ Return indices of the maximum values along the given axis.
+
+ Refer to `numpy.argmax` for full documentation.
+
+ See Also
+ --------
+ numpy.argmax : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('argmin',
+ """
+ a.argmin(axis=None, out=None)
+
+ Return indices of the minimum values along the given axis.
+
+ Refer to `numpy.argmin` for detailed documentation.
+
+ See Also
+ --------
+ numpy.argmin : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('argsort',
+ """
+ a.argsort(axis=-1, kind=None, order=None)
+
+ Returns the indices that would sort this array.
+
+ Refer to `numpy.argsort` for full documentation.
+
+ See Also
+ --------
+ numpy.argsort : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('argpartition',
+ """
+ a.argpartition(kth, axis=-1, kind='introselect', order=None)
+
+ Returns the indices that would partition this array.
+
+ Refer to `numpy.argpartition` for full documentation.
+
+ .. versionadded:: 1.8.0
+
+ See Also
+ --------
+ numpy.argpartition : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('astype',
+ """
+ a.astype(dtype, order='K', casting='unsafe', subok=True, copy=True)
+
+ Copy of the array, cast to a specified type.
+
+ Parameters
+ ----------
+ dtype : str or dtype
+ Typecode or data-type to which the array is cast.
+ order : {'C', 'F', 'A', 'K'}, optional
+ Controls the memory layout order of the result.
+ 'C' means C order, 'F' means Fortran order, 'A'
+ means 'F' order if all the arrays are Fortran contiguous,
+ 'C' order otherwise, and 'K' means as close to the
+ order the array elements appear in memory as possible.
+ Default is 'K'.
+ casting : {'no', 'equiv', 'safe', 'same_kind', 'unsafe'}, optional
+ Controls what kind of data casting may occur. Defaults to 'unsafe'
+ for backwards compatibility.
+
+ * 'no' means the data types should not be cast at all.
+ * 'equiv' means only byte-order changes are allowed.
+ * 'safe' means only casts which can preserve values are allowed.
+ * 'same_kind' means only safe casts or casts within a kind,
+ like float64 to float32, are allowed.
+ * 'unsafe' means any data conversions may be done.
+ subok : bool, optional
+ If True, then sub-classes will be passed-through (default), otherwise
+ the returned array will be forced to be a base-class array.
+ copy : bool, optional
+ By default, astype always returns a newly allocated array. If this
+ is set to false, and the `dtype`, `order`, and `subok`
+ requirements are satisfied, the input array is returned instead
+ of a copy.
+
+ Returns
+ -------
+ arr_t : ndarray
+ Unless `copy` is False and the other conditions for returning the input
+ array are satisfied (see description for `copy` input parameter), `arr_t`
+ is a new array of the same shape as the input array, with dtype, order
+ given by `dtype`, `order`.
+
+ Notes
+ -----
+ .. versionchanged:: 1.17.0
+ Casting between a simple data type and a structured one is possible only
+ for "unsafe" casting. Casting to multiple fields is allowed, but
+ casting from multiple fields is not.
+
+ .. versionchanged:: 1.9.0
+ Casting from numeric to string types in 'safe' casting mode requires
+ that the string dtype length is long enough to store the max
+ integer/float value converted.
+
+ Raises
+ ------
+ ComplexWarning
+ When casting from complex to float or int. To avoid this,
+ one should use ``a.real.astype(t)``.
+
+ Examples
+ --------
+ >>> x = np.array([1, 2, 2.5])
+ >>> x
+ array([1. , 2. , 2.5])
+
+ >>> x.astype(int)
+ array([1, 2, 2])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('byteswap',
+ """
+ a.byteswap(inplace=False)
+
+ Swap the bytes of the array elements
+
+ Toggle between low-endian and big-endian data representation by
+ returning a byteswapped array, optionally swapped in-place.
+ Arrays of byte-strings are not swapped. The real and imaginary
+ parts of a complex number are swapped individually.
+
+ Parameters
+ ----------
+ inplace : bool, optional
+ If ``True``, swap bytes in-place, default is ``False``.
+
+ Returns
+ -------
+ out : ndarray
+ The byteswapped array. If `inplace` is ``True``, this is
+ a view to self.
+
+ Examples
+ --------
+ >>> A = np.array([1, 256, 8755], dtype=np.int16)
+ >>> list(map(hex, A))
+ ['0x1', '0x100', '0x2233']
+ >>> A.byteswap(inplace=True)
+ array([ 256, 1, 13090], dtype=int16)
+ >>> list(map(hex, A))
+ ['0x100', '0x1', '0x3322']
+
+ Arrays of byte-strings are not swapped
+
+ >>> A = np.array([b'ceg', b'fac'])
+ >>> A.byteswap()
+ array([b'ceg', b'fac'], dtype='|S3')
+
+ ``A.newbyteorder().byteswap()`` produces an array with the same values
+ but different representation in memory
+
+ >>> A = np.array([1, 2, 3])
+ >>> A.view(np.uint8)
+ array([1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0,
+ 0, 0], dtype=uint8)
+ >>> A.newbyteorder().byteswap(inplace=True)
+ array([1, 2, 3])
+ >>> A.view(np.uint8)
+ array([0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
+ 0, 3], dtype=uint8)
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('choose',
+ """
+ a.choose(choices, out=None, mode='raise')
+
+ Use an index array to construct a new array from a set of choices.
+
+ Refer to `numpy.choose` for full documentation.
+
+ See Also
+ --------
+ numpy.choose : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('clip',
+ """
+ a.clip(min=None, max=None, out=None, **kwargs)
+
+ Return an array whose values are limited to ``[min, max]``.
+ One of max or min must be given.
+
+ Refer to `numpy.clip` for full documentation.
+
+ See Also
+ --------
+ numpy.clip : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('compress',
+ """
+ a.compress(condition, axis=None, out=None)
+
+ Return selected slices of this array along given axis.
+
+ Refer to `numpy.compress` for full documentation.
+
+ See Also
+ --------
+ numpy.compress : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('conj',
+ """
+ a.conj()
+
+ Complex-conjugate all elements.
+
+ Refer to `numpy.conjugate` for full documentation.
+
+ See Also
+ --------
+ numpy.conjugate : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('conjugate',
+ """
+ a.conjugate()
+
+ Return the complex conjugate, element-wise.
+
+ Refer to `numpy.conjugate` for full documentation.
+
+ See Also
+ --------
+ numpy.conjugate : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('copy',
+ """
+ a.copy(order='C')
+
+ Return a copy of the array.
+
+ Parameters
+ ----------
+ order : {'C', 'F', 'A', 'K'}, optional
+ Controls the memory layout of the copy. 'C' means C-order,
+ 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous,
+ 'C' otherwise. 'K' means match the layout of `a` as closely
+ as possible. (Note that this function and :func:`numpy.copy` are very
+ similar, but have different default values for their order=
+ arguments.)
+
+ See also
+ --------
+ numpy.copy
+ numpy.copyto
+
+ Examples
+ --------
+ >>> x = np.array([[1,2,3],[4,5,6]], order='F')
+
+ >>> y = x.copy()
+
+ >>> x.fill(0)
+
+ >>> x
+ array([[0, 0, 0],
+ [0, 0, 0]])
+
+ >>> y
+ array([[1, 2, 3],
+ [4, 5, 6]])
+
+ >>> y.flags['C_CONTIGUOUS']
+ True
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('cumprod',
+ """
+ a.cumprod(axis=None, dtype=None, out=None)
+
+ Return the cumulative product of the elements along the given axis.
+
+ Refer to `numpy.cumprod` for full documentation.
+
+ See Also
+ --------
+ numpy.cumprod : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('cumsum',
+ """
+ a.cumsum(axis=None, dtype=None, out=None)
+
+ Return the cumulative sum of the elements along the given axis.
+
+ Refer to `numpy.cumsum` for full documentation.
+
+ See Also
+ --------
+ numpy.cumsum : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('diagonal',
+ """
+ a.diagonal(offset=0, axis1=0, axis2=1)
+
+ Return specified diagonals. In NumPy 1.9 the returned array is a
+ read-only view instead of a copy as in previous NumPy versions. In
+ a future version the read-only restriction will be removed.
+
+ Refer to :func:`numpy.diagonal` for full documentation.
+
+ See Also
+ --------
+ numpy.diagonal : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('dot',
+ """
+ a.dot(b, out=None)
+
+ Dot product of two arrays.
+
+ Refer to `numpy.dot` for full documentation.
+
+ See Also
+ --------
+ numpy.dot : equivalent function
+
+ Examples
+ --------
+ >>> a = np.eye(2)
+ >>> b = np.ones((2, 2)) * 2
+ >>> a.dot(b)
+ array([[2., 2.],
+ [2., 2.]])
+
+ This array method can be conveniently chained:
+
+ >>> a.dot(b).dot(b)
+ array([[8., 8.],
+ [8., 8.]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('dump',
+ """a.dump(file)
+
+ Dump a pickle of the array to the specified file.
+ The array can be read back with pickle.load or numpy.load.
+
+ Parameters
+ ----------
+ file : str or Path
+ A string naming the dump file.
+
+ .. versionchanged:: 1.17.0
+ `pathlib.Path` objects are now accepted.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('dumps',
+ """
+ a.dumps()
+
+ Returns the pickle of the array as a string.
+ pickle.loads or numpy.loads will convert the string back to an array.
+
+ Parameters
+ ----------
+ None
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('fill',
+ """
+ a.fill(value)
+
+ Fill the array with a scalar value.
+
+ Parameters
+ ----------
+ value : scalar
+ All elements of `a` will be assigned this value.
+
+ Examples
+ --------
+ >>> a = np.array([1, 2])
+ >>> a.fill(0)
+ >>> a
+ array([0, 0])
+ >>> a = np.empty(2)
+ >>> a.fill(1)
+ >>> a
+ array([1., 1.])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('flatten',
+ """
+ a.flatten(order='C')
+
+ Return a copy of the array collapsed into one dimension.
+
+ Parameters
+ ----------
+ order : {'C', 'F', 'A', 'K'}, optional
+ 'C' means to flatten in row-major (C-style) order.
+ 'F' means to flatten in column-major (Fortran-
+ style) order. 'A' means to flatten in column-major
+ order if `a` is Fortran *contiguous* in memory,
+ row-major order otherwise. 'K' means to flatten
+ `a` in the order the elements occur in memory.
+ The default is 'C'.
+
+ Returns
+ -------
+ y : ndarray
+ A copy of the input array, flattened to one dimension.
+
+ See Also
+ --------
+ ravel : Return a flattened array.
+ flat : A 1-D flat iterator over the array.
+
+ Examples
+ --------
+ >>> a = np.array([[1,2], [3,4]])
+ >>> a.flatten()
+ array([1, 2, 3, 4])
+ >>> a.flatten('F')
+ array([1, 3, 2, 4])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('getfield',
+ """
+ a.getfield(dtype, offset=0)
+
+ Returns a field of the given array as a certain type.
+
+ A field is a view of the array data with a given data-type. The values in
+ the view are determined by the given type and the offset into the current
+ array in bytes. The offset needs to be such that the view dtype fits in the
+ array dtype; for example an array of dtype complex128 has 16-byte elements.
+ If taking a view with a 32-bit integer (4 bytes), the offset needs to be
+ between 0 and 12 bytes.
+
+ Parameters
+ ----------
+ dtype : str or dtype
+ The data type of the view. The dtype size of the view can not be larger
+ than that of the array itself.
+ offset : int
+ Number of bytes to skip before beginning the element view.
+
+ Examples
+ --------
+ >>> x = np.diag([1.+1.j]*2)
+ >>> x[1, 1] = 2 + 4.j
+ >>> x
+ array([[1.+1.j, 0.+0.j],
+ [0.+0.j, 2.+4.j]])
+ >>> x.getfield(np.float64)
+ array([[1., 0.],
+ [0., 2.]])
+
+ By choosing an offset of 8 bytes we can select the complex part of the
+ array for our view:
+
+ >>> x.getfield(np.float64, offset=8)
+ array([[1., 0.],
+ [0., 4.]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('item',
+ """
+ a.item(*args)
+
+ Copy an element of an array to a standard Python scalar and return it.
+
+ Parameters
+ ----------
+ \\*args : Arguments (variable number and type)
+
+ * none: in this case, the method only works for arrays
+ with one element (`a.size == 1`), which element is
+ copied into a standard Python scalar object and returned.
+
+ * int_type: this argument is interpreted as a flat index into
+ the array, specifying which element to copy and return.
+
+ * tuple of int_types: functions as does a single int_type argument,
+ except that the argument is interpreted as an nd-index into the
+ array.
+
+ Returns
+ -------
+ z : Standard Python scalar object
+ A copy of the specified element of the array as a suitable
+ Python scalar
+
+ Notes
+ -----
+ When the data type of `a` is longdouble or clongdouble, item() returns
+ a scalar array object because there is no available Python scalar that
+ would not lose information. Void arrays return a buffer object for item(),
+ unless fields are defined, in which case a tuple is returned.
+
+ `item` is very similar to a[args], except, instead of an array scalar,
+ a standard Python scalar is returned. This can be useful for speeding up
+ access to elements of the array and doing arithmetic on elements of the
+ array using Python's optimized math.
+
+ Examples
+ --------
+ >>> np.random.seed(123)
+ >>> x = np.random.randint(9, size=(3, 3))
+ >>> x
+ array([[2, 2, 6],
+ [1, 3, 6],
+ [1, 0, 1]])
+ >>> x.item(3)
+ 1
+ >>> x.item(7)
+ 0
+ >>> x.item((0, 1))
+ 2
+ >>> x.item((2, 2))
+ 1
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('itemset',
+ """
+ a.itemset(*args)
+
+ Insert scalar into an array (scalar is cast to array's dtype, if possible)
+
+ There must be at least 1 argument, and define the last argument
+ as *item*. Then, ``a.itemset(*args)`` is equivalent to but faster
+ than ``a[args] = item``. The item should be a scalar value and `args`
+ must select a single item in the array `a`.
+
+ Parameters
+ ----------
+ \\*args : Arguments
+ If one argument: a scalar, only used in case `a` is of size 1.
+ If two arguments: the last argument is the value to be set
+ and must be a scalar, the first argument specifies a single array
+ element location. It is either an int or a tuple.
+
+ Notes
+ -----
+ Compared to indexing syntax, `itemset` provides some speed increase
+ for placing a scalar into a particular location in an `ndarray`,
+ if you must do this. However, generally this is discouraged:
+ among other problems, it complicates the appearance of the code.
+ Also, when using `itemset` (and `item`) inside a loop, be sure
+ to assign the methods to a local variable to avoid the attribute
+ look-up at each loop iteration.
+
+ Examples
+ --------
+ >>> np.random.seed(123)
+ >>> x = np.random.randint(9, size=(3, 3))
+ >>> x
+ array([[2, 2, 6],
+ [1, 3, 6],
+ [1, 0, 1]])
+ >>> x.itemset(4, 0)
+ >>> x.itemset((2, 2), 9)
+ >>> x
+ array([[2, 2, 6],
+ [1, 0, 6],
+ [1, 0, 9]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('max',
+ """
+ a.max(axis=None, out=None, keepdims=False, initial=, where=True)
+
+ Return the maximum along a given axis.
+
+ Refer to `numpy.amax` for full documentation.
+
+ See Also
+ --------
+ numpy.amax : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('mean',
+ """
+ a.mean(axis=None, dtype=None, out=None, keepdims=False, *, where=True)
+
+ Returns the average of the array elements along given axis.
+
+ Refer to `numpy.mean` for full documentation.
+
+ See Also
+ --------
+ numpy.mean : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('min',
+ """
+ a.min(axis=None, out=None, keepdims=False, initial=, where=True)
+
+ Return the minimum along a given axis.
+
+ Refer to `numpy.amin` for full documentation.
+
+ See Also
+ --------
+ numpy.amin : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('newbyteorder',
+ """
+ arr.newbyteorder(new_order='S', /)
+
+ Return the array with the same data viewed with a different byte order.
+
+ Equivalent to::
+
+ arr.view(arr.dtype.newbytorder(new_order))
+
+ Changes are also made in all fields and sub-arrays of the array data
+ type.
+
+
+
+ Parameters
+ ----------
+ new_order : string, optional
+ Byte order to force; a value from the byte order specifications
+ below. `new_order` codes can be any of:
+
+ * 'S' - swap dtype from current to opposite endian
+ * {'<', 'little'} - little endian
+ * {'>', 'big'} - big endian
+ * '=' - native order, equivalent to `sys.byteorder`
+ * {'|', 'I'} - ignore (no change to byte order)
+
+ The default value ('S') results in swapping the current
+ byte order.
+
+
+ Returns
+ -------
+ new_arr : array
+ New array object with the dtype reflecting given change to the
+ byte order.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('nonzero',
+ """
+ a.nonzero()
+
+ Return the indices of the elements that are non-zero.
+
+ Refer to `numpy.nonzero` for full documentation.
+
+ See Also
+ --------
+ numpy.nonzero : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('prod',
+ """
+ a.prod(axis=None, dtype=None, out=None, keepdims=False, initial=1, where=True)
+
+ Return the product of the array elements over the given axis
+
+ Refer to `numpy.prod` for full documentation.
+
+ See Also
+ --------
+ numpy.prod : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('ptp',
+ """
+ a.ptp(axis=None, out=None, keepdims=False)
+
+ Peak to peak (maximum - minimum) value along a given axis.
+
+ Refer to `numpy.ptp` for full documentation.
+
+ See Also
+ --------
+ numpy.ptp : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('put',
+ """
+ a.put(indices, values, mode='raise')
+
+ Set ``a.flat[n] = values[n]`` for all `n` in indices.
+
+ Refer to `numpy.put` for full documentation.
+
+ See Also
+ --------
+ numpy.put : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('ravel',
+ """
+ a.ravel([order])
+
+ Return a flattened array.
+
+ Refer to `numpy.ravel` for full documentation.
+
+ See Also
+ --------
+ numpy.ravel : equivalent function
+
+ ndarray.flat : a flat iterator on the array.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('repeat',
+ """
+ a.repeat(repeats, axis=None)
+
+ Repeat elements of an array.
+
+ Refer to `numpy.repeat` for full documentation.
+
+ See Also
+ --------
+ numpy.repeat : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('reshape',
+ """
+ a.reshape(shape, order='C')
+
+ Returns an array containing the same data with a new shape.
+
+ Refer to `numpy.reshape` for full documentation.
+
+ See Also
+ --------
+ numpy.reshape : equivalent function
+
+ Notes
+ -----
+ Unlike the free function `numpy.reshape`, this method on `ndarray` allows
+ the elements of the shape parameter to be passed in as separate arguments.
+ For example, ``a.reshape(10, 11)`` is equivalent to
+ ``a.reshape((10, 11))``.
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('resize',
+ """
+ a.resize(new_shape, refcheck=True)
+
+ Change shape and size of array in-place.
+
+ Parameters
+ ----------
+ new_shape : tuple of ints, or `n` ints
+ Shape of resized array.
+ refcheck : bool, optional
+ If False, reference count will not be checked. Default is True.
+
+ Returns
+ -------
+ None
+
+ Raises
+ ------
+ ValueError
+ If `a` does not own its own data or references or views to it exist,
+ and the data memory must be changed.
+ PyPy only: will always raise if the data memory must be changed, since
+ there is no reliable way to determine if references or views to it
+ exist.
+
+ SystemError
+ If the `order` keyword argument is specified. This behaviour is a
+ bug in NumPy.
+
+ See Also
+ --------
+ resize : Return a new array with the specified shape.
+
+ Notes
+ -----
+ This reallocates space for the data area if necessary.
+
+ Only contiguous arrays (data elements consecutive in memory) can be
+ resized.
+
+ The purpose of the reference count check is to make sure you
+ do not use this array as a buffer for another Python object and then
+ reallocate the memory. However, reference counts can increase in
+ other ways so if you are sure that you have not shared the memory
+ for this array with another Python object, then you may safely set
+ `refcheck` to False.
+
+ Examples
+ --------
+ Shrinking an array: array is flattened (in the order that the data are
+ stored in memory), resized, and reshaped:
+
+ >>> a = np.array([[0, 1], [2, 3]], order='C')
+ >>> a.resize((2, 1))
+ >>> a
+ array([[0],
+ [1]])
+
+ >>> a = np.array([[0, 1], [2, 3]], order='F')
+ >>> a.resize((2, 1))
+ >>> a
+ array([[0],
+ [2]])
+
+ Enlarging an array: as above, but missing entries are filled with zeros:
+
+ >>> b = np.array([[0, 1], [2, 3]])
+ >>> b.resize(2, 3) # new_shape parameter doesn't have to be a tuple
+ >>> b
+ array([[0, 1, 2],
+ [3, 0, 0]])
+
+ Referencing an array prevents resizing...
+
+ >>> c = a
+ >>> a.resize((1, 1))
+ Traceback (most recent call last):
+ ...
+ ValueError: cannot resize an array that references or is referenced ...
+
+ Unless `refcheck` is False:
+
+ >>> a.resize((1, 1), refcheck=False)
+ >>> a
+ array([[0]])
+ >>> c
+ array([[0]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('round',
+ """
+ a.round(decimals=0, out=None)
+
+ Return `a` with each element rounded to the given number of decimals.
+
+ Refer to `numpy.around` for full documentation.
+
+ See Also
+ --------
+ numpy.around : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('searchsorted',
+ """
+ a.searchsorted(v, side='left', sorter=None)
+
+ Find indices where elements of v should be inserted in a to maintain order.
+
+ For full documentation, see `numpy.searchsorted`
+
+ See Also
+ --------
+ numpy.searchsorted : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('setfield',
+ """
+ a.setfield(val, dtype, offset=0)
+
+ Put a value into a specified place in a field defined by a data-type.
+
+ Place `val` into `a`'s field defined by `dtype` and beginning `offset`
+ bytes into the field.
+
+ Parameters
+ ----------
+ val : object
+ Value to be placed in field.
+ dtype : dtype object
+ Data-type of the field in which to place `val`.
+ offset : int, optional
+ The number of bytes into the field at which to place `val`.
+
+ Returns
+ -------
+ None
+
+ See Also
+ --------
+ getfield
+
+ Examples
+ --------
+ >>> x = np.eye(3)
+ >>> x.getfield(np.float64)
+ array([[1., 0., 0.],
+ [0., 1., 0.],
+ [0., 0., 1.]])
+ >>> x.setfield(3, np.int32)
+ >>> x.getfield(np.int32)
+ array([[3, 3, 3],
+ [3, 3, 3],
+ [3, 3, 3]], dtype=int32)
+ >>> x
+ array([[1.0e+000, 1.5e-323, 1.5e-323],
+ [1.5e-323, 1.0e+000, 1.5e-323],
+ [1.5e-323, 1.5e-323, 1.0e+000]])
+ >>> x.setfield(np.eye(3), np.int32)
+ >>> x
+ array([[1., 0., 0.],
+ [0., 1., 0.],
+ [0., 0., 1.]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('setflags',
+ """
+ a.setflags(write=None, align=None, uic=None)
+
+ Set array flags WRITEABLE, ALIGNED, (WRITEBACKIFCOPY and UPDATEIFCOPY),
+ respectively.
+
+ These Boolean-valued flags affect how numpy interprets the memory
+ area used by `a` (see Notes below). The ALIGNED flag can only
+ be set to True if the data is actually aligned according to the type.
+ The WRITEBACKIFCOPY and (deprecated) UPDATEIFCOPY flags can never be set
+ to True. The flag WRITEABLE can only be set to True if the array owns its
+ own memory, or the ultimate owner of the memory exposes a writeable buffer
+ interface, or is a string. (The exception for string is made so that
+ unpickling can be done without copying memory.)
+
+ Parameters
+ ----------
+ write : bool, optional
+ Describes whether or not `a` can be written to.
+ align : bool, optional
+ Describes whether or not `a` is aligned properly for its type.
+ uic : bool, optional
+ Describes whether or not `a` is a copy of another "base" array.
+
+ Notes
+ -----
+ Array flags provide information about how the memory area used
+ for the array is to be interpreted. There are 7 Boolean flags
+ in use, only four of which can be changed by the user:
+ WRITEBACKIFCOPY, UPDATEIFCOPY, WRITEABLE, and ALIGNED.
+
+ WRITEABLE (W) the data area can be written to;
+
+ ALIGNED (A) the data and strides are aligned appropriately for the hardware
+ (as determined by the compiler);
+
+ UPDATEIFCOPY (U) (deprecated), replaced by WRITEBACKIFCOPY;
+
+ WRITEBACKIFCOPY (X) this array is a copy of some other array (referenced
+ by .base). When the C-API function PyArray_ResolveWritebackIfCopy is
+ called, the base array will be updated with the contents of this array.
+
+ All flags can be accessed using the single (upper case) letter as well
+ as the full name.
+
+ Examples
+ --------
+ >>> y = np.array([[3, 1, 7],
+ ... [2, 0, 0],
+ ... [8, 5, 9]])
+ >>> y
+ array([[3, 1, 7],
+ [2, 0, 0],
+ [8, 5, 9]])
+ >>> y.flags
+ C_CONTIGUOUS : True
+ F_CONTIGUOUS : False
+ OWNDATA : True
+ WRITEABLE : True
+ ALIGNED : True
+ WRITEBACKIFCOPY : False
+ UPDATEIFCOPY : False
+ >>> y.setflags(write=0, align=0)
+ >>> y.flags
+ C_CONTIGUOUS : True
+ F_CONTIGUOUS : False
+ OWNDATA : True
+ WRITEABLE : False
+ ALIGNED : False
+ WRITEBACKIFCOPY : False
+ UPDATEIFCOPY : False
+ >>> y.setflags(uic=1)
+ Traceback (most recent call last):
+ File "", line 1, in
+ ValueError: cannot set WRITEBACKIFCOPY flag to True
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('sort',
+ """
+ a.sort(axis=-1, kind=None, order=None)
+
+ Sort an array in-place. Refer to `numpy.sort` for full documentation.
+
+ Parameters
+ ----------
+ axis : int, optional
+ Axis along which to sort. Default is -1, which means sort along the
+ last axis.
+ kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional
+ Sorting algorithm. The default is 'quicksort'. Note that both 'stable'
+ and 'mergesort' use timsort under the covers and, in general, the
+ actual implementation will vary with datatype. The 'mergesort' option
+ is retained for backwards compatibility.
+
+ .. versionchanged:: 1.15.0.
+ The 'stable' option was added.
+
+ order : str or list of str, optional
+ When `a` is an array with fields defined, this argument specifies
+ which fields to compare first, second, etc. A single field can
+ be specified as a string, and not all fields need be specified,
+ but unspecified fields will still be used, in the order in which
+ they come up in the dtype, to break ties.
+
+ See Also
+ --------
+ numpy.sort : Return a sorted copy of an array.
+ numpy.argsort : Indirect sort.
+ numpy.lexsort : Indirect stable sort on multiple keys.
+ numpy.searchsorted : Find elements in sorted array.
+ numpy.partition: Partial sort.
+
+ Notes
+ -----
+ See `numpy.sort` for notes on the different sorting algorithms.
+
+ Examples
+ --------
+ >>> a = np.array([[1,4], [3,1]])
+ >>> a.sort(axis=1)
+ >>> a
+ array([[1, 4],
+ [1, 3]])
+ >>> a.sort(axis=0)
+ >>> a
+ array([[1, 3],
+ [1, 4]])
+
+ Use the `order` keyword to specify a field to use when sorting a
+ structured array:
+
+ >>> a = np.array([('a', 2), ('c', 1)], dtype=[('x', 'S1'), ('y', int)])
+ >>> a.sort(order='y')
+ >>> a
+ array([(b'c', 1), (b'a', 2)],
+ dtype=[('x', 'S1'), ('y', '>> a = np.array([3, 4, 2, 1])
+ >>> a.partition(3)
+ >>> a
+ array([2, 1, 3, 4])
+
+ >>> a.partition((1, 3))
+ >>> a
+ array([1, 2, 3, 4])
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('squeeze',
+ """
+ a.squeeze(axis=None)
+
+ Remove axes of length one from `a`.
+
+ Refer to `numpy.squeeze` for full documentation.
+
+ See Also
+ --------
+ numpy.squeeze : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('std',
+ """
+ a.std(axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True)
+
+ Returns the standard deviation of the array elements along given axis.
+
+ Refer to `numpy.std` for full documentation.
+
+ See Also
+ --------
+ numpy.std : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('sum',
+ """
+ a.sum(axis=None, dtype=None, out=None, keepdims=False, initial=0, where=True)
+
+ Return the sum of the array elements over the given axis.
+
+ Refer to `numpy.sum` for full documentation.
+
+ See Also
+ --------
+ numpy.sum : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('swapaxes',
+ """
+ a.swapaxes(axis1, axis2)
+
+ Return a view of the array with `axis1` and `axis2` interchanged.
+
+ Refer to `numpy.swapaxes` for full documentation.
+
+ See Also
+ --------
+ numpy.swapaxes : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('take',
+ """
+ a.take(indices, axis=None, out=None, mode='raise')
+
+ Return an array formed from the elements of `a` at the given indices.
+
+ Refer to `numpy.take` for full documentation.
+
+ See Also
+ --------
+ numpy.take : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('tofile',
+ """
+ a.tofile(fid, sep="", format="%s")
+
+ Write array to a file as text or binary (default).
+
+ Data is always written in 'C' order, independent of the order of `a`.
+ The data produced by this method can be recovered using the function
+ fromfile().
+
+ Parameters
+ ----------
+ fid : file or str or Path
+ An open file object, or a string containing a filename.
+
+ .. versionchanged:: 1.17.0
+ `pathlib.Path` objects are now accepted.
+
+ sep : str
+ Separator between array items for text output.
+ If "" (empty), a binary file is written, equivalent to
+ ``file.write(a.tobytes())``.
+ format : str
+ Format string for text file output.
+ Each entry in the array is formatted to text by first converting
+ it to the closest Python type, and then using "format" % item.
+
+ Notes
+ -----
+ This is a convenience function for quick storage of array data.
+ Information on endianness and precision is lost, so this method is not a
+ good choice for files intended to archive data or transport data between
+ machines with different endianness. Some of these problems can be overcome
+ by outputting the data as text files, at the expense of speed and file
+ size.
+
+ When fid is a file object, array contents are directly written to the
+ file, bypassing the file object's ``write`` method. As a result, tofile
+ cannot be used with files objects supporting compression (e.g., GzipFile)
+ or file-like objects that do not support ``fileno()`` (e.g., BytesIO).
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('tolist',
+ """
+ a.tolist()
+
+ Return the array as an ``a.ndim``-levels deep nested list of Python scalars.
+
+ Return a copy of the array data as a (nested) Python list.
+ Data items are converted to the nearest compatible builtin Python type, via
+ the `~numpy.ndarray.item` function.
+
+ If ``a.ndim`` is 0, then since the depth of the nested list is 0, it will
+ not be a list at all, but a simple Python scalar.
+
+ Parameters
+ ----------
+ none
+
+ Returns
+ -------
+ y : object, or list of object, or list of list of object, or ...
+ The possibly nested list of array elements.
+
+ Notes
+ -----
+ The array may be recreated via ``a = np.array(a.tolist())``, although this
+ may sometimes lose precision.
+
+ Examples
+ --------
+ For a 1D array, ``a.tolist()`` is almost the same as ``list(a)``,
+ except that ``tolist`` changes numpy scalars to Python scalars:
+
+ >>> a = np.uint32([1, 2])
+ >>> a_list = list(a)
+ >>> a_list
+ [1, 2]
+ >>> type(a_list[0])
+
+ >>> a_tolist = a.tolist()
+ >>> a_tolist
+ [1, 2]
+ >>> type(a_tolist[0])
+
+
+ Additionally, for a 2D array, ``tolist`` applies recursively:
+
+ >>> a = np.array([[1, 2], [3, 4]])
+ >>> list(a)
+ [array([1, 2]), array([3, 4])]
+ >>> a.tolist()
+ [[1, 2], [3, 4]]
+
+ The base case for this recursion is a 0D array:
+
+ >>> a = np.array(1)
+ >>> list(a)
+ Traceback (most recent call last):
+ ...
+ TypeError: iteration over a 0-d array
+ >>> a.tolist()
+ 1
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('tobytes', """
+ a.tobytes(order='C')
+
+ Construct Python bytes containing the raw data bytes in the array.
+
+ Constructs Python bytes showing a copy of the raw contents of
+ data memory. The bytes object is produced in C-order by default.
+ This behavior is controlled by the ``order`` parameter.
+
+ .. versionadded:: 1.9.0
+
+ Parameters
+ ----------
+ order : {'C', 'F', 'A'}, optional
+ Controls the memory layout of the bytes object. 'C' means C-order,
+ 'F' means F-order, 'A' (short for *Any*) means 'F' if `a` is
+ Fortran contiguous, 'C' otherwise. Default is 'C'.
+
+ Returns
+ -------
+ s : bytes
+ Python bytes exhibiting a copy of `a`'s raw data.
+
+ Examples
+ --------
+ >>> x = np.array([[0, 1], [2, 3]], dtype='>> x.tobytes()
+ b'\\x00\\x00\\x01\\x00\\x02\\x00\\x03\\x00'
+ >>> x.tobytes('C') == x.tobytes()
+ True
+ >>> x.tobytes('F')
+ b'\\x00\\x00\\x02\\x00\\x01\\x00\\x03\\x00'
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('tostring', r"""
+ a.tostring(order='C')
+
+ A compatibility alias for `tobytes`, with exactly the same behavior.
+
+ Despite its name, it returns `bytes` not `str`\ s.
+
+ .. deprecated:: 1.19.0
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('trace',
+ """
+ a.trace(offset=0, axis1=0, axis2=1, dtype=None, out=None)
+
+ Return the sum along diagonals of the array.
+
+ Refer to `numpy.trace` for full documentation.
+
+ See Also
+ --------
+ numpy.trace : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('transpose',
+ """
+ a.transpose(*axes)
+
+ Returns a view of the array with axes transposed.
+
+ For a 1-D array this has no effect, as a transposed vector is simply the
+ same vector. To convert a 1-D array into a 2D column vector, an additional
+ dimension must be added. `np.atleast2d(a).T` achieves this, as does
+ `a[:, np.newaxis]`.
+ For a 2-D array, this is a standard matrix transpose.
+ For an n-D array, if axes are given, their order indicates how the
+ axes are permuted (see Examples). If axes are not provided and
+ ``a.shape = (i[0], i[1], ... i[n-2], i[n-1])``, then
+ ``a.transpose().shape = (i[n-1], i[n-2], ... i[1], i[0])``.
+
+ Parameters
+ ----------
+ axes : None, tuple of ints, or `n` ints
+
+ * None or no argument: reverses the order of the axes.
+
+ * tuple of ints: `i` in the `j`-th place in the tuple means `a`'s
+ `i`-th axis becomes `a.transpose()`'s `j`-th axis.
+
+ * `n` ints: same as an n-tuple of the same ints (this form is
+ intended simply as a "convenience" alternative to the tuple form)
+
+ Returns
+ -------
+ out : ndarray
+ View of `a`, with axes suitably permuted.
+
+ See Also
+ --------
+ ndarray.T : Array property returning the array transposed.
+ ndarray.reshape : Give a new shape to an array without changing its data.
+
+ Examples
+ --------
+ >>> a = np.array([[1, 2], [3, 4]])
+ >>> a
+ array([[1, 2],
+ [3, 4]])
+ >>> a.transpose()
+ array([[1, 3],
+ [2, 4]])
+ >>> a.transpose((1, 0))
+ array([[1, 3],
+ [2, 4]])
+ >>> a.transpose(1, 0)
+ array([[1, 3],
+ [2, 4]])
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('var',
+ """
+ a.var(axis=None, dtype=None, out=None, ddof=0, keepdims=False, *, where=True)
+
+ Returns the variance of the array elements, along given axis.
+
+ Refer to `numpy.var` for full documentation.
+
+ See Also
+ --------
+ numpy.var : equivalent function
+
+ """))
+
+
+add_newdoc('numpy.core.multiarray', 'ndarray', ('view',
+ """
+ a.view([dtype][, type])
+
+ New view of array with the same data.
+
+ .. note::
+ Passing None for ``dtype`` is different from omitting the parameter,
+ since the former invokes ``dtype(None)`` which is an alias for
+ ``dtype('float_')``.
+
+ Parameters
+ ----------
+ dtype : data-type or ndarray sub-class, optional
+ Data-type descriptor of the returned view, e.g., float32 or int16.
+ Omitting it results in the view having the same data-type as `a`.
+ This argument can also be specified as an ndarray sub-class, which
+ then specifies the type of the returned object (this is equivalent to
+ setting the ``type`` parameter).
+ type : Python type, optional
+ Type of the returned view, e.g., ndarray or matrix. Again, omission
+ of the parameter results in type preservation.
+
+ Notes
+ -----
+ ``a.view()`` is used two different ways:
+
+ ``a.view(some_dtype)`` or ``a.view(dtype=some_dtype)`` constructs a view
+ of the array's memory with a different data-type. This can cause a
+ reinterpretation of the bytes of memory.
+
+ ``a.view(ndarray_subclass)`` or ``a.view(type=ndarray_subclass)`` just
+ returns an instance of `ndarray_subclass` that looks at the same array
+ (same shape, dtype, etc.) This does not cause a reinterpretation of the
+ memory.
+
+ For ``a.view(some_dtype)``, if ``some_dtype`` has a different number of
+ bytes per entry than the previous dtype (for example, converting a
+ regular array to a structured array), then the behavior of the view
+ cannot be predicted just from the superficial appearance of ``a`` (shown
+ by ``print(a)``). It also depends on exactly how ``a`` is stored in
+ memory. Therefore if ``a`` is C-ordered versus fortran-ordered, versus
+ defined as a slice or transpose, etc., the view may give different
+ results.
+
+
+ Examples
+ --------
+ >>> x = np.array([(1, 2)], dtype=[('a', np.int8), ('b', np.int8)])
+
+ Viewing array data using a different type and dtype:
+
+ >>> y = x.view(dtype=np.int16, type=np.matrix)
+ >>> y
+ matrix([[513]], dtype=int16)
+ >>> print(type(y))
+
+
+ Creating a view on a structured array so it can be used in calculations
+
+ >>> x = np.array([(1, 2),(3,4)], dtype=[('a', np.int8), ('b', np.int8)])
+ >>> xv = x.view(dtype=np.int8).reshape(-1,2)
+ >>> xv
+ array([[1, 2],
+ [3, 4]], dtype=int8)
+ >>> xv.mean(0)
+ array([2., 3.])
+
+ Making changes to the view changes the underlying array
+
+ >>> xv[0,1] = 20
+ >>> x
+ array([(1, 20), (3, 4)], dtype=[('a', 'i1'), ('b', 'i1')])
+
+ Using a view to convert an array to a recarray:
+
+ >>> z = x.view(np.recarray)
+ >>> z.a
+ array([1, 3], dtype=int8)
+
+ Views share data:
+
+ >>> x[0] = (9, 10)
+ >>> z[0]
+ (9, 10)
+
+ Views that change the dtype size (bytes per entry) should normally be
+ avoided on arrays defined by slices, transposes, fortran-ordering, etc.:
+
+ >>> x = np.array([[1,2,3],[4,5,6]], dtype=np.int16)
+ >>> y = x[:, 0:2]
+ >>> y
+ array([[1, 2],
+ [4, 5]], dtype=int16)
+ >>> y.view(dtype=[('width', np.int16), ('length', np.int16)])
+ Traceback (most recent call last):
+ ...
+ ValueError: To change to a dtype of a different size, the array must be C-contiguous
+ >>> z = y.copy()
+ >>> z.view(dtype=[('width', np.int16), ('length', np.int16)])
+ array([[(1, 2)],
+ [(4, 5)]], dtype=[('width', '>> oct_array = np.frompyfunc(oct, 1, 1)
+ >>> oct_array(np.array((10, 30, 100)))
+ array(['0o12', '0o36', '0o144'], dtype=object)
+ >>> np.array((oct(10), oct(30), oct(100))) # for comparison
+ array(['0o12', '0o36', '0o144'], dtype='>> np.geterrobj() # first get the defaults
+ [8192, 521, None]
+
+ >>> def err_handler(type, flag):
+ ... print("Floating point error (%s), with flag %s" % (type, flag))
+ ...
+ >>> old_bufsize = np.setbufsize(20000)
+ >>> old_err = np.seterr(divide='raise')
+ >>> old_handler = np.seterrcall(err_handler)
+ >>> np.geterrobj()
+ [8192, 521, ]
+
+ >>> old_err = np.seterr(all='ignore')
+ >>> np.base_repr(np.geterrobj()[1], 8)
+ '0'
+ >>> old_err = np.seterr(divide='warn', over='log', under='call',
+ ... invalid='print')
+ >>> np.base_repr(np.geterrobj()[1], 8)
+ '4351'
+
+ """)
+
+add_newdoc('numpy.core.umath', 'seterrobj',
+ """
+ seterrobj(errobj)
+
+ Set the object that defines floating-point error handling.
+
+ The error object contains all information that defines the error handling
+ behavior in NumPy. `seterrobj` is used internally by the other
+ functions that set error handling behavior (`seterr`, `seterrcall`).
+
+ Parameters
+ ----------
+ errobj : list
+ The error object, a list containing three elements:
+ [internal numpy buffer size, error mask, error callback function].
+
+ The error mask is a single integer that holds the treatment information
+ on all four floating point errors. The information for each error type
+ is contained in three bits of the integer. If we print it in base 8, we
+ can see what treatment is set for "invalid", "under", "over", and
+ "divide" (in that order). The printed string can be interpreted with
+
+ * 0 : 'ignore'
+ * 1 : 'warn'
+ * 2 : 'raise'
+ * 3 : 'call'
+ * 4 : 'print'
+ * 5 : 'log'
+
+ See Also
+ --------
+ geterrobj, seterr, geterr, seterrcall, geterrcall
+ getbufsize, setbufsize
+
+ Notes
+ -----
+ For complete documentation of the types of floating-point exceptions and
+ treatment options, see `seterr`.
+
+ Examples
+ --------
+ >>> old_errobj = np.geterrobj() # first get the defaults
+ >>> old_errobj
+ [8192, 521, None]
+
+ >>> def err_handler(type, flag):
+ ... print("Floating point error (%s), with flag %s" % (type, flag))
+ ...
+ >>> new_errobj = [20000, 12, err_handler]
+ >>> np.seterrobj(new_errobj)
+ >>> np.base_repr(12, 8) # int for divide=4 ('print') and over=1 ('warn')
+ '14'
+ >>> np.geterr()
+ {'over': 'warn', 'divide': 'print', 'invalid': 'ignore', 'under': 'ignore'}
+ >>> np.geterrcall() is err_handler
+ True
+
+ """)
+
+
+##############################################################################
+#
+# compiled_base functions
+#
+##############################################################################
+
+add_newdoc('numpy.core.multiarray', 'add_docstring',
+ """
+ add_docstring(obj, docstring)
+
+ Add a docstring to a built-in obj if possible.
+ If the obj already has a docstring raise a RuntimeError
+ If this routine does not know how to add a docstring to the object
+ raise a TypeError
+ """)
+
+add_newdoc('numpy.core.umath', '_add_newdoc_ufunc',
+ """
+ add_ufunc_docstring(ufunc, new_docstring)
+
+ Replace the docstring for a ufunc with new_docstring.
+ This method will only work if the current docstring for
+ the ufunc is NULL. (At the C level, i.e. when ufunc->doc is NULL.)
+
+ Parameters
+ ----------
+ ufunc : numpy.ufunc
+ A ufunc whose current doc is NULL.
+ new_docstring : string
+ The new docstring for the ufunc.
+
+ Notes
+ -----
+ This method allocates memory for new_docstring on
+ the heap. Technically this creates a mempory leak, since this
+ memory will not be reclaimed until the end of the program
+ even if the ufunc itself is removed. However this will only
+ be a problem if the user is repeatedly creating ufuncs with
+ no documentation, adding documentation via add_newdoc_ufunc,
+ and then throwing away the ufunc.
+ """)
+
+add_newdoc('numpy.core.multiarray', '_set_madvise_hugepage',
+ """
+ _set_madvise_hugepage(enabled: bool) -> bool
+
+ Set or unset use of ``madvise (2)`` MADV_HUGEPAGE support when
+ allocating the array data. Returns the previously set value.
+ See `global_state` for more information.
+ """)
+
+add_newdoc('numpy.core._multiarray_tests', 'format_float_OSprintf_g',
+ """
+ format_float_OSprintf_g(val, precision)
+
+ Print a floating point scalar using the system's printf function,
+ equivalent to:
+
+ printf("%.*g", precision, val);
+
+ for half/float/double, or replacing 'g' by 'Lg' for longdouble. This
+ method is designed to help cross-validate the format_float_* methods.
+
+ Parameters
+ ----------
+ val : python float or numpy floating scalar
+ Value to format.
+
+ precision : non-negative integer, optional
+ Precision given to printf.
+
+ Returns
+ -------
+ rep : string
+ The string representation of the floating point value
+
+ See Also
+ --------
+ format_float_scientific
+ format_float_positional
+ """)
+
+
+##############################################################################
+#
+# Documentation for ufunc attributes and methods
+#
+##############################################################################
+
+
+##############################################################################
+#
+# ufunc object
+#
+##############################################################################
+
+add_newdoc('numpy.core', 'ufunc',
+ """
+ Functions that operate element by element on whole arrays.
+
+ To see the documentation for a specific ufunc, use `info`. For
+ example, ``np.info(np.sin)``. Because ufuncs are written in C
+ (for speed) and linked into Python with NumPy's ufunc facility,
+ Python's help() function finds this page whenever help() is called
+ on a ufunc.
+
+ A detailed explanation of ufuncs can be found in the docs for :ref:`ufuncs`.
+
+ **Calling ufuncs:** ``op(*x[, out], where=True, **kwargs)``
+
+ Apply `op` to the arguments `*x` elementwise, broadcasting the arguments.
+
+ The broadcasting rules are:
+
+ * Dimensions of length 1 may be prepended to either array.
+ * Arrays may be repeated along dimensions of length 1.
+
+ Parameters
+ ----------
+ *x : array_like
+ Input arrays.
+ out : ndarray, None, or tuple of ndarray and None, optional
+ Alternate array object(s) in which to put the result; if provided, it
+ must have a shape that the inputs broadcast to. A tuple of arrays
+ (possible only as a keyword argument) must have length equal to the
+ number of outputs; use None for uninitialized outputs to be
+ allocated by the ufunc.
+ where : array_like, optional
+ This condition is broadcast over the input. At locations where the
+ condition is True, the `out` array will be set to the ufunc result.
+ Elsewhere, the `out` array will retain its original value.
+ Note that if an uninitialized `out` array is created via the default
+ ``out=None``, locations within it where the condition is False will
+ remain uninitialized.
+ **kwargs
+ For other keyword-only arguments, see the :ref:`ufunc docs `.
+
+ Returns
+ -------
+ r : ndarray or tuple of ndarray
+ `r` will have the shape that the arrays in `x` broadcast to; if `out` is
+ provided, it will be returned. If not, `r` will be allocated and
+ may contain uninitialized values. If the function has more than one
+ output, then the result will be a tuple of arrays.
+
+ """)
+
+
+##############################################################################
+#
+# ufunc attributes
+#
+##############################################################################
+
+add_newdoc('numpy.core', 'ufunc', ('identity',
+ """
+ The identity value.
+
+ Data attribute containing the identity element for the ufunc, if it has one.
+ If it does not, the attribute value is None.
+
+ Examples
+ --------
+ >>> np.add.identity
+ 0
+ >>> np.multiply.identity
+ 1
+ >>> np.power.identity
+ 1
+ >>> print(np.exp.identity)
+ None
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('nargs',
+ """
+ The number of arguments.
+
+ Data attribute containing the number of arguments the ufunc takes, including
+ optional ones.
+
+ Notes
+ -----
+ Typically this value will be one more than what you might expect because all
+ ufuncs take the optional "out" argument.
+
+ Examples
+ --------
+ >>> np.add.nargs
+ 3
+ >>> np.multiply.nargs
+ 3
+ >>> np.power.nargs
+ 3
+ >>> np.exp.nargs
+ 2
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('nin',
+ """
+ The number of inputs.
+
+ Data attribute containing the number of arguments the ufunc treats as input.
+
+ Examples
+ --------
+ >>> np.add.nin
+ 2
+ >>> np.multiply.nin
+ 2
+ >>> np.power.nin
+ 2
+ >>> np.exp.nin
+ 1
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('nout',
+ """
+ The number of outputs.
+
+ Data attribute containing the number of arguments the ufunc treats as output.
+
+ Notes
+ -----
+ Since all ufuncs can take output arguments, this will always be (at least) 1.
+
+ Examples
+ --------
+ >>> np.add.nout
+ 1
+ >>> np.multiply.nout
+ 1
+ >>> np.power.nout
+ 1
+ >>> np.exp.nout
+ 1
+
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('ntypes',
+ """
+ The number of types.
+
+ The number of numerical NumPy types - of which there are 18 total - on which
+ the ufunc can operate.
+
+ See Also
+ --------
+ numpy.ufunc.types
+
+ Examples
+ --------
+ >>> np.add.ntypes
+ 18
+ >>> np.multiply.ntypes
+ 18
+ >>> np.power.ntypes
+ 17
+ >>> np.exp.ntypes
+ 7
+ >>> np.remainder.ntypes
+ 14
+
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('types',
+ """
+ Returns a list with types grouped input->output.
+
+ Data attribute listing the data-type "Domain-Range" groupings the ufunc can
+ deliver. The data-types are given using the character codes.
+
+ See Also
+ --------
+ numpy.ufunc.ntypes
+
+ Examples
+ --------
+ >>> np.add.types
+ ['??->?', 'bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l',
+ 'LL->L', 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D',
+ 'GG->G', 'OO->O']
+
+ >>> np.multiply.types
+ ['??->?', 'bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l',
+ 'LL->L', 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D',
+ 'GG->G', 'OO->O']
+
+ >>> np.power.types
+ ['bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L',
+ 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'FF->F', 'DD->D', 'GG->G',
+ 'OO->O']
+
+ >>> np.exp.types
+ ['f->f', 'd->d', 'g->g', 'F->F', 'D->D', 'G->G', 'O->O']
+
+ >>> np.remainder.types
+ ['bb->b', 'BB->B', 'hh->h', 'HH->H', 'ii->i', 'II->I', 'll->l', 'LL->L',
+ 'qq->q', 'QQ->Q', 'ff->f', 'dd->d', 'gg->g', 'OO->O']
+
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('signature',
+ """
+ Definition of the core elements a generalized ufunc operates on.
+
+ The signature determines how the dimensions of each input/output array
+ are split into core and loop dimensions:
+
+ 1. Each dimension in the signature is matched to a dimension of the
+ corresponding passed-in array, starting from the end of the shape tuple.
+ 2. Core dimensions assigned to the same label in the signature must have
+ exactly matching sizes, no broadcasting is performed.
+ 3. The core dimensions are removed from all inputs and the remaining
+ dimensions are broadcast together, defining the loop dimensions.
+
+ Notes
+ -----
+ Generalized ufuncs are used internally in many linalg functions, and in
+ the testing suite; the examples below are taken from these.
+ For ufuncs that operate on scalars, the signature is None, which is
+ equivalent to '()' for every argument.
+
+ Examples
+ --------
+ >>> np.core.umath_tests.matrix_multiply.signature
+ '(m,n),(n,p)->(m,p)'
+ >>> np.linalg._umath_linalg.det.signature
+ '(m,m)->()'
+ >>> np.add.signature is None
+ True # equivalent to '(),()->()'
+ """))
+
+##############################################################################
+#
+# ufunc methods
+#
+##############################################################################
+
+add_newdoc('numpy.core', 'ufunc', ('reduce',
+ """
+ reduce(array, axis=0, dtype=None, out=None, keepdims=False, initial=, where=True)
+
+ Reduces `array`'s dimension by one, by applying ufunc along one axis.
+
+ Let :math:`array.shape = (N_0, ..., N_i, ..., N_{M-1})`. Then
+ :math:`ufunc.reduce(array, axis=i)[k_0, ..,k_{i-1}, k_{i+1}, .., k_{M-1}]` =
+ the result of iterating `j` over :math:`range(N_i)`, cumulatively applying
+ ufunc to each :math:`array[k_0, ..,k_{i-1}, j, k_{i+1}, .., k_{M-1}]`.
+ For a one-dimensional array, reduce produces results equivalent to:
+ ::
+
+ r = op.identity # op = ufunc
+ for i in range(len(A)):
+ r = op(r, A[i])
+ return r
+
+ For example, add.reduce() is equivalent to sum().
+
+ Parameters
+ ----------
+ array : array_like
+ The array to act on.
+ axis : None or int or tuple of ints, optional
+ Axis or axes along which a reduction is performed.
+ The default (`axis` = 0) is perform a reduction over the first
+ dimension of the input array. `axis` may be negative, in
+ which case it counts from the last to the first axis.
+
+ .. versionadded:: 1.7.0
+
+ If this is None, a reduction is performed over all the axes.
+ If this is a tuple of ints, a reduction is performed on multiple
+ axes, instead of a single axis or all the axes as before.
+
+ For operations which are either not commutative or not associative,
+ doing a reduction over multiple axes is not well-defined. The
+ ufuncs do not currently raise an exception in this case, but will
+ likely do so in the future.
+ dtype : data-type code, optional
+ The type used to represent the intermediate results. Defaults
+ to the data-type of the output array if this is provided, or
+ the data-type of the input array if no output array is provided.
+ out : ndarray, None, or tuple of ndarray and None, optional
+ A location into which the result is stored. If not provided or None,
+ a freshly-allocated array is returned. For consistency with
+ ``ufunc.__call__``, if given as a keyword, this may be wrapped in a
+ 1-element tuple.
+
+ .. versionchanged:: 1.13.0
+ Tuples are allowed for keyword argument.
+ keepdims : bool, optional
+ If this is set to True, the axes which are reduced are left
+ in the result as dimensions with size one. With this option,
+ the result will broadcast correctly against the original `array`.
+
+ .. versionadded:: 1.7.0
+ initial : scalar, optional
+ The value with which to start the reduction.
+ If the ufunc has no identity or the dtype is object, this defaults
+ to None - otherwise it defaults to ufunc.identity.
+ If ``None`` is given, the first element of the reduction is used,
+ and an error is thrown if the reduction is empty.
+
+ .. versionadded:: 1.15.0
+
+ where : array_like of bool, optional
+ A boolean array which is broadcasted to match the dimensions
+ of `array`, and selects elements to include in the reduction. Note
+ that for ufuncs like ``minimum`` that do not have an identity
+ defined, one has to pass in also ``initial``.
+
+ .. versionadded:: 1.17.0
+
+ Returns
+ -------
+ r : ndarray
+ The reduced array. If `out` was supplied, `r` is a reference to it.
+
+ Examples
+ --------
+ >>> np.multiply.reduce([2,3,5])
+ 30
+
+ A multi-dimensional array example:
+
+ >>> X = np.arange(8).reshape((2,2,2))
+ >>> X
+ array([[[0, 1],
+ [2, 3]],
+ [[4, 5],
+ [6, 7]]])
+ >>> np.add.reduce(X, 0)
+ array([[ 4, 6],
+ [ 8, 10]])
+ >>> np.add.reduce(X) # confirm: default axis value is 0
+ array([[ 4, 6],
+ [ 8, 10]])
+ >>> np.add.reduce(X, 1)
+ array([[ 2, 4],
+ [10, 12]])
+ >>> np.add.reduce(X, 2)
+ array([[ 1, 5],
+ [ 9, 13]])
+
+ You can use the ``initial`` keyword argument to initialize the reduction
+ with a different value, and ``where`` to select specific elements to include:
+
+ >>> np.add.reduce([10], initial=5)
+ 15
+ >>> np.add.reduce(np.ones((2, 2, 2)), axis=(0, 2), initial=10)
+ array([14., 14.])
+ >>> a = np.array([10., np.nan, 10])
+ >>> np.add.reduce(a, where=~np.isnan(a))
+ 20.0
+
+ Allows reductions of empty arrays where they would normally fail, i.e.
+ for ufuncs without an identity.
+
+ >>> np.minimum.reduce([], initial=np.inf)
+ inf
+ >>> np.minimum.reduce([[1., 2.], [3., 4.]], initial=10., where=[True, False])
+ array([ 1., 10.])
+ >>> np.minimum.reduce([])
+ Traceback (most recent call last):
+ ...
+ ValueError: zero-size array to reduction operation minimum which has no identity
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('accumulate',
+ """
+ accumulate(array, axis=0, dtype=None, out=None)
+
+ Accumulate the result of applying the operator to all elements.
+
+ For a one-dimensional array, accumulate produces results equivalent to::
+
+ r = np.empty(len(A))
+ t = op.identity # op = the ufunc being applied to A's elements
+ for i in range(len(A)):
+ t = op(t, A[i])
+ r[i] = t
+ return r
+
+ For example, add.accumulate() is equivalent to np.cumsum().
+
+ For a multi-dimensional array, accumulate is applied along only one
+ axis (axis zero by default; see Examples below) so repeated use is
+ necessary if one wants to accumulate over multiple axes.
+
+ Parameters
+ ----------
+ array : array_like
+ The array to act on.
+ axis : int, optional
+ The axis along which to apply the accumulation; default is zero.
+ dtype : data-type code, optional
+ The data-type used to represent the intermediate results. Defaults
+ to the data-type of the output array if such is provided, or the
+ the data-type of the input array if no output array is provided.
+ out : ndarray, None, or tuple of ndarray and None, optional
+ A location into which the result is stored. If not provided or None,
+ a freshly-allocated array is returned. For consistency with
+ ``ufunc.__call__``, if given as a keyword, this may be wrapped in a
+ 1-element tuple.
+
+ .. versionchanged:: 1.13.0
+ Tuples are allowed for keyword argument.
+
+ Returns
+ -------
+ r : ndarray
+ The accumulated values. If `out` was supplied, `r` is a reference to
+ `out`.
+
+ Examples
+ --------
+ 1-D array examples:
+
+ >>> np.add.accumulate([2, 3, 5])
+ array([ 2, 5, 10])
+ >>> np.multiply.accumulate([2, 3, 5])
+ array([ 2, 6, 30])
+
+ 2-D array examples:
+
+ >>> I = np.eye(2)
+ >>> I
+ array([[1., 0.],
+ [0., 1.]])
+
+ Accumulate along axis 0 (rows), down columns:
+
+ >>> np.add.accumulate(I, 0)
+ array([[1., 0.],
+ [1., 1.]])
+ >>> np.add.accumulate(I) # no axis specified = axis zero
+ array([[1., 0.],
+ [1., 1.]])
+
+ Accumulate along axis 1 (columns), through rows:
+
+ >>> np.add.accumulate(I, 1)
+ array([[1., 1.],
+ [0., 1.]])
+
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('reduceat',
+ """
+ reduceat(array, indices, axis=0, dtype=None, out=None)
+
+ Performs a (local) reduce with specified slices over a single axis.
+
+ For i in ``range(len(indices))``, `reduceat` computes
+ ``ufunc.reduce(array[indices[i]:indices[i+1]])``, which becomes the i-th
+ generalized "row" parallel to `axis` in the final result (i.e., in a
+ 2-D array, for example, if `axis = 0`, it becomes the i-th row, but if
+ `axis = 1`, it becomes the i-th column). There are three exceptions to this:
+
+ * when ``i = len(indices) - 1`` (so for the last index),
+ ``indices[i+1] = array.shape[axis]``.
+ * if ``indices[i] >= indices[i + 1]``, the i-th generalized "row" is
+ simply ``array[indices[i]]``.
+ * if ``indices[i] >= len(array)`` or ``indices[i] < 0``, an error is raised.
+
+ The shape of the output depends on the size of `indices`, and may be
+ larger than `array` (this happens if ``len(indices) > array.shape[axis]``).
+
+ Parameters
+ ----------
+ array : array_like
+ The array to act on.
+ indices : array_like
+ Paired indices, comma separated (not colon), specifying slices to
+ reduce.
+ axis : int, optional
+ The axis along which to apply the reduceat.
+ dtype : data-type code, optional
+ The type used to represent the intermediate results. Defaults
+ to the data type of the output array if this is provided, or
+ the data type of the input array if no output array is provided.
+ out : ndarray, None, or tuple of ndarray and None, optional
+ A location into which the result is stored. If not provided or None,
+ a freshly-allocated array is returned. For consistency with
+ ``ufunc.__call__``, if given as a keyword, this may be wrapped in a
+ 1-element tuple.
+
+ .. versionchanged:: 1.13.0
+ Tuples are allowed for keyword argument.
+
+ Returns
+ -------
+ r : ndarray
+ The reduced values. If `out` was supplied, `r` is a reference to
+ `out`.
+
+ Notes
+ -----
+ A descriptive example:
+
+ If `array` is 1-D, the function `ufunc.accumulate(array)` is the same as
+ ``ufunc.reduceat(array, indices)[::2]`` where `indices` is
+ ``range(len(array) - 1)`` with a zero placed
+ in every other element:
+ ``indices = zeros(2 * len(array) - 1)``,
+ ``indices[1::2] = range(1, len(array))``.
+
+ Don't be fooled by this attribute's name: `reduceat(array)` is not
+ necessarily smaller than `array`.
+
+ Examples
+ --------
+ To take the running sum of four successive values:
+
+ >>> np.add.reduceat(np.arange(8),[0,4, 1,5, 2,6, 3,7])[::2]
+ array([ 6, 10, 14, 18])
+
+ A 2-D example:
+
+ >>> x = np.linspace(0, 15, 16).reshape(4,4)
+ >>> x
+ array([[ 0., 1., 2., 3.],
+ [ 4., 5., 6., 7.],
+ [ 8., 9., 10., 11.],
+ [12., 13., 14., 15.]])
+
+ ::
+
+ # reduce such that the result has the following five rows:
+ # [row1 + row2 + row3]
+ # [row4]
+ # [row2]
+ # [row3]
+ # [row1 + row2 + row3 + row4]
+
+ >>> np.add.reduceat(x, [0, 3, 1, 2, 0])
+ array([[12., 15., 18., 21.],
+ [12., 13., 14., 15.],
+ [ 4., 5., 6., 7.],
+ [ 8., 9., 10., 11.],
+ [24., 28., 32., 36.]])
+
+ ::
+
+ # reduce such that result has the following two columns:
+ # [col1 * col2 * col3, col4]
+
+ >>> np.multiply.reduceat(x, [0, 3], 1)
+ array([[ 0., 3.],
+ [ 120., 7.],
+ [ 720., 11.],
+ [2184., 15.]])
+
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('outer',
+ r"""
+ outer(A, B, /, **kwargs)
+
+ Apply the ufunc `op` to all pairs (a, b) with a in `A` and b in `B`.
+
+ Let ``M = A.ndim``, ``N = B.ndim``. Then the result, `C`, of
+ ``op.outer(A, B)`` is an array of dimension M + N such that:
+
+ .. math:: C[i_0, ..., i_{M-1}, j_0, ..., j_{N-1}] =
+ op(A[i_0, ..., i_{M-1}], B[j_0, ..., j_{N-1}])
+
+ For `A` and `B` one-dimensional, this is equivalent to::
+
+ r = empty(len(A),len(B))
+ for i in range(len(A)):
+ for j in range(len(B)):
+ r[i,j] = op(A[i], B[j]) # op = ufunc in question
+
+ Parameters
+ ----------
+ A : array_like
+ First array
+ B : array_like
+ Second array
+ kwargs : any
+ Arguments to pass on to the ufunc. Typically `dtype` or `out`.
+
+ Returns
+ -------
+ r : ndarray
+ Output array
+
+ See Also
+ --------
+ numpy.outer : A less powerful version of ``np.multiply.outer``
+ that `ravel`\ s all inputs to 1D. This exists
+ primarily for compatibility with old code.
+
+ tensordot : ``np.tensordot(a, b, axes=((), ()))`` and
+ ``np.multiply.outer(a, b)`` behave same for all
+ dimensions of a and b.
+
+ Examples
+ --------
+ >>> np.multiply.outer([1, 2, 3], [4, 5, 6])
+ array([[ 4, 5, 6],
+ [ 8, 10, 12],
+ [12, 15, 18]])
+
+ A multi-dimensional example:
+
+ >>> A = np.array([[1, 2, 3], [4, 5, 6]])
+ >>> A.shape
+ (2, 3)
+ >>> B = np.array([[1, 2, 3, 4]])
+ >>> B.shape
+ (1, 4)
+ >>> C = np.multiply.outer(A, B)
+ >>> C.shape; C
+ (2, 3, 1, 4)
+ array([[[[ 1, 2, 3, 4]],
+ [[ 2, 4, 6, 8]],
+ [[ 3, 6, 9, 12]]],
+ [[[ 4, 8, 12, 16]],
+ [[ 5, 10, 15, 20]],
+ [[ 6, 12, 18, 24]]]])
+
+ """))
+
+add_newdoc('numpy.core', 'ufunc', ('at',
+ """
+ at(a, indices, b=None, /)
+
+ Performs unbuffered in place operation on operand 'a' for elements
+ specified by 'indices'. For addition ufunc, this method is equivalent to
+ ``a[indices] += b``, except that results are accumulated for elements that
+ are indexed more than once. For example, ``a[[0,0]] += 1`` will only
+ increment the first element once because of buffering, whereas
+ ``add.at(a, [0,0], 1)`` will increment the first element twice.
+
+ .. versionadded:: 1.8.0
+
+ Parameters
+ ----------
+ a : array_like
+ The array to perform in place operation on.
+ indices : array_like or tuple
+ Array like index object or slice object for indexing into first
+ operand. If first operand has multiple dimensions, indices can be a
+ tuple of array like index objects or slice objects.
+ b : array_like
+ Second operand for ufuncs requiring two operands. Operand must be
+ broadcastable over first operand after indexing or slicing.
+
+ Examples
+ --------
+ Set items 0 and 1 to their negative values:
+
+ >>> a = np.array([1, 2, 3, 4])
+ >>> np.negative.at(a, [0, 1])
+ >>> a
+ array([-1, -2, 3, 4])
+
+ Increment items 0 and 1, and increment item 2 twice:
+
+ >>> a = np.array([1, 2, 3, 4])
+ >>> np.add.at(a, [0, 1, 2, 2], 1)
+ >>> a
+ array([2, 3, 5, 4])
+
+ Add items 0 and 1 in first array to second array,
+ and store results in first array:
+
+ >>> a = np.array([1, 2, 3, 4])
+ >>> b = np.array([1, 2])
+ >>> np.add.at(a, [0, 1], b)
+ >>> a
+ array([2, 4, 3, 4])
+
+ """))
+
+##############################################################################
+#
+# Documentation for dtype attributes and methods
+#
+##############################################################################
+
+##############################################################################
+#
+# dtype object
+#
+##############################################################################
+
+add_newdoc('numpy.core.multiarray', 'dtype',
+ """
+ dtype(dtype, align=False, copy=False)
+
+ Create a data type object.
+
+ A numpy array is homogeneous, and contains elements described by a
+ dtype object. A dtype object can be constructed from different
+ combinations of fundamental numeric types.
+
+ Parameters
+ ----------
+ dtype
+ Object to be converted to a data type object.
+ align : bool, optional
+ Add padding to the fields to match what a C compiler would output
+ for a similar C-struct. Can be ``True`` only if `obj` is a dictionary
+ or a comma-separated string. If a struct dtype is being created,
+ this also sets a sticky alignment flag ``isalignedstruct``.
+ copy : bool, optional
+ Make a new copy of the data-type object. If ``False``, the result
+ may just be a reference to a built-in data-type object.
+
+ See also
+ --------
+ result_type
+
+ Examples
+ --------
+ Using array-scalar type:
+
+ >>> np.dtype(np.int16)
+ dtype('int16')
+
+ Structured type, one field name 'f1', containing int16:
+
+ >>> np.dtype([('f1', np.int16)])
+ dtype([('f1', '>> np.dtype([('f1', [('f1', np.int16)])])
+ dtype([('f1', [('f1', '>> np.dtype([('f1', np.uint64), ('f2', np.int32)])
+ dtype([('f1', '>> np.dtype([('a','f8'),('b','S10')])
+ dtype([('a', '>> np.dtype("i4, (2,3)f8")
+ dtype([('f0', '>> np.dtype([('hello',(np.int64,3)),('world',np.void,10)])
+ dtype([('hello', '>> np.dtype((np.int16, {'x':(np.int8,0), 'y':(np.int8,1)}))
+ dtype((numpy.int16, [('x', 'i1'), ('y', 'i1')]))
+
+ Using dictionaries. Two fields named 'gender' and 'age':
+
+ >>> np.dtype({'names':['gender','age'], 'formats':['S1',np.uint8]})
+ dtype([('gender', 'S1'), ('age', 'u1')])
+
+ Offsets in bytes, here 0 and 25:
+
+ >>> np.dtype({'surname':('S25',0),'age':(np.uint8,25)})
+ dtype([('surname', 'S25'), ('age', 'u1')])
+
+ """)
+
+##############################################################################
+#
+# dtype attributes
+#
+##############################################################################
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('alignment',
+ """
+ The required alignment (bytes) of this data-type according to the compiler.
+
+ More information is available in the C-API section of the manual.
+
+ Examples
+ --------
+
+ >>> x = np.dtype('i4')
+ >>> x.alignment
+ 4
+
+ >>> x = np.dtype(float)
+ >>> x.alignment
+ 8
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('byteorder',
+ """
+ A character indicating the byte-order of this data-type object.
+
+ One of:
+
+ === ==============
+ '=' native
+ '<' little-endian
+ '>' big-endian
+ '|' not applicable
+ === ==============
+
+ All built-in data-type objects have byteorder either '=' or '|'.
+
+ Examples
+ --------
+
+ >>> dt = np.dtype('i2')
+ >>> dt.byteorder
+ '='
+ >>> # endian is not relevant for 8 bit numbers
+ >>> np.dtype('i1').byteorder
+ '|'
+ >>> # or ASCII strings
+ >>> np.dtype('S2').byteorder
+ '|'
+ >>> # Even if specific code is given, and it is native
+ >>> # '=' is the byteorder
+ >>> import sys
+ >>> sys_is_le = sys.byteorder == 'little'
+ >>> native_code = sys_is_le and '<' or '>'
+ >>> swapped_code = sys_is_le and '>' or '<'
+ >>> dt = np.dtype(native_code + 'i2')
+ >>> dt.byteorder
+ '='
+ >>> # Swapped code shows up as itself
+ >>> dt = np.dtype(swapped_code + 'i2')
+ >>> dt.byteorder == swapped_code
+ True
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('char',
+ """A unique character code for each of the 21 different built-in types.
+
+ Examples
+ --------
+
+ >>> x = np.dtype(float)
+ >>> x.char
+ 'd'
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('descr',
+ """
+ `__array_interface__` description of the data-type.
+
+ The format is that required by the 'descr' key in the
+ `__array_interface__` attribute.
+
+ Warning: This attribute exists specifically for `__array_interface__`,
+ and passing it directly to `np.dtype` will not accurately reconstruct
+ some dtypes (e.g., scalar and subarray dtypes).
+
+ Examples
+ --------
+
+ >>> x = np.dtype(float)
+ >>> x.descr
+ [('', '>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
+ >>> dt.descr
+ [('name', '>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
+ >>> print(dt.fields)
+ {'grades': (dtype(('float64',(2,))), 16), 'name': (dtype('|S16'), 0)}
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('flags',
+ """
+ Bit-flags describing how this data type is to be interpreted.
+
+ Bit-masks are in `numpy.core.multiarray` as the constants
+ `ITEM_HASOBJECT`, `LIST_PICKLE`, `ITEM_IS_POINTER`, `NEEDS_INIT`,
+ `NEEDS_PYAPI`, `USE_GETITEM`, `USE_SETITEM`. A full explanation
+ of these flags is in C-API documentation; they are largely useful
+ for user-defined data-types.
+
+ The following example demonstrates that operations on this particular
+ dtype requires Python C-API.
+
+ Examples
+ --------
+
+ >>> x = np.dtype([('a', np.int32, 8), ('b', np.float64, 6)])
+ >>> x.flags
+ 16
+ >>> np.core.multiarray.NEEDS_PYAPI
+ 16
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('hasobject',
+ """
+ Boolean indicating whether this dtype contains any reference-counted
+ objects in any fields or sub-dtypes.
+
+ Recall that what is actually in the ndarray memory representing
+ the Python object is the memory address of that object (a pointer).
+ Special handling may be required, and this attribute is useful for
+ distinguishing data types that may contain arbitrary Python objects
+ and data-types that won't.
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('isbuiltin',
+ """
+ Integer indicating how this dtype relates to the built-in dtypes.
+
+ Read-only.
+
+ = ========================================================================
+ 0 if this is a structured array type, with fields
+ 1 if this is a dtype compiled into numpy (such as ints, floats etc)
+ 2 if the dtype is for a user-defined numpy type
+ A user-defined type uses the numpy C-API machinery to extend
+ numpy to handle a new array type. See
+ :ref:`user.user-defined-data-types` in the NumPy manual.
+ = ========================================================================
+
+ Examples
+ --------
+ >>> dt = np.dtype('i2')
+ >>> dt.isbuiltin
+ 1
+ >>> dt = np.dtype('f8')
+ >>> dt.isbuiltin
+ 1
+ >>> dt = np.dtype([('field1', 'f8')])
+ >>> dt.isbuiltin
+ 0
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('isnative',
+ """
+ Boolean indicating whether the byte order of this dtype is native
+ to the platform.
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('isalignedstruct',
+ """
+ Boolean indicating whether the dtype is a struct which maintains
+ field alignment. This flag is sticky, so when combining multiple
+ structs together, it is preserved and produces new dtypes which
+ are also aligned.
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('itemsize',
+ """
+ The element size of this data-type object.
+
+ For 18 of the 21 types this number is fixed by the data-type.
+ For the flexible data-types, this number can be anything.
+
+ Examples
+ --------
+
+ >>> arr = np.array([[1, 2], [3, 4]])
+ >>> arr.dtype
+ dtype('int64')
+ >>> arr.itemsize
+ 8
+
+ >>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
+ >>> dt.itemsize
+ 80
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('kind',
+ """
+ A character code (one of 'biufcmMOSUV') identifying the general kind of data.
+
+ = ======================
+ b boolean
+ i signed integer
+ u unsigned integer
+ f floating-point
+ c complex floating-point
+ m timedelta
+ M datetime
+ O object
+ S (byte-)string
+ U Unicode
+ V void
+ = ======================
+
+ Examples
+ --------
+
+ >>> dt = np.dtype('i4')
+ >>> dt.kind
+ 'i'
+ >>> dt = np.dtype('f8')
+ >>> dt.kind
+ 'f'
+ >>> dt = np.dtype([('field1', 'f8')])
+ >>> dt.kind
+ 'V'
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('metadata',
+ """
+ Either ``None`` or a readonly dictionary of metadata (mappingproxy).
+
+ The metadata field can be set using any dictionary at data-type
+ creation. NumPy currently has no uniform approach to propagating
+ metadata; although some array operations preserve it, there is no
+ guarantee that others will.
+
+ .. warning::
+
+ Although used in certain projects, this feature was long undocumented
+ and is not well supported. Some aspects of metadata propagation
+ are expected to change in the future.
+
+ Examples
+ --------
+
+ >>> dt = np.dtype(float, metadata={"key": "value"})
+ >>> dt.metadata["key"]
+ 'value'
+ >>> arr = np.array([1, 2, 3], dtype=dt)
+ >>> arr.dtype.metadata
+ mappingproxy({'key': 'value'})
+
+ Adding arrays with identical datatypes currently preserves the metadata:
+
+ >>> (arr + arr).dtype.metadata
+ mappingproxy({'key': 'value'})
+
+ But if the arrays have different dtype metadata, the metadata may be
+ dropped:
+
+ >>> dt2 = np.dtype(float, metadata={"key2": "value2"})
+ >>> arr2 = np.array([3, 2, 1], dtype=dt2)
+ >>> (arr + arr2).dtype.metadata is None
+ True # The metadata field is cleared so None is returned
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('name',
+ """
+ A bit-width name for this data-type.
+
+ Un-sized flexible data-type objects do not have this attribute.
+
+ Examples
+ --------
+
+ >>> x = np.dtype(float)
+ >>> x.name
+ 'float64'
+ >>> x = np.dtype([('a', np.int32, 8), ('b', np.float64, 6)])
+ >>> x.name
+ 'void640'
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('names',
+ """
+ Ordered list of field names, or ``None`` if there are no fields.
+
+ The names are ordered according to increasing byte offset. This can be
+ used, for example, to walk through all of the named fields in offset order.
+
+ Examples
+ --------
+ >>> dt = np.dtype([('name', np.str_, 16), ('grades', np.float64, (2,))])
+ >>> dt.names
+ ('name', 'grades')
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('num',
+ """
+ A unique number for each of the 21 different built-in types.
+
+ These are roughly ordered from least-to-most precision.
+
+ Examples
+ --------
+
+ >>> dt = np.dtype(str)
+ >>> dt.num
+ 19
+
+ >>> dt = np.dtype(float)
+ >>> dt.num
+ 12
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('shape',
+ """
+ Shape tuple of the sub-array if this data type describes a sub-array,
+ and ``()`` otherwise.
+
+ Examples
+ --------
+
+ >>> dt = np.dtype(('i4', 4))
+ >>> dt.shape
+ (4,)
+
+ >>> dt = np.dtype(('i4', (2, 3)))
+ >>> dt.shape
+ (2, 3)
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('ndim',
+ """
+ Number of dimensions of the sub-array if this data type describes a
+ sub-array, and ``0`` otherwise.
+
+ .. versionadded:: 1.13.0
+
+ Examples
+ --------
+ >>> x = np.dtype(float)
+ >>> x.ndim
+ 0
+
+ >>> x = np.dtype((float, 8))
+ >>> x.ndim
+ 1
+
+ >>> x = np.dtype(('i4', (3, 4)))
+ >>> x.ndim
+ 2
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('str',
+ """The array-protocol typestring of this data-type object."""))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('subdtype',
+ """
+ Tuple ``(item_dtype, shape)`` if this `dtype` describes a sub-array, and
+ None otherwise.
+
+ The *shape* is the fixed shape of the sub-array described by this
+ data type, and *item_dtype* the data type of the array.
+
+ If a field whose dtype object has this attribute is retrieved,
+ then the extra dimensions implied by *shape* are tacked on to
+ the end of the retrieved array.
+
+ See Also
+ --------
+ dtype.base
+
+ Examples
+ --------
+ >>> x = numpy.dtype('8f')
+ >>> x.subdtype
+ (dtype('float32'), (8,))
+
+ >>> x = numpy.dtype('i2')
+ >>> x.subdtype
+ >>>
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('base',
+ """
+ Returns dtype for the base element of the subarrays,
+ regardless of their dimension or shape.
+
+ See Also
+ --------
+ dtype.subdtype
+
+ Examples
+ --------
+ >>> x = numpy.dtype('8f')
+ >>> x.base
+ dtype('float32')
+
+ >>> x = numpy.dtype('i2')
+ >>> x.base
+ dtype('int16')
+
+ """))
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('type',
+ """The type object used to instantiate a scalar of this data-type."""))
+
+##############################################################################
+#
+# dtype methods
+#
+##############################################################################
+
+add_newdoc('numpy.core.multiarray', 'dtype', ('newbyteorder',
+ """
+ newbyteorder(new_order='S', /)
+
+ Return a new dtype with a different byte order.
+
+ Changes are also made in all fields and sub-arrays of the data type.
+
+ Parameters
+ ----------
+ new_order : string, optional
+ Byte order to force; a value from the byte order specifications
+ below. The default value ('S') results in swapping the current
+ byte order. `new_order` codes can be any of:
+
+ * 'S' - swap dtype from current to opposite endian
+ * {'<', 'little'} - little endian
+ * {'>', 'big'} - big endian
+ * '=' - native order
+ * {'|', 'I'} - ignore (no change to byte order)
+
+ Returns
+ -------
+ new_dtype : dtype
+ New dtype object with the given change to the byte order.
+
+ Notes
+ -----
+ Changes are also made in all fields and sub-arrays of the data type.
+
+ Examples
+ --------
+ >>> import sys
+ >>> sys_is_le = sys.byteorder == 'little'
+ >>> native_code = sys_is_le and '<' or '>'
+ >>> swapped_code = sys_is_le and '>' or '<'
+ >>> native_dt = np.dtype(native_code+'i2')
+ >>> swapped_dt = np.dtype(swapped_code+'i2')
+ >>> native_dt.newbyteorder('S') == swapped_dt
+ True
+ >>> native_dt.newbyteorder() == swapped_dt
+ True
+ >>> native_dt == swapped_dt.newbyteorder('S')
+ True
+ >>> native_dt == swapped_dt.newbyteorder('=')
+ True
+ >>> native_dt == swapped_dt.newbyteorder('N')
+ True
+ >>> native_dt == native_dt.newbyteorder('|')
+ True
+ >>> np.dtype('