0.6.0
-----
    This release replaces boto with boto3. This library upgrade required renaming
    several public and private items. In order to simplify code and ease upgrading,
    using the old names will cause Exceptions to be raised. Py2 support is
    maintained for users with legacy projects.

    * switched to boto3
    * renames:
     * `._s3Connection` -> `._s3_client`
     * `.s3_connection` -> `.s3_client`
     * `bucket_public_headers` -> `boto3_ExtraArgs_default_public`
     * `bucket_archive_headers` -> `boto3_ExtraArgs_default_archive`

    Please note the former "*_headers" configurations now use the boto3 arguments
    for `ExtraArgs`.
    For example:

        - bucket_public_headers={
        -   "x-amz-acl": "public-read"
        -    "Cache-Control": "max-age=5184000",
        - }

    is now:

        + boto3_ExtraArgs_default_public={
        +    "ACL": "public-read",
        +    "CacheControl": "max-age=5184000",
        + }

    The `boto3_ExtraArgs_*` configurations are passed directly to boto3 as `ExtraArgs`
    
    * imagehelper.saver.s3 now has `NonCloseableBufferedReader()` a helper class to get around a boto3 bug.  see source, tests and demo for more information.

    * Dealing with files/filelike objects was an "elegant hack" under Python2. With Python2+Python3 side-by-side support it became messy. Thanks to a workaround needed for a bug in the botocore/s3 transfer library, this was standardized to use `io.xxx` classes and is much cleaner.

0.5.3
    2021.04.07
    * improved imports
    * Python2 now recognizes `io.IOBase`

0.5.2
    2021.03.25
    * packaging layout

0.5.1
    2020.10.20
    * upgraded black
    * integrated with pre-commit

0.5.0
-----
2019.08.02
This was going to be 0.4.5, but a new kwarg was added to the localfile logger which may be backwards incompatible
* moved tests and test-data
* cleaned up Python exceptions
* cleaned up docstrings
* added new `errors.ImageError_InstructionsError`
* added some tests, specifically for localfile and s3 "simple saving"
* localfile saving now logs the "filepath" (new kwarg to logger)
* adopted black formatting

0.4.2
-----
* improvements to autodetect

0.4.0
-----
2019.04.28
* python3 support
* the way commandline optimization libraries are called/setup has drastically changed. instead of multiple variables being used to control this, they are now in a single `OPTIMIZE_SUPPORT`. they are also autodetected. this ensures we do not run programs that do not exist on an operating system.
* added tests to ensure the resizer doesn't have null objects

0.3.0
-----
* looks okay after a few months

0.3.0rc9
0.3.0rc8
------------------
* distribution issue. MANIFEST kept ignoring /saver

0.3.0rc7
------------------
* making selected_resizes mutable
* making filename detection a bit more lenient

0.3.0rc6
------------------
* retooled resizer logic so that an "original" image can be independently resized

0.3.0rc5
------------------
* adding support for image animation detection; TODO - resize animated images
* image optimization:
    * cleaned up code
    * documented functionality
    * brought in line with current ImageOptim settings
    * added package-wide overrides

0.3.0rc4
------------------
* adding 'dry_run' option for testing


0.3.0rc3
------------------
* missed `size` arg.  this should not have passed tests.

0.3.0rc2
------------------
* in the cases of ORIGINAL/AUTODETECT image deleting, `generate_filenames` did not have the appropriate data

0.3.0rc1
------------------
This release is not backwards compatible.
In order to better support alternate save methods (not s3), the S3 classes were nested into a 'saver' namespace
* adding s3_localfile for testing with local files (instead of uploads)
* `imagehelper.s3` is now `imagehelper.saver.s3`
* renamed `imagehelper.saver.s3.S3Logger().log_upload` to `log_save`
* renamed `imagehelper.saver.s3.S3Logger` to `SaverLoger`
* renamed `imagehelper.saver.s3.S3Config` to `SaverConfig`
* renamed `imagehelper.saver.s3.S3ManagerFactory` to `SaverManagerFactory`
* renamed `imagehelper.saver.s3.S3Manager` to `SaverManager`

* renamed `imagehelper.saver.s3.S3SimpleAccess` to `SaverSimpleAccess`
* renamed `imagehelper.saver.s3._S3CoreManager` to `SaverCoreManager`
* added `ImageError_SaverUpload` as parent class of `ImageError_S3Upload`
* renamed `imagehelper.saver.s3._SaverCoreManager.s3_delete` to `files_delete`
* renamed `imagehelper.saver.s3.SaverManager.files_save` to `files_save`
* renamed `imagehelper.saver.s3.SaverSimpleAccess.s3_file_upload` to `file_save`
* renamed most `._s3Config` to `_saverConfig`
* renamed most `._s3Logger` to `_saverLogger`
* renamed most `.s3_manager` to `saver_manager`
* renamed most `.s3_simple_access` to `saver_simple_access`
* renamed most `.simple_uploads_mapping` to `simple_saves_mapping`



0.2.1
------------------
* adding in support for pass-through uploads/encoding
* resizer config "constraint-method='passthrough:no-resize'" will not apply any size transformations
* resizer config "format='auto'" will encode based on source.  GIF/PNG as PNG; all others as JPEG


0.2.0 rc 2
------------------
* fixed demo.py to pass in the right optimize params.  it was not inline with the test
* flake8


0.2.0 rc 1
------------------
* backwards incompatible changes
* gutted `image_wrapper.py`:
* multiple classes in `image_wrapper` now inherit from BasicImage, which wraps teh file
* `WrappedImage` now contains a `basicImage` and `pilObject`.
* multiple functions in `WrappedImage` removed.  functions previously hitting `WrappedImage` should call the attributes of `WrappedImage.basicImage`
* `BasicImage` can "optimize" an image. this is accomplished by piping the data into gifsicle, pngcrush, jpegtran.  This can be run on original and resize
* resizerConfig , resize and register_image_file now require information on optimizing the original & resize.  NOTE - large images can take some time!
* NOTE - the optimization will not work on windows. this is because it uses NamedTemporaryFile to create files.
* now requires `envoy`, which makes using the subprocess module a bit better.


0.1.0 rc 10
------------------
* better checking of supported types
* allowing a prefeerence for file-like objects to be configured

0.1.0 rc 9
------------------
* added `utils.PIL_type_to_extension`
* added `image_wrapper.ResizedImage.file_extension`; proxies call to `utils.PIL_type_to_extension`
* added `image_wrapper.FakedOriginal.file_extension`; proxies call to `utils.PIL_type_to_extension`


0.1.0 rc 8
------------------
* docs change to illustrate allowing factory managers to upload archive or resizes only


0.1.0 rc 7
------------------
* updated demo.py to reflect current narrative docs
* added `imagehelper.image_wrapper.ResizedImage().file_b64`
* added `imagehelper.image_wrapper.ImageWrapper().file_b64`
* added `imagehelper.utils.file_b64`
* added `imagehelper.utils.b64_decode_to_file`
* updated `imagehelper.resizer.ResizerFactory().resizer()` now accepts `file_b64` data
* updated `imagehelper.resizer.Resizer().register_image_file()` now accepts `file_b64` data


0.1.0 rc 6
------------------
* refactored `imagehelper.s3.S3Uploader`
** new base class `_S3CoreManager` for `_S3Manager` and new class `S3SimpleAccess`
** base class houses `s3_connection` , `s3_buckets` , `s3_delete`
* new class `imagehelper.s3.S3SimpleAccess`
** `imagehelper.s3.S3SimpleAccess().file_upload()` upload a single file/bucket
** `imagehelper.s3.S3SimpleAccess().simple_uploads_mapping()` generates a `s3_uploads` compatible dict for deletion

0.1.0 rc 5
------------------
* updated docs for deleting
* renamed `imagehelper.resize.Resizer().fake_resultset()` to `imagehelper.resize.Resizer().fake_resize()`
* removed `imagehelper.resize.Resizer().reset()`. this should never be done.
* added `imagehelper.resize.Resizer().get_original()`. proxies to the internal image object
* renamed `imagehelper.resize.Resizer().image` to `imagehelper.resize.Resizer()._image`
* renamed `imagehelper.resize.Resizer().resizerConfig` to `imagehelper.resize.Resizer()._resizerConfig`



0.1.0 rc 4
------------------
* renamed `imagehelper.s3.S3Uploader()` to `imagehelper.s3.S3Manager()`
* added `imagehelper.s3.S3ManagerFactory()` class to generate `S3Manager` instances via `s3_manager()` method.


0.1.0 rc 3
------------------
* added `imagehelper.resizer.ResizerFactory.resizer(imagefile=None)` to return a new resizer object.  this is useful for validating a file.
* fixed location of error codes; were moved to `utils` from (deprecated) `constants`
* removed `imagehelper.image_wrapper.ImageObject().imageObject_mode`
* renamed `imagehelper.resizer.Resizer().imageWrapper` to  `imagehelper.image_wrapper.`imagehelper.resizer.Resizer().image`
* added proxied properties to `imagehelper.image_wrapper.ImageObject`
** name = self.imageObject_name
** mode = self.imageObject.mode
** size = self.imageObject.size
** format = self.imageObject.format
** format_standardized = utils.PIL_type_to_standardized( self.imageObject.format )
* renamed `imagehelper.resize.ResizedImage().filesize` to `file_size`
* added `imagehelper.utils.file_md5`
* added `imagehelper.resize.ResizedImage().file_md5`
* added `imagehelper.utils._standardized_to_PIL_type`
* added `imagehelper.utils.standardized_to_PIL_type()`
* added `imagehelper.image_wrapper.FakedOriginal()`
* added `imagehelper.resize.Resizer().fake_resultset()` to generate a resultset compatible with s3 operations ( specifically delete )
* renamed `imagehelper.s3.S3Logger().log_upload` is now passed `file_size` instead of `filesize`
* addded `imagehelper.s3.S3Logger().log_upload` is now passed `file_md5`
* removed `imagehelper.resize.ResizeFactory().resize()` ; the factory should only return configured `imagehelper.resize.Resize()` objects, not proxy actions to them



0.1.0 rc 2
------------------
* standardized kwargs and attributes of config objects to be camelCase for instances
* renamed `image_resizes` to `resizesSchema`
* renamed `image_resizes_selected` to `selected_resizes`
* added tests for image resizing

0.1.0 rc 1
------------------
* THIS TOTALLY AND ENTIRELY BREAKS PRIOR INTEGRATIONS
* simplifying interface
* splitting code into multiple files with better organization
* supporting Pillow , as PIL isn't really used by many people
* cleaning up S3 interface
* this entirely breaks older versions
* the older schema definitions ( dicts ) remain unchanged. the python
  integration has completely changed
* started adding tests

notable changes :

* classes have been logically separated into different namespaces
* resizing does not automatically upload to s3 anymore. you must chain this
  in your own code
* s3logger objects
** kwarg `bucket` is now `bucket_name`
** kwarg `filesize` is now sent on upload



0.0.4 (2012-06-07)
------------------
- fixed setup script


0.0.3 (2012-03-25)
------------------
- not backwards compatible. sorry.

# Tracking the "archive" image was changed.

1. photo_sizes now reserve an initial @ character for internal usage
2. archived fullsize images are now tracked as:

    dict[bucket_name]['@archive'][filename]

before there was a dual-use dict, that was just hard to manage

    dict[public_bucket_name][size][filename]
    dict[archive_bucket_name][filename]

this created issues where you couldn't save the archived image to the same s3 bucket.  now you can.

# added s3_generate_filenames

this call just generates the filenames that would be saved to s3.
this is necessary for deletion or external auditing of your uploads

# added s3_delete

you can now delete s3 files

# this still doesn't have proper tests

check the demo.py


0.0.2 (2012-03-23)
------------------
- corrected error in handling of failed items.  created a check for DictType and StringTypes.

0.0.1 (2012-03-14)
------------------
- initial release
